1# Copyright (c) 2012 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import hashlib 6import os 7import sys 8# when pylint runs the third_party module is the one from depot_tools 9# pylint: disable=E0611 10from third_party import fancy_urllib 11import urllib2 12 13 14SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) 15 16 17def UrlOpen(url): 18 request = fancy_urllib.FancyRequest(url) 19 ca_certs = os.path.join(SCRIPT_DIR, 'cacerts.txt') 20 request.set_ssl_info(ca_certs=ca_certs) 21 url_opener = urllib2.build_opener( 22 fancy_urllib.FancyProxyHandler(), 23 fancy_urllib.FancyRedirectHandler(), 24 fancy_urllib.FancyHTTPSHandler()) 25 return url_opener.open(request) 26 27 28def MakeProgressFunction(file_size): 29 # An inner function can only read nonlocal variables, not assign them. We can 30 # work around this by using a list of one element. 31 dots = [0] 32 def ShowKnownProgress(progress): 33 '''Returns a progress function based on a known file size''' 34 if progress == 0: 35 sys.stdout.write('|%s|\n' % ('=' * 48)) 36 elif progress == -1: 37 sys.stdout.write('\n') 38 else: 39 new_dots = progress * 50 / file_size - dots[0] 40 sys.stdout.write('.' * new_dots) 41 dots[0] += new_dots 42 sys.stdout.flush() 43 44 return ShowKnownProgress 45 46 47def DownloadAndComputeHash(from_stream, to_stream=None, progress_func=None): 48 '''Read from from-stream and generate sha1 and size info. 49 50 Args: 51 from_stream: An input stream that supports read. 52 to_stream: [optional] the data is written to to_stream if it is 53 provided. 54 progress_func: [optional] A function used to report download progress. If 55 provided, progress_func is called with progress=0 at the 56 beginning of the download, periodically with progress>0 57 (== number of bytes read do far) during the download, and 58 progress=-1 at the end or if the download was aborted. 59 60 Return 61 A tuple (sha1, size) where sha1 is a sha1-hash for the archive data and 62 size is the size of the archive data in bytes.''' 63 # Use a no-op progress function if none is specified. 64 def progress_no_op(progress): 65 pass 66 if not progress_func: 67 progress_func = progress_no_op 68 69 sha1_hash = hashlib.sha1() 70 size = 0 71 try: 72 progress_func(progress=0) 73 while True: 74 data = from_stream.read(32768) 75 if not data: 76 break 77 sha1_hash.update(data) 78 size += len(data) 79 if to_stream: 80 to_stream.write(data) 81 progress_func(size) 82 finally: 83 progress_func(progress=-1) 84 return sha1_hash.hexdigest(), size 85