Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/scripts/nodejs/node.py |
| diff --git a/third_party/WebKit/Source/devtools/scripts/nodejs/node.py b/third_party/WebKit/Source/devtools/scripts/nodejs/node.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..7502f77869583029d8f6ceda0307a23539f6464f |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/devtools/scripts/nodejs/node.py |
| @@ -0,0 +1,122 @@ |
| +#!/usr/bin/env python |
| +# 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.
|
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +"""Download and run node.js.""" |
| +# 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.
|
| + |
| +import os |
| +import shutil |
| +import sys |
| +import subprocess |
| +import tarfile |
| +import tempfile |
| +import urllib2 |
| + |
| +THIS_DIR = os.path.dirname(os.path.abspath(__file__)) |
| + |
| +DEFAULT_VERSION = '0.12.2' |
| +BUCKET = 'chromium-infra-bins' |
| + |
| + |
| +def install_latest_node_js(version, tmp_dir): |
| + target_dir = os.path.join(THIS_DIR, 'runtimes', version) |
| + version_file = os.path.join(target_dir, 'VERSION') |
| + |
| + if sys.platform == 'win32': |
| + bin_location = os.path.join(target_dir, 'node.exe') |
| + else: |
| + bin_location = os.path.join(target_dir, 'bin', 'node') |
| + |
| + # We assume that, if the VERSION file exists, then the installation is good. |
| + if os.path.exists(version_file): |
| + with open(version_file, 'r') as f: |
| + if f.read() == version: |
| + return bin_location |
| + |
| + # TODO(hinoka): This probably doesn't work that well on Windows... |
| + shutil.rmtree(target_dir, ignore_errors=True) |
| + |
| + # Get the target name correct. |
| + if sys.platform == 'win32': |
| + target = 'node.exe' |
| + elif sys.platform == 'darwin': |
| + target = 'node-v%s-darwin-x86.tar.gz' % version |
| + elif sys.platform == 'linux2': |
| + target = 'node-v%s-linux-x86.tar.gz' % version |
| + else: |
| + raise Exception('Unrecognized platform %s' % sys.platform) |
| + |
| + dest = os.path.join(tmp_dir, 'node_download') |
| + url = 'https://storage.googleapis.com/%s/node/%s/%s' % ( |
| + BUCKET, version, target) |
| + print('Fetching %s' % url) |
| + u = urllib2.urlopen(url) |
| + with open(dest, 'wb') as f: |
| + while True: |
| + chunk = u.read(2 ** 20) |
| + if not chunk: |
| + break |
| + f.write(chunk) |
| + |
| + # When multiple node.py instances run at the same time for the first time, |
| + # the check to see whether or not the installation occured already. But then |
| + # they all race to see who's the first to run shutil.move(), which obviously |
| + # fails for everyone other than the first instance. This CL makes |
| + # os.rename() not fail, since its assumed that if it fails that means |
| + # someone else already created an installation. |
| + # |
| + # Another approach is to use an flock, but then it starts to get messy when |
| + # you have to keep polling filesystem state to see if another instance |
| + # finished, or add timeouts to remove an flock if it was left on the system by |
| + # a failed attempt, etc, etc. This just seemed like a less flaky solution, |
| + # despite the fact that it means multiple network requests are spawned. |
| + write_version = True |
| + if sys.platform != 'win32': |
| + # The Windows version comes as a self contained executable, the other |
| + # versions come as a tar.gz that needs to be extracted. |
| + with tarfile.open(dest, 'r:gz') as f: |
| + f.extractall(path=tmp_dir) |
| + try: |
| + os.mkdir(os.path.join(THIS_DIR, 'runtimes')) |
| + os.rename(os.path.join(tmp_dir, target[:-len('.tar.gz')]), |
| + target_dir) |
| + except OSError: |
| + write_version = False |
| + os.remove(dest) |
| + else: |
| + try: |
| + # Still potentiall racy, from python docs: |
| + # "On Windows...there may be no way to implement an atomic rename when dst |
| + # names an existing file." |
| + os.mkdir(target_dir) |
| + os.rename(dest, bin_location) |
| + except OSError: |
| + write_version = False |
| + |
| + if write_version: |
| + with open(version_file, 'w') as f: |
| + f.write(version) |
| + |
| + return bin_location |
| + |
| + |
| +def main(mode=None): |
| + version = os.environ.get('NODE_VERSION', DEFAULT_VERSION) |
| + try: |
| + tmp_dir = tempfile.mkdtemp(dir=THIS_DIR) |
| + bin_location = install_latest_node_js(version, tmp_dir) |
| + finally: |
| + if os.path.exists(tmp_dir): |
| + shutil.rmtree(tmp_dir) |
| + |
| + if mode == 'npm': |
| + # TODO(hinoka): How about Windows...? |
| + bin_location = os.path.join(os.path.dirname(bin_location), 'npm') |
| + |
| + return subprocess.call([bin_location, ] + sys.argv[1:]) |
| + |
| + |
| +if __name__ == '__main__': |
| + sys.exit(main()) |