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

Side by Side Diff: tools/update_reference_build.py

Issue 33353002: Add option to download reference build from internal storage. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix svn ignored file extensions Created 7 years, 2 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 | no next file » | no next file with comments »
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 # 2 #
3 # Copyright (c) 2013 The Chromium Authors. All rights reserved. 3 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 """Updates the Chrome reference builds. 7 """Updates the Chrome reference builds.
8 8
9 Use -r option to update a Chromium reference build, or -b option for Chrome 9 Use -r option to update a Chromium reference build, or -b option for Chrome
10 official builds. 10 official builds.
(...skipping 16 matching lines...) Expand all
27 import time 27 import time
28 import urllib 28 import urllib
29 import urllib2 29 import urllib2
30 import zipfile 30 import zipfile
31 31
32 # Example chromium build location: 32 # Example chromium build location:
33 # gs://chromium-browser-snapshots/Linux/228977/chrome-linux.zip 33 # gs://chromium-browser-snapshots/Linux/228977/chrome-linux.zip
34 CHROMIUM_URL_FMT = ('http://commondatastorage.googleapis.com/' 34 CHROMIUM_URL_FMT = ('http://commondatastorage.googleapis.com/'
35 'chromium-browser-snapshots/%s/%s/%s') 35 'chromium-browser-snapshots/%s/%s/%s')
36 36
37 # Example Chrome build location (no public wed URL's): 37 # Chrome official build storage
38 # https://wiki.corp.google.com/twiki/bin/view/Main/ChromeOfficialBuilds
39
40 # Internal Google archive of official Chrome builds, example:
41 # https://goto.google.com/chrome_official_builds/
42 # 32.0.1677.0/precise32bit/chrome-precise32bit.zip
43 CHROME_INTERNAL_URL_FMT = ('http://master.chrome.corp.google.com/'
44 'official_builds/%s/%s/%s')
shadi 2013/10/23 22:41:36 I was not able to bypass login requirements with g
45
46 # Google storage location (no public web URL's), example:
38 # gs://chrome-archive/30/30.0.1595.0/precise32bit/chrome-precise32bit.zip 47 # gs://chrome-archive/30/30.0.1595.0/precise32bit/chrome-precise32bit.zip
39 CHROME_URL_FMT = ('gs://chrome-archive/%s/%s/%s/%s') 48 CHROME_GS_URL_FMT = ('gs://chrome-archive/%s/%s/%s/%s')
40 49
41 50
42 class BuildUpdater(object): 51 class BuildUpdater(object):
43 _PLATFORM_FILES_MAP = { 52 _PLATFORM_FILES_MAP = {
44 'Win': [ 53 'Win': [
45 'chrome-win32.zip', 54 'chrome-win32.zip',
46 'chrome-win32-syms.zip', 55 'chrome-win32-syms.zip',
47 ], 56 ],
48 'Mac': [ 57 'Mac': [
49 'chrome-mac.zip', 58 'chrome-mac.zip',
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 'Linux': 'chrome_linux', 93 'Linux': 'chrome_linux',
85 'Linux_x64': 'chrome_linux64', 94 'Linux_x64': 'chrome_linux64',
86 'Win': 'chrome_win', 95 'Win': 'chrome_win',
87 'Mac': 'chrome_mac', 96 'Mac': 'chrome_mac',
88 } 97 }
89 98
90 def __init__(self, options): 99 def __init__(self, options):
91 self._platforms = options.platforms.split(',') 100 self._platforms = options.platforms.split(',')
92 self._revision = options.build_number or int(options.revision) 101 self._revision = options.build_number or int(options.revision)
93 self._use_build_number = bool(options.build_number) 102 self._use_build_number = bool(options.build_number)
103 self._use_gs = options.use_gs
94 104
95 @staticmethod 105 @staticmethod
96 def _GetCmdStatusAndOutput(args, cwd=None, shell=False): 106 def _GetCmdStatusAndOutput(args, cwd=None, shell=False):
97 """Executes a subprocess and returns its exit code and output. 107 """Executes a subprocess and returns its exit code and output.
98 108
99 Args: 109 Args:
100 args: A string or a sequence of program arguments. 110 args: A string or a sequence of program arguments.
101 cwd: If not None, the subprocess's current directory will be changed to 111 cwd: If not None, the subprocess's current directory will be changed to
102 |cwd| before it's executed. 112 |cwd| before it's executed.
103 shell: Whether to execute args as a shell command. 113 shell: Whether to execute args as a shell command.
104 114
105 Returns: 115 Returns:
106 The tuple (exit code, output). 116 The tuple (exit code, output).
107 """ 117 """
108 logging.info(str(args) + ' ' + (cwd or '')) 118 logging.info(str(args) + ' ' + (cwd or ''))
109 p = subprocess.Popen(args=args, cwd=cwd, stdout=subprocess.PIPE, 119 p = subprocess.Popen(args=args, cwd=cwd, stdout=subprocess.PIPE,
110 stderr=subprocess.PIPE, shell=shell) 120 stderr=subprocess.PIPE, shell=shell)
111 stdout, stderr = p.communicate() 121 stdout, stderr = p.communicate()
112 exit_code = p.returncode 122 exit_code = p.returncode
113 if stderr: 123 if stderr:
114 logging.critical(stderr) 124 logging.critical(stderr)
115 logging.info(stdout) 125 logging.info(stdout)
116 return (exit_code, stdout) 126 return (exit_code, stdout)
117 127
118 def _GetBuildUrl(self, platform, revision, filename): 128 def _GetBuildUrl(self, platform, revision, filename):
119 if self._use_build_number: 129 if self._use_build_number:
120 release = revision[:revision.find('.')] 130 # Chrome Google storage bucket.
121 return (CHROME_URL_FMT % 131 if self._use_gs:
122 (release, revision, self._BUILD_PLATFORM_MAP[platform], filename)) 132 release = revision[:revision.find('.')]
133 return (CHROME_GS_URL_FMT % (
134 release,
135 revision,
136 self._BUILD_PLATFORM_MAP[platform],
137 filename))
138 # Chrome internal archive.
139 return (CHROME_INTERNAL_URL_FMT % (
140 revision,
141 self._BUILD_PLATFORM_MAP[platform],
142 filename))
143 # Chromium archive.
123 return CHROMIUM_URL_FMT % (urllib.quote_plus(platform), revision, filename) 144 return CHROMIUM_URL_FMT % (urllib.quote_plus(platform), revision, filename)
124 145
125 def _FindBuildRevision(self, platform, revision, filename): 146 def _FindBuildRevision(self, platform, revision, filename):
126 # TODO(shadi): Iterate over build numbers to find a valid one. 147 # TODO(shadi): Iterate over build numbers to find a valid one.
127 if self._use_build_number: 148 if self._use_build_number:
128 return (revision 149 return (revision
129 if self._DoesChromeBuildExist(platform, revision, filename) else 150 if self._DoesBuildExist(platform, revision, filename) else None)
130 None)
131 151
132 MAX_REVISIONS_PER_BUILD = 100 152 MAX_REVISIONS_PER_BUILD = 100
133 for revision_guess in xrange(revision, revision + MAX_REVISIONS_PER_BUILD): 153 for revision_guess in xrange(revision, revision + MAX_REVISIONS_PER_BUILD):
134 if self._DoesChromiumBuildExist(platform, revision_guess, filename): 154 if self._DoesBuildExist(platform, revision_guess, filename):
135 return revision_guess 155 return revision_guess
136 else: 156 else:
137 time.sleep(.1) 157 time.sleep(.1)
138 return None 158 return None
139 159
140 def _DoesChromiumBuildExist(self, platform, build_number, filename): 160 def _DoesBuildExist(self, platform, build_number, filename):
141 url = self._GetBuildUrl(platform, build_number, filename) 161 url = self._GetBuildUrl(platform, build_number, filename)
162 if self._use_gs:
163 return self._DoesGSFileExist(url)
164
142 r = urllib2.Request(url) 165 r = urllib2.Request(url)
143 r.get_method = lambda: 'HEAD' 166 r.get_method = lambda: 'HEAD'
144 try: 167 try:
145 urllib2.urlopen(r) 168 urllib2.urlopen(r)
146 return True 169 return True
147 except urllib2.HTTPError, err: 170 except urllib2.HTTPError, err:
148 if err.code == 404: 171 if err.code == 404:
149 return False 172 return False
150 173
151 def _DoesChromeBuildExist(self, platform, build_number, filename): 174 def _DoesGSFileExist(self, gs_file_name):
152 release = build_number[:build_number.find('.')] 175 exit_code = BuildUpdater._GetCmdStatusAndOutput(
153 gs_file = (CHROME_URL_FMT % 176 ['gsutil', 'ls', gs_file_name])[0]
154 (release,
155 build_number,
156 self._BUILD_PLATFORM_MAP[platform],
157 filename))
158 (exit_code, stdout) = BuildUpdater._GetCmdStatusAndOutput(
159 ['gsutil', 'ls', gs_file])
160
161 return not exit_code 177 return not exit_code
162 178
163 def _GetPlatformFiles(self, platform): 179 def _GetPlatformFiles(self, platform):
164 if self._use_build_number: 180 if self._use_build_number:
165 return BuildUpdater._CHROME_PLATFORM_FILES_MAP[platform] 181 return BuildUpdater._CHROME_PLATFORM_FILES_MAP[platform]
166 return BuildUpdater._PLATFORM_FILES_MAP[platform] 182 return BuildUpdater._PLATFORM_FILES_MAP[platform]
167 183
168 def _DownloadBuilds(self): 184 def _DownloadBuilds(self):
169 for platform in self._platforms: 185 for platform in self._platforms:
170 for f in self._GetPlatformFiles(platform): 186 for f in self._GetPlatformFiles(platform):
171 output = os.path.join('dl', platform, 187 output = os.path.join('dl', platform,
172 '%s_%s_%s' % (platform, self._revision, f)) 188 '%s_%s_%s' % (platform, self._revision, f))
173 if os.path.exists(output): 189 if os.path.exists(output):
174 logging.info('%s alread exists, skipping download' % output) 190 logging.info('%s alread exists, skipping download', output)
175 continue 191 continue
176 build_revision = self._FindBuildRevision(platform, self._revision, f) 192 build_revision = self._FindBuildRevision(platform, self._revision, f)
177 if not build_revision: 193 if not build_revision:
178 logging.critical('Failed to find %s build for r%s\n' % ( 194 logging.critical('Failed to find %s build for r%s\n', platform,
179 platform, self._revision)) 195 self._revision)
180 sys.exit(1) 196 sys.exit(1)
181 dirname = os.path.dirname(output) 197 dirname = os.path.dirname(output)
182 if dirname and not os.path.exists(dirname): 198 if dirname and not os.path.exists(dirname):
183 os.makedirs(dirname) 199 os.makedirs(dirname)
184 url = self._GetBuildUrl(platform, build_revision, f) 200 url = self._GetBuildUrl(platform, build_revision, f)
185 self._DownloadFile(url, output) 201 self._DownloadFile(url, output)
186 202
187 def _DownloadFile(self, url, output): 203 def _DownloadFile(self, url, output):
188 logging.info('Downloading %s, saving to %s' % (url, output)) 204 logging.info('Downloading %s, saving to %s', url, output)
189 if self._use_build_number: 205 if self._use_build_number and self._use_gs:
190 BuildUpdater._GetCmdStatusAndOutput(['gsutil', 'cp', url, output]) 206 BuildUpdater._GetCmdStatusAndOutput(['gsutil', 'cp', url, output])
191 else: 207 else:
192 r = urllib2.urlopen(url) 208 r = urllib2.urlopen(url)
193 with file(output, 'wb') as f: 209 with file(output, 'wb') as f:
194 f.write(r.read()) 210 f.write(r.read())
195 211
196 def _FetchSvnRepos(self): 212 def _FetchSvnRepos(self):
197 if not os.path.exists('reference_builds'): 213 if not os.path.exists('reference_builds'):
198 os.makedirs('reference_builds') 214 os.makedirs('reference_builds')
199 BuildUpdater._GetCmdStatusAndOutput( 215 BuildUpdater._GetCmdStatusAndOutput(
200 ['gclient', 'config', 216 ['gclient', 'config',
201 'svn://svn.chromium.org/chrome/trunk/deps/reference_builds'], 217 'svn://svn.chromium.org/chrome/trunk/deps/reference_builds'],
202 'reference_builds') 218 'reference_builds')
203 BuildUpdater._GetCmdStatusAndOutput( 219 BuildUpdater._GetCmdStatusAndOutput(
204 ['gclient', 'sync'], 'reference_builds') 220 ['gclient', 'sync'], 'reference_builds')
205 221
206 def _UnzipFile(self, dl_file, dest_dir): 222 def _UnzipFile(self, dl_file, dest_dir):
207 if not zipfile.is_zipfile(dl_file): 223 if not zipfile.is_zipfile(dl_file):
208 return False 224 return False
209 logging.info('Opening %s' % dl_file) 225 logging.info('Opening %s', dl_file)
210 with zipfile.ZipFile(dl_file, 'r') as z: 226 with zipfile.ZipFile(dl_file, 'r') as z:
211 for content in z.namelist(): 227 for content in z.namelist():
212 dest = os.path.join(dest_dir, content[content.find('/')+1:]) 228 dest = os.path.join(dest_dir, content[content.find('/')+1:])
213 # Create dest parent dir if it does not exist. 229 # Create dest parent dir if it does not exist.
214 if not os.path.isdir(os.path.dirname(dest)): 230 if not os.path.isdir(os.path.dirname(dest)):
215 os.makedirs(os.path.dirname(dest)) 231 os.makedirs(os.path.dirname(dest))
216 # If dest is just a dir listing, do nothing. 232 # If dest is just a dir listing, do nothing.
217 if not os.path.basename(dest): 233 if not os.path.basename(dest):
218 continue 234 continue
219 with z.open(content) as unzipped_content: 235 with z.open(content) as unzipped_content:
220 logging.info('Extracting %s to %s (%s)' % (content, dest, dl_file)) 236 logging.info('Extracting %s to %s (%s)', content, dest, dl_file)
221 with file(dest, 'wb') as dest_file: 237 with file(dest, 'wb') as dest_file:
222 dest_file.write(unzipped_content.read()) 238 dest_file.write(unzipped_content.read())
223 permissions = z.getinfo(content).external_attr >> 16 239 permissions = z.getinfo(content).external_attr >> 16
224 if permissions: 240 if permissions:
225 os.chmod(dest, permissions) 241 os.chmod(dest, permissions)
226 return True 242 return True
227 243
228 def _ClearDir(self, dir): 244 def _ClearDir(self, dir):
229 """Clears all files in |dir| except for hidden files and folders.""" 245 """Clears all files in |dir| except for hidden files and folders."""
230 for root, dirs, files in os.walk(dir): 246 for root, dirs, files in os.walk(dir):
231 # Skip hidden files and folders (like .svn and .git). 247 # Skip hidden files and folders (like .svn and .git).
232 files = [f for f in files if f[0] != '.'] 248 files = [f for f in files if f[0] != '.']
233 dirs[:] = [d for d in dirs if d[0] != '.'] 249 dirs[:] = [d for d in dirs if d[0] != '.']
234 250
235 for f in files: 251 for f in files:
236 os.remove(os.path.join(root, f)) 252 os.remove(os.path.join(root, f))
237 253
238 def _ExtractBuilds(self): 254 def _ExtractBuilds(self):
239 for platform in self._platforms: 255 for platform in self._platforms:
240 if os.path.exists('tmp_unzip'): 256 if os.path.exists('tmp_unzip'):
241 os.path.unlink('tmp_unzip') 257 os.path.unlink('tmp_unzip')
242 dest_dir = os.path.join('reference_builds', 'reference_builds', 258 dest_dir = os.path.join('reference_builds', 'reference_builds',
243 BuildUpdater._PLATFORM_DEST_MAP[platform]) 259 BuildUpdater._PLATFORM_DEST_MAP[platform])
244 self._ClearDir(dest_dir) 260 self._ClearDir(dest_dir)
245 for root, _, dl_files in os.walk(os.path.join('dl', platform)): 261 for root, _, dl_files in os.walk(os.path.join('dl', platform)):
246 for dl_file in dl_files: 262 for dl_file in dl_files:
247 dl_file = os.path.join(root, dl_file) 263 dl_file = os.path.join(root, dl_file)
248 if not self._UnzipFile(dl_file, dest_dir): 264 if not self._UnzipFile(dl_file, dest_dir):
249 logging.info('Copying %s to %s' % (dl_file, dest_dir)) 265 logging.info('Copying %s to %s', dl_file, dest_dir)
250 shutil.copy(dl_file, dest_dir) 266 shutil.copy(dl_file, dest_dir)
251 267
252 def _SvnAddAndRemove(self): 268 def _SvnAddAndRemove(self):
253 svn_dir = os.path.join('reference_builds', 'reference_builds') 269 svn_dir = os.path.join('reference_builds', 'reference_builds')
254 stat = BuildUpdater._GetCmdStatusAndOutput(['svn', 'stat'], svn_dir)[1] 270 # List all changes without ignoring any files.
271 stat = BuildUpdater._GetCmdStatusAndOutput(['svn', 'stat', '--no-ignore'],
272 svn_dir)[1]
255 for line in stat.splitlines(): 273 for line in stat.splitlines():
256 action, filename = line.split(None, 1) 274 action, filename = line.split(None, 1)
257 if action == '?': 275 # Add new and ignored files.
276 if action == '?' or action == 'I':
258 BuildUpdater._GetCmdStatusAndOutput( 277 BuildUpdater._GetCmdStatusAndOutput(
259 ['svn', 'add', filename], svn_dir) 278 ['svn', 'add', filename], svn_dir)
260 elif action == '!': 279 elif action == '!':
261 BuildUpdater._GetCmdStatusAndOutput( 280 BuildUpdater._GetCmdStatusAndOutput(
262 ['svn', 'delete', filename], svn_dir) 281 ['svn', 'delete', filename], svn_dir)
263 filepath = os.path.join(svn_dir, filename) 282 filepath = os.path.join(svn_dir, filename)
264 if not os.path.isdir(filepath) and os.access(filepath, os.X_OK): 283 if not os.path.isdir(filepath) and os.access(filepath, os.X_OK):
265 BuildUpdater._GetCmdStatusAndOutput( 284 BuildUpdater._GetCmdStatusAndOutput(
266 ['svn', 'propset', 'svn:executable', 'true', filename], svn_dir) 285 ['svn', 'propset', 'svn:executable', 'true', filename], svn_dir)
267 286
268 def DownloadAndUpdateBuilds(self): 287 def DownloadAndUpdateBuilds(self):
269 self._DownloadBuilds() 288 self._DownloadBuilds()
270 self._FetchSvnRepos() 289 self._FetchSvnRepos()
271 self._ExtractBuilds() 290 self._ExtractBuilds()
272 self._SvnAddAndRemove() 291 self._SvnAddAndRemove()
273 292
274 293
275 def ParseOptions(argv): 294 def ParseOptions(argv):
276 parser = optparse.OptionParser() 295 parser = optparse.OptionParser()
277 usage = 'usage: %prog <options>' 296 usage = 'usage: %prog <options>'
278 parser.set_usage(usage) 297 parser.set_usage(usage)
279 parser.add_option('-b', dest='build_number', 298 parser.add_option('-b', dest='build_number',
280 help='Chrome official build number to pick up.') 299 help='Chrome official build number to pick up.')
281 parser.add_option('-r', dest='revision', 300 parser.add_option('--gs', dest='use_gs', action='store_true', default=False,
282 help='Revision to pick up.') 301 help='Use Google storage for official builds. Used with -b '
302 'option. Default is false (i.e. use internal storage.')
283 parser.add_option('-p', dest='platforms', 303 parser.add_option('-p', dest='platforms',
284 default='Win,Mac,Linux,Linux_x64', 304 default='Win,Mac,Linux,Linux_x64',
285 help='Comma separated list of platforms to download ' 305 help='Comma separated list of platforms to download '
286 '(as defined by the chromium builders).') 306 '(as defined by the chromium builders).')
307 parser.add_option('-r', dest='revision',
308 help='Revision to pick up.')
309
287 (options, _) = parser.parse_args(argv) 310 (options, _) = parser.parse_args(argv)
288 if not options.revision and not options.build_number: 311 if not options.revision and not options.build_number:
289 logging.critical('Must specify either -r or -b.\n') 312 logging.critical('Must specify either -r or -b.\n')
290 sys.exit(1) 313 sys.exit(1)
291 if options.revision and options.build_number: 314 if options.revision and options.build_number:
292 logging.critical('Must specify either -r or -b but not both.\n') 315 logging.critical('Must specify either -r or -b but not both.\n')
293 sys.exit(1) 316 sys.exit(1)
317 if options.use_gs and not options.build_number:
318 logging.critical('Can only use --gs with -b option.\n')
319 sys.exit(1)
294 320
295 return options 321 return options
296 322
297 323
298 def main(argv): 324 def main(argv):
299 logging.getLogger().setLevel(logging.DEBUG) 325 logging.getLogger().setLevel(logging.DEBUG)
300 options = ParseOptions(argv) 326 options = ParseOptions(argv)
301 b = BuildUpdater(options) 327 b = BuildUpdater(options)
302 b.DownloadAndUpdateBuilds() 328 b.DownloadAndUpdateBuilds()
303 logging.info('Successfully updated reference builds. Move to ' 329 logging.info('Successfully updated reference builds. Move to '
304 'reference_builds/reference_builds and make a change with gcl.') 330 'reference_builds/reference_builds and make a change with gcl.')
305 331
306 if __name__ == '__main__': 332 if __name__ == '__main__':
307 sys.exit(main(sys.argv)) 333 sys.exit(main(sys.argv))
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698