2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
14 # Print a dot every time this number of bytes is read.
15 PROGRESS_SPACING
= 128 * 1024
18 def ReadFile(filename
):
19 fh
= open(filename
, 'r')
26 def WriteFile(filename
, data
):
27 fh
= open(filename
, 'w')
34 def HashFile(filename
):
35 hasher
= hashlib
.sha1()
36 fh
= open(filename
, 'rb')
45 return hasher
.hexdigest()
48 def CopyStream(input_stream
, output_stream
):
49 """Copies the contents of input_stream to output_stream. Prints
50 dots to indicate progress.
55 data
= input_stream
.read(4096)
58 output_stream
.write(data
)
59 bytes_read
+= len(data
)
60 if bytes_read
/ PROGRESS_SPACING
> dots_printed
:
66 def RenameWithRetry(old_path
, new_path
):
67 # Renames of files that have recently been closed are known to be
68 # unreliable on Windows, because virus checkers like to keep the
69 # file open for a little while longer. This tends to happen more
70 # for files that look like Windows executables, which does not apply
71 # to our files, but we retry the rename here just in case.
72 if sys
.platform
in ('win32', 'cygwin'):
75 if os
.path
.exists(new_path
):
77 os
.rename(old_path
, new_path
)
79 except Exception, exn
:
80 sys
.stdout
.write('Rename failed with %r. Retrying...\n' % str(exn
))
83 raise Exception('Unabled to rename irt file')
85 os
.rename(old_path
, new_path
)
88 def DownloadFile(dest_path
, url
):
89 url_path
= '%s.url' % dest_path
90 temp_path
= '%s.temp' % dest_path
91 if os
.path
.exists(url_path
) and ReadFile(url_path
).strip() == url
:
92 # The URL matches that of the file we previously downloaded, so
93 # there should be nothing to do.
95 sys
.stdout
.write('Downloading %r to %r\n' % (url
, dest_path
))
96 output_fh
= open(temp_path
, 'wb')
97 stream
= urllib2
.urlopen(url
)
98 CopyStream(stream
, output_fh
)
100 sys
.stdout
.write(' done\n')
101 if os
.path
.exists(url_path
):
103 RenameWithRetry(temp_path
, dest_path
)
104 WriteFile(url_path
, url
+ '\n')
108 def DownloadFileWithRetry(dest_path
, url
):
111 DownloadFile(dest_path
, url
)
113 except urllib2
.HTTPError
, exn
:
114 if exn
.getcode() == 404:
116 sys
.stdout
.write('Download failed with error %r. Retrying...\n'
122 def EvalDepsFile(path
):
123 scope
= {'Var': lambda name
: scope
['vars'][name
]}
124 execfile(path
, {}, scope
)
129 parser
= optparse
.OptionParser()
131 '--base_url', dest
='base_url',
132 # For a view of this site that includes directory listings, see:
133 # http://gsdview.appspot.com/nativeclient-archive2/
134 # (The trailing slash is required.)
135 default
=('http://commondatastorage.googleapis.com/'
136 'nativeclient-archive2/irt'),
137 help='Base URL from which to download.')
139 '--nacl_revision', dest
='nacl_revision',
140 help='Download an IRT binary that was built from this '
141 'SVN revision of Native Client.')
143 '--file_hash', dest
='file_hashes', action
='append', nargs
=2, default
=[],
145 help='ARCH gives the name of the architecture (e.g. "x86_32") for '
146 'which to download an IRT binary. '
147 'HASH gives the expected SHA1 hash of the file.')
148 options
, args
= parser
.parse_args()
150 parser
.error('Unexpected arguments: %r' % args
)
152 if options
.nacl_revision
is None and len(options
.file_hashes
) == 0:
153 # The script must have been invoked directly with no arguments,
154 # rather than being invoked by gclient. In this case, read the
155 # DEPS file ourselves rather than having gclient pass us values
157 deps_data
= EvalDepsFile(os
.path
.join('src', 'DEPS'))
158 options
.nacl_revision
= deps_data
['vars']['nacl_revision']
159 options
.file_hashes
= [
160 ('x86_32', deps_data
['vars']['nacl_irt_hash_x86_32']),
161 ('x86_64', deps_data
['vars']['nacl_irt_hash_x86_64']),
164 nacl_dir
= os
.path
.join('src', 'native_client')
165 if not os
.path
.exists(nacl_dir
):
166 # If "native_client" is not present, this might be because the
167 # developer has put '"src/native_client": None' in their
168 # '.gclient' file, because they don't want to build Chromium with
169 # Native Client support. So don't create 'src/native_client',
170 # because that would interfere with checking it out from SVN
173 'The directory %r does not exist: skipping downloading binaries '
174 'for Native Client\'s IRT library\n' % nacl_dir
)
176 if len(options
.file_hashes
) == 0:
177 sys
.stdout
.write('No --file_hash arguments given: nothing to update\n')
180 for arch
, expected_hash
in options
.file_hashes
:
181 url
= '%s/r%s/irt_%s.nexe' % (options
.base_url
,
182 options
.nacl_revision
,
184 dest_dir
= os
.path
.join(nacl_dir
, 'irt_binaries')
185 if not os
.path
.exists(dest_dir
):
186 os
.makedirs(dest_dir
)
187 dest_path
= os
.path
.join(dest_dir
, 'nacl_irt_%s.nexe' % arch
)
188 DownloadFileWithRetry(dest_path
, url
)
189 downloaded_hash
= HashFile(dest_path
)
190 if downloaded_hash
!= expected_hash
:
192 'Hash mismatch: the file downloaded from URL %r had hash %r, '
193 'but we expected %r\n' % (url
, downloaded_hash
, expected_hash
))
194 new_deps
.append(' "nacl_irt_hash_%s": "%s",\n'
195 % (arch
, downloaded_hash
))
197 if len(new_deps
) > 0:
198 sys
.stdout
.write('\nIf you have changed nacl_revision, the DEPS file '
199 'probably needs to be updated with the following:\n%s\n'
204 if __name__
== '__main__':