openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
build_info.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 # use encoding=utf8
3 # ----------------------------------------------------------------------------
4 # openCARP is an open cardiac electrophysiology simulator.
5 #
6 # Copyright (C) 2020 openCARP project
7 #
8 # This program is licensed under the openCARP Academic Public License (APL)
9 # v1.0: You can use and redistribute it and/or modify it in non-commercial
10 # academic environments under the terms of APL as published by the openCARP
11 # project v1.0, or (at your option) any later version. Commercial use requires
12 # a commercial license (info@opencarp.org).
13 #
14 # This program is distributed without any warranty; see the openCARP APL for
15 # more details.
16 #
17 # You should have received a copy of the openCARP APL along with this program
18 # and can find it online: http://www.opencarp.org/license
19 # ----------------------------------------------------------------------------
20 
21 """
22 Generate a C header file defining some information about the build.
23 """
24 
25 import os
26 import sys
27 import subprocess
28 
29 def run(cmd, env={}):
30  """
31  Run a command with subprocess and return the stdout.
32 
33  Avoiding use of subprocess.check_output to maintain backwards
34  compatibility.
35  """
36  proc = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE)
37  out = proc.communicate()
38  if proc.returncode != 0:
39  tpl = 'execution of command "{0}" failed'
40  raise Exception(tpl.format(' '.join(cmd)))
41  return out[0]
42 
43 def locale():
44  """
45  Determine the locale to use in SVN.
46  """
47 
48  de = None
49 
50  for line in run(['locale', '-a']).split('\n'):
51 
52  entry = line.strip()
53 
54  if entry.startswith('en'):
55  return entry
56 
57  if entry.startswith('de'):
58  de = entry
59 
60  # German a good fallback as 'revision' and 'relative url' are the same
61  if de is not None:
62  return de
63 
64  # If all else fails
65  return 'C'
66 
67 SVN_NAME_MAPPING = {'RĂ©vision': 'Revision'}
68 
69 def svn(directory='.'):
70  """
71  Get information about the SVN repository.
72 
73  Uses the --show-item syntax instead of parsing the normal svn info output
74  to avoid issues with language locales.
75  """
76 
77  start_wd = os.getcwd()
78 
79  os.chdir(directory)
80  result = run(['svn', 'info'], env={'LC_MESSAGES': locale()})
81  os.chdir(start_wd)
82 
83  info = {}
84 
85  for line in result.split('\n'):
86 
87  try:
88  name, value = line.split(': ')
89  except ValueError:
90  continue
91 
92  # Translate where necessary
93  name = SVN_NAME_MAPPING.get(name.strip(), name.strip())
94  name = name.lower().replace(' ', '-')
95 
96  info[name] = value.strip()
97 
98  if name == 'revision':
99  info['commit'] = info[name]
100 
101  return info
102 
103 def git(directory='.'):
104  start_wd = os.getcwd()
105  os.chdir(directory)
106  info = {}
107 
108  # get the git revision count
109  result = run(['git', 'rev-list', '--all', '--count'])
110  info['revision'] = str(int(result));
111 
112  # get commit hash
113  result = run(['git', 'rev-parse', 'HEAD'])
114  result = result[0:len(result)-1]
115  info['commit'] = result.decode('ascii')
116 
117  # get the git tag
118  result = run(['git', 'describe', '--tags', '--always'])
119  result = result[0:len(result)-1]
120  info['tag'] = result.decode('ascii')
121 
122  # get the git remote url
123  result = run(['git', 'remote', '-v'])
124 
125  for line in result.decode('ascii').split('\n'):
126  line = ' '.join(line.split())
127 
128  try:
129  alias, path, direction = line.split(' ')
130  except ValueError:
131  continue
132 
133  if alias == 'origin':
134  info['url'] = path
135 
136  # the subrepo is just '.'
137  info['subrepo'] = '.'
138 
139  os.chdir(start_wd)
140 
141  return info
142 
143 
144 
145 TEMPLATE = """#ifndef __BUILD_INFO__
146 #define __BUILD_INFO__
147 
148 #define GIT_COMMIT_TAG "{tag}"
149 #define GIT_COMMIT_HASH "{commit}"
150 #define GIT_COMMIT_COUNT {revision}
151 #define GIT_PATH "{url}"
152 
153 #define SUBREPO_REVISIONS "{subrepo}"
154 
155 #define SUBREPO_COMMITS "{subrepocommit}"
156 
157 #endif
158 """
159 
160 def generate():
161 
162  # check whether we are in a git repo
163  if subprocess.call(["git", "branch"], stderr=subprocess.STDOUT, stdout=open(os.devnull, 'w')) == 0:
164  info = git(os.path.dirname(os.path.abspath(__file__)))
165 
166  # Get subrepo info
167  repo_versions = []
168  repo_commits = []
169 
170  # we currently have no sub-repos. still, we leave the mechanism in here for later
171  # repo_versions.append(('slimfem', git('../fem/slimfem')['revision']))
172  # repo_commits.append(( 'slimfem', git('../fem/slimfem')['commit']))
173 
174  info['subrepo'] = ','.join(['{0[0]}={0[1]}'.format(v) for v in repo_versions])
175 
176  # Assemble commit hashes / revisions
177  newline = '," \\\n' + ' ' * 24 + '"'
178  info['subrepocommit'] = newline.join(['{0[0]}={0[1]}'.format(v) for v in repo_commits])
179 
180  else:
181  info = {}
182  info['tag'] = "built outside a repository"
183  info['commit'] = "built outside a repository"
184  info['revision'] = 0
185  info['url'] = "https://git.opencarp.org/openCARP/openCARP.git"
186  info['subrepo'] = ""
187  info['subrepocommit'] = ""
188 
189  return TEMPLATE.format(**info)
190 
191 def print_build_info(filename):
192  """
193  print build info
194  """
195  git_info = generate()
196  update_file = True
197 
198  # check if there's a change of the build info if the file already exists
199  if os.path.isfile(filename):
200  with open(filename, 'r') as myfile:
201  info_h = myfile.read()
202  if info_h == git_info:
203  update_file = False
204 
205  # write build info file
206  if update_file:
207  f = open(filename, "w")
208  f.write(git_info)
209 
210 if __name__ == '__main__':
211  if(len(sys.argv) > 1):
212  filename = sys.argv[1]
213  else:
214  filename = 'build_info.h'
215  print_build_info(filename)
def print_build_info(filename)
Definition: build_info.py:191
def svn(directory='.')
Definition: build_info.py:69
def locale()
Definition: build_info.py:43
def run(cmd, env={})
Definition: build_info.py:29
def generate()
Definition: build_info.py:160
def git(directory='.')
Definition: build_info.py:103