#!/usr/bin/env python3 """ install_dependencies.py Installs all requirements for compress_folder.py: - Checks the Python version (3.10+) - Detects the OS and installs 7-Zip via the appropriate method - Verifies the installation when done """ import os import sys import shutil import subprocess import platform # ── Terminal colors (no third-party deps needed here either) ───────────────── IS_TTY = sys.stdout.isatty() def _c(code, text): return f"\033[{code}m{text}\033[0m" if IS_TTY else text def green(t): return _c("32", t) def yellow(t): return _c("33", t) def cyan(t): return _c("36", t) def bold(t): return _c("1", t) def dim(t): return _c("2", t) def red(t): return _c("31", t) # ── Helpers ─────────────────────────────────────────────────────────────────── def header(text): print(f"\n{bold('── ' + text + ' ' + '─' * max(0, 54 - len(text)))}") def ok(text): print(f" {green('✔')} {text}") def info(text): print(f" {cyan('ℹ')} {text}") def warn(text): print(f" {yellow('⚠')} {text}") def fail(text): print(f" {red('✘')} {text}") def run(cmd, check=True, capture=False): """Run a shell command, print it first, and return the CompletedProcess.""" print(f"\n {dim('$')} {dim(' '.join(cmd))}") return subprocess.run( cmd, check=check, capture_output=capture, text=True, ) # ── Step 1: Python version ──────────────────────────────────────────────────── def check_python(): header("Checking Python version") major, minor = sys.version_info[:2] ver = f"{major}.{minor}.{sys.version_info.micro}" if (major, minor) >= (3, 10): ok(f"Python {ver} — requirement satisfied (3.10+)") return True else: fail(f"Python {ver} is too old. compress_folder.py requires Python 3.10 or higher.") info("Download the latest Python from https://www.python.org/downloads/") return False # ── Step 2: Detect OS and pick install strategy ─────────────────────────────── def detect_os() -> dict: """Return a dict describing the OS and the best install method.""" system = platform.system() if system == "Windows": return {"os": "windows"} if system == "Darwin": brew = shutil.which("brew") port = shutil.which("port") method = "homebrew" if brew else ("macports" if port else "manual") return {"os": "macos", "method": method, "brew": brew, "port": port} if system == "Linux": # Identify distro family for mgr, cmd in ( ("apt", ["apt", "--version"]), ("dnf", ["dnf", "--version"]), ("yum", ["yum", "--version"]), ("pacman", ["pacman", "--version"]), ("zypper", ["zypper", "--version"]), ): if shutil.which(mgr): return {"os": "linux", "manager": mgr} return {"os": "linux", "manager": None} return {"os": "unknown"} # ── Step 3: Install 7-Zip ───────────────────────────────────────────────────── def already_installed() -> str | None: """Return the path to 7-Zip if it is already on PATH.""" for name in ("7z", "7za", "7zz"): path = shutil.which(name) if path: return path if sys.platform == "win32": for p in ( r"C:\Program Files\7-Zip\7z.exe", r"C:\Program Files (x86)\7-Zip\7z.exe", ): if os.path.isfile(p): return p return None def get_7zip_version(path: str) -> str: """Return the version string reported by 7-Zip.""" try: result = subprocess.run( [path, "i"], capture_output=True, text=True, check=False ) for line in (result.stdout + result.stderr).splitlines(): if "7-Zip" in line: return line.strip() except Exception: pass return "(version unknown)" def install_linux(manager: str) -> bool: install_cmds = { "apt": ["sudo", "apt", "install", "-y", "p7zip-full"], "dnf": ["sudo", "dnf", "install", "-y", "p7zip", "p7zip-plugins"], "yum": ["sudo", "yum", "install", "-y", "p7zip", "p7zip-plugins"], "pacman": ["sudo", "pacman", "-S", "--noconfirm", "p7zip"], "zypper": ["sudo", "zypper", "install", "-y", "p7zip"], } cmd = install_cmds.get(manager) if not cmd: return False try: run(cmd) return True except subprocess.CalledProcessError: return False def install_macos(method: str, brew: str | None, port: str | None) -> bool: if method == "homebrew": try: run([brew, "install", "p7zip"]) return True except subprocess.CalledProcessError: return False if method == "macports": try: run(["sudo", port, "install", "p7zip"]) return True except subprocess.CalledProcessError: return False return False def install_windows() -> bool: """Try winget first, then chocolatey, then fall back to manual.""" if shutil.which("winget"): try: run(["winget", "install", "--id", "7zip.7zip", "-e", "--silent"]) return True except subprocess.CalledProcessError: pass if shutil.which("choco"): try: run(["choco", "install", "7zip", "-y"]) return True except subprocess.CalledProcessError: pass return False def install_7zip(os_info: dict) -> bool: header("Installing 7-Zip") # Already present? path = already_installed() if path: ver = get_7zip_version(path) ok(f"7-Zip is already installed: {dim(path)}") ok(f"{dim(ver)}") return True system = os_info["os"] if system == "linux": manager = os_info.get("manager") if not manager: fail("No supported package manager found (apt / dnf / yum / pacman / zypper).") info("Install 7-Zip manually: https://www.7-zip.org/download.html") return False info(f"Using package manager: {bold(manager)}") success = install_linux(manager) elif system == "macos": method = os_info.get("method", "manual") if method == "manual": fail("Neither Homebrew nor MacPorts was found.") info("Install Homebrew first: https://brew.sh") info("Then re-run this script, or install p7zip manually.") return False info(f"Using: {bold(method)}") success = install_macos(method, os_info.get("brew"), os_info.get("port")) elif system == "windows": info("Trying winget → chocolatey …") success = install_windows() if not success: fail("Automatic install failed.") info("Download 7-Zip manually from: https://www.7-zip.org/download.html") info("After installing, re-run this script to verify.") return False else: fail(f"Unsupported OS: {platform.system()}") info("Install 7-Zip manually: https://www.7-zip.org/download.html") return False if not success: fail("Installation command failed. Check the output above for details.") return False return True # ── Step 4: Verify everything ───────────────────────────────────────────────── def verify(): header("Verifying installation") path = already_installed() if path: ver = get_7zip_version(path) ok(f"7-Zip found: {dim(path)}") ok(f"{dim(ver)}") return True else: fail("7-Zip still not found on PATH after installation.") warn("You may need to restart your terminal or add 7-Zip to your PATH manually.") if sys.platform == "win32": info("Typical Windows location: C:\\Program Files\\7-Zip\\") info("Add that directory to your PATH environment variable.") return False # ── Main ────────────────────────────────────────────────────────────────────── def main(): print(f"\n{bold('🔧 compress_folder.py — Dependency Installer')}") print(f" Platform: {cyan(platform.system())} {platform.release()} | " f"Python {sys.version.split()[0]}") all_ok = True # 1. Python check if not check_python(): all_ok = False # 2. Detect OS header("Detecting operating system") os_info = detect_os() system = os_info["os"] if system == "linux": mgr = os_info.get("manager", "unknown") ok(f"Linux detected — package manager: {bold(mgr)}") elif system == "macos": method = os_info.get("method", "manual") ok(f"macOS detected — install method: {bold(method)}") elif system == "windows": ok("Windows detected") else: warn(f"Unrecognised OS: {platform.system()}") # 3. Install 7-Zip if not install_7zip(os_info): all_ok = False # 4. Verify verified = verify() if not verified: all_ok = False # 5. Final report header("Summary") if all_ok and verified: print(f"\n {green('✅ All dependencies satisfied.')}") print(f" You are ready to run: {bold('python compress_folder.py')}\n") else: print(f"\n {yellow('⚠ One or more steps did not complete successfully.')}") print( " Review the output above and resolve any issues before running") print(f" {bold('compress_folder.py')}.\n") sys.exit(1) if __name__ == "__main__": main()