Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Z4nzu
GitHub Repository: Z4nzu/hackingtool
Path: blob/master/os_detect.py
2370 views
1
import platform
2
import shutil
3
from dataclasses import dataclass, field
4
from pathlib import Path
5
6
7
@dataclass
8
class OSInfo:
9
system: str # "linux", "macos", "windows", "unknown"
10
distro_id: str = "" # "kali", "ubuntu", "arch", "fedora", etc.
11
distro_like: str = "" # "debian", "rhel", etc. (from ID_LIKE)
12
distro_version: str = "" # "2024.1", "22.04", etc.
13
pkg_manager: str = "" # "apt-get", "pacman", "dnf", "brew", etc.
14
is_root: bool = False
15
home_dir: Path = field(default_factory=Path.home)
16
is_wsl: bool = False # Windows Subsystem for Linux
17
arch: str = "" # "x86_64", "aarch64", "arm64"
18
19
20
def detect() -> OSInfo:
21
"""
22
Fully detect the current OS, distro, and available package manager.
23
Never asks the user — entirely automatic.
24
"""
25
import os
26
27
system_raw = platform.system()
28
system = system_raw.lower()
29
if system == "darwin":
30
system = "macos"
31
32
info = OSInfo(
33
system = system,
34
is_root = (os.geteuid() == 0) if hasattr(os, "geteuid") else False,
35
home_dir = Path.home(),
36
arch = platform.machine(),
37
)
38
39
# ── Linux-specific ─────────────────────────────────────────────────────────
40
if system == "linux":
41
# Detect WSL
42
try:
43
info.is_wsl = "microsoft" in Path("/proc/version").read_text().lower()
44
except (FileNotFoundError, PermissionError):
45
pass
46
47
# Read /etc/os-release (standard on all modern distros)
48
os_release: dict[str, str] = {}
49
for path in ("/etc/os-release", "/usr/lib/os-release"):
50
try:
51
for line in Path(path).read_text().splitlines():
52
k, _, v = line.partition("=")
53
os_release[k.strip()] = v.strip().strip('"')
54
break
55
except FileNotFoundError:
56
continue
57
58
info.distro_id = os_release.get("ID", "").lower()
59
info.distro_like = os_release.get("ID_LIKE", "").lower()
60
info.distro_version = os_release.get("VERSION_ID", "")
61
62
# ── Package manager detection (in priority order) ──────────────────────────
63
for mgr in ("apt-get", "pacman", "dnf", "zypper", "apk", "brew", "pkg"):
64
if shutil.which(mgr):
65
info.pkg_manager = mgr
66
break
67
68
return info
69
70
71
# Module-level singleton — computed once on import
72
CURRENT_OS: OSInfo = detect()
73
74
75
# ── Per-OS package manager commands ────────────────────────────────────────────
76
PACKAGE_INSTALL_CMDS: dict[str, str] = {
77
"apt-get": "apt-get install -y {packages}",
78
"pacman": "pacman -S --noconfirm {packages}",
79
"dnf": "dnf install -y {packages}",
80
"zypper": "zypper install -y {packages}",
81
"apk": "apk add {packages}",
82
"brew": "brew install {packages}",
83
"pkg": "pkg install -y {packages}",
84
}
85
86
PACKAGE_UPDATE_CMDS: dict[str, str] = {
87
"apt-get": "apt-get update -qq && apt-get upgrade -y",
88
"pacman": "pacman -Syu --noconfirm",
89
"dnf": "dnf upgrade -y",
90
"zypper": "zypper update -y",
91
"apk": "apk update && apk upgrade",
92
"brew": "brew update && brew upgrade",
93
"pkg": "pkg update && pkg upgrade -y",
94
}
95
96
# Core system packages needed per package manager
97
REQUIRED_PACKAGES: dict[str, list[str]] = {
98
"apt-get": ["git", "python3-pip", "python3-venv", "curl", "wget",
99
"ruby", "ruby-dev", "golang-go", "php", "default-jre-headless"],
100
"pacman": ["git", "python-pip", "curl", "wget",
101
"ruby", "go", "php", "jre-openjdk-headless"],
102
"dnf": ["git", "python3-pip", "curl", "wget",
103
"ruby", "golang", "php", "java-17-openjdk-headless"],
104
"zypper": ["git", "python3-pip", "curl", "wget", "ruby", "go", "php"],
105
"brew": ["git", "python3", "curl", "wget", "ruby", "go", "php"],
106
"pkg": ["git", "python3", "py39-pip", "curl", "wget", "ruby", "go", "php83"],
107
}
108
109
110
def install_packages(packages: list[str], os_info: OSInfo | None = None) -> bool:
111
"""Install system packages using the detected package manager."""
112
import subprocess
113
if os_info is None:
114
os_info = CURRENT_OS
115
116
mgr = os_info.pkg_manager
117
if mgr not in PACKAGE_INSTALL_CMDS:
118
print(f"[warning] Unknown package manager. Install manually: {packages}")
119
return False
120
121
cmd_template = PACKAGE_INSTALL_CMDS[mgr]
122
pkg_str = " ".join(packages)
123
cmd = cmd_template.format(packages=pkg_str)
124
125
# Prepend privilege escalation only on Linux (brew on macOS doesn't need sudo)
126
if os_info.system == "linux" and not os_info.is_root:
127
from constants import PRIV_CMD
128
cmd = f"{PRIV_CMD} {cmd}"
129
130
result = subprocess.run(cmd, shell=True, check=False)
131
return result.returncode == 0
132