Files
7Z_Python_Script/install_dependencies.py
2026-09-13 19:48:16 +01:00

309 lines
10 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()