blob: 9321f819c9d369464e328386b369bc03176e03bd [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 logging
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,
)
PATCHES = (
"http-server-14.1.1-darkmode.patch",
"http-server-14.1.1-coop.patch",
)
PATCHES_DIR = libdot.DIR / "patches"
for patch in PATCHES:
stamp = NODE_MODULES_DIR / f".stamp.{patch}"
if not stamp.exists():
logging.info("Applying patch %s", patch)
with (PATCHES_DIR / patch).open("rb") as fp:
libdot.run(["patch", "-p1"], stdin=fp, cwd=NODE_MODULES_DIR)
stamp.write_bytes(b"")
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:]))