| The Gaudi Framework v32r1 (f65d50dc)

prepare_gaudi_release.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 '''
3 Script to prepare the release of Gaudi.
4
5 @author Marco Clemencic
6 '''
7
8 import os
9 import sys
10 import logging
11 import re
12 from subprocess import check_output, CalledProcessError
13
14
15 def checkGitVersion():
16 '''
17 Ensure we have a usable version of Git (>= 1.7.9.1).
18
19 See:
20 * https://raw.githubusercontent.com/git/git/master/Documentation/RelNotes/1.7.9.1.txt
21 * https://github.com/git/git/commit/36ed1913e1d5de0930e59db6eeec3ccb2bd58bd9
22 '''
23 version = check_output(['git', '--version']).split()[-1]
24 if versionKey(version) < versionKey('1.7.9.1'):
25 raise RuntimeError(
26 'bad version of git found: %s (1.7.9.1 required)' % version)
27
28
29 _VK_RE = re.compile(r'(\d+|\D+)')
30
31
32 def versionKey(x):
33 '''
34 Key function to be passes to list.sort() to sort strings
35 as version numbers.
36 '''
37 return [
38 int(i) if i[0] in '0123456789' else i for i in _VK_RE.split(x) if i
39 ]
40
41
42 def findLatestTag():
43 '''
44 Return the latest Gaudi tag (of the format "v*r*...").
45 '''
46 logging.info('looking for latest tag')
47 cmd = ['git', 'tag']
48 logging.debug('using command %r', cmd)
49 output = check_output(cmd)
50 vers_exp = re.compile(r'^v\d+r\d+(p\d+)?$')
51 tags = [tag for tag in output.splitlines() if vers_exp.match(tag)]
52 if tags:
53 tags.sort(key=versionKey)
54 logging.info('found %s', tags[-1])
55 return tags[-1]
56 logging.info('no valid tag found')
57
58
59 def releaseNotes(path=os.curdir, from_tag=None, branch=None):
60 '''
61 Return the release notes (in the old LHCb format) extracted from git
62 commits for a given path.
63 '''
64 cmd = [
65 'git', 'log', '--first-parent', '--date=short',
66 '--pretty=format:! %ad - commit %h%n%n%w(80,1,3)- %s%n%n%b%n'
67 ]
68 if from_tag:
69 cmd.append('{0}..{1}'.format(from_tag, branch or ''))
70 elif branch:
71 cmd.append(branch)
72 cmd.append('--')
73 cmd.append(path)
74 logging.info('preparing release notes for %s%s', path,
75 ' since ' + from_tag if from_tag else '')
76 logging.debug('using command %r', cmd)
77 # remove '\r' characters from commit messages
78 out = check_output(cmd).replace('\r', '')
79
80 # replace ' - commit 123abc' with ' - Contributor Name (commit 123abc)'
81 def add_contributors(match):
82 try:
83 authors = set(
84 check_output([
85 'git',
86 'log',
87 '--pretty=format:%aN',
88 '{0}^1..{0}^2'.format(match.group(1)),
89 ]).splitlines())
90 return ' - {0} (commit {1})'.format(', '.join(sorted(authors)),
91 match.group(1))
92 except CalledProcessError:
93 return match.group(0)
94
95 out = re.sub(r' - commit ([0-9a-f]+)', add_contributors, out)
96 return out
97
98
99 def updateReleaseNotes(path, notes):
100 '''
101 Smartly prepend the content of notes to the release.notes file in path.
102 '''
103 notes_filename = os.path.join(path, 'doc', 'release.notes')
104 logging.info('updating %s', notes_filename)
105 from itertools import takewhile, dropwhile
106
107 def dropuntil(predicate, iterable):
108 return dropwhile(lambda x: not predicate(x), iterable)
109
110 with open(notes_filename) as notes_file:
111 orig_data = iter(list(notes_file))
112 header = takewhile(str.strip, orig_data)
113 with open(notes_filename, 'w') as notes_file:
114 notes_file.writelines(header)
115 notes_file.write('\n')
116 notes_file.writelines(l.rstrip() + '\n' for l in notes.splitlines())
117 notes_file.write('\n')
118 notes_file.writelines(
119 dropuntil(re.compile(r'^!?============').match, orig_data))
120
121
122 def tag_bar(pkg, version=None):
123 title = ' %s %s ' % (pkg, version)
124 letf_chars = (78 - len(title)) / 2
125 right_chars = 78 - letf_chars - len(title)
126 separator = ('=' * letf_chars) + title + ('=' * right_chars)
127 return separator
128
129
130 def main():
131 logging.basicConfig(level=logging.DEBUG)
132 os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
133 # Find the version of HEPTools (LCG)
134 for l in open('toolchain.cmake'):
135 m = re.match(r'^\s*set\(\s*heptools_version\s+(\S*)\s*\)', l)
136 if m:
137 HEPToolsVers = m.group(1)
138 print "Using HEPTools", HEPToolsVers
139 break
140 else:
141 logging.error('Cannot find HEPTools version')
142 sys.exit(1)
143
144 # Collect all the packages in the project with their directory
145 def all_subdirs():
146 for dirpath, dirnames, filenames in os.walk(os.curdir):
147 if 'CMakeLists.txt' in filenames and dirpath != os.curdir:
148 dirnames[:] = []
149 yield dirpath
150 else:
151 dirnames[:] = [
152 dirname for dirname in dirnames
153 if (not dirname.startswith('build.') and dirname != 'cmake'
154 )
155 ]
156
157 # Ask for the version of the project
158 latest_tag = findLatestTag()
159
160 old_version = latest_tag.split('_')[-1]
161 new_version = raw_input(("The old version of the project is %s, "
162 "which is the new one? ") % old_version)
163
164 release_notes = {}
165 # for each package in the project update the release.notes
166 for pkgdir in all_subdirs():
167 updateReleaseNotes(
168 pkgdir,
169 tag_bar('Gaudi', new_version) + '\n\n' + releaseNotes(
170 pkgdir, latest_tag, 'master'))
171
172 # update the global CMakeLists.txt
173 out = []
174 for l in open('CMakeLists.txt'):
175 if l.strip().startswith('gaudi_project'):
176 l = 'gaudi_project(Gaudi %s)\n' % new_version
177 out.append(l)
178 open('CMakeLists.txt', "w").writelines(out)
179
180
181 if __name__ == '__main__':
182 checkGitVersion()
183 main()
format
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:109
prepare_gaudi_release.releaseNotes
def releaseNotes(path=os.curdir, from_tag=None, branch=None)
Definition: prepare_gaudi_release.py:59
prepare_gaudi_release.findLatestTag
def findLatestTag()
Definition: prepare_gaudi_release.py:42
prepare_gaudi_release.main
def main()
Definition: prepare_gaudi_release.py:130
prepare_gaudi_release.tag_bar
def tag_bar(pkg, version=None)
Definition: prepare_gaudi_release.py:122
prepare_gaudi_release.updateReleaseNotes
def updateReleaseNotes(path, notes)
Definition: prepare_gaudi_release.py:99
prepare_gaudi_release.versionKey
def versionKey(x)
Definition: prepare_gaudi_release.py:32
prepare_gaudi_release.checkGitVersion
def checkGitVersion()
Definition: prepare_gaudi_release.py:15