16320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org#!/usr/bin/python 26320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org# Copyright (c) 2012 The Native Client Authors. All rights reserved. 36320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org# Use of this source code is governed by a BSD-style license that can be 46320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org# found in the LICENSE file. 56320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 66320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org"""A library to assist automatically downloading files. 76320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 86320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgThis library is used by scripts that download tarballs, zipfiles, etc. as part 96320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgof the build process. 106320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org""" 116320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 126320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgimport hashlib 136320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgimport http_download 146320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgimport os.path 156320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgimport re 166320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgimport shutil 176320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgimport sys 186320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgimport time 196320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgimport urllib2 206320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 216320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgSOURCE_STAMP = 'SOURCE_URL' 226320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgHASH_STAMP = 'SOURCE_SHA1' 236320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 246320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 256320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org# Designed to handle more general inputs than sys.platform because the platform 266320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org# name may come from the command line. 276320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgPLATFORM_COLLAPSE = { 286320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 'windows': 'windows', 296320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 'win32': 'windows', 306320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 'cygwin': 'windows', 316320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 'linux': 'linux', 326320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 'linux2': 'linux', 336320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 'linux3': 'linux', 346320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 'darwin': 'mac', 356320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 'mac': 'mac', 366320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org} 376320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 386320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgARCH_COLLAPSE = { 396320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 'i386' : 'x86', 406320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 'i686' : 'x86', 416320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 'x86_64': 'x86', 426320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 'armv7l': 'arm', 436320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org} 446320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 456320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 466320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgclass HashError(Exception): 476320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org def __init__(self, download_url, expected_hash, actual_hash): 486320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org self.download_url = download_url 496320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org self.expected_hash = expected_hash 506320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org self.actual_hash = actual_hash 516320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 526320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org def __str__(self): 536320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return 'Got hash "%s" but expected hash "%s" for "%s"' % ( 546320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org self.actual_hash, self.expected_hash, self.download_url) 556320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 566320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 576320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef PlatformName(name=None): 586320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if name is None: 596320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org name = sys.platform 606320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return PLATFORM_COLLAPSE[name] 616320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 626320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef ArchName(name=None): 636320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if name is None: 646320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if PlatformName() == 'windows': 656320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # TODO(pdox): Figure out how to auto-detect 32-bit vs 64-bit Windows. 666320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org name = 'i386' 676320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org else: 686320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org import platform 696320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org name = platform.machine() 706320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return ARCH_COLLAPSE[name] 716320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 726320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef EnsureFileCanBeWritten(filename): 736320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org directory = os.path.dirname(filename) 746320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if not os.path.exists(directory): 756320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org os.makedirs(directory) 766320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 776320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 786320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef WriteData(filename, data): 796320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org EnsureFileCanBeWritten(filename) 806320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org f = open(filename, 'wb') 816320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org f.write(data) 826320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org f.close() 836320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 846320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 856320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef WriteDataFromStream(filename, stream, chunk_size, verbose=True): 866320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org EnsureFileCanBeWritten(filename) 876320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org dst = open(filename, 'wb') 886320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org try: 896320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org while True: 906320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org data = stream.read(chunk_size) 916320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if len(data) == 0: 926320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org break 936320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org dst.write(data) 946320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if verbose: 956320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # Indicate that we're still writing. 966320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org sys.stdout.write('.') 976320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org sys.stdout.flush() 986320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org finally: 996320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if verbose: 1006320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org sys.stdout.write('\n') 1016320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org dst.close() 1026320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1036320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1046320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef DoesStampMatch(stampfile, expected, index): 1056320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org try: 1066320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org f = open(stampfile, 'r') 1076320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org stamp = f.read() 1086320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org f.close() 1096320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if stamp.split('\n')[index] == expected: 1106320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return "already up-to-date." 1116320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org elif stamp.startswith('manual'): 1126320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return "manual override." 1136320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return False 1146320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org except IOError: 1156320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return False 1166320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1176320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1186320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef WriteStamp(stampfile, data): 1196320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org EnsureFileCanBeWritten(stampfile) 1206320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org f = open(stampfile, 'w') 1216320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org f.write(data) 1226320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org f.close() 1236320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1246320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1256320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef StampIsCurrent(path, stamp_name, stamp_contents, min_time=None, index=0): 1266320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org stampfile = os.path.join(path, stamp_name) 1276320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1286320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # Check if the stampfile is older than the minimum last mod time 1296320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if min_time: 1306320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org try: 1316320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org stamp_time = os.stat(stampfile).st_mtime 1326320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if stamp_time <= min_time: 1336320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return False 1346320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org except OSError: 1356320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return False 1366320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1376320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return DoesStampMatch(stampfile, stamp_contents, index) 1386320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1396320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1406320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef WriteSourceStamp(path, url): 1416320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org stampfile = os.path.join(path, SOURCE_STAMP) 1426320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org WriteStamp(stampfile, url) 1436320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1446320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef WriteHashStamp(path, hash_val): 1456320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org hash_stampfile = os.path.join(path, HASH_STAMP) 1466320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org WriteStamp(hash_stampfile, hash_val) 1476320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1486320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1496320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef Retry(op, *args): 1506320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # Windows seems to be prone to having commands that delete files or 1516320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # directories fail. We currently do not have a complete understanding why, 1526320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # and as a workaround we simply retry the command a few times. 1536320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # It appears that file locks are hanging around longer than they should. This 1546320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # may be a secondary effect of processes hanging around longer than they 1556320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # should. This may be because when we kill a browser sel_ldr does not exit 1566320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # immediately, etc. 1576320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # Virus checkers can also accidently prevent files from being deleted, but 1586320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # that shouldn't be a problem on the bots. 1596320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if sys.platform in ('win32', 'cygwin'): 1606320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org count = 0 1616320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org while True: 1626320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org try: 1636320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org op(*args) 1646320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org break 1656320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org except Exception: 1666320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org sys.stdout.write("FAILED: %s %s\n" % (op.__name__, repr(args))) 1676320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org count += 1 1686320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if count < 5: 1696320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org sys.stdout.write("RETRY: %s %s\n" % (op.__name__, repr(args))) 1706320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org time.sleep(pow(2, count)) 1716320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org else: 1726320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # Don't mask the exception. 1736320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org raise 1746320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org else: 1756320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org op(*args) 1766320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1776320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1786320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef MoveDirCleanly(src, dst): 1796320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org RemoveDir(dst) 1806320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org MoveDir(src, dst) 1816320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1826320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1836320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef MoveDir(src, dst): 1846320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org Retry(shutil.move, src, dst) 1856320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1866320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1876320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef RemoveDir(path): 1886320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if os.path.exists(path): 1896320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org Retry(shutil.rmtree, path) 1906320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1916320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1926320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef RemoveFile(path): 1936320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if os.path.exists(path): 1946320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org Retry(os.unlink, path) 1956320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1966320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 1976320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef _HashFileHandle(fh): 1986320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org """sha1 of a file like object. 1996320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2006320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org Arguments: 2016320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org fh: file handle like object to hash. 2026320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org Returns: 2036320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org sha1 as a string. 2046320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org """ 2056320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org hasher = hashlib.sha1() 2066320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org try: 2076320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org while True: 2086320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org data = fh.read(4096) 2096320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if not data: 2106320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org break 2116320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org hasher.update(data) 2126320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org finally: 2136320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org fh.close() 2146320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return hasher.hexdigest() 2156320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2166320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2176320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef HashFile(filename): 2186320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org """sha1 a file on disk. 2196320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2206320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org Arguments: 2216320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org filename: filename to hash. 2226320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org Returns: 2236320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org sha1 as a string. 2246320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org """ 2256320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org fh = open(filename, 'rb') 2266320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return _HashFileHandle(fh) 2276320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2286320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2296320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef HashUrlByDownloading(url): 2306320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org """sha1 the data at an url. 2316320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2326320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org Arguments: 2336320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org url: url to download from. 2346320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org Returns: 2356320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org sha1 of the data at the url. 2366320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org """ 2376320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org try: 2386320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org fh = urllib2.urlopen(url) 2396320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org except: 2406320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org sys.stderr.write("Failed fetching URL: %s\n" % url) 2416320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org raise 2426320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return _HashFileHandle(fh) 2436320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2446320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2456320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org# Attempts to get the SHA1 hash of a file given a URL by looking for 2466320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org# an adjacent file with a ".sha1hash" suffix. This saves having to 2476320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org# download a large tarball just to get its hash. Otherwise, we fall 2486320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org# back to downloading the main file. 2496320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef HashUrl(url): 2506320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org hash_url = '%s.sha1hash' % url 2516320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org try: 2526320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org fh = urllib2.urlopen(hash_url) 2536320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org data = fh.read(100) 2546320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org fh.close() 2556320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org except urllib2.HTTPError, exn: 2566320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if exn.code == 404: 2576320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return HashUrlByDownloading(url) 2586320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org raise 2596320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org else: 2606320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if not re.match('[0-9a-f]{40}\n?$', data): 2616320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org raise AssertionError('Bad SHA1 hash file: %r' % data) 2626320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return data.strip() 2636320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2646320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2656320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.orgdef SyncURL(url, filename=None, stamp_dir=None, min_time=None, 2666320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org hash_val=None, keep=False, verbose=False, stamp_index=0): 2676320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org """Synchronize a destination file with a URL 2686320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2696320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if the URL does not match the URL stamp, then we must re-download it. 2706320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2716320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org Arugments: 2726320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org url: the url which will to compare against and download 2736320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org filename: the file to create on download 2746320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org path: the download path 2756320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org stamp_dir: the filename containing the URL stamp to check against 2766320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org hash_val: if set, the expected hash which must be matched 2776320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org verbose: prints out status as it runs 2786320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org stamp_index: index within the stamp file to check. 2796320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org Returns: 2806320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org True if the file is replaced 2816320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org False if the file is not replaced 2826320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org Exception: 2836320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org HashError: if the hash does not match 2846320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org """ 2856320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2866320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org assert url and filename 2876320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2886320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # If we are not keeping the tarball, or we already have it, we can 2896320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # skip downloading it for this reason. If we are keeping it, 2906320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # it must exist. 2916320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if keep: 2926320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org tarball_ok = os.path.isfile(filename) 2936320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org else: 2946320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org tarball_ok = True 2956320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 2966320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # If we don't need the tarball and the stamp_file matches the url, then 2976320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # we must be up to date. If the URL differs but the recorded hash matches 2986320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # the one we'll insist the tarball has, then that's good enough too. 2996320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # TODO(mcgrathr): Download the .sha1sum file first to compare with 3006320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org # the cached hash, in case --file-hash options weren't used. 3016320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if tarball_ok and stamp_dir is not None: 3026320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if StampIsCurrent(stamp_dir, SOURCE_STAMP, url, min_time): 3036320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if verbose: 3046320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org print '%s is already up to date.' % filename 3056320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return False 3066320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if (hash_val is not None and 3076320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org StampIsCurrent(stamp_dir, HASH_STAMP, hash_val, min_time, stamp_index)): 3086320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if verbose: 3096320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org print '%s is identical to the up to date file.' % filename 3106320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return False 3116320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 3126320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if verbose: 3136320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org print 'Updating %s\n\tfrom %s.' % (filename, url) 3146320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org EnsureFileCanBeWritten(filename) 3156320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org http_download.HttpDownload(url, filename) 3166320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 3176320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if hash_val: 3186320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org tar_hash = HashFile(filename) 3196320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org if hash_val != tar_hash: 3206320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org raise HashError(actual_hash=tar_hash, expected_hash=hash_val, 3216320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org download_url=url) 3226320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org 3236320e8f393539b7a536b32b5a072a474709da5ffcommit-bot@chromium.org return True 324