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

Side by Side Diff: tools/download_and_extract.py

Issue 209853003: Adding binutils as a DEPS to allow DebugFission on Ubuntu Precise when compiling with clang. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixing DEPS file. Created 6 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
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2014 The Chromium Authors. All rights reserved.
Lei Zhang 2014/04/01 05:10:48 nit: no (c) in new copyright headers.
mithro-old 2014/04/02 04:22:33 Done.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5 # vim: set ts=2 sw=2 et sts=2 ai:
6
7 """Download files for your platfrom and extract its contents into a directory.
8
9 Uses download_from_google_storage for the actual download process.
10 Uses tar to extract the files from the archive.
11
12 The input is a list of sha1 files suitable for download_from_google_storage.
13 """
14
15 """
16 TODO: Replace the other download/extract scripts that exist in the chrome tree.
17
18 Replace chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py
19 download_and_extract.py \\
20 --default-file-arch Linux \\
21 --bucket chrome-linux-sysroot \\
22 --extract ????/debian_wheezy_???-sysroot \\
23 <sha1 files??>
24
25 Replace build/linux/install-arm-sysroot.py
26 download_and_extract.py \\
27 --bucket nativeclient-archive2 \\
28 --extract build/linux/arm-sys-root \\
29 <sha1 files??>
30
31 Replace download part of tools/clang/scripts/update.(py|sh)
32 download_and_extract.py \\
33 --bucket chromium-browser-clang \\
34 --extract third_party/llvm-build/Release+Asserts \\
35 <sha1 files??>
36 """
37
38
39 import optparse
40 import os
41 import os.path
Lei Zhang 2014/04/01 05:10:48 already covered under import os.
mithro-old 2014/04/02 04:22:33 Fixed. Old habit from when os.path you had to bac
42 import re
43 import shutil
44 import subprocess
45 import sys
46
47
48 def MatchPatterns(mapping, string, error):
49 for pattern, result in mapping:
50 if re.search(pattern, string, re.I):
51 return result
52 raise ValueError(error % string)
53
54
55 def ExtractAndNormalizeArch(string):
56 """Extract and normalize an architecture string.
57 >>> # Linux arch / uname output
58 >>> ExtractAndNormalizeArch('x86_64')
59 'amd64'
60 >>> ExtractAndNormalizeArch('i686')
61 'i386'
62 >>> ExtractAndNormalizeArch('i386')
63 'i386'
64
65 >>> # autoconf "platform" tuple
66 >>> ExtractAndNormalizeArch('i686-pc-linux-gnu')
67 'i386'
68 >>> ExtractAndNormalizeArch('x86_64-unknown-linux-gnu')
69 'amd64'
70
71 >>> # platform.machine()
72 >>> ExtractAndNormalizeArch('i386')
73 'i386'
74 >>> ExtractAndNormalizeArch('x86_64')
75 'amd64'
76
77 >>> # GYP Defines
78 >>> ExtractAndNormalizeArch('target_arch=x64')
79 'amd64'
80 >>> ExtractAndNormalizeArch('target_arch=ia32')
81 'i386'
82 >>> ExtractAndNormalizeArch('x64')
83 'amd64'
84 >>> ExtractAndNormalizeArch('ia32')
85 'i386'
86
87 >>> # Empty Arch
88 >>> ExtractAndNormalizeArch('')
89 ''
90 """
91 ARCH_MAPPING = [
92 # Linux 'arch' outputs
93 ('i[3456]?86', 'i386'),
94 ('i86pc', 'i386'),
95 ('x86_64', 'amd64'),
96 ('amd64', 'amd64'),
97 ('mips64', 'mips64'), # Must be before mips
98 ('mips', 'mips'),
99 ('arm', 'arm'),
100 ('aarch', 'arm64'),
101 # Windows
102 ('win32', 'i386'),
103 ('win64', 'amd64'),
104 # GYP defines
105 ('ia32', 'i386'),
106 ('x64', 'amd64'),
107 # Empty arch
108 ('^$', ''),
109 ]
110 return MatchPatterns(
111 ARCH_MAPPING, string,
112 'Was not able to extract architecture from %s')
113
114
115 def ExtractAndNormalizeOS(string):
116 """Extract and normalize an OS string.
117
118 >>> # Used by download_from_storage
119 >>> # sys.platform
120 >>> ExtractAndNormalizeOS('linux2')
121 'Linux'
122 >>> ExtractAndNormalizeOS('darwin')
123 'Mac'
124 >>> ExtractAndNormalizeOS('cygwin')
125 'Win'
126 >>> ExtractAndNormalizeOS('win32')
127 'Win'
128 >>> ExtractAndNormalizeOS('win64')
129 'Win'
130
131 >>> # platform.system()
132 >>> ExtractAndNormalizeOS('Linux')
133 'Linux'
134 >>> ExtractAndNormalizeOS('Windows')
135 'Win'
136
137 >>> # Used by tools/clang/scripts
138 >>> # uname -s
139 >>> ExtractAndNormalizeOS('Linux')
140 'Linux'
141 >>> ExtractAndNormalizeOS('Darwin')
142 'Mac'
143
144 >>> # GYP defines
145 >>> ExtractAndNormalizeOS('win')
146 'Win'
147 >>> ExtractAndNormalizeOS('linux')
148 'Linux'
149 >>> ExtractAndNormalizeOS('mac')
150 'Mac'
151
152 >>> # GNU triplets
153 >>> ExtractAndNormalizeOS('i686-pc-linux-gnu')
154 'Linux'
155 >>> ExtractAndNormalizeOS('x86_64-unknown-linux-gnu')
156 'Linux'
157 >>> ExtractAndNormalizeOS('i586-pc-mingw32')
158 'Win'
159 >>> ExtractAndNormalizeOS('i386-pc-cygwin')
160 'Win'
161 >>> ExtractAndNormalizeOS('i386-pc-win32')
162 'Win'
163 >>> ExtractAndNormalizeOS('x86_64-apple-darwin10')
164 'Mac'
165 """
166 PLATFORM_MAPPING = [
167 # Mac
168 ('darwin', 'Mac'),
169 ('mac', 'Mac'),
170 # Linux
171 ('linux.*', 'Linux'),
172 # Windows
173 ('cygwin', 'Win'),
174 ('mingw', 'Win'),
175 ('win', 'Win'),
176 ]
177 return MatchPatterns(
178 PLATFORM_MAPPING, string,
179 'Was not able to extract operating system from %s')
180
181
182 def GetSystemArch(os_str):
183 if os_str == 'Linux':
184 # Try calling arch first, then fall back to uname
185 try:
186 return subprocess.check_output(['arch']).strip()
187 except subprocess.CalledProcessError, e:
188 # We want the architecture, which is roughly the machine hardware name
189 # in uname.
190 # -m, --machine; print the machine hardware name
191 # These other two are possibilities?
192 # -p, --processor; print the processor type or 'unknown'
193 # -i, --hardware-platform; print the hardware platform or 'unknown'
194 return subprocess.check_output(['uname', '-m']).strip()
195 else:
196 # TODO: Make this work under Mac / Windows
197 return ''
198
199
200 def FilterFilesByPlatform(files, target_os, target_arch,
201 file_os_default=None, file_arch_default=''):
202 """Filter input files to given platform.
203
204 We assume the target arch is the host arch if not overridden.
205
206 >>> clang_style = [
207 ... 'abc/Linux_ia32/xxx.sha1',
208 ... 'abc/Linux_x64/xxx.sha1',
209 ... 'abc/Mac/xxx.sha1',
210 ... 'abc/Win/xxx.sha1',
211 ... ]
212 >>> FilterFilesByPlatform(clang_style, 'Linux', 'i386')
213 ['abc/Linux_ia32/xxx.sha1']
214 >>> FilterFilesByPlatform(clang_style, 'Linux', 'amd64')
215 ['abc/Linux_x64/xxx.sha1']
216 >>> FilterFilesByPlatform(clang_style, 'Win', '')
217 ['abc/Win/xxx.sha1']
218 >>> FilterFilesByPlatform(clang_style, 'Mac', '')
219 ['abc/Mac/xxx.sha1']
220
221 >>> gnu_style = [
222 ... 'XXX-i686-pc-linux-gnu.XXX.sha1',
223 ... 'XXX-x86_64-unknown-linux-gnu.XXX.sha1',
224 ... 'XXX-i586-pc-mingw32.XXX.sha1',
225 ... 'XXX-i386-pc-win32.XXX.sha1',
226 ... 'XXX-x86_64-apple-darwin10.XXX.sha1',
227 ... ]
228 >>> FilterFilesByPlatform(gnu_style, 'Linux', 'i386')
229 ['XXX-i686-pc-linux-gnu.XXX.sha1']
230 >>> FilterFilesByPlatform(gnu_style, 'Linux', 'amd64')
231 ['XXX-x86_64-unknown-linux-gnu.XXX.sha1']
232 >>> FilterFilesByPlatform(gnu_style, 'Win', '')
233 ['XXX-i586-pc-mingw32.XXX.sha1', 'XXX-i386-pc-win32.XXX.sha1']
234 >>> FilterFilesByPlatform(gnu_style, 'Mac', '')
235 ['XXX-x86_64-apple-darwin10.XXX.sha1']
236
237 >>> simple_no_os = [
238 ... 'XXXX_amd64_XXX',
239 ... 'XXXX_i386_XXX',
240 ... ]
241 >>> FilterFilesByPlatform(
242 ... simple_no_os, 'Linux', 'i386', file_os_default='Linux')
243 ['XXXX_i386_XXX']
244 >>> FilterFilesByPlatform(
245 ... simple_no_os, 'Linux', 'amd64', file_os_default='Linux')
246 ['XXXX_amd64_XXX']
247 >>> FilterFilesByPlatform(
248 ... simple_no_os, 'Win', '', file_os_default='Linux')
249 []
250 >>> # Fails when no default is provided and can't extract from filename.
251 >>> FilterFilesByPlatform(simple_no_os, 'Linux', 'i386')
252 Traceback (most recent call last):
253 ...
254 ValueError: Was not able to extract operating system from XXXX_amd64_XXX
255 """
256 todo = []
Lei Zhang 2014/04/01 05:10:48 Would "sha1_paths" or "download_sha1s" be better n
mithro-old 2014/04/02 04:22:33 This function isn't actually specific to .sha1 nor
257 for filename in files:
258 try:
259 file_os = ExtractAndNormalizeOS(filename)
260 except ValueError, e:
261 if file_os_default is None:
262 raise
263 file_os = file_os_default
264
265 try:
266 file_arch = ExtractAndNormalizeArch(filename)
267 except ValueError:
268 if file_arch_default is None:
269 raise
270 file_arch = file_arch_default
271
272 match = True
273 if target_os != '' and file_os != '':
274 match = target_os == file_os
275
276 if target_arch != '' and file_arch != '':
277 match = match and target_arch == file_arch
278
279 if match:
280 todo.append(filename)
281
282 return todo
283
284
285 class StampFile(object):
286 """Stores a stamp for when an action occured.
287
288 This is normally a revision number or checksum of the input files to the
289 process. Proper usage of stamping will mean a partial action is never
290 considered successful.
291
292 Proper usage is;
293 * /Check/ -- Check the stamp file matches your revision/checksum.
294 * /Delete/ -- Delete the existing stamp file.
295 * /Clean up/ -- Clean up any partially failed previous attempt.
296 * /Do action/ -- Do your work.
297 * /Set/ -- Set the stamp file to your revision/checksum.
298
299 For example:
300 >>> stamp = 'mySHA1sum'
301 >>> action_stamp = StampFile('stamp.action')
302 >>> # Check stamp
303 >>> if stamp != action_stamp.get(): # doctest: +SKIP
304 ... # Delete stamp
305 ... action_stamp.delete()
306 ... # Clean up
307 ... if os.path.exists(filename):
308 ... os.unlink(filename)
309 ... # Action
310 ... do_download(filename)
311 ... # Set stamp
312 ... action_stamp.set(stamp)
313 """
314
315 def __init__(self, filename):
316 self.filename = filename
317
318 def get(self):
319 try:
320 return file(self.filename, 'r').read()
321 except IOError, e:
322 # We use NaN because it is not equal even to itself, so equality checks
323 # will always fail.
324 return float('NaN')
325
326 def delete(self):
327 if os.path.exists(self.filename):
328 os.unlink(self.filename)
329
330 def set(self, stamp):
331 if os.path.exists(self.filename):
332 raise IOError('Stamp file %r currently exist!' % filename)
333
334 f = file(self.filename, 'w')
335 f.write(stamp)
336 # Force a fsync so this ends up on disk and other processes can see it.
337 os.fsync(f)
338 f.close()
339
340
341 def main(args):
342 usage = (
343 'usage: %prog [options] targets\n\n'
344 'Downloads and extracts targets which match the platform.\n'
345 'Targets must be a list of a .sha1 file, containing a sha1 sum'
346 'used by download_from_google_storage tool.')
347
348 parser = optparse.OptionParser(usage)
349 parser.add_option(
350 '-b', '--bucket',
351 help='Google Storage bucket to fetch from.')
352 parser.add_option(
353 '-e', '--extract',
354 help='Directory to extract the downloaded files into.')
355 parser.add_option(
356 '-a', '--target-arch',
357 help='Override architecture to given value.')
358 parser.add_option(
359 '', '--default-file-arch',
360 help='Override input file architecture to given value.')
361 parser.add_option(
362 '', '--default-file-os',
363 help='Override input file operating system to given value.')
364 parser.add_option(
365 '', '--self-test', default=False, action="store_true",
366 help='Run the internal tests.')
367
368 (options, files) = parser.parse_args()
369
370 if options.self_test:
371 import doctest
372 return doctest.testmod()
373
374 errors = []
375 if not options.bucket:
376 errors.append('--bucket (-b) is required option.')
377
378 if not options.extract:
379 errors.append('--extract (-e) is required option.')
380
381 if not files:
382 errors.append('Need to specify files to download.')
383
384 for filename in files:
385 if not os.path.exists(filename):
386 errors.append('File %s does not exist.' % filename)
387
388 if errors:
389 parser.error('\n '.join(errors))
390
391 # Figure out which files we want to download. Filter by the current platform
392 # the tool is being run on.
393 target_os = ExtractAndNormalizeOS(sys.platform)
394
395 target_arch = None
396 if options.target_arch:
397 target_arch = options.target_arch
398 else:
399 # Try to get target_arch out of GYP
400 gyp_target_arch = re.search(
401 '(target_arch=[^ ]*)', os.environ.get('GYP_DEFINES', ''))
402 if gyp_target_arch:
403 target_arch = gyp_target_arch.groups(1)
404
405 if target_arch is None: # '' is a valid target_arch
406 target_arch = GetSystemArch(target_os)
407
408 target_arch = ExtractAndNormalizeArch(target_arch)
409
410 todo = FilterFilesByPlatform(
411 files,
412 target_os,
413 target_arch,
414 file_os_default=options.default_file_os,
415 file_arch_default=options.default_file_arch)
416
417 if len(todo) == 0:
418 print 'No files to download.'
419 return 0
420
421 elif len(todo) > 1:
422 # TODO: Support downloading and extracting multiple files.
423 parser.error(
424 'Matched multiple files on this platform!\n' + '\n'.join(todo))
425 return 1
426
427 # Process the files
428 for filename in todo:
429 filename = os.path.abspath(filename)
430
431 basename, ext = os.path.splitext(filename)
432 assert ext == '.sha1', 'Input filename %s does not end in .sha1' % filename
433 sha1 = file(filename, 'r').read().strip()
434
435 # Download the tarball
436 download_stamp = StampFile('%s.stamp.download' % basename)
437 if sha1 != download_stamp.get():
438 print "Downloading", basename
439 download_stamp.delete()
440 if os.path.exists(basename):
441 os.unlink(basename)
442
443 subprocess.check_call([
444 'download_from_google_storage',
445 '--no_resume',
446 '--no_auth',
447 '--bucket', options.bucket,
448 '-s', filename])
449
450 download_stamp.set(sha1)
451
452 # Extract the tarball
453 extract_stamp = StampFile('%s.stamp.untar' % basename)
454 if sha1 != extract_stamp.get():
455 print "Extracting", basename
456 extract_stamp.delete()
457 if os.path.exists(options.extract):
458 shutil.rmtree(options.extract)
459
460 taroptions = 'xf'
Lei Zhang 2014/04/01 05:10:48 you can tar axf any.common.tar.extension. a = --a
mithro-old 2014/04/02 04:22:33 Done. Removed the file type detection and using a
461 if basename.endswith('.bz2'):
462 taroptions += 'j'
463 if basename.endswith('.gz'):
464 taroptions += 'z'
465 if basename.endswith('.xz'):
466 taroptions += 'J'
467
468 os.makedirs(options.extract)
469 # TODO: Use https://docs.python.org/2/library/tarfile.html rather than
Lei Zhang 2014/04/01 05:10:48 I was just going to mention this. :)
Lei Zhang 2014/04/01 05:10:48 nit: TODO(username), same above.
mithro-old 2014/04/02 04:22:33 I did a search and replace for "TODO:" to "TODO(mi
mithro-old 2014/04/02 04:22:33 If we want to support windows then using tarfile i
Lei Zhang 2014/04/02 07:22:28 Erm. If you really can't commit to finishing up th
Lei Zhang 2014/04/02 07:22:28 This is also a bit troublesome. Since it's in tool
470 # tar cmdline.
471 subprocess.check_call(
472 ['tar', taroptions, basename], cwd=options.extract)
473
474 extract_stamp.set(sha1)
475
476 return 0
477
478
479 if __name__ == '__main__':
480 sys.exit(main(sys.argv))
OLDNEW
« third_party/binutils/upload.sh ('K') | « third_party/binutils/upload.sh ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698