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