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