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

Side by Side Diff: native_client_sdk/src/build_tools/sdk_tools/sdk_update.py

Issue 10065030: [NaCl SDK] Change build script to test sdk_updater, also push manifest snippets per bot. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 8 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 | « native_client_sdk/src/build_tools/manifest_util.py ('k') | 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 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium 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 '''A simple tool to update the Native Client SDK to the latest version''' 6 '''A simple tool to update the Native Client SDK to the latest version'''
7 7
8 import cStringIO 8 import cStringIO
9 import cygtar 9 import cygtar
10 import errno 10 import errno
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 mgs: A string to send to stderr.''' 96 mgs: A string to send to stderr.'''
97 sys.stderr.write("WARNING: %s\n" % msg) 97 sys.stderr.write("WARNING: %s\n" % msg)
98 sys.stderr.flush() 98 sys.stderr.flush()
99 99
100 100
101 class Error(Exception): 101 class Error(Exception):
102 '''Generic error/exception for sdk_update module''' 102 '''Generic error/exception for sdk_update module'''
103 pass 103 pass
104 104
105 105
106 def GetHostOS():
107 '''Returns the host_os value that corresponds to the current host OS'''
108 return {
109 'linux2': 'linux',
110 'darwin': 'mac',
111 'cygwin': 'win',
112 'win32': 'win'
113 }[sys.platform]
114
115 def UrlOpen(url): 106 def UrlOpen(url):
116 request = fancy_urllib.FancyRequest(url) 107 request = fancy_urllib.FancyRequest(url)
117 ca_certs = os.path.join(os.path.dirname(os.path.abspath(__file__)), 108 ca_certs = os.path.join(os.path.dirname(os.path.abspath(__file__)),
118 'cacerts.txt') 109 'cacerts.txt')
119 request.set_ssl_info(ca_certs=ca_certs) 110 request.set_ssl_info(ca_certs=ca_certs)
120 url_opener = urllib2.build_opener( 111 url_opener = urllib2.build_opener(
121 fancy_urllib.FancyProxyHandler(), 112 fancy_urllib.FancyProxyHandler(),
122 fancy_urllib.FancyRedirectHandler(), 113 fancy_urllib.FancyRedirectHandler(),
123 fancy_urllib.FancyHTTPSHandler()) 114 fancy_urllib.FancyHTTPSHandler())
124 return url_opener.open(request) 115 return url_opener.open(request)
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 # handling a Windows flaky access error. Sleep one second and try 191 # handling a Windows flaky access error. Sleep one second and try
201 # again. 192 # again.
202 time.sleep(num_tries + 1) 193 time.sleep(num_tries + 1)
203 # end of while loop -- could not RenameDir 194 # end of while loop -- could not RenameDir
204 raise Error('Could not RenameDir %s => %s after %d tries.\n' % 195 raise Error('Could not RenameDir %s => %s after %d tries.\n' %
205 'Please check that no shells or applications ' 196 'Please check that no shells or applications '
206 'are accessing files in %s.' 197 'are accessing files in %s.'
207 % (srcdir, destdir, num_tries, destdir)) 198 % (srcdir, destdir, num_tries, destdir))
208 199
209 200
210 def ShowProgress(progress):
211 ''' A download-progress function used by class Archive.
212 (See DownloadAndComputeHash).'''
213 global count # A divider, so we don't emit dots too often.
214
215 if progress == 0:
216 count = 0
217 elif progress == 100:
218 sys.stdout.write('\n')
219 else:
220 count = count + 1
221 if count > 10:
222 sys.stdout.write('.')
223 sys.stdout.flush()
224 count = 0
225
226
227 class ProgressFunction(object): 201 class ProgressFunction(object):
228 '''Create a progress function for a file with a given size''' 202 '''Create a progress function for a file with a given size'''
229 203
230 def __init__(self, file_size=0): 204 def __init__(self, file_size=0):
231 '''Constructor 205 '''Constructor
232 206
233 Args: 207 Args:
234 file_size: number of bytes in file. 0 indicates unknown''' 208 file_size: number of bytes in file. 0 indicates unknown'''
235 self.dots = 0 209 self.dots = 0
236 self.file_size = int(file_size) 210 self.file_size = int(file_size)
237 211
238 def GetProgressFunction(self): 212 def GetProgressFunction(self):
239 '''Returns a progress function based on a known file size''' 213 '''Returns a progress function based on a known file size'''
240 def ShowKnownProgress(progress): 214 def ShowKnownProgress(progress):
241 if progress == 0: 215 if progress == 0:
242 sys.stdout.write('|%s|\n' % ('=' * 48)) 216 sys.stdout.write('|%s|\n' % ('=' * 48))
243 else: 217 else:
244 new_dots = progress * 50 / self.file_size - self.dots 218 new_dots = progress * 50 / self.file_size - self.dots
245 sys.stdout.write('.' * new_dots) 219 sys.stdout.write('.' * new_dots)
246 self.dots += new_dots 220 self.dots += new_dots
247 if progress == self.file_size: 221 if progress == self.file_size:
248 sys.stdout.write('\n') 222 sys.stdout.write('\n')
249 sys.stdout.flush() 223 sys.stdout.flush()
250 224
251 return ShowKnownProgress 225 return ShowKnownProgress
252 226
253 227
254 def DownloadAndComputeHash(from_stream, to_stream=None, progress_func=None): 228 def DownloadArchiveToFile(archive, dest_path):
255 ''' Download the archive data from from-stream and generate sha1 and 229 '''Download the archive's data to a file at dest_path.
256 size info. 230
231 As a side effect, computes the sha1 hash and data size, both returned as a
232 tuple. Raises an Error if the url can't be opened, or an IOError exception if
233 dest_path can't be opened.
257 234
258 Args: 235 Args:
259 from_stream: An input stream that supports read. 236 dest_path: Path for the file that will receive the data.
260 to_stream: [optional] the data is written to to_stream if it is 237 Return:
261 provided. 238 A tuple (sha1, size) with the sha1 hash and data size respectively.'''
262 progress_func: [optional] A function used to report download progress. If 239 sha1 = None
263 provided, progress_func is called with progress=0 at the
264 beginning of the download, periodically with progress=1
265 during the download, and progress=100 at the end.
266
267 Return
268 A tuple (sha1, size) where sha1 is a sha1-hash for the archive data and
269 size is the size of the archive data in bytes.'''
270 # Use a no-op progress function if none is specified.
271 def progress_no_op(progress):
272 pass
273 if not progress_func:
274 progress_func = progress_no_op
275
276 sha1_hash = hashlib.sha1()
277 size = 0 240 size = 0
278 progress_func(progress=0) 241 with open(dest_path, 'wb') as to_stream:
279 while(1): 242 from_stream = None
280 data = from_stream.read(32768) 243 try:
281 if not data: 244 from_stream = UrlOpen(archive.url)
282 break 245 except urllib2.URLError:
283 sha1_hash.update(data) 246 raise Error('Cannot open "%s" for archive %s' %
284 size += len(data) 247 (archive.url, archive.host_os))
285 if to_stream: 248 try:
286 to_stream.write(data) 249 content_length = int(from_stream.info()[HTTP_CONTENT_LENGTH])
287 progress_func(size) 250 progress_function = ProgressFunction(content_length).GetProgressFunction()
288 251 InfoPrint('Downloading %s' % archive.url)
289 progress_func(progress=100) 252 sha1, size = manifest_util.DownloadAndComputeHash(
290 return sha1_hash.hexdigest(), size 253 from_stream,
254 to_stream=to_stream,
255 progress_func=progress_function)
256 if size != content_length:
257 raise Error('Download size mismatch for %s.\n'
258 'Expected %s bytes but got %s' %
259 (archive.url, content_length, size))
260 finally:
261 if from_stream: from_stream.close()
262 return sha1, size
291 263
292 264
293 def LoadManifestFromFile(path): 265 def LoadManifestFromFile(path):
294 '''Returns a manifest loaded from the JSON file at |path|. 266 '''Returns a manifest loaded from the JSON file at |path|.
295 267
296 If the path does not exist or is invalid, returns an empty manifest.''' 268 If the path does not exist or is invalid, returns an empty manifest.'''
297 if not os.path.exists(path): 269 if not os.path.exists(path):
298 return manifest_util.SDKManifest() 270 return manifest_util.SDKManifest()
299 271
300 with open(path, 'r') as f: 272 with open(path, 'r') as f:
301 json_string = f.read() 273 json_string = f.read()
302 if not json_string: 274 if not json_string:
303 return manifest_util.SDKManifest() 275 return manifest_util.SDKManifest()
304 276
305 manifest = manifest_util.SDKManifest() 277 manifest = manifest_util.SDKManifest()
306 manifest.LoadManifestString(json_string) 278 manifest.LoadManifestString(json_string)
307 return manifest 279 return manifest
308 280
309 281
310 def LoadManifestFromURL(url): 282 def LoadManifestFromURL(url):
311 '''Returns a manifest loaded from |url|.''' 283 '''Returns a manifest loaded from |url|.'''
312 try: 284 try:
313 url_stream = UrlOpen(url) 285 url_stream = UrlOpen(url)
314 except urllib2.URLError as e: 286 except urllib2.URLError as e:
315 raise Error('Unable to open %s. [%s]' % (url, e)) 287 raise Error('Unable to open %s. [%s]' % (url, e))
316 288
317 manifest_stream = cStringIO.StringIO() 289 manifest_stream = cStringIO.StringIO()
318 sha1, size = DownloadAndComputeHash( 290 sha1, size = manifest_util.DownloadAndComputeHash(url_stream, manifest_stream)
319 url_stream, manifest_stream)
320 manifest = manifest_util.SDKManifest() 291 manifest = manifest_util.SDKManifest()
321 manifest.LoadManifestString(manifest_stream.getvalue()) 292 manifest.LoadManifestString(manifest_stream.getvalue())
322 293
323 def BundleFilter(bundle): 294 def BundleFilter(bundle):
324 # Only add this bundle if it's supported on this platform. 295 # Only add this bundle if it's supported on this platform.
325 return bundle.GetArchive(GetHostOS()) 296 return bundle.GetHostOSArchive()
326 297
327 manifest.FilterBundles(BundleFilter) 298 manifest.FilterBundles(BundleFilter)
328 return manifest 299 return manifest
329 300
330 301
331 def WriteManifestToFile(manifest, path): 302 def WriteManifestToFile(manifest, path):
332 '''Write |manifest| to a JSON file at |path|.''' 303 '''Write |manifest| to a JSON file at |path|.'''
333 json_string = manifest.GetManifestString() 304 json_string = manifest.GetManifestString()
334 305
335 # Write the JSON data to a temp file. 306 # Write the JSON data to a temp file.
336 temp_file_name = None 307 temp_file_name = None
337 # TODO(dspringer): Use file locks here so that multiple sdk_updates can 308 # TODO(dspringer): Use file locks here so that multiple sdk_updates can
338 # run at the same time. 309 # run at the same time.
339 with tempfile.NamedTemporaryFile(mode='w', delete=False) as f: 310 with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
340 f.write(json_string) 311 f.write(json_string)
341 temp_file_name = f.name 312 temp_file_name = f.name
342 # Move the temp file to the actual file. 313 # Move the temp file to the actual file.
343 if os.path.exists(path): 314 if os.path.exists(path):
344 os.remove(path) 315 os.remove(path)
345 shutil.move(temp_file_name, path) 316 shutil.move(temp_file_name, path)
346 317
347 318
348 def DownloadArchiveToFile(archive, dest_path):
349 '''Download the archive's data to a file at dest_path.
350
351 As a side effect, computes the sha1 hash and data size, both returned as a
352 tuple. Raises an Error if the url can't be opened, or an IOError exception if
353 dest_path can't be opened.
354
355 Args:
356 dest_path: Path for the file that will receive the data.
357 Return:
358 A tuple (sha1, size) with the sha1 hash and data size respectively.'''
359 sha1 = None
360 size = 0
361 with open(dest_path, 'wb') as to_stream:
362 from_stream = None
363 try:
364 from_stream = UrlOpen(archive.url)
365 except urllib2.URLError:
366 raise Error('Cannot open "%s" for archive %s' %
367 (archive.url, archive.host_os))
368 try:
369 content_length = int(from_stream.info()[HTTP_CONTENT_LENGTH])
370 progress_function = ProgressFunction(content_length).GetProgressFunction()
371 InfoPrint('Downloading %s' % archive.url)
372 sha1, size = DownloadAndComputeHash(
373 from_stream,
374 to_stream=to_stream,
375 progress_func=progress_function)
376 if size != content_length:
377 raise Error('Download size mismatch for %s.\n'
378 'Expected %s bytes but got %s' %
379 (archive.url, content_length, size))
380 finally:
381 if from_stream: from_stream.close()
382 return sha1, size
383
384
385 #------------------------------------------------------------------------------ 319 #------------------------------------------------------------------------------
386 # Commands 320 # Commands
387 321
388 322
389 def List(options, argv): 323 def List(options, argv):
390 '''Usage: %prog [options] list 324 '''Usage: %prog [options] list
391 325
392 Lists the available SDK bundles that are available for download.''' 326 Lists the available SDK bundles that are available for download.'''
393 def PrintBundles(bundles): 327 def PrintBundles(bundles):
394 for bundle in bundles: 328 for bundle in bundles:
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 398
465 for bundle in bundles: 399 for bundle in bundles:
466 bundle_path = os.path.join(options.sdk_root_dir, bundle.name) 400 bundle_path = os.path.join(options.sdk_root_dir, bundle.name)
467 bundle_update_path = '%s_update' % bundle_path 401 bundle_update_path = '%s_update' % bundle_path
468 if not (bundle.name in args or 402 if not (bundle.name in args or
469 ALL in args or (RECOMMENDED in args and 403 ALL in args or (RECOMMENDED in args and
470 bundle[RECOMMENDED] == 'yes')): 404 bundle[RECOMMENDED] == 'yes')):
471 continue 405 continue
472 def UpdateBundle(): 406 def UpdateBundle():
473 '''Helper to install a bundle''' 407 '''Helper to install a bundle'''
474 archive = bundle.GetArchive(GetHostOS()) 408 archive = bundle.GetHostOSArchive()
475 (scheme, host, path, _, _, _) = urlparse.urlparse(archive['url']) 409 (scheme, host, path, _, _, _) = urlparse.urlparse(archive['url'])
476 dest_filename = os.path.join(options.user_data_dir, path.split('/')[-1]) 410 dest_filename = os.path.join(options.user_data_dir, path.split('/')[-1])
477 sha1, size = DownloadArchiveToFile(archive, dest_filename) 411 sha1, size = DownloadArchiveToFile(archive, dest_filename)
478 if sha1 != archive.GetChecksum(): 412 if sha1 != archive.GetChecksum():
479 raise Error("SHA1 checksum mismatch on '%s'. Expected %s but got %s" % 413 raise Error("SHA1 checksum mismatch on '%s'. Expected %s but got %s" %
480 (bundle.name, archive.GetChecksum(), sha1)) 414 (bundle.name, archive.GetChecksum(), sha1))
481 if size != archive.size: 415 if size != archive.size:
482 raise Error("Size mismatch on Archive. Expected %s but got %s bytes" % 416 raise Error("Size mismatch on Archive. Expected %s but got %s bytes" %
483 (archive.size, size)) 417 (archive.size, size))
484 InfoPrint('Updating bundle %s to version %s, revision %s' % ( 418 InfoPrint('Updating bundle %s to version %s, revision %s' % (
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
611 545
612 return 0 # Success 546 return 0 # Success
613 547
614 548
615 if __name__ == '__main__': 549 if __name__ == '__main__':
616 try: 550 try:
617 sys.exit(main(sys.argv[1:])) 551 sys.exit(main(sys.argv[1:]))
618 except Error as error: 552 except Error as error:
619 print "Error: %s" % error 553 print "Error: %s" % error
620 sys.exit(1) 554 sys.exit(1)
OLDNEW
« no previous file with comments | « native_client_sdk/src/build_tools/manifest_util.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698