blob: 82152ba59007b0c911357958cc11bef42e2b8d16 [file]
#!/usr/bin/env python3
# Copyright 2019 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Run node with the right settings."""
import os
import platform
import shutil
import sys
import libdot
# The hash of the node_modules that we maintain.
# Allow a long line for easy automated updating.
# pylint: disable=line-too-long
NODE_MODULES_HASH = (
"9fa46a29844cc1c69c67698c8dddff1e5bcd015037ffe30e6fad786b9e674719"
)
# pylint: enable=line-too-long
# In sync with Chromium's DEPS file because it's easier to use something that
# already exists than maintain our own.
# Run `./node_sync_with_chromium` to update these settings.
NODE_VER = "16.13.0"
NODE_LINUX_HASH = "ab9544e24e752d3d17f335fb7b2055062e582d11"
NODE_MAC_HASH = "16dfd094763b71988933a31735f9dea966f9abd6"
NODE_WIN_HASH = "5ef847033c517c499f56f9d136d159b663bab717"
# Bucket maintained by Chromium.
# gsutil ls gs://chromium-nodejs/
NODE_BASE_URI = "https://storage.googleapis.com/chromium-nodejs"
# Bucket maintained by us.
NODE_MODULES_GS_FRAGMENT = "chromeos-localmirror/secureshell/distfiles"
NODE_MODULES_GS_URI = f"gs://{NODE_MODULES_GS_FRAGMENT}"
NODE_MODULES_BASE_URI = (
f"https://storage.googleapis.com/{NODE_MODULES_GS_FRAGMENT}"
)
# The node_modules & node/npm paths.
NODE_MODULES_DIR = libdot.LIBAPPS_DIR / "node_modules"
NODE_BIN_DIR = NODE_MODULES_DIR / ".bin"
NODE = NODE_BIN_DIR / "node"
NPM = NODE_BIN_DIR / "npm"
# Use a dotdir as npm expects to manage everything under node_modules/.
NODE_DIR = NODE_MODULES_DIR / ".node"
def run(cmd, **kwargs):
"""Run the node |cmd|.
This assumes |cmd| is a node program. Different OS's might need to invoke
node differently, so wrap the calls here.
"""
# We need the node bin dir to be at the start of the $PATH as some packages
# will try to run other npm packages directly.
extra_env = kwargs.setdefault("extra_env", {})
assert "PATH" not in extra_env
extra_env["PATH"] = os.pathsep.join((str(NODE_BIN_DIR), os.getenv("PATH")))
return libdot.run(
cmd[1:],
cmd_prefix=[NODE, NODE_BIN_DIR / cmd[0]],
log_prefix=[cmd[0]],
**kwargs,
)
def update():
"""Download & update our copy of node."""
osname = platform.system()
if osname == "Linux":
node_hash = NODE_LINUX_HASH
elif osname == "Darwin":
node_hash = NODE_MAC_HASH
elif osname == "Windows":
node_hash = NODE_WIN_HASH
else:
raise RuntimeError(f"Unknown OS {osname}")
# In case of an upgrade, nuke existing dir.
hash_file = NODE_DIR / node_hash
if not hash_file.exists():
shutil.rmtree(NODE_DIR, ignore_errors=True)
node = NODE
if osname == "Windows":
node = node.with_suffix(".exe")
if not node.exists():
os.makedirs(NODE_BIN_DIR, exist_ok=True)
os.makedirs(NODE_DIR, exist_ok=True)
# Download & unpack the archive.
uri = "/".join((NODE_BASE_URI, NODE_VER, node_hash))
output = NODE_DIR / node_hash
libdot.fetch(uri, output)
if osname == "Windows":
libdot.unlink(node)
output.rename(node)
else:
libdot.unpack(output, cwd=NODE_DIR)
libdot.unlink(output)
# Create canonical symlinks for node & npm.
path = next(NODE_DIR.glob("*/bin/node"))
libdot.symlink(path, NODE)
path = next(NODE_DIR.glob("*/*/node_modules/npm/bin/npm-cli.js"))
libdot.symlink(path, NPM)
# Mark the hash of this checkout.
libdot.touch(hash_file)
def modules_update():
"""Download & update our copy of node_modules."""
libdot.download_tarball(
f"node_modules-{NODE_MODULES_HASH}.tar.xz",
NODE_MODULES_BASE_URI,
NODE_MODULES_DIR,
NODE_MODULES_HASH,
)
def main(argv):
"""The main func!"""
libdot.setup_logging()
libdot.node_and_npm_setup()
os.execv(NODE, ["node"] + argv)
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))