All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
update_versions.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 __author__ = "Marco Clemencic <Marco.Clemencic@cern.ch>"
4 __version__ = "$Id: update_versions.py,v 1.3 2008/11/10 19:43:31 marcocle Exp $"
5 
6 import os, re, sys, time
7 
8 # special_packages = [ "Gaudi", "GaudiSys", "GaudiExamples" ]
9 
10 # guess current version
11 _req_version_pattern = re.compile(r"^\s*version\s*(v[0-9]+r[0-9]+(?:p[0-9]+)?)\s*$")
12 _cml_version_pattern = re.compile(r"^\s*gaudi_subdir\s*\(\s*\S+\s+(v[0-9]+r[0-9]+(?:p[0-9]+)?)\)\s*$")
13 def extract_version(path):
14  """
15  Find the version number of a subdirectory.
16  """
17  global _cml_version_pattern
18  for l in open(os.path.join(path, 'CMakeLists.txt')):
19  m = _cml_version_pattern.match(l)
20  if m:
21  return m.group(1)
22  return None
23 
24 def change_cml_version(cml, newversion):
25  if os.path.exists(cml):
26  out = []
27  changed = False
28  for l in open(cml):
29  m = _cml_version_pattern.match(l)
30  if m and m.group(1) != newversion:
31  print "%s: %s -> %s"%(cml, m.group(1), newversion)
32  l = l.replace(m.group(1), newversion)
33  changed = True
34  out.append(l)
35  if changed:
36  open(cml, "w").writelines(out)
37 
38 def change_version(packagedir, newversion):
39  """
40  Compare the version of the package with the new one and update the package if
41  needed.
42 
43  Returns true if the package have been modified.
44  """
45  global _req_version_pattern
46  changed = False
47  out = []
48  req = os.path.join(packagedir, 'cmt', 'requirements')
49  for l in open(req):
50  m = _req_version_pattern.match(l)
51  if m:
52  if m.group(1) != newversion:
53  print "%s: %s -> %s"%(packagedir,m.group(1),newversion)
54  l = l.replace(m.group(1),newversion)
55  changed = True
56  out.append(l)
57  if changed:
58  open(req,"w").writelines(out)
59  # verify the version.cmt file
60  ver = os.path.join(packagedir,"version.cmt")
61  if os.path.exists(ver):
62  current = open(ver).read().strip()
63  if current != newversion:
64  open(ver,"w").write(newversion + "\n")
65  # update CMakeLists.txt
66  cml = os.path.normpath(os.path.join(packagedir, 'CMakeLists.txt'))
67  change_cml_version(cml, newversion)
68  if 'GaudiKernel' in packagedir:
69  cml = os.path.normpath(os.path.join(packagedir, 'src', 'Util', 'CMakeLists.txt'))
70  change_cml_version(cml, newversion)
71  return changed
72 
74  changelog_entry = re.compile(r'^(! [0-9]{4}-[0-9]{2}-[0-9]{2} -)|!?============')
75  separator_entry = re.compile(r'^!?============')
76  notes = []
77  state = "searching"
78  for l in open(filename):
79  # looking for the first changelog entry
80  if state == "searching":
81  if changelog_entry.match(l):
82  state = "found"
83  # when found, we start collecting lines until the next separator
84  if state == "found":
85  if not separator_entry.match(l):
86  notes.append(l)
87  else:
88  break
89  # remove trailing empty lines
90  while notes and not notes[-1].strip(): notes.pop()
91  return "".join(notes)
92 
93 def add_release_separator_bar(filename, pkg, version):
94  changelog_entry = re.compile(r'^(! [0-9]{4}-[0-9]{2}-[0-9]{2} -)|============')
95  title = " %s %s " % (pkg, version)
96  letf_chars = (78 - len(title)) / 2
97  right_chars = 78 - letf_chars - len(title)
98  separator = ("=" * letf_chars) + title + ("=" * right_chars) + "\n"
99  out = []
100  found = False
101  for l in open(filename):
102  # looking for the first changelog entry
103  if not found:
104  if changelog_entry.match(l):
105  out.append(separator)
106  found = True
107  # if found, just go on appending lines
108  out.append(l)
109  if found:
110  open(filename,"w").writelines(out)
111  else:
112  print "Warning: could not update release.notes in %s" % pkg
113 
114 def main():
115 
116  # Find the version of HEPTools (LCG)
117  for l in open('toolchain.cmake'):
118  m = re.match(r'^\s*set\(\s*heptools_version\s+(\S*)\s*\)', l)
119  if m:
120  HEPToolsVers = m.group(1)
121  print "Using HEPTools", HEPToolsVers
122  break
123  else:
124  print "Cannot find HEPTools version"
125  sys.exit(1)
126 
127  # Collect all the packages in the project with their directory
128  def all_subdirs():
129  for dirpath, dirnames, filenames in os.walk(os.curdir):
130  if 'CMakeLists.txt' in filenames and dirpath != os.curdir:
131  dirnames[:] = []
132  yield dirpath
133  else:
134  dirnames[:] = [dirname for dirname in dirnames
135  if not dirname.startswith('build.') and
136  dirname != 'cmake']
137 
138  # Packages which version must match the version of the project
139  special_subdirs = ["Gaudi", "GaudiExamples", "GaudiSys", "GaudiRelease"]
140 
141  # Ask for the version of the project
142  top_cml = ' '.join(l.strip().split('#', 1)[0]
143  for l in open('CMakeLists.txt').readlines())
144  old_version = re.search(r'gaudi_project\(\s*\S+\s+(\S+)', top_cml).group(1)
145  new_version = raw_input("The old version of the project is %s, which is the new one? " % old_version)
146 
147  old_versions = {}
148  release_notes = {}
149  new_versions = {}
150  # for each package in the project check if there were changes and ask for the new version number
151  for pkgdir in all_subdirs():
152  relnotefile = os.path.join(pkgdir, 'doc', 'release.notes')
153  cmlfile = os.path.join(pkgdir, 'CMakeLists.txt')
154  reqfile = os.path.join(pkgdir, 'cmt', 'requirements')
155 
156  pkg = os.path.basename(pkgdir)
157  old_versions[pkg] = extract_version(pkgdir)
158 
159  if os.path.exists(relnotefile): # ignore missing release.notes
160  release_notes[pkg] = extract_recent_rel_notes(relnotefile)
161  else:
162  release_notes[pkg] = ''
163 
164  if pkg in special_subdirs:
165  new_versions[pkg] = new_version
166  else:
167  if release_notes[pkg]:
168  msg = ('\nThe old version of %s is %s, these are the changes:\n'
169  '%s\n'
170  'Which version you want (old is %s)? ') % \
171  (pkg, old_versions[pkg], release_notes[pkg],
172  old_versions[pkg])
173  new_versions[pkg] = raw_input(msg)
174  else:
175  new_versions[pkg] = old_versions[pkg]
176  # update infos
177  if new_versions[pkg] != old_versions[pkg]:
178  change_version(pkgdir, new_versions[pkg])
179  if os.path.exists(relnotefile):
180  add_release_separator_bar(relnotefile, pkg, new_versions[pkg])
181  print "=" * 80
182  # The changes in the GaudiRelease requirements for the other packages can be postponed to now
183  # FIXME: we need another file with the list of versions for CMake
184  reqfile = os.path.join('GaudiRelease', 'cmt', 'requirements')
185  out = []
186  for l in open(reqfile):
187  sl = l.strip().split()
188  if sl and sl[0] == "use":
189  if sl[1] in new_versions:
190  if sl[2] != new_versions[sl[1]]:
191  l = l.replace(sl[2], new_versions[sl[1]])
192  out.append(l)
193  open(reqfile, "w").writelines(out)
194 
195  # update the global release notes
196  new_lines = []
197  new_lines.append("<!-- ====================================================================== -->")
198  data = { "vers": new_version, "date": time.strftime("%Y-%m-%d") }
199  new_lines.append('<h2><a name="%(vers)s">Gaudi %(vers)s</a> (%(date)s)</h2>' % data)
200  data = { "vers": HEPToolsVers }
201  new_lines.append('<h3>Externals version: <a href="http://lcgsoft.cern.ch/index.py?page=cfg_overview&cfg=%(vers)s">LCGCMT_%(vers)s</a></h3>' % data)
202  new_lines.append("<h3>General Changes</h3>")
203  new_lines.append('<ul>\n<li><br/>\n (<span class="author"></span>)</li>\n</ul>')
204  new_lines.append("<h3>Packages Changes</h3>")
205  new_lines.append("<ul>")
206  for pkg in release_notes:
207  if release_notes[pkg]:
208  new_lines.append('<li>%s (%s):\n<ul>\n<li><br/>\n (<span class="author"></span>)</li>\n</ul>\n<pre>'%(pkg,new_versions[pkg]))
209  new_lines.append(release_notes[pkg].replace('&','&amp;') \
210  .replace('<','&lt;') \
211  .replace('>','&gt;') + "</pre>")
212  new_lines.append("</li>")
213  new_lines.append("</ul>")
214 
215  global_rel_notes = os.path.join("GaudiRelease", "doc", "release.notes.html")
216  out = []
217  separator = re.compile("<!-- =+ -->")
218  block_added = False
219  for l in open(global_rel_notes):
220  if not block_added and separator.match(l.strip()):
221  out.append("\n".join(new_lines) + "\n")
222  block_added = True
223  out.append(l)
224  open(global_rel_notes, "w").writelines(out)
225 
226  # update the global CMakeLists.txt
227  out = []
228  for l in open('CMakeLists.txt'):
229  if l.strip().startswith('gaudi_project'):
230  l = 'gaudi_project(Gaudi %s)\n' % new_version
231  out.append(l)
232  open('CMakeLists.txt', "w").writelines(out)
233 
234 
235 if __name__ == '__main__':
236  main()