diff --git a/npm_install.py b/npm_install.py index b2b30a5..5919bd4 100644 --- a/npm_install.py +++ b/npm_install.py @@ -6,6 +6,11 @@ from glob import glob DEBUG = False + +# ========== Configuration ========== +# Maximum supported Node.js version (can be updated in the future) +MAX_NODEJS_VERSION = 21 + # ========== UI / Spinner ========== class Spinner: @@ -170,6 +175,31 @@ def write_resolvers_conf(ipv6_enabled: bool): content = f"resolver {' '.join(ips)} valid=10s{ipv6_flag};\n" write_file(Path("/etc/angie/conf.d/include/resolvers.conf"), content, 0o644) +def validate_nodejs_version(version: str) -> tuple[bool, str, str | None]: + version_map = { + 'latest': '22', + 'lts': '22', + 'current': '23' + } + + resolved = version_map.get(version.lower(), version) + + match = re.match(r'(\d+)', resolved) + if not match: + return False, resolved, f"Invalid version format: {version}" + + major_version = int(match.group(1)) + + if major_version > MAX_NODEJS_VERSION: + warning = ( + f"⚠ WARNING: Requested Node.js v{major_version} exceeds maximum tested version (v{MAX_NODEJS_VERSION}).\n" + f" NPM may not be compatible with Node.js v{major_version}.\n" + f" Falling back to Node.js v{MAX_NODEJS_VERSION}.\n" + f" To allow v{major_version}, update MAX_NODEJS_VERSION in the script." + ) + return False, str(MAX_NODEJS_VERSION), warning + + return True, resolved, None def comment_x_served_by_step(path="/etc/angie/conf.d/include/proxy.conf"): p = Path(path) @@ -861,17 +891,13 @@ def adjust_nginx_like_paths_in_tree(root: Path): txt = txt.replace("daemon on;", "#daemon on;") cand.write_text(txt, encoding="utf-8") -def install_node_from_nodesource(version: str): - - version_map = { - 'latest': '22', - 'lts': '22', - 'current': '23' - } +def install_node_from_nodesource(version: str): + is_valid, resolved_version, warning = validate_nodejs_version(version) - node_version = version_map.get(version.lower(), version) + if warning: + print(warning) - match = re.match(r'(\d+)', node_version) + match = re.match(r'(\d+)', resolved_version) if not match: raise ValueError(f"Invalid Node.js version: {version}") @@ -900,15 +926,14 @@ def install_node_from_nodesource(version: str): try: run(["curl", "-fsSL", setup_url, "-o", script_path]) - # Make it executable - os.chmod(script_path, 0o755) - + os.chmod(script_path, 0o755) + if DEBUG: subprocess.run(["bash", script_path], check=True) else: run(["bash", script_path]) - run(["apt-get", "update", "-y"]) + run(["apt-get", "update", "-y"]) run(["apt-get", "install", "-y", "nodejs"]) finally: @@ -921,13 +946,15 @@ def install_node_from_nodesource(version: str): installed_major = re.match(r'v?(\d+)', node_ver) if installed_major and installed_major.group(1) != major_version: print(f"⚠ WARNING: Requested Node.js v{major_version}.x but got {node_ver}") - print(f" This likely means NodeSource doesn't support your distribution yet.") + print(f" This likely means NodeSource doesn't support your distribution yet.") if shutil.which("npm"): npm_ver = run_out(["npm", "--version"], check=False).strip() - print(f"✔ Node.js {node_ver} | npm {npm_ver}") + print(f" Node.js: {node_ver}") + print(f" npm: {npm_ver}") else: - print(f"✔ Install npm") + print(f" Node.js: {node_ver}") + print(f" ⚠ npm not found, attempting to install...") run(["apt-get", "install", "-y", "npm"], check=False) @@ -936,9 +963,9 @@ def install_node_from_nodesource(version: str): if shutil.which("npm"): npm_ver = run_out(["npm", "--version"], check=False).strip() - print(f"✔ npm {npm_ver} installed successfully") + print(f" ✔ npm {npm_ver} installed successfully") else: - print(f"✖ npm could not be installed - manual intervention required") + print(f" ✖ npm could not be installed - manual intervention required") else: print("✖ Node.js installation failed") raise RuntimeError("Node.js installation failed") @@ -1554,7 +1581,9 @@ def main(): formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser.add_argument("--nodejs-pkg", default="nodejs", help="APT Node.js package name (e.g. nodejs, nodejs-18).") - parser.add_argument("--node-version", default=None, help="Install Node.js from NodeSource repo (e.g. 'latest', '22', '20', '18'). Overrides --nodejs-pkg.") + parser.add_argument("--node-version", default=None, + help=f"Install Node.js from NodeSource repo (e.g. 'latest', '21', '20', '18'). " + f"Maximum supported: v{MAX_NODEJS_VERSION}. Overrides --nodejs-pkg.") parser.add_argument("--npm-version", default=None, help="Force NPM app version (e.g. 2.12.6). Default: latest release.") parser.add_argument("--motd", choices=["yes","no"], default="yes", help="Update MOTD after completion.") parser.add_argument("--enable-ipv6", action="store_true",