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 |