OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Downloads a Firefox Nightly build for the current platform.""" | 6 """Downloads a Firefox Nightly build for the current platform.""" |
7 | 7 |
| 8 import datetime |
| 9 import glob |
8 import os | 10 import os |
9 import shutil | 11 import shutil |
10 import sys | 12 import sys |
11 import subprocess | 13 import subprocess |
12 import tarfile | 14 import tarfile |
| 15 import time |
13 import zipfile | 16 import zipfile |
14 | 17 |
15 from optparse import OptionParser | 18 from optparse import OptionParser |
16 | 19 |
17 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | 20 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) |
18 THIRD_PARTY_DIR = os.path.abspath(os.path.join(BASE_DIR, 'third_party')) | 21 THIRD_PARTY_DIR = os.path.abspath(os.path.join(BASE_DIR, 'third_party')) |
19 | 22 |
20 sys.path.append(os.path.join(THIRD_PARTY_DIR, 'mozdownload')) | 23 sys.path.append(os.path.join(THIRD_PARTY_DIR, 'mozdownload')) |
21 sys.path.append(os.path.join(THIRD_PARTY_DIR, 'mozinfo')) | 24 sys.path.append(os.path.join(THIRD_PARTY_DIR, 'mozinfo')) |
22 | 25 |
23 from mozdownload import scraper | 26 from mozdownload import scraper |
24 | 27 |
25 | 28 |
26 def main(): | 29 def _Touch(a_file): |
27 usage = 'usage: %prog -t <target_dir>' | 30 with open(a_file, 'a'): |
28 parser = OptionParser(usage) | 31 os.utime(a_file, None) |
29 parser.add_option('-t', '--target-dir', | |
30 help=('Target directory to put the downloaded and extracted' | |
31 ' folder with the Firefox Nightly build in.')) | |
32 parser.add_option('-f', '--force', action='store_true', | |
33 help=('Force download even if the current nightly is ' | |
34 'already downloaded.')) | |
35 options, _args = parser.parse_args() | |
36 if not options.target_dir: | |
37 parser.error('You must specify the target directory.') | |
38 | 32 |
39 target_dir = options.target_dir | |
40 if not os.path.isdir(target_dir): | |
41 os.mkdir(target_dir) | |
42 | 33 |
43 downloader = scraper.DailyScraper(directory=target_dir, version=None) | 34 def _FindFallbackFirefoxBuild(target_dir): |
44 firefox_archive = os.path.join(target_dir, | 35 firefox_archives = glob.glob(os.path.join(target_dir, '*tar.bz2')) |
45 downloader.build_filename(downloader.binary)) | 36 if not firefox_archives: |
| 37 return None |
46 | 38 |
47 if os.path.exists(firefox_archive) and not options.force: | 39 firefox_archives.sort(key=os.path.getmtime, reverse=True) |
48 print 'Skipping download as %s is already downloaded.' % firefox_archive | 40 newest_build = firefox_archives[0] |
49 return 0 | 41 build_age_seconds = time.time() - os.path.getmtime(newest_build) |
| 42 build_age_days = datetime.timedelta(seconds=build_age_seconds).days |
50 | 43 |
51 downloader.download() | 44 return newest_build, build_age_days |
52 print 'Downloaded %s' % firefox_archive | |
53 | 45 |
54 # Extract the archive. | 46 |
55 # TODO(phoglund): implement on win/mac | 47 def _MaybeDownload(target_dir, force): |
| 48 try: |
| 49 downloader = scraper.DailyScraper(directory=target_dir, version=None) |
| 50 filename = downloader.build_filename(downloader.binary) |
| 51 firefox_archive = os.path.join(target_dir, filename) |
| 52 |
| 53 if os.path.exists(firefox_archive) and not force: |
| 54 # Touch the file anyway since we were 'successful', so we can accurately |
| 55 # compute the age of the most recent download attempt and act accordingly |
| 56 # when a download fails later. |
| 57 _Touch(firefox_archive) |
| 58 print 'Skipping download as %s is already downloaded.' % firefox_archive |
| 59 return None |
| 60 |
| 61 downloader.download() |
| 62 print 'Downloaded %s' % firefox_archive |
| 63 return firefox_archive |
| 64 except scraper.NotFoundException as exception: |
| 65 print 'Failed to download firefox: %s.' % exception |
| 66 fallback_build, age_days = _FindFallbackFirefoxBuild(target_dir) |
| 67 |
| 68 if not fallback_build: |
| 69 raise Exception('We failed to download Firefox and we have no builds to ' |
| 70 'fall back on; failing...') |
| 71 if age_days > 3: |
| 72 raise Exception('We have failed to download firefox builds for more ' |
| 73 'than 3 days now: failing so someone looks at it. The ' |
| 74 'most recent build we have is %d days old.' % age_days) |
| 75 |
| 76 print 'Using %s instead; it is %d days old.' % (fallback_build, age_days) |
| 77 return fallback_build |
| 78 |
| 79 |
| 80 def _ExtractArchive(firefox_archive, target_dir): |
| 81 # TODO(phoglund): implement on win/mac. See http://crbug.com/454303. |
56 if sys.platform == 'darwin': | 82 if sys.platform == 'darwin': |
57 print "Temporarily disabled on mac..." | 83 print "Disabled on mac..." |
58 return 0 | 84 return 0 |
59 volume = '/Volumes/Nightly' | 85 volume = '/Volumes/Nightly' |
60 firefox_executable = '%s/FirefoxNightly.app' % target_dir | 86 firefox_executable = '%s/FirefoxNightly.app' % target_dir |
61 | 87 |
62 # Unmount any previous downloads. | 88 # Unmount any previous downloads. |
63 subprocess.call(['hdiutil', 'detach', volume]) | 89 subprocess.call(['hdiutil', 'detach', volume]) |
64 | 90 |
65 subprocess.check_call(['hdiutil', 'attach', firefox_archive]) | 91 subprocess.check_call(['hdiutil', 'attach', firefox_archive]) |
66 shutil.copytree('%s/FirefoxNightly.app' % volume, firefox_executable) | 92 shutil.copytree('%s/FirefoxNightly.app' % volume, firefox_executable) |
67 subprocess.check_call(['hdiutil', 'detach', volume]) | 93 subprocess.check_call(['hdiutil', 'detach', volume]) |
68 elif sys.platform == 'linux2': | 94 elif sys.platform == 'linux2': |
69 tar_archive = tarfile.open(firefox_archive, 'r:bz2') | 95 tar_archive = tarfile.open(firefox_archive, 'r:bz2') |
70 tar_archive.extractall(path=target_dir) | 96 tar_archive.extractall(path=target_dir) |
71 elif sys.platform == 'win32': | 97 elif sys.platform == 'win32': |
72 print "Temporarily disabled on win..." | 98 print "Disabled on win..." |
73 return 0 | 99 return 0 |
74 zip_archive = zipfile.ZipFile(firefox_archive) | 100 zip_archive = zipfile.ZipFile(firefox_archive) |
75 zip_archive.extractall(path=target_dir) | 101 zip_archive.extractall(path=target_dir) |
76 else: | 102 else: |
77 print >> sys.stderr, 'Unsupported platform: %s' % sys.platform | 103 print >> sys.stderr, 'Unsupported platform: %s' % sys.platform |
78 return 1 | 104 return 1 |
79 | 105 |
80 print 'Extracted %s' % firefox_archive | 106 print 'Extracted %s' % firefox_archive |
81 return 0 | 107 return 0 |
82 | 108 |
| 109 |
| 110 def main(): |
| 111 usage = 'usage: %prog -t <target_dir>' |
| 112 parser = OptionParser(usage) |
| 113 parser.add_option('-t', '--target-dir', |
| 114 help=('Target directory to put the downloaded and extracted' |
| 115 ' folder with the Firefox Nightly build in.')) |
| 116 parser.add_option('-f', '--force', action='store_true', |
| 117 help=('Force download even if the current nightly is ' |
| 118 'already downloaded.')) |
| 119 options, _args = parser.parse_args() |
| 120 if not options.target_dir: |
| 121 parser.error('You must specify the target directory.') |
| 122 |
| 123 target_dir = options.target_dir |
| 124 if not os.path.isdir(target_dir): |
| 125 os.mkdir(target_dir) |
| 126 |
| 127 firefox_archive = _MaybeDownload(target_dir, options.force) |
| 128 if firefox_archive: |
| 129 return _ExtractArchive(firefox_archive, target_dir) |
| 130 |
83 if __name__ == '__main__': | 131 if __name__ == '__main__': |
84 sys.exit(main()) | 132 sys.exit(main()) |
OLD | NEW |