blob: e2814c5614012f94a7a362e7bc55db4ec368e588 [file] [log] [blame]
#!/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
# Bucket maintained by us.
NODE_MODULES_GS_FRAGMENT = "chromeos-localmirror/secureshell/distfiles"
NODE_MODULES_GS_URI = f"gs://{NODE_MODULES_GS_FRAGMENT}"
# The node_modules & node paths.
NODE_MODULES_DIR = libdot.LIBAPPS_DIR / "node_modules"
NODE_BIN_DIR = NODE_MODULES_DIR / ".bin"
NODE = NODE_BIN_DIR / "node"
# 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.
"""
extra_env = kwargs.setdefault("extra_env", {})
# 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.
assert "PATH" not in extra_env
extra_env["PATH"] = os.pathsep.join((str(NODE_BIN_DIR), os.getenv("PATH")))
# We'll manage this ourselves to keep node_modules size small.
extra_env["PUPPETEER_SKIP_DOWNLOAD"] = "true"
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":
item = "node/linux"
elif osname == "Darwin":
item = "node/mac"
elif osname == "Windows":
item = "node/win"
else:
raise RuntimeError(f"Unknown OS {osname}")
# In case of an upgrade, nuke existing dir.
spec = libdot.fetch_manifest_lookup(libdot.DIR / "fetch.json", item)
hash_file = NODE_DIR / spec.hashes["sha256"]
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.
output = NODE_DIR / "node.tmp"
libdot.fetch_manifest_spec(spec, 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.
path = next(NODE_DIR.glob("*/bin/node"))
libdot.symlink(path, NODE)
# Mark the hash of this checkout.
libdot.touch(hash_file)
def modules_update():
"""Download & update our copy of node_modules."""
libdot.download_tarball_manifest(
libdot.DIR / "fetch.json",
"node/modules",
NODE_MODULES_DIR,
)
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:]))