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*$")
14  """
15  Find the version number in a requirements file.
16  """
17  global _req_version_pattern
18  for l in open(f):
19  m = _req_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,"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 
73 _use_pattern = re.compile(r"^\s*use\s*(\w+)\s*(v[0-9]+r[0-9]+(?:p[0-9]+)?)\s*(\w+)?\s*$")
75  global _use_pattern
76  versions = {}
77  for l in open(f):
78  m = _use_pattern.match(l)
79  if m:
80  versions[m.group(1)] = m.group(2)
81  return versions
82 
84  changelog_entry = re.compile(r'^(! [0-9]{4}-[0-9]{2}-[0-9]{2} -)|!?============')
85  separator_entry = re.compile(r'^!?============')
86  notes = []
87  state = "searching"
88  for l in open(filename):
89  # looking for the first changelog entry
90  if state == "searching":
91  if changelog_entry.match(l):
92  state = "found"
93  # when found, we start collecting lines until the next separator
94  if state == "found":
95  if not separator_entry.match(l):
96  notes.append(l)
97  else:
98  break
99  # remove trailing empty lines
100  while notes and not notes[-1].strip(): notes.pop()
101  return "".join(notes)
102 
103 def add_release_separator_bar(filename, pkg, version):
104  changelog_entry = re.compile(r'^(! [0-9]{4}-[0-9]{2}-[0-9]{2} -)|============')
105  title = " %s %s " % (pkg, version)
106  letf_chars = (78 - len(title)) / 2
107  right_chars = 78 - letf_chars - len(title)
108  separator = ("=" * letf_chars) + title + ("=" * right_chars) + "\n"
109  out = []
110  found = False
111  for l in open(filename):
112  # looking for the first changelog entry
113  if not found:
114  if changelog_entry.match(l):
115  out.append(separator)
116  found = True
117  # if found, just go on appending lines
118  out.append(l)
119  if found:
120  open(filename,"w").writelines(out)
121  else:
122  print "Warning: could not update release.notes in %s" % pkg
123 
124 def main():
125 
126  # Find the version of LCGCMT
127  m = re.search("use\s*LCGCMT\s*LCGCMT_(\S*)",open(os.path.join("..","..","cmt","project.cmt")).read())
128  if m:
129  LCGCMTVers = m.group(1)
130  print "Using LCGCMT", LCGCMTVers
131  else:
132  print "Cannot find LCGCMT version"
133  sys.exit(1)
134 
135  # Collect all the packages in the project with their directory
136  # (I want to preserve the order that cmt broadcast gives)
137  all_packages_tmp = []
138  exec(os.popen(r"""cmt broadcast 'echo "all_packages_tmp.append((\"<package>\"", \"$PWD\""))"'""","r").read())
139  all_packages_names = []
140  all_packages = {}
141  for k,v in all_packages_tmp:
142  all_packages_names.append(k)
143  all_packages[k] = v
144 
145  # Packages which version must match the version of the project
146  special_packages = ["Gaudi", "GaudiExamples", "GaudiSys", "GaudiRelease"]
147 
148  # Ask for the version of the project
149  old_version = extract_version("requirements")
150  new_version = raw_input("The old version of the project is %s, which is the new one? " % old_version)
151 
152  old_versions = {}
153  release_notes = {}
154  new_versions = {}
155  # for each package in the project check if there were changes and ask for the new version number
156  for pkg in all_packages_names:
157  reqfile = os.path.join(all_packages[pkg], "requirements")
158  relnotefile = os.path.join(all_packages[pkg], "..", "doc", "release.notes")
159  old_versions[pkg] = extract_version(reqfile)
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  if pkg in special_packages:
165  new_versions[pkg] = new_version
166  else:
167  if release_notes[pkg]:
168  new_versions[pkg] = raw_input("\nThe old version of %s is %s, this are the changes:\n%s\nWhich version you want (old is %s)? " % (pkg, old_versions[pkg], release_notes[pkg], old_versions[pkg]))
169  else:
170  new_versions[pkg] = old_versions[pkg]
171  # update infos
172  if new_versions[pkg] != old_versions[pkg]:
173  change_version(all_packages[pkg], new_versions[pkg])
174  if os.path.exists(relnotefile):
175  add_release_separator_bar(relnotefile, pkg, new_versions[pkg])
176  print "=" * 80
177  # The changes in the GaudiRelease requirements for the other packages can be postponed to now
178  reqfile = os.path.join(all_packages["GaudiRelease"], "requirements")
179  out = []
180  for l in open(reqfile):
181  sl = l.strip().split()
182  if sl and sl[0] == "use":
183  if sl[1] in new_versions:
184  if sl[2] != new_versions[sl[1]]:
185  l = l.replace(sl[2], new_versions[sl[1]])
186  out.append(l)
187  open(reqfile, "w").writelines(out)
188 
189  # update the global release notes
190  new_lines = []
191  new_lines.append("<!-- ====================================================================== -->")
192  data = { "vers": new_version, "date": time.strftime("%Y-%m-%d") }
193  new_lines.append('<h2><a name="%(vers)s">Gaudi %(vers)s</a> (%(date)s)</h2>' % data)
194  data = { "vers": LCGCMTVers }
195  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)
196  new_lines.append("<h3>General Changes</h3>")
197  new_lines.append('<ul>\n<li><br/>\n (<span class="author"></span>)</li>\n</ul>')
198  new_lines.append("<h3>Packages Changes</h3>")
199  new_lines.append("<ul>")
200  for pkg in all_packages_names:
201  if release_notes[pkg]:
202  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]))
203  new_lines.append(release_notes[pkg].replace('&','&amp;') \
204  .replace('<','&lt;') \
205  .replace('>','&gt;') + "</pre>")
206  new_lines.append("</li>")
207  new_lines.append("</ul>")
208 
209  global_rel_notes = os.path.join("..", "doc", "release.notes.html")
210  out = []
211  separator = re.compile("<!-- =+ -->")
212  block_added = False
213  for l in open(global_rel_notes):
214  if not block_added and separator.match(l.strip()):
215  out.append("\n".join(new_lines) + "\n")
216  block_added = True
217  out.append(l)
218  open(global_rel_notes, "w").writelines(out)
219 
220  # update the global CMakeLists.txt
221  global_cmakelists = os.path.join("..","..","CMakeLists.txt")
222  out = []
223  for l in open(global_cmakelists):
224  if l.strip().startswith('gaudi_project'):
225  l = 'gaudi_project(Gaudi %s)\n' % new_version
226  out.append(l)
227  open(global_cmakelists, "w").writelines(out)
228 
229 if __name__ == '__main__':
230  main()