Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 # Copyright (c) 2015 The Chromium Authors. All rights reserved. | |
|
dgozman
2016/08/26 19:08:05
new files should have new copyright: no (c), 2016
chenwilliam
2016/08/29 18:42:27
Done.
| |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 """Download and run node.js.""" | |
| 7 # File originally from https://cs.chromium.org/chromium/infra/node/node.py | |
|
dgozman
2016/08/26 19:08:05
Remove.
chenwilliam
2016/08/29 18:42:27
Done.
| |
| 8 | |
| 9 import os | |
| 10 import shutil | |
| 11 import sys | |
| 12 import subprocess | |
| 13 import tarfile | |
| 14 import tempfile | |
| 15 import urllib2 | |
| 16 | |
| 17 THIS_DIR = os.path.dirname(os.path.abspath(__file__)) | |
| 18 | |
| 19 DEFAULT_VERSION = '0.12.2' | |
| 20 BUCKET = 'chromium-infra-bins' | |
| 21 | |
| 22 | |
| 23 def install_latest_node_js(version, tmp_dir): | |
| 24 target_dir = os.path.join(THIS_DIR, 'runtimes', version) | |
| 25 version_file = os.path.join(target_dir, 'VERSION') | |
| 26 | |
| 27 if sys.platform == 'win32': | |
| 28 bin_location = os.path.join(target_dir, 'node.exe') | |
| 29 else: | |
| 30 bin_location = os.path.join(target_dir, 'bin', 'node') | |
| 31 | |
| 32 # We assume that, if the VERSION file exists, then the installation is good. | |
| 33 if os.path.exists(version_file): | |
| 34 with open(version_file, 'r') as f: | |
| 35 if f.read() == version: | |
| 36 return bin_location | |
| 37 | |
| 38 # TODO(hinoka): This probably doesn't work that well on Windows... | |
| 39 shutil.rmtree(target_dir, ignore_errors=True) | |
| 40 | |
| 41 # Get the target name correct. | |
| 42 if sys.platform == 'win32': | |
| 43 target = 'node.exe' | |
| 44 elif sys.platform == 'darwin': | |
| 45 target = 'node-v%s-darwin-x86.tar.gz' % version | |
| 46 elif sys.platform == 'linux2': | |
| 47 target = 'node-v%s-linux-x86.tar.gz' % version | |
| 48 else: | |
| 49 raise Exception('Unrecognized platform %s' % sys.platform) | |
| 50 | |
| 51 dest = os.path.join(tmp_dir, 'node_download') | |
| 52 url = 'https://storage.googleapis.com/%s/node/%s/%s' % ( | |
| 53 BUCKET, version, target) | |
| 54 print('Fetching %s' % url) | |
| 55 u = urllib2.urlopen(url) | |
| 56 with open(dest, 'wb') as f: | |
| 57 while True: | |
| 58 chunk = u.read(2 ** 20) | |
| 59 if not chunk: | |
| 60 break | |
| 61 f.write(chunk) | |
| 62 | |
| 63 # When multiple node.py instances run at the same time for the first time, | |
| 64 # the check to see whether or not the installation occured already. But the n | |
| 65 # they all race to see who's the first to run shutil.move(), which obviously | |
| 66 # fails for everyone other than the first instance. This CL makes | |
| 67 # os.rename() not fail, since its assumed that if it fails that means | |
| 68 # someone else already created an installation. | |
| 69 # | |
| 70 # Another approach is to use an flock, but then it starts to get messy when | |
| 71 # you have to keep polling filesystem state to see if another instance | |
| 72 # finished, or add timeouts to remove an flock if it was left on the system by | |
| 73 # a failed attempt, etc, etc. This just seemed like a less flaky solution, | |
| 74 # despite the fact that it means multiple network requests are spawned. | |
| 75 write_version = True | |
| 76 if sys.platform != 'win32': | |
| 77 # The Windows version comes as a self contained executable, the other | |
| 78 # versions come as a tar.gz that needs to be extracted. | |
| 79 with tarfile.open(dest, 'r:gz') as f: | |
| 80 f.extractall(path=tmp_dir) | |
| 81 try: | |
| 82 os.mkdir(os.path.join(THIS_DIR, 'runtimes')) | |
| 83 os.rename(os.path.join(tmp_dir, target[:-len('.tar.gz')]), | |
| 84 target_dir) | |
| 85 except OSError: | |
| 86 write_version = False | |
| 87 os.remove(dest) | |
| 88 else: | |
| 89 try: | |
| 90 # Still potentiall racy, from python docs: | |
| 91 # "On Windows...there may be no way to implement an atomic rename wh en dst | |
| 92 # names an existing file." | |
| 93 os.mkdir(target_dir) | |
| 94 os.rename(dest, bin_location) | |
| 95 except OSError: | |
| 96 write_version = False | |
| 97 | |
| 98 if write_version: | |
| 99 with open(version_file, 'w') as f: | |
| 100 f.write(version) | |
| 101 | |
| 102 return bin_location | |
| 103 | |
| 104 | |
| 105 def main(mode=None): | |
| 106 version = os.environ.get('NODE_VERSION', DEFAULT_VERSION) | |
| 107 try: | |
| 108 tmp_dir = tempfile.mkdtemp(dir=THIS_DIR) | |
| 109 bin_location = install_latest_node_js(version, tmp_dir) | |
| 110 finally: | |
| 111 if os.path.exists(tmp_dir): | |
| 112 shutil.rmtree(tmp_dir) | |
| 113 | |
| 114 if mode == 'npm': | |
| 115 # TODO(hinoka): How about Windows...? | |
| 116 bin_location = os.path.join(os.path.dirname(bin_location), 'npm') | |
| 117 | |
| 118 return subprocess.call([bin_location, ] + sys.argv[1:]) | |
| 119 | |
| 120 | |
| 121 if __name__ == '__main__': | |
| 122 sys.exit(main()) | |
| OLD | NEW |