Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18182aee58 | ||
|
|
5b184d81ff | ||
|
|
8668c12f7d | ||
|
|
539833344b |
+43
-21
@@ -5,7 +5,7 @@ Bootstrap packages declared in formatted_packages.py.
|
||||
Sections handled:
|
||||
System Packages — installed via dnf, apt-get, or brew (macOS)
|
||||
Flatpak Packages — installed via flatpak from Flathub (Linux only;
|
||||
skipped with --no-gui and skipped entirely on macOS)
|
||||
skipped by default and skipped entirely on macOS; use --gui to enable)
|
||||
Custom Packages — downloaded, verified, extracted
|
||||
macOS firecracker VM — provisions a Fedora cloud image under a
|
||||
hypervisor that supports nested virtualization,
|
||||
@@ -23,8 +23,8 @@ Xcode Command Line Tools and Homebrew, which is then used as the system
|
||||
package manager.
|
||||
|
||||
Usage:
|
||||
Linux: sudo python3 bootstrap_environment.py [--only system|flatpak|custom] [--no-gui]
|
||||
macOS: python3 bootstrap_environment.py [--only system|custom] [--no-gui] [--no-vm]
|
||||
Linux: sudo python3 bootstrap_environment.py [--only system|flatpak|custom] [--gui]
|
||||
macOS: python3 bootstrap_environment.py [--only system|custom] [--gui] [--no-vm]
|
||||
(do NOT use sudo on macOS — Homebrew refuses to run as root)
|
||||
"""
|
||||
|
||||
@@ -47,7 +47,7 @@ import urllib.error
|
||||
import urllib.request
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
|
||||
import formatted_packages
|
||||
|
||||
@@ -649,7 +649,7 @@ _SPECIAL_PKGS: set[str] = (
|
||||
else {"github-desktop", "zoom", "obsidian", "minikube", "bashtop", "pipx", "poetry"}
|
||||
)
|
||||
|
||||
# GUI apps — skipped when --no-gui is passed (headless environments).
|
||||
# GUI apps — skipped by default (headless); included only when --gui is passed.
|
||||
_GUI_SYSTEM_PKGS = {
|
||||
"github-desktop",
|
||||
"google-chrome-stable",
|
||||
@@ -890,7 +890,8 @@ class CustomPackage:
|
||||
name: str
|
||||
version: Optional[str] = None # pinned fallback version
|
||||
url_template: Optional[str] = None # uses {version}, {arch}, {arch_go}
|
||||
sha256: Optional[str] = None # hex digest of the pinned archive
|
||||
sha256: Optional[str] = None # single-arch hex digest (set by _resolve_latest)
|
||||
sha256_map: Optional[dict] = None # per-platform pinned digests: {"os-arch": hex}
|
||||
sha256_url_template: Optional[str] = None # template for a .minisig URL
|
||||
minisign_key: Optional[str] = None # base64 public key for minisign verification
|
||||
fetch_latest: Optional[str] = None # latest-version resolver hint
|
||||
@@ -907,6 +908,22 @@ class CustomPackage:
|
||||
if self.sha256_url_template else None
|
||||
)
|
||||
|
||||
@property
|
||||
def resolved_sha256(self) -> Optional[str]:
|
||||
"""Return the SHA256 hex for the current OS+arch, lowercased.
|
||||
|
||||
sha256 (set dynamically by _resolve_latest) takes priority over sha256_map
|
||||
so that a freshly fetched checksum always wins over the pinned fallback.
|
||||
"""
|
||||
if self.sha256:
|
||||
return self.sha256.lower()
|
||||
if self.sha256_map:
|
||||
key = f"{OS}-{ARCH}"
|
||||
val = self.sha256_map.get(key)
|
||||
if val:
|
||||
return val.lower()
|
||||
return None
|
||||
|
||||
@property
|
||||
def display_name(self) -> str:
|
||||
return f"{self.name}-{self.version}" if self.version else self.name
|
||||
@@ -974,10 +991,11 @@ def _sha256_of(path: Path) -> str:
|
||||
|
||||
def _verify(archive: Path, pkg: CustomPackage) -> bool:
|
||||
"""Returns True if verification passed (or nothing to verify), False on failure."""
|
||||
if pkg.sha256:
|
||||
expected = pkg.resolved_sha256
|
||||
if expected:
|
||||
actual = _sha256_of(archive)
|
||||
if actual != pkg.sha256:
|
||||
err(f"SHA256 mismatch for {pkg.name}: expected {pkg.sha256}, got {actual}")
|
||||
if actual != expected:
|
||||
err(f"SHA256 mismatch for {pkg.name}: expected {expected}, got {actual}")
|
||||
return False
|
||||
print(" SHA256 OK")
|
||||
elif pkg.sha256_url:
|
||||
@@ -1469,7 +1487,7 @@ def _resolve_latest(pkg: CustomPackage) -> None:
|
||||
return
|
||||
print(f" Latest is {latest_version} (pinned was {pkg.version}); using latest.")
|
||||
pkg.version = latest_version
|
||||
pkg.sha256 = latest_sha
|
||||
pkg.sha256 = latest_sha.lower()
|
||||
pkg.sha256_url_template = None # prefer the freshly resolved sha256
|
||||
|
||||
|
||||
@@ -1483,6 +1501,11 @@ def install_custom_packages(to_install: list[CustomPackage]) -> None:
|
||||
if check_path is None and name_lower != "pip":
|
||||
warn(f"{pkg.name}: no known install path — script will not detect future installs")
|
||||
|
||||
# Packages that are OS-specific
|
||||
if name_lower == "firecracker" and IS_MACOS:
|
||||
warn(f"{pkg.name}: Linux-only — skipping on macOS")
|
||||
continue
|
||||
|
||||
# Handlers that manage their own download/install
|
||||
if name_lower == "nvm":
|
||||
_install_nvm()
|
||||
@@ -2203,10 +2226,10 @@ def main() -> None:
|
||||
)
|
||||
ap.add_argument("--only", choices=["system", "flatpak", "custom"],
|
||||
help="Install only the named section")
|
||||
ap.add_argument("--no-gui", action="store_true",
|
||||
help="Skip GUI applications (suitable for headless environments). "
|
||||
"Excludes GUI system packages and skips the entire Flatpak "
|
||||
"section, including installing flatpak itself.")
|
||||
ap.add_argument("--gui", action="store_true",
|
||||
help="Include GUI applications (headed environments). "
|
||||
"Adds GUI system packages and enables the Flatpak "
|
||||
"section. By default GUI apps and Flatpak are skipped.")
|
||||
ap.add_argument("--no-vm", action="store_true",
|
||||
help="macOS only: skip provisioning the Fedora-on-QEMU VM that "
|
||||
"backs the firecracker() zsh wrapper.")
|
||||
@@ -2222,8 +2245,8 @@ def main() -> None:
|
||||
print(f"OS: {OS}")
|
||||
print(f"Architecture: {ARCH}")
|
||||
print(f"Package manager: {PKG_MGR}")
|
||||
if args.no_gui:
|
||||
print("Mode: headless (--no-gui) — skipping GUI apps and Flatpak")
|
||||
if not args.gui:
|
||||
print("Mode: headless (default) — skipping GUI apps and Flatpak")
|
||||
|
||||
if IS_MACOS:
|
||||
# Refuse to run as root before doing anything (brew won't run as root).
|
||||
@@ -2233,19 +2256,18 @@ def main() -> None:
|
||||
|
||||
print("Checking installed packages ...")
|
||||
|
||||
if args.no_gui:
|
||||
if not args.gui:
|
||||
skipped_gui = [p for p in system_pkgs if p in _GUI_SYSTEM_PKGS]
|
||||
system_pkgs = [p for p in system_pkgs if p not in _GUI_SYSTEM_PKGS]
|
||||
if skipped_gui:
|
||||
print(f" [NO-GUI] Skipping GUI system packages: {_fmt(skipped_gui)}")
|
||||
print(f" [HEADLESS] Skipping GUI system packages: {_fmt(skipped_gui)}")
|
||||
flatpak_pkgs = []
|
||||
|
||||
# Flatpak is Linux-only — macOS has no Flatpak section regardless of flags.
|
||||
# --no-gui also suppresses the Flatpak section entirely (both `flatpak`
|
||||
# itself and the Flathub apps), even when --only=flatpak is requested.
|
||||
# GUI apps and Flatpak are skipped by default; --gui re-enables them.
|
||||
do_flatpak = (
|
||||
args.only in (None, "flatpak")
|
||||
and not args.no_gui
|
||||
and args.gui
|
||||
and not IS_MACOS
|
||||
)
|
||||
|
||||
|
||||
+12
-2
@@ -36,6 +36,7 @@ SYSTEM_PACKAGES: list[str] = [
|
||||
"git",
|
||||
"github-desktop",
|
||||
"google-chrome-stable",
|
||||
"lazygit",
|
||||
"lua",
|
||||
"minisign",
|
||||
"minikube",
|
||||
@@ -43,6 +44,7 @@ SYSTEM_PACKAGES: list[str] = [
|
||||
"obsidian",
|
||||
"pipx",
|
||||
"poetry",
|
||||
"pulumi",
|
||||
"podman",
|
||||
"qemu",
|
||||
"restic",
|
||||
@@ -94,7 +96,12 @@ CUSTOM_PACKAGES: list[dict] = [
|
||||
"name": "go",
|
||||
"version": "1.26.3",
|
||||
"url_template": "https://go.dev/dl/go{version}.{os_go}-{arch_go}.tar.gz",
|
||||
"sha256": "2b2cfc7148493da5e73981bffbf3353af381d5f93e789c82c79aff64962eb556",
|
||||
"sha256_map": {
|
||||
"linux-x86_64": "2b2cfc7148493da5e73981bffbf3353af381d5f93e789c82c79aff64962eb556",
|
||||
"linux-aarch64": "9d89a3ea57d141c2b22d70083f2c8459ba3890f2d9e818e7e933b75614936565",
|
||||
"macos-x86_64": "278d580b32e299fe4a9c990fcf2d02acfe538c7e551a6ee18f9c7164573d2c63",
|
||||
"macos-aarch64": "875cf54a15311eee2c99b9dd67c68c4a49351d489ab622bf2cfd28c8f2078d3c",
|
||||
},
|
||||
"fetch_latest": "go",
|
||||
},
|
||||
{"name": "neovim"},
|
||||
@@ -105,7 +112,10 @@ CUSTOM_PACKAGES: list[dict] = [
|
||||
"https://github.com/firecracker-microvm/firecracker/releases/download/"
|
||||
"v{version}/firecracker-v{version}-{arch}.tgz"
|
||||
),
|
||||
"sha256": "d4a32ab2322d887ca1bc4a4e7afa9cc35393e6362dfc2b3becb389d362e4275a",
|
||||
"sha256_map": {
|
||||
"linux-x86_64": "d4a32ab2322d887ca1bc4a4e7afa9cc35393e6362dfc2b3becb389d362e4275a",
|
||||
"linux-aarch64": "00654ac1e702a22744121ea9f10a4f792ebd7c3a744cba587dfac9fcb79b41a5",
|
||||
},
|
||||
"fetch_latest": "firecracker",
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user