Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 275 lines (219 sloc) 9.21 kb
85545412 »
2012-12-07 initial commit
1 #!/usr/bin/env python
2 #
3 # Copyright 2012 SUSE Linux
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
15 # under the License.
16
17 import argparse
18 from datetime import datetime
08e252c4 »
2012-12-10 update all .spec/.changes files in the current directory
19 import glob
d06886fe »
2012-12-11 Make --package parameter optional
20 import os
85545412 »
2012-12-07 initial commit
21 import re
22 import sys
23 import tarfile
24 import urllib
25
26
27 COMMIT_HASH_SIZE = 7
28
29
251d4dc3 »
2012-12-11 replace component/version params with a url param
30 def download_tarball(url, filename):
85545412 »
2012-12-07 initial commit
31 """Download an upstream tarball
32
251d4dc3 »
2012-12-11 replace component/version params with a url param
33 :url: remote source of the tarball
85545412 »
2012-12-07 initial commit
34 :filename: where to save the downloaded tarball
35
36 """
37 try:
4ea6b0b8 »
2012-12-10 Revert "make filename parameter optional"
38 urllib.urlretrieve(url, filename)
85545412 »
2012-12-07 initial commit
39 except IOError as e:
40 sys.exit(e)
41
42
43 def get_changelog_from_tarball(tar_name):
b0d30079 »
2013-01-18 test get_upstream_commit
44 """Get the ChangeLog file form the tarball as a string"""
3a29237a »
2012-12-19 Replace 'with' statement with 'try ... finally' clauses.
45 try:
46 tar = tarfile.open(tar_name)
85545412 »
2012-12-07 initial commit
47 changelog_file = next(f for f in tar.getnames()
48 if f.endswith('ChangeLog'))
49 t = tar.getmember(changelog_file)
50 changelog = tar.extractfile(t).read()
5d2bc476 »
2013-01-02 exit if the ChangeLog file can not be found
51 except StopIteration:
52 sys.exit("Could not find a 'ChangeLog' file. ")
3a29237a »
2012-12-19 Replace 'with' statement with 'try ... finally' clauses.
53 finally:
54 tar.close()
85545412 »
2012-12-07 initial commit
55 return changelog
56
57
c96cde2f »
2013-01-17 Add a version-regexp option to customize how to extract version
58 def get_parent_dir_and_version_from_tarball(tar_name, version_regexp):
59 tar = tarfile.open(tar_name)
60 parent_dir = tar.firstmember.name
61 tar.close()
62
3a29237a »
2012-12-19 Replace 'with' statement with 'try ... finally' clauses.
63 try:
c96cde2f »
2013-01-17 Add a version-regexp option to customize how to extract version
64 match = re.match(version_regexp, parent_dir)
65 except re.error, e:
66 sys.exit("Could not use '%s' as regular expression to find "
67 "version: " % (version_regexp, e))
68
69 if match is None:
70 sys.exit("Could not use '%s' as regular expression to find "
71 "version in '%s': no match" % (version_regexp, parent_dir))
72 elif len(match.groups()) != 1:
73 sys.exit("Could not use '%s' as regular expression to find "
bff9f666 »
2013-01-17 fix pep8 issues
74 "version in '%s': more than one match" %
75 (version_regexp, parent_dir))
c96cde2f »
2013-01-17 Add a version-regexp option to customize how to extract version
76 else:
77 version = match.group(1)
78
79 return (parent_dir, version)
6c49a465 »
2012-12-10 use major version from tarball name
80
bff9f666 »
2013-01-17 fix pep8 issues
81
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
82 def get_upstream_commit(changelog):
b0d30079 »
2013-01-18 test get_upstream_commit
83 """Get the latest commit in the upstream git repository as a string"""
f85bf586 »
2012-12-10 update version in spec file
84 try:
85 return re.search(r'^commit (.*?)$', changelog, re.MULTILINE).group(1)
86 except AttributeError:
87 sys.exit("Could not parse ChangeLog file.")
88
89
85545412 »
2012-12-07 initial commit
90 def parse_changelog(changelog):
49d5cb09 »
2013-01-18 re.finditer never raises an AttributeError
91 """Parse a git ChangeLog file
85545412 »
2012-12-07 initial commit
92
93 :changelog: string with the contents of the file
94
49d5cb09 »
2013-01-18 re.finditer never raises an AttributeError
95 Returns an iterable of _sre.SRE_Match match objects from python's `re`
96
382122dd »
2013-01-18 test parse_changelog
97 Each object will have the following attributes:
98 commit, author, date, message
99
85545412 »
2012-12-07 initial commit
100 """
49d5cb09 »
2013-01-18 re.finditer never raises an AttributeError
101 # FIXME: we can actually ignore Merge commits altogether.
102 return re.finditer(r'^commit (?P<commit>.*?)$'
103 '.*?'
104 '^Author:\s+(?P<author>.*?)$'
105 '.*?'
106 '^Date:\s+(?P<date>.*?)$'
107 '.*?'
108 '\n\n\s+(?P<message>.*?)$'
109 '(?:\n\n|\n.*?)',
110 changelog, re.MULTILINE | re.DOTALL)
85545412 »
2012-12-07 initial commit
111
112
113 def get_commit_from_spec(package):
8c8d3c18 »
2013-01-16 fix Version parsing from spec file
114 """Parse the spec's Version field for a previously set commit version
115
116 :package: name of the package
117
118 Returns None in case no commit could be read.
119
120 """
3a29237a »
2012-12-19 Replace 'with' statement with 'try ... finally' clauses.
121 try:
122 f = open(package + '.spec')
8c8d3c18 »
2013-01-16 fix Version parsing from spec file
123 return re.search(r'^Version:\s+.*\+git\.\d+\.(.*?)(\s+#.*)?$',
3a29237a »
2012-12-19 Replace 'with' statement with 'try ... finally' clauses.
124 f.read(), flags=re.MULTILINE).group(1)
125 except AttributeError:
72e163d3 »
2013-01-16 fix first run as different from no changes
126 return None
3a29237a »
2012-12-19 Replace 'with' statement with 'try ... finally' clauses.
127 finally:
128 f.close()
85545412 »
2012-12-07 initial commit
129
130
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
131 def package_version(upstream_version, upstream_commit):
132 return '%s+git.%s.%s' % (upstream_version,
c2e4222d »
2012-12-19 Do not use utcnow() if formatting time as %s
133 datetime.now().strftime('%s'),
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
134 upstream_commit[:COMMIT_HASH_SIZE])
135
136
ea0ad868 »
2013-01-22 generalize %setup parsing to support more %setup options
137 def parse_update_spec_file(contents, package_version,
138 tarball_parent_dir, filename):
139 contents = re.sub(r'\n((Version:\s+).*)\n',
140 r'\n\g<2>%s\n' % package_version,
141 contents, count=1)
142 # only replace the "-n" option, leave everything else intact
143 contents = re.sub(r'\n(%setup.*?-n\s+)(\S+?)(|[ \t]+.*?)\n',
144 r'\n\g<1>%s\g<3>\n' % tarball_parent_dir,
145 contents, count=1)
146 contents = re.sub(r'\n((Source0?:\s+).*)\n',
147 r'\n\g<2>%s\n' % filename,
148 contents, count=1)
149 return contents
150
151
152 def update_spec_files(package_version, tarball_parent_dir, filename):
08e252c4 »
2012-12-10 update all .spec/.changes files in the current directory
153 for specfile in glob.glob('./*.spec'):
3a29237a »
2012-12-19 Replace 'with' statement with 'try ... finally' clauses.
154 try:
155 f = open(specfile, 'r+')
08e252c4 »
2012-12-10 update all .spec/.changes files in the current directory
156 contents = f.read()
157 f.seek(0)
158 f.truncate()
ea0ad868 »
2013-01-22 generalize %setup parsing to support more %setup options
159 contents = parse_update_spec_file(contents, package_version,
160 tarball_parent_dir, filename)
08e252c4 »
2012-12-10 update all .spec/.changes files in the current directory
161 f.write(contents)
3a29237a »
2012-12-19 Replace 'with' statement with 'try ... finally' clauses.
162 finally:
163 f.close()
f85bf586 »
2012-12-10 update version in spec file
164
165
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
166 def diff_changes(changes_list, package_commit):
167 """Return a list of dict changes newer than the ones in package_version
bff9f666 »
2013-01-17 fix pep8 issues
168
85545412 »
2012-12-07 initial commit
169 :changes_list: a list of dicts from the ChangeLog file
bff9f666 »
2013-01-17 fix pep8 issues
170 :package_commit: a git commit hash of the current version from the
171 spec file
85545412 »
2012-12-07 initial commit
172
f85bf586 »
2012-12-10 update version in spec file
173 Returns an empty list if there are no newer commits.
174
85545412 »
2012-12-07 initial commit
175 """
176 new_changes = []
177 for change in changes_list:
178 change = change.groupdict()
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
179 if change['commit'].startswith(package_commit):
85545412 »
2012-12-07 initial commit
180 break
181 new_changes.append(change)
182
183 return new_changes
184
185
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
186 def create_changes(changes_list, package_version, package_commit, email):
ea498e6b »
2012-12-10 handle case when there are no changes
187 """Return a string with the new changes for the .changes file
85545412 »
2012-12-07 initial commit
188
ea498e6b »
2012-12-10 handle case when there are no changes
189 :changes_list: a list of dicts from the ChangeLog file
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
190 :package_version: release version string for the .changes file entry
bff9f666 »
2013-01-17 fix pep8 issues
191 :package_commit: a git commit hash of the current version from the
192 spec file
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
193 :email: email address used for the .changes file entry
ea498e6b »
2012-12-10 handle case when there are no changes
194
195 """
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
196 changes_diff = diff_changes(changes_list, package_commit)
ea498e6b »
2012-12-10 handle case when there are no changes
197 if not changes_diff:
400d0ff7 »
2012-12-19 Don't quit if there are no new changes.
198 print "There are no new changes."
7882c375 »
2013-01-02 only update changes files if there are new changes
199 return
ea498e6b »
2012-12-10 handle case when there are no changes
200
201 timestamp = datetime.utcnow().strftime('%a %b %e %T UTC %Y')
85545412 »
2012-12-07 initial commit
202
331c75c2 »
2012-12-10 ignore Merge commits
203 # XXX Merge commits should be skipped when parsing the changelog
204 commits = " + " + "\n + ".join(c['message'] for c in changes_diff
205 if not c['message'].startswith('Merge "'))
85545412 »
2012-12-07 initial commit
206 change = (
bff9f666 »
2013-01-17 fix pep8 issues
207 '--------------------------------------------------------------------'
208 '\n%(timestamp)s - %(email)s\n'
85545412 »
2012-12-07 initial commit
209 '\n'
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
210 '- Update to version %(package_version)s:\n'
6b779e48 »
2012-12-10 use better var names
211 '%(commits)s\n'
85545412 »
2012-12-07 initial commit
212 '\n' % locals())
6b779e48 »
2012-12-10 use better var names
213
85545412 »
2012-12-07 initial commit
214 return change
215
216
217 def update_changes_file(package, changes):
bff9f666 »
2013-01-17 fix pep8 issues
218 try:
58005900 »
2013-01-16 only update the main package's .changes file
219 f = open(package + '.changes', 'r+')
220 contents = f.read()
221 f.seek(0)
222 f.write(changes)
223 f.write(contents)
224 finally:
225 f.close()
85545412 »
2012-12-07 initial commit
226
227
228 if __name__ == '__main__':
6cd8ef6f »
2012-12-11 Make --filename parameter optional
229 parser = argparse.ArgumentParser(description='Git Tarballs')
230 parser.add_argument('--url', required=True,
231 help='upstream tarball URL to download')
232 parser.add_argument('--filename',
233 help='where to save the downloaded tarball')
d06886fe »
2012-12-11 Make --package parameter optional
234 parser.add_argument('--package',
235 help='the OBS package name')
6cd8ef6f »
2012-12-11 Make --filename parameter optional
236 parser.add_argument('--email', required=True,
bff9f666 »
2013-01-17 fix pep8 issues
237 help='email of the commit author '
238 '(for the .changes file)')
c96cde2f »
2013-01-17 Add a version-regexp option to customize how to extract version
239 parser.add_argument('--version-regexp', default='.*-([^-]+)',
bff9f666 »
2013-01-17 fix pep8 issues
240 help='regular expression for extracting version from '
241 'top-level directory in tarball '
242 '(default: ".*-([^-]+)")')
243 parser.add_argument('--outdir',
244 help='osc service parameter that does nothing')
85545412 »
2012-12-07 initial commit
245 args = parser.parse_args()
6cd8ef6f »
2012-12-11 Make --filename parameter optional
246
247 if not args.filename:
248 args.filename = args.url.rsplit("/", 1)[1]
d06886fe »
2012-12-11 Make --package parameter optional
249 if not args.package:
250 args.package = os.getcwd().rsplit("/", 1)[1]
6cd8ef6f »
2012-12-11 Make --filename parameter optional
251
251d4dc3 »
2012-12-11 replace component/version params with a url param
252 download_tarball(args.url, args.filename)
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
253
4ea6b0b8 »
2012-12-10 Revert "make filename parameter optional"
254 changelog = get_changelog_from_tarball(args.filename)
85545412 »
2012-12-07 initial commit
255 changes_list = parse_changelog(changelog)
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
256 upstream_commit = get_upstream_commit(changelog)
bff9f666 »
2013-01-17 fix pep8 issues
257 tarball_parent_dir, upstream_version = \
258 get_parent_dir_and_version_from_tarball(
259 args.filename, args.version_regexp)
3390ccdc »
2012-12-11 Use the same version string in changes file entry that is found in the
260
261 package_commit = get_commit_from_spec(args.package)
262 package_version = package_version(upstream_version, upstream_commit)
72e163d3 »
2013-01-16 fix first run as different from no changes
263 if not package_commit:
264 # on first run, we only set the fields in the spec file;
265 # there are no changes
ea0ad868 »
2013-01-22 generalize %setup parsing to support more %setup options
266 update_spec_files(package_version, tarball_parent_dir, args.filename)
72e163d3 »
2013-01-16 fix first run as different from no changes
267 print "Initialized .spec file with git_tarball."
268 sys.exit()
269
270 changes = create_changes(changes_list, package_version,
271 package_commit, args.email)
7882c375 »
2013-01-02 only update changes files if there are new changes
272 if changes:
273 update_changes_file(args.package, changes)
ea0ad868 »
2013-01-22 generalize %setup parsing to support more %setup options
274 update_spec_files(package_version, tarball_parent_dir, args.filename)
Something went wrong with that request. Please try again.