#!/usr/bin/env python3 import json import shutil import subprocess import sys from pathlib import Path # Compatibility with Angie exec_name = "nginx" def get_nginx_info() -> tuple[str | None, str | None]: try: output = subprocess.check_output( [exec_name, "-V"], stderr=subprocess.STDOUT ).decode("utf-8") version: str | None = None module_path: str | None = None for line in output.splitlines(): if line.startswith(f"{exec_name} version:"): # Output is: nginx version: nginx/1.24.0 (Ubuntu) version = line.split("/")[1].split(" ")[0].strip() elif "--modules-path=" in line: # Output is: configure arguments: ... --modules-path=/usr/lib/nginx/modules ... module_path = line.split("--modules-path=")[1].split(" ")[0].strip() if version and module_path: print(f"Nginx version: {version}") print(f"Nginx modules path: {module_path}") return version, module_path except Exception as e: print(f"Error getting Nginx version: {e}") return (None, None) def download_and_unpack(url: str) -> str: print(f"Downloading '{url}'...") file_name = url.split("/")[-1] if Path(file_name).exists(): print(f"File '{file_name}' already exists. Skipping download.") else: subprocess.call(["wget", url]) file_name_without_ext = file_name.rsplit(".", 2)[0] # Remove .tar.gz shutil.rmtree( file_name_without_ext, ignore_errors=True ) # Remove existing dir if exists print("Unpacking...") subprocess.call(["tar", "zxvf", file_name]) print(f"Download and unpack complete: {file_name} to {file_name_without_ext}") return file_name_without_ext def main(): config_file = "ngx_modules.json" for arg in sys.argv[1:]: if arg.startswith("--config="): config_file = arg.split("--config=")[1] elif arg == "--angie": print("Angie compatibility mode enabled") global exec_name exec_name = "angie" print(f"Using config file: {config_file}") config = json.load(open(config_file)) version, module_path = get_nginx_info() if not version or not module_path: print("Could not determine Nginx version or modules path. Exiting.") return source_dir = None nginx_url = None if exec_name == "nginx": nginx_url = f"http://nginx.org/download/nginx-{version}.tar.gz" elif exec_name == "angie": nginx_url = f"https://download.angie.software/files/angie-{version}.tar.gz" else: print(f"Unknown executable name: {exec_name}. Exiting.") return print("Downloading and unpacking Nginx source code...") source_dir = download_and_unpack(nginx_url) module_source_dirs = [] for module in config["modules"]: print(f"Downloading module: {module}") module_source_dir = download_and_unpack(module) print(f"Module '{module}' downloaded successfully.") module_source_dirs.append(module_source_dir) # Configure and build modules args = [f"--add-dynamic-module=../{dir}" for dir in module_source_dirs] print("Configuring and building modules...") subprocess.call(["./configure", "--with-compat", *args], cwd=source_dir) subprocess.call(["make", "modules"], cwd=source_dir) # Copy .so files to module path for module in module_source_dirs: so_file = f"{module}.so" source_so_path = f"{source_dir}/objs/{so_file}" dest_so_path = f"{module_path}/{so_file}" print(f"Copying {source_so_path} to {dest_so_path}...") subprocess.call(["cp", source_so_path, dest_so_path]) print("All modules installed successfully.") if __name__ == "__main__": main()