OLD | NEW |
| (Empty) |
1 #!/usr/bin/python | |
2 | |
3 # Update Dartium DEPS automatically. | |
4 | |
5 from datetime import datetime, timedelta | |
6 import optparse | |
7 import os | |
8 import re | |
9 from subprocess import Popen, PIPE | |
10 import sys | |
11 from time import strptime | |
12 | |
13 # Instructions: | |
14 # | |
15 # To run locally: | |
16 # (a) Create and change to a directory to run the updater in: | |
17 # > mkdir /usr/local/google/home/$USER/dartium_deps_updater | |
18 # > cd /usr/local/google/home/$USER/dartium_deps_updater | |
19 # | |
20 # (b) Checkout a copy of the DEPS for the updater to process / update: | |
21 # > svn co https://dart.googlecode.com/svn/branches/bleeding_edge/deps/dart
ium.deps | |
22 # | |
23 # (c) Checkout dartium_tools (with this script) using the current branch instea
d of 1750: | |
24 # > svn co svn://svn.chromium.org/chrome/branches/dart/1750/src/dartium_too
ls | |
25 # | |
26 # (d) If your home directory is remote, consider redefining it for this shell/s
cript: | |
27 # > cp -R $HOME/.subversion /usr/local/google/home/$USER | |
28 # > export HOME=/usr/local/google/home/$USER | |
29 # | |
30 # (e) Test by running (Ctrl-C to quit): | |
31 # > ./dartium_tools/update_deps.py | |
32 # | |
33 # (f) Run periodical update: | |
34 # > while true; do ./dartium_tools/update_deps.py --force ; sleep 300 ; don
e | |
35 | |
36 ######################################################################## | |
37 # Repositories to auto-update | |
38 ######################################################################## | |
39 | |
40 # Each element in this map represents a repository to update. Entries | |
41 # take the form: | |
42 # (repo_tag: (svn_url, view_url)) | |
43 # | |
44 # The repo_tag must match the DEPS revision entry. I.e, there must be | |
45 # an entry of the form: | |
46 # 'dartium_%s_revision' % repo_tag | |
47 # to roll forward. | |
48 # | |
49 # The view_url should be parameterized by revision number. This is | |
50 # used to generated the commit message. | |
51 REPOSITORY_INFO = { | |
52 'webkit': ( | |
53 'http://src.chromium.org/blink/branches/dart/1750', | |
54 'http://src.chromium.org/viewvc/blink/branches/dart/1750?view=rev&revisi
on=%s'), | |
55 'chromium': ( | |
56 'http://src.chromium.org/chrome/branches/dart/1750/src', | |
57 'http://src.chromium.org/viewvc/chrome/branches/dart/1750/src?view=rev&r
evision=%s'), | |
58 } | |
59 | |
60 REPOSITORIES = REPOSITORY_INFO.keys() | |
61 | |
62 ######################################################################## | |
63 # Actions | |
64 ######################################################################## | |
65 | |
66 def write_file(filename, content): | |
67 f = open(filename, "w") | |
68 f.write(content) | |
69 f.close() | |
70 | |
71 def run_cmd(cmd): | |
72 print "\n[%s]\n$ %s" % (os.getcwd(), " ".join(cmd)) | |
73 pipe = Popen(cmd, stdout=PIPE, stderr=PIPE) | |
74 output = pipe.communicate() | |
75 if pipe.returncode == 0: | |
76 return output[0] | |
77 else: | |
78 print output[1] | |
79 print "FAILED. RET_CODE=%d" % pipe.returncode | |
80 sys.exit(pipe.returncode) | |
81 | |
82 def parse_iso_time(s): | |
83 pair = s.rsplit(' ', 1) | |
84 d = datetime.strptime(pair[0], '%Y-%m-%d %H:%M:%S') | |
85 offset = timedelta(hours=int(pair[1][0:3])) | |
86 return d - offset | |
87 | |
88 def parse_git_log(output, repo): | |
89 if len(output) < 4: | |
90 return [] | |
91 lst = output.split(os.linesep) | |
92 lst = [s.strip('\'') for s in lst] | |
93 lst = [s.split(',', 3) for s in lst] | |
94 lst = [{'repo': repo, | |
95 'rev': s[0], | |
96 'isotime':s[1], | |
97 'author': s[2], | |
98 'utctime': parse_iso_time(s[1]), | |
99 'info': s[3]} for s in lst] | |
100 return lst | |
101 | |
102 def parse_svn_log(output, repo): | |
103 lst = output.split(os.linesep) | |
104 lst = [s.strip('\'') for s in lst] | |
105 output = '_LINESEP_'.join(lst) | |
106 lst = output.split('----------------------------------------------------------
--------------') | |
107 lst = [s.replace('_LINESEP_', '\n') for s in lst] | |
108 lst = [s.strip('\n') for s in lst] | |
109 lst = [s.strip(' ') for s in lst] | |
110 lst = [s for s in lst if len(s) > 0] | |
111 pattern = re.compile(' \| (\d+) line(s|)') | |
112 lst = [pattern.sub(' | ', s) for s in lst] | |
113 lst = [s.split(' | ', 3) for s in lst] | |
114 lst = [{'repo': repo, | |
115 'rev': s[0].replace('r', ''), | |
116 'author': s[1], | |
117 'isotime':s[2][0:25], | |
118 'utctime': parse_iso_time(s[2][0:25]), | |
119 'info': s[3].split('\n')[2]} for s in lst] | |
120 return lst | |
121 | |
122 def commit_url(repo, rev): | |
123 numrev = rev.replace('r', '') | |
124 if repo in REPOSITORIES: | |
125 (_, view_url) = REPOSITORY_INFO[repo] | |
126 return view_url % numrev | |
127 else: | |
128 raise Exception('Unknown repo'); | |
129 | |
130 def find_max(revs): | |
131 max_time = None | |
132 max_position = None | |
133 for i, rev in enumerate(revs): | |
134 if rev == []: | |
135 continue | |
136 if max_time is None or rev[0]['utctime'] > max_time: | |
137 max_time = rev[0]['utctime'] | |
138 max_position = i | |
139 return max_position | |
140 | |
141 def merge_revs(revs): | |
142 position = find_max(revs) | |
143 if position is None: | |
144 return [] | |
145 item = revs[position][0] | |
146 revs[position] = revs[position][1:] | |
147 return [item] + merge_revs(revs) | |
148 | |
149 def main(): | |
150 option_parser = optparse.OptionParser() | |
151 option_parser.add_option('', '--force', help="Push DEPS update to server witho
ut prompting", action="store_true", dest="force") | |
152 options, args = option_parser.parse_args() | |
153 | |
154 src_dir = "/usr/local/google/home/%s/dartium_deps_updater/dartium.deps" % os.e
nviron["USER"] | |
155 os.putenv("GIT_PAGER", "") | |
156 | |
157 if not os.path.exists(src_dir): | |
158 print "Error: prior to running this script, you need to check out a Dartium
source tree at" | |
159 print " %s" % src_dir | |
160 print "Please reserve the above directory for this script and do not use it
for other purposes." | |
161 sys.exit(1) | |
162 | |
163 os.chdir(src_dir) | |
164 | |
165 # parse DEPS | |
166 deps = run_cmd(['svn', 'cat', 'https://dart.googlecode.com/svn/branches/bleedi
ng_edge/deps/dartium.deps/DEPS']) | |
167 rev_num = {} | |
168 for repo in REPOSITORIES: | |
169 revision = 'dartium_%s_revision":\s*"(.+)"' % repo | |
170 rev_num[repo] = re.search(revision, deps).group(1) | |
171 | |
172 # update repos | |
173 all_revs = [] | |
174 for repo, (svn_url, _) in REPOSITORY_INFO.items(): | |
175 output = run_cmd(["svn", "log", "-r", "HEAD:%s" % rev_num[repo], svn_url]) | |
176 revs = parse_svn_log(output, repo) | |
177 if revs and revs[-1]['rev'] == rev_num[repo]: | |
178 revs.pop() | |
179 all_revs.append(revs) | |
180 | |
181 pending_updates = merge_revs(all_revs) | |
182 pending_updates.reverse() | |
183 | |
184 print | |
185 print "Current DEPS revisions:" | |
186 for repo in REPOSITORIES: | |
187 print ' dartium_%s_revision=%s' % (repo, rev_num[repo]) | |
188 | |
189 if len(pending_updates) == 0: | |
190 print "DEPS is up-to-date." | |
191 sys.exit(0) | |
192 else: | |
193 print "Pending DEPS updates:" | |
194 for s in pending_updates: | |
195 print " %s to %s (%s) %s" % (s['repo'], s['rev'], s['isotime'], s['info']
) | |
196 | |
197 # make the next DEPS update | |
198 os.chdir(src_dir) | |
199 run_cmd(['rm', 'DEPS']) | |
200 print run_cmd(['svn', 'update']) | |
201 s = pending_updates[0] | |
202 | |
203 pattern = re.compile('dartium_' + s['repo'] + '_revision":\s*"(.+)"') | |
204 new_deps = pattern.sub('dartium_' + s['repo'] + '_revision": "' + s['rev'] + '
"', deps) | |
205 write_file('DEPS', new_deps) | |
206 | |
207 commit_log = 'DEPS AutoUpdate: %s to %s (%s) %s\n' % (s['repo'], s['rev'], s['
isotime'], s['author']) | |
208 commit_log += s['info'] + '\n' + commit_url(s['repo'], s['rev']) | |
209 | |
210 write_file('commit_log.txt', commit_log) | |
211 print run_cmd(['svn', 'diff']) | |
212 print | |
213 print "Commit log:" | |
214 print "---------------------------------------------" | |
215 print commit_log | |
216 print "---------------------------------------------" | |
217 | |
218 if not options.force: | |
219 print "Ready to push; press Enter to continue or Control-C to abort..." | |
220 sys.stdin.readline() | |
221 print run_cmd(['svn', 'commit', '--file', 'commit_log.txt']) | |
222 print "Done." | |
223 | |
224 | |
225 if '__main__' == __name__: | |
226 main() | |
OLD | NEW |