diff --git a/npm_install.py b/npm_install.py index 5919bd4..3ac6153 100644 --- a/npm_install.py +++ b/npm_install.py @@ -194,8 +194,7 @@ def validate_nodejs_version(version: str) -> tuple[bool, str, str | None]: 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." + f" Falling back to Node.js v{MAX_NODEJS_VERSION}." ) return False, str(MAX_NODEJS_VERSION), warning @@ -302,40 +301,32 @@ def setup_certbot_venv(venv_dir: Path = Path("/opt/certbot")): distro_id = (info.get("ID") or "").lower() # ============================================================ - # STEP 1: Check if we already have Python 3.11+ available + # STEP 1: Check if Python 3.11 is already available # ============================================================ - python_candidates = ["python3.13", "python3.12", "python3.11", "python3"] - available_python = None - python_version_str = None - - for py_cmd in python_candidates: - if shutil.which(py_cmd): - try: - # Check version - ver_output = run_out([py_cmd, "--version"], check=False).strip() - # Extract version (e.g., "Python 3.11.2" -> major=3, minor=11) - match = re.search(r'Python (\d+)\.(\d+)', ver_output) - if match: - major, minor = int(match.group(1)), int(match.group(2)) - if major == 3 and minor >= 11: - available_python = py_cmd - python_version_str = ver_output - if DEBUG: - print(f"✔ Found suitable Python: {py_cmd} ({ver_output})") - break - except Exception: - continue + python311_available = False + if shutil.which("python3.11"): + try: + ver_output = run_out(["python3.11", "--version"], check=False).strip() + match = re.search(r'Python (\d+)\.(\d+)', ver_output) + if match: + major, minor = int(match.group(1)), int(match.group(2)) + if major == 3 and minor == 11: + python311_available = True + if DEBUG: + print(f"✔ Found system Python 3.11: {ver_output}") + except Exception: + pass # ============================================================ - # STEP 2: If Python 3.11+ is available, use it directly + # STEP 2: Use system Python 3.11 if available # ============================================================ - if available_python: - with step(f"Using system Python ({available_python}) for certbot venv"): - if distro_id in ["debian", "ubuntu"]: - apt_try_install(["python3-venv", "python3-pip"]) + if python311_available: + with step(f"Using system Python 3.11 for certbot venv"): + # Ensure python3.11-venv is installed + apt_try_install(["python3.11-venv", "python3-pip"]) venv_dir.mkdir(parents=True, exist_ok=True) - run([available_python, "-m", "venv", str(venv_dir)]) + run(["python3.11", "-m", "venv", str(venv_dir)]) venv_bin = venv_dir / "bin" pip_path = venv_bin / "pip" @@ -355,20 +346,16 @@ def setup_certbot_venv(venv_dir: Path = Path("/opt/certbot")): cb_ver = run_out([str(certbot_path), "--version"], check=False) or "" pip_ver = run_out([str(pip_path), "--version"], check=False) or "" - - cb_clean = cb_ver.strip().split('\n')[0] - pip_clean = pip_ver.strip().split(' from ')[0] - - print(f" Python: {python_version_str}") - print(f" Certbot: {cb_clean}") - print(f" Pip: {pip_clean}") + print(f" Python: {ver_output}") + print(f" Certbot: {cb_ver.strip()}") + print(f" Pip: {pip_ver.strip().split(' from ')[0]}") return # ============================================================ # STEP 3: Ubuntu - install Python 3.11 from deadsnakes PPA # ============================================================ if distro_id == "ubuntu": - with step(f"Ubuntu detected: {info.get('PRETTY','Ubuntu')}. Installing Python 3.11 via deadsnakes PPA"): + with step(f"Ubuntu detected: {info.get('PRETTY','Ubuntu')}. Install Python 3.11 via deadsnakes"): try: run(["apt-get", "update", "-y"], check=False) apt_try_install(["software-properties-common"]) @@ -379,7 +366,7 @@ def setup_certbot_venv(venv_dir: Path = Path("/opt/certbot")): run(["apt-get", "update", "-y"], check=False) run(["apt-get", "install", "-y", "python3.11", "python3.11-venv"]) - with step(f"Creating venv at {venv_dir} using python3.11"): + with step(f"Create venv at {venv_dir} using python3.11"): venv_dir.mkdir(parents=True, exist_ok=True) run(["python3.11", "-m", "venv", str(venv_dir)]) @@ -401,15 +388,14 @@ def setup_certbot_venv(venv_dir: Path = Path("/opt/certbot")): cb_ver = run_out([str(certbot_path), "--version"], check=False) or "" pip_ver = run_out([str(pip_path), "--version"], check=False) or "" + print(f" Python: Python 3.11 (deadsnakes)") print(f" Certbot: {cb_ver.strip()}") print(f" Pip: {pip_ver.strip().split(' from ')[0]}") return # ============================================================ - # STEP 4: Debian (old) - use pyenv to install Python 3.11 + # STEP 4: Debian - install Python 3.11 via pyenv # ============================================================ - print("⚠ Python 3.11+ not found. Installing via pyenv (this may take 3-5 minutes)...") - PYENV_ROOT = Path("/opt/npm/.pyenv") PYENV_OWNER = "npm" PYTHON_VERSION = "3.11.14" @@ -437,7 +423,7 @@ def setup_certbot_venv(venv_dir: Path = Path("/opt/certbot")): pyenv_bin = next((c for c in PYENV_BIN_CANDIDATES if shutil.which(c)), None) if not pyenv_bin: - raise RuntimeError("No 'pyenv' found. Try: apt-get install pyenv") + raise RuntimeError("No 'pyenv' (try /usr/bin/pyenv or /usr/lib/pyenv/bin/pyenv).") with step(f"Installing Python {PYTHON_VERSION} via pyenv into {PYENV_ROOT}"): run(["mkdir", "-p", str(PYENV_ROOT)]) @@ -519,6 +505,7 @@ fi run(["chown", "-R", f"{PYENV_OWNER}:{PYENV_OWNER}", str(PYENV_ROOT)], check=False) + def configure_letsencrypt(): with step("configure letsencrypt"): run(["chown", "-R", "npm:npm", "/opt/certbot"], check=False)