Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(240)

Side by Side Diff: nacl_deps_bump.py

Issue 872813004: Switching nacl_deps_bump to git. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/parasite/
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | nacl_deps_bump_cronjob.py » ('j') | nacl_deps_bump_cronjob.py » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Native Client Authors. All rights reserved. 2 # Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """ 6 """
7 This tool helps with updating nacl_revision in Chromium's DEPS file to 7 This tool helps with updating nacl_revision in Chromium's DEPS file to
8 the latest revision of NaCl. It creates a Rietveld code review for 8 the latest revision of NaCl. It creates a Rietveld code review for
9 the update, listing the new NaCl commits. It kicks off a try job, 9 the update, listing the new NaCl commits. It kicks off a try job,
10 using relevant trybots. 10 using relevant trybots.
11 11
12 This tool should be run from a Git checkout of Chromium. 12 This tool should be run from a Git checkout of Chromium.
13 """ 13 """
14 14
15 import re 15 import re
16 import optparse 16 import optparse
17 import os 17 import os
18 import subprocess 18 import subprocess
19 import sys 19 import sys
20 import time 20 import time
21 21
22 # This dependency can be installed with: 22
23 # apt-get install python-svn 23 NACL_GIT_ROOT = 'native_client'
24 import pysvn
25 24
26 25
27 def ReadFile(filename): 26 def ReadFile(filename):
28 fh = open(filename, "r") 27 fh = open(filename, "r")
29 try: 28 try:
30 return fh.read() 29 return fh.read()
31 finally: 30 finally:
32 fh.close() 31 fh.close()
33 32
34 33
35 def WriteFile(filename, data): 34 def WriteFile(filename, data):
36 fh = open(filename, "w") 35 fh = open(filename, "w")
37 try: 36 try:
38 fh.write(data) 37 fh.write(data)
39 finally: 38 finally:
40 fh.close() 39 fh.close()
41 40
42 41
43 # The 'svn:' URL is faster than the 'http:' URL but only works if you
44 # have SVN committer credentials set up.
45 # NACL_SVN = 'http://src.chromium.org/native_client/trunk/src/native_client'
46 NACL_SVN = 'svn://svn.chromium.org/native_client/trunk/src/native_client'
47 # When querying for the latest revision, use the root URL. Otherwise,
48 # if the most recent change touched a branch and not trunk, the query
49 # will return an empty list.
50 NACL_SVN_ROOT = 'svn://svn.chromium.org/native_client'
51
52
53 def MatchKey(data, key): 42 def MatchKey(data, key):
54 if key == 'nacl_revision': 43 if key == 'nacl_revision':
55 # Pattern for fields in Chromium's DEPS file. 44 # Pattern for fields in Chromium's DEPS file.
56 match = re.search("^\s*'%s':\s*'(\S+)',\s*(#.*)?$" % key, data, re.M) 45 match = re.search("^\s*'%s':\s*'(\S+)',\s*(#.*)?$" % key, data, re.M)
57 else: 46 else:
58 # Pattern for fields in NaCl's DEPS file. 47 # Pattern for fields in NaCl's DEPS file.
59 match = re.search('^\s*"%s":\s*"(\S+)",\s*(#.*)?$' % key, data, re.M) 48 match = re.search('^\s*"%s":\s*"(\S+)",\s*(#.*)?$' % key, data, re.M)
60 if match is None: 49 if match is None:
61 raise Exception('Key %r not found' % key) 50 raise Exception('Key %r not found' % key)
62 return match 51 return match
63 52
64 53
65 def GetDepsField(data, key): 54 def GetDepsField(data, key):
66 match = MatchKey(data, key) 55 match = MatchKey(data, key)
67 return match.group(1) 56 return match.group(1)
68 57
69 58
70 def SetDepsField(data, key, value): 59 def SetDepsField(data, key, value):
71 match = MatchKey(data, key) 60 match = MatchKey(data, key)
72 return ''.join([data[:match.start(1)], 61 return ''.join([data[:match.start(1)],
73 value, 62 value,
74 data[match.end(1):]]) 63 data[match.end(1):]])
75 64
76 65
77 def SetDepsFieldWithComment(data, key, value, comment): 66 def GetNaClRev(git_dir):
78 assert key == 'nacl_revision', key 67 return subprocess.check_output(
79 match = MatchKey(data, key) 68 ['git', 'rev-parse', 'origin/master'], cwd=git_dir).strip()
80 return data[:match.start(1)] + value + "', # " + comment + data[match.end():]
81 69
82 70
83 def GetLatestRootRev(): 71 def GetLog(git_dir, rev1, rev2):
84 rev = pysvn.Revision(pysvn.opt_revision_kind.head) 72 stdout = subprocess.check_output(
85 lst = pysvn.Client().log(NACL_SVN_ROOT, revision_start=rev, revision_end=rev, 73 ['git', 'log', '--pretty=format:%h %ae %s', rev1 + '..' + rev2],
Mark Seaborn 2015/01/28 16:34:21 Can you add "--reverse", so that the oldest change
86 discover_changed_paths=True) 74 cwd=git_dir)
87 assert len(lst) == 1, lst
88 return lst[0].revision.number
89
90
91 def GetNaClRev():
92 # Find the revision number for the most recent commit to the subdir
93 # specified by NACL_SVN. Unfortunately, SVN does not make it easy
94 # to query this directly. If the HEAD commit did not change the
95 # subdir (e.g. because it changed other branches), "svn log
96 # -rHEAD:HEAD <subdir>" yields an empty list. This means we must
97 # start with the latest root revision and search backwards until we
98 # hit a change to the subdir.
99 now = time.time()
100 rev_num = GetLatestRootRev()
101 while True:
102 rev = pysvn.Revision(pysvn.opt_revision_kind.number, rev_num)
103 lst = pysvn.Client().log(NACL_SVN, revision_start=rev, revision_end=rev)
104 assert len(lst) in (0, 1), lst
105 if len(lst) == 1:
106 age_mins = (now - lst[0].date) / 60
107 print 'r%i committed %.1f minutes ago' % (
108 lst[0].revision.number, age_mins)
109 return lst[0].revision.number
110 rev_num -= 1
111
112
113 def GetLog(rev1, rev2):
114 # Get info on commits from rev1 (older, exclusive) to rev2 (newer,
115 # inclusive). Returns commit info formatted as a string, and a list
116 # of author e-mail addresses.
117 items = pysvn.Client().log(
118 NACL_SVN,
119 revision_start=pysvn.Revision(pysvn.opt_revision_kind.number, rev1 + 1),
120 revision_end=pysvn.Revision(pysvn.opt_revision_kind.number, rev2))
121 got = [] 75 got = []
122 authors = [] 76 authors = []
123 for item in items: 77 for line in stdout.splitlines():
124 line1 = item.message.split('\n')[0] 78 h, author, message = line.split(' ', 2)
125 author = item.author.split('@', 1)[0] 79 authors.append(author)
126 if line1 == 'Update .DEPS.git' and author == 'chrome-admin': 80 got.append('%s (%s) %s\n' % (h, author, message))
Mark Seaborn 2015/01/28 16:44:15 Can you add a colon, i.e. '%s: (%s) %s\n' to mat
127 # Skip these automated commits.
128 continue
129 authors.append(item.author)
130 got.append('r%i: (%s) %s\n' % (item.revision.number, author, line1))
131 return ''.join(got), authors 81 return ''.join(got), authors
132 82
133 83
134 def AssertIsGitRev(git_rev):
135 assert re.match('[0-9a-f]{40}$', git_rev) is not None, git_rev
136
137
138 # Returns the result of "git svn find-rev", which converts Git commit IDs
139 # to SVN revision numbers and vice versa.
140 def GitSvnFindRev(git_dir, arg):
141 stdout = subprocess.check_output(['git', 'svn', 'find-rev', arg],
142 cwd=git_dir)
143 # git-svn annoyingly sends "Partial-building" log output to stdout rather
144 # than stderr, so we have to ignore everything except the result on the
145 # last line.
146 lines = stdout.strip().split('\n')
147 return lines[-1].strip()
148
149
150 def GitToSvnRev(git_dir, git_rev):
151 AssertIsGitRev(git_rev)
152 rev = GitSvnFindRev(git_dir, git_rev)
153 return int(rev)
154
155
156 def SvnToGitRev(git_dir, svn_rev):
157 git_rev = GitSvnFindRev(git_dir, 'r%i' % int(svn_rev))
158 AssertIsGitRev(git_rev)
159 return git_rev
160
161
162 def RunTrybots(): 84 def RunTrybots():
163 try_cmd = ['git', 'cl', 'try'] 85 try_cmd = ['git', 'cl', 'try']
164 # Run the default trybots. 86 # Run the default trybots.
165 subprocess.check_call(try_cmd) 87 subprocess.check_call(try_cmd)
166 # Run some non-default trybots. 88 # Run some non-default trybots.
167 subprocess.check_call( 89 subprocess.check_call(
168 try_cmd + ['-m', 'tryserver.chromium.linux', 90 try_cmd + ['-m', 'tryserver.chromium.linux',
169 '-b', 'linux_arm', 91 '-b', 'linux_arm',
170 '-b', 'linux_arm_compile', 92 '-b', 'linux_arm_compile',
171 '-b', 'linux_rel_precise32', 93 '-b', 'linux_rel_precise32',
172 '-b', 'linux_nacl_sdk_build', 94 '-b', 'linux_nacl_sdk_build',
173 ]) 95 ])
174 subprocess.check_call( 96 subprocess.check_call(
175 try_cmd + ['-m', 'tryserver.chromium.mac', 97 try_cmd + ['-m', 'tryserver.chromium.mac',
176 '-b', 'mac_nacl_sdk_build', 98 '-b', 'mac_nacl_sdk_build',
177 ]) 99 ])
178 subprocess.check_call( 100 subprocess.check_call(
179 try_cmd + ['-m', 'tryserver.chromium.win', 101 try_cmd + ['-m', 'tryserver.chromium.win',
180 '-b', 'win_nacl_sdk_build', 102 '-b', 'win_nacl_sdk_build',
181 ]) 103 ])
182 104
183 105
184 def Main(args): 106 def Main(args):
185 parser = optparse.OptionParser('%prog [options]\n\n' + __doc__.strip()) 107 parser = optparse.OptionParser('%prog [options]\n\n' + __doc__.strip())
186 parser.add_option('-r', '--revision', default=None, type='int', 108 parser.add_option('-r', '--revision', default=None,
187 help='NaCl SVN revision to use (default is HEAD)') 109 help='NaCl GIT revision to use (default is HEAD)')
Mark Seaborn 2015/01/28 16:34:21 Nit: capitalise as "Git"
188 parser.add_option('--no-fetch', action='store_true', default=False, 110 parser.add_option('--no-fetch', action='store_true', default=False,
189 help='Do not run "git fetch". This is useful to speed' 111 help='Do not run "git fetch". This is useful to speed'
190 ' up rerunning the script if you know that the local Git' 112 ' up rerunning the script if you know that the local Git'
191 ' repos are already reasonably up-to-date.') 113 ' repos are already reasonably up-to-date.')
192 parser.add_option('--force-branch', action='store_true', default=False, 114 parser.add_option('--force-branch', action='store_true', default=False,
193 help='Force overwriting the Git branch. This is useful' 115 help='Force overwriting the Git branch. This is useful'
194 ' if a previous run of the script failed after creating' 116 ' if a previous run of the script failed after creating'
195 ' a nacl-deps-rN branch.') 117 ' a nacl-deps-rN branch.')
196 parser.add_option('-n', '--no-commit', action='store_true', default=False, 118 parser.add_option('-n', '--no-commit', action='store_true', default=False,
197 help='Do not run "git commit" (implies --no-upload)') 119 help='Do not run "git commit" (implies --no-upload)')
(...skipping 10 matching lines...) Expand all
208 # those should be retrievable via the reflog. This can also lose 130 # those should be retrievable via the reflog. This can also lose
209 # changes that have been staged to the index but then undone in the 131 # changes that have been staged to the index but then undone in the
210 # working files. 132 # working files.
211 proc = subprocess.Popen(['git', 'diff', '--name-only', 'HEAD'], 133 proc = subprocess.Popen(['git', 'diff', '--name-only', 'HEAD'],
212 stdout=subprocess.PIPE) 134 stdout=subprocess.PIPE)
213 changes = proc.communicate()[0] 135 changes = proc.communicate()[0]
214 assert proc.wait() == 0, proc.wait() 136 assert proc.wait() == 0, proc.wait()
215 if len(changes) != 0: 137 if len(changes) != 0:
216 raise AssertionError('You have uncommitted changes:\n%s' % changes) 138 raise AssertionError('You have uncommitted changes:\n%s' % changes)
217 139
218 svn_rev = options.revision 140 nacl_git_dir = NACL_GIT_ROOT
219 if svn_rev is None:
220 svn_rev = GetNaClRev()
221
222 nacl_git_dir = 'native_client'
223 if not options.no_fetch: 141 if not options.no_fetch:
224 subprocess.check_call(['git', 'fetch']) 142 subprocess.check_call(['git', 'fetch'])
225 subprocess.check_call(['git', 'fetch'], cwd=nacl_git_dir) 143 subprocess.check_call(['git', 'fetch'], cwd=nacl_git_dir)
JF 2015/01/28 07:12:17 I'm not sure I understand what the NaCl cwd is exp
Mark Seaborn 2015/01/28 16:34:21 This just assumes it's run from a Chromium checkou
bradn 2015/01/28 17:37:32 Correct.
bradn 2015/01/28 17:37:32 What mark said.
226 144
227 branch_name = 'nacl-deps-r%s' % svn_rev 145 new_rev = options.revision
146 if new_rev is None:
147 new_rev = GetNaClRev(nacl_git_dir)
148
149 branch_name = 'nacl-deps-%s' % new_rev
228 if options.force_branch: 150 if options.force_branch:
229 checkout_opt = '-B' 151 checkout_opt = '-B'
230 else: 152 else:
231 checkout_opt = '-b' 153 checkout_opt = '-b'
232 subprocess.check_call(['git', 'checkout', checkout_opt, branch_name, 154 subprocess.check_call(['git', 'checkout', checkout_opt, branch_name,
233 'origin/master']) 155 'origin/master'])
234 156
235 deps_data = ReadFile('DEPS') 157 deps_data = ReadFile('DEPS')
236 old_rev_git = GetDepsField(deps_data, 'nacl_revision') 158 old_rev = GetDepsField(deps_data, 'nacl_revision')
237 159
238 new_rev_comment = 'from svn revision r%s' % svn_rev 160 deps_data = SetDepsField(deps_data, 'nacl_revision', new_rev)
239 new_rev_git = SvnToGitRev(nacl_git_dir, svn_rev)
240 deps_data = SetDepsFieldWithComment(deps_data, 'nacl_revision', new_rev_git,
241 new_rev_comment)
242 161
243 old_rev = GitToSvnRev(nacl_git_dir, old_rev_git) 162 msg_logs, authors = GetLog(nacl_git_dir, old_rev, new_rev)
244 163 msg = 'NaCl: Update revision in DEPS, %s -> %s' % (old_rev[:9], new_rev[:9])
JF 2015/01/28 07:12:17 Isn't the default short hash 7?
Mark Seaborn 2015/01/28 16:34:21 Yes, JF is right. Let's use 7.
bradn 2015/01/28 17:37:32 Done.
bradn 2015/01/28 17:37:32 Done.
245 msg_logs, authors = GetLog(old_rev, svn_rev)
246 msg = 'NaCl: Update revision in DEPS, r%i -> r%i' % (old_rev, svn_rev)
247 msg += '\n\nThis pulls in the following Native Client changes:\n\n' 164 msg += '\n\nThis pulls in the following Native Client changes:\n\n'
248 msg += msg_logs 165 msg += msg_logs
249 msg += '\nBUG=none\nTEST=browser_tests and nacl_integration\n' 166 msg += '\nBUG=none\nTEST=browser_tests and nacl_integration\n'
250 msg += 'CQ_EXTRA_TRYBOTS=tryserver.chromium.linux:linux_rel_precise32,linux_ar m_compile,linux_nacl_sdk_build\n' 167 msg += 'CQ_EXTRA_TRYBOTS=tryserver.chromium.linux:linux_rel_precise32,linux_ar m_compile,linux_nacl_sdk_build\n'
251 print msg 168 print msg
252 cc_list = ', '.join(['native-client-reviews@googlegroups.com'] + 169 cc_list = ', '.join(['native-client-reviews@googlegroups.com'] +
253 sorted(set(authors))) 170 sorted(set(authors)))
254 print 'CC:', cc_list 171 print 'CC:', cc_list
255 172
256 # Copy revision numbers across from native_client/DEPS.
257 # We do this because 'From()' is not supported in Chrome's DEPS.
258 proc = subprocess.Popen(['svn', 'cat', '%s/DEPS@%s' % (NACL_SVN, svn_rev)],
259 stdout=subprocess.PIPE)
260 nacl_deps = proc.communicate()[0]
261 assert proc.wait() == 0, proc.wait()
262 tools_rev = GetDepsField(nacl_deps, 'tools_rev')
263 # Chromium's DEPS file used to contain a single "nacl_tools_revision"
264 # field that we would update to match NaCl's "tools_rev". Since Chromium
265 # switched to using Git revisions in DEPS, "nacl_tools_revision" has been
266 # replaced by multiple fields. We don't currently support updating those
267 # fields automatically. Instead, just assert that NaCl's "tools_rev"
268 # hasn't changed.
269 # TODO(mseaborn): Fix this automatic syncing. Maybe this should wait
Mark Seaborn 2015/01/28 16:34:21 I guess we can add back this automatic syncing if
bradn 2015/01/28 17:37:32 Yeah I figure its problematic for the moment.
270 # until NaCl has also switched to using Git revisions in its DEPS file.
271 assert tools_rev in ('13077', '13800'), tools_rev
272
273 WriteFile('DEPS', deps_data) 173 WriteFile('DEPS', deps_data)
274 174
275 if options.no_commit: 175 if options.no_commit:
276 return 176 return
277 subprocess.check_call(['git', 'commit', '-a', '-m', msg]) 177 subprocess.check_call(['git', 'commit', '-a', '-m', msg])
278 178
279 if options.no_upload: 179 if options.no_upload:
280 return 180 return
281 # Override EDITOR so that "git cl upload" will run non-interactively. 181 # Override EDITOR so that "git cl upload" will run non-interactively.
282 environ = os.environ.copy() 182 environ = os.environ.copy()
(...skipping 11 matching lines...) Expand all
294 # This CC does not happen by default for DEPS. 194 # This CC does not happen by default for DEPS.
295 '--cc', cc_list, 195 '--cc', cc_list,
296 ], env=environ) 196 ], env=environ)
297 if options.no_try: 197 if options.no_try:
298 return 198 return
299 RunTrybots() 199 RunTrybots()
300 200
301 201
302 if __name__ == '__main__': 202 if __name__ == '__main__':
303 Main(sys.argv[1:]) 203 Main(sys.argv[1:])
OLDNEW
« no previous file with comments | « no previous file | nacl_deps_bump_cronjob.py » ('j') | nacl_deps_bump_cronjob.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698