Installer Module¶
The installer subpackage is a comprehensive cross-platform package installation system that provides unified installation capabilities across Linux, macOS, and Windows.
Quick Start¶
# Install a single package
devops install btop
# Install multiple packages
devops install btop,fd,bat,rg
# Install a package group
devops install termabc --group
# Interactive package selection (with TV/fzf interface)
devops install --interactive
Architecture Overview¶
The installer system consists of several interconnected components:
flowchart TB
subgraph CLI["CLI Layer"]
A[devops install] --> B[main_installer_cli]
end
subgraph Core["Core Engine"]
B --> C{Installation Mode}
C -->|Single/Multiple| D[install_clis]
C -->|Group| E[install_group]
C -->|Interactive| F[install_interactively]
end
subgraph Installer["Installer Class"]
D --> G[Installer]
E --> H[install_bulk]
F --> G
H --> G
G --> I{repoURL Type}
end
subgraph Methods["Installation Methods"]
I -->|CMD| J[Package Manager / Script / URL]
I -->|GitHub URL| K[GitHub Release Download]
J --> L[Shell Command]
J --> M[Python Script]
J --> N[Direct URL]
K --> O[binary_download]
O --> P[get_github_release]
end
subgraph Platform["Platform Handler"]
L --> Q{Platform}
M --> Q
N --> Q
P --> Q
Q -->|Windows| R[find_move_delete_windows]
Q -->|Linux/macOS| S[find_move_delete_linux]
end
subgraph Post["Post-Install"]
R --> T[Version Tracking]
S --> T
T --> U[INSTALL_VERSION_ROOT]
end
Installation Methods¶
The installer supports multiple installation strategies based on the repoURL field in the installer data:
Method 1: Package Manager Commands (repoURL: "CMD")¶
When repoURL is "CMD", the fileNamePattern contains the actual installation command or script reference.
Shell Commands¶
Direct package manager commands:
{
"appName": "git",
"repoURL": "CMD",
"doc": "Distributed version control system",
"fileNamePattern": {
"amd64": {
"linux": "sudo nala install git",
"windows": "winget install --no-upgrade --name \"Git\" --Id \"Git.Git\" --source winget --scope user --accept-package-agreements --accept-source-agreements",
"macos": "brew install git"
}
}
}
Supported Package Managers:
| Platform | Package Managers |
|---|---|
| Linux | apt, nala, snap, cargo, pip, npm, bun |
| macOS | brew, cargo, pip, npm, bun |
| Windows | winget, scoop, cargo, pip, npm, bun |
Python Scripts (.py)¶
For complex installations requiring custom logic:
{
"appName": "yazi",
"repoURL": "CMD",
"fileNamePattern": {
"amd64": {
"linux": "yazi.py",
"windows": "yazi.py",
"macos": "yazi.py"
}
}
}
The Python script must implement a main(installer_data: InstallerData, version: Optional[str]) function.
Shell Scripts (.sh)¶
For Linux/macOS platform-specific installations:
PowerShell Scripts (.ps1)¶
For Windows-specific installations:
Direct URLs¶
Direct download URLs for pre-built binaries:
{
"appName": "speedtest",
"repoURL": "CMD",
"fileNamePattern": {
"amd64": {
"linux": "https://install.speedtest.net/app/cli/ookla-speedtest-1.2.0-linux-x86_64.tgz"
}
}
}
Method 2: GitHub Releases (repoURL: "https://github.com/...")¶
Automatic download from GitHub releases with version pattern matching:
{
"appName": "btop",
"repoURL": "https://github.com/aristocratos/btop",
"doc": "Resource monitor for Linux, FreeBSD and MacOS",
"fileNamePattern": {
"amd64": {
"linux": "btop-x86_64-linux-musl.tbz",
"macos": null,
"windows": null
},
"arm64": {
"linux": "btop-aarch64-linux-musl.tbz"
}
}
}
Version Templating:
Use {version} placeholder for version-specific filenames:
The system automatically:
- Fetches the latest release from GitHub API
- Extracts the version tag (e.g.,
v0.6.4) - Replaces
{version}in the pattern - Downloads the matching asset
InstallerData Schema¶
The core data structure for package definitions:
class InstallerData(TypedDict):
appName: str # Display name (also used for executable lookup)
doc: str # Description shown in interactive mode
repoURL: str # "CMD" or GitHub repository URL
fileNamePattern: dict[ # Platform-specific installation patterns
CPU_ARCHITECTURES, # "amd64" | "arm64"
dict[
OPERATING_SYSTEMS, # "windows" | "linux" | "macos"
Optional[str] # Installation pattern or None if unsupported
]
]
Field Details:
| Field | Type | Description |
|---|---|---|
appName |
str |
Package identifier. Lowercase version becomes the executable name |
doc |
str |
Description displayed during interactive selection |
repoURL |
str |
Either "CMD" for command-based install or a GitHub URL |
fileNamePattern |
dict |
Nested dict mapping arch -> os -> installation pattern |
Architecture Values:
amd64: Intel/AMD 64-bit (x86_64)arm64: ARM 64-bit (aarch64)
Operating System Values:
windows: Microsoft Windowslinux: Linux distributionsmacos: macOS (Darwin)
Installer Class¶
The main installation orchestrator:
from machineconfig.utils.installer_utils.installer_class import Installer
from machineconfig.utils.schemas.installer.installer_types import InstallerData
installer_data: InstallerData = {
"appName": "fd",
"repoURL": "https://github.com/sharkdp/fd",
"doc": "A simple, fast and user-friendly alternative to find",
"fileNamePattern": {
"amd64": {
"linux": "fd-v{version}-x86_64-unknown-linux-musl.tar.gz",
"windows": "fd-v{version}-x86_64-pc-windows-msvc.zip",
"macos": "fd-v{version}-x86_64-apple-darwin.tar.gz"
},
"arm64": {
"linux": "fd-v{version}-aarch64-unknown-linux-musl.tar.gz",
"macos": "fd-v{version}-aarch64-apple-darwin.tar.gz",
"windows": None
}
}
}
installer = Installer(installer_data)
Methods¶
install(version: Optional[str]) -> None¶
Main installation method. Handles all installation strategies.
installer.install(version=None) # Install latest
installer.install(version="v9.0.0") # Install specific version
install_robust(version: Optional[str]) -> str¶
Wrapped installation with error handling. Returns status message.
status = installer.install_robust(version=None)
# Returns: "fd updated from v8.7.0 -> v9.0.0"
# Or: "fd, same version: v9.0.0"
# Or: "Failed to install `fd` with error: ..."
binary_download(version: Optional[str]) -> tuple[PathExtended, str]¶
Downloads and extracts the binary without installing.
extracted_path, version = installer.binary_download(version=None)
# extracted_path: PathExtended to extracted files
# version: Actual version string (e.g., "v9.0.0")
get_github_release(repo_url: str, version: Optional[str]) -> tuple[Optional[str], Optional[str]]¶
Retrieves download URL and version from GitHub API.
download_url, version = installer.get_github_release(
repo_url="https://github.com/sharkdp/fd",
version=None # or specific version
)
get_description() -> str¶
Returns formatted description for interactive selection.
Package Groups¶
Pre-defined collections of related packages for bulk installation.
Available Groups¶
| Group | Description | Package Count |
|---|---|---|
sysabc |
System essentials (package managers, build tools) | 1 (meta-package) |
termabc |
Terminal power tools (40+ tools) | ~60 |
gui |
GUI applications (browsers, editors) | 3 |
dev |
Full development environment | ~80 |
dev-utils |
Development utilities | 4 |
term-eye-candy |
Terminal visual enhancements | 4 |
agents |
AI/LLM coding assistants | 15+ |
terminal-emulator |
Terminal emulators | 6 |
shell |
Shell enhancements | 9 |
browsers |
Web browsers | 6 |
code-editors |
Code editors and IDEs | 3 |
code-analysis |
Code analysis and Git tools | 14 |
db |
Database tools | 8 |
media |
Media players | 5 |
file-sharing |
File sharing and cloud tools | 17 |
productivity |
Productivity tools | 12 |
sys-monitor |
System monitors | 11 |
search |
File search and navigation | 22 |
Group Contents¶
agents - AI/LLM Coding Assistants¶
aider, aichat, copilot, gemini, crush, opencode-ai, chatgpt, mods, q,
qwen-code, cursor-cli, droid, kilocode, cline, auggie
termabc - Terminal Essentials¶
Combines: code-analysis + sys-monitor + shell + search
# Code Analysis
nano, lazygit, onefetch, gitcs, lazydocker, hyperfine, kondo, tokei,
navi, tealdeer, gitui, delta, gh, watchexec, jq
# System Monitors
btop, btm, ntop, procs, bandwhich, ipinfo, sniffnet, cpufetch,
fastfetch, topgrade, speedtest
# Shell Enhancements
zellij, mprocs, mcfly, atuin, starship, gotty, ttyd, rclone, cb
# Search & File Tools
nerdfont, fd, fzf, tv, broot, rg, rga, ugrep, ouch, pistol, bat, viu,
yazi, tere, lsd, zoxide, diskonaut, dua, dust, cpz, rmz
terminal-emulator - Terminal Emulators¶
code-editors - Code Editors¶
db - Database Tools¶
Installing Groups¶
# Install terminal essentials
devops install termabc --group
devops install termabc -g
# Install AI assistants
devops install agents -g
# Install full dev environment
devops install dev -g
Custom Python Installers¶
For packages requiring complex installation logic, custom Python scripts are provided in jobs/installer/python_scripts/.
Available Custom Installers¶
| Package | Script | Description |
|---|---|---|
alacritty |
alacritty.py |
Terminal emulator with theme setup |
brave |
brave.py |
Brave browser with platform-specific methods |
boxes |
boxes.py |
ASCII box drawing tool (Windows binary) |
bypass_paywall |
bypass_paywall.py |
Chrome extension for bypassing paywalls |
cloudflare_warp_cli |
cloudflare_warp_cli.py |
Cloudflare WARP VPN client |
code |
code.py |
VS Code with official installation scripts |
cursor |
cursor.py |
Cursor IDE (AppImage on Linux, exe on Windows) |
dubdb_adbc |
dubdb_adbc.py |
DuckDB ADBC library |
espanso |
espanso.py |
Text expander with Wayland/X11 detection |
gh |
gh.py |
GitHub CLI with Copilot extension |
goes |
goes.py |
Gorilla (natural language to API) |
hx |
hx.py |
Helix editor with runtime and LSP setup |
lvim |
lvim.py |
LunarVim with official installer |
nerdfont |
nerdfont.py |
Nerd Fonts (cross-platform) |
redis |
redis.py |
Redis server |
sysabc |
sysabc.py |
System essentials meta-installer |
wezterm |
wezterm.py |
WezTerm terminal emulator |
winget |
winget.py |
Windows Package Manager bootstrap |
yazi |
yazi.py |
File manager with plugins and flavors |
Custom Installer Interface¶
All custom installers follow this pattern:
from typing import Optional
from machineconfig.utils.schemas.installer.installer_types import InstallerData
def main(installer_data: InstallerData, version: Optional[str]) -> None:
"""
Main entry point for custom installation.
Args:
installer_data: The installer configuration from installer_data.json
version: Specific version to install, or None for latest
"""
# Platform detection
import platform
system = platform.system() # "Windows", "Linux", "Darwin"
# Installation logic...
Example: Helix Editor Installer¶
The hx.py installer demonstrates a complex installation:
- Downloads from GitHub releases
- Extracts executable, runtime, and contrib directories
- Installs grammar files for supported languages
- Handles Windows and Unix paths differently
# Supported languages for grammar installation
LANGUAGES_SUPPORTED = ["python", "nu", "bash", "lua", "powershell"]
def main(installer_data: InstallerData, version: Optional[str], install_lib: bool = True):
# Download binary
downloaded, _version = inst.binary_download(version=version)
# Install executable
hx_file.move(folder=target_bin_path, overwrite=True)
# Install runtime (selectively for supported languages)
if install_lib:
for child in runtime.iterdir():
if child.name == "grammars":
for lang in LANGUAGES_SUPPORTED:
lang_file = child.joinpath(f"{lang}.so")
if lang_file.exists():
lang_file.copy(folder=target_runtime.joinpath("grammars"))
Platform-Specific Behavior¶
Installation Paths¶
| Platform | Binary Path | Config Path |
|---|---|---|
| Windows | %LOCALAPPDATA%\Microsoft\WindowsApps |
%APPDATA% |
| Linux | ~/.local/bin |
~/.config |
| macOS | /usr/local/bin |
~/.config |
Executable Handling¶
Windows:
def find_move_delete_windows(downloaded_file_path, tool_name, delete, rename_to):
# Finds .exe in downloaded archive
# Moves to WindowsApps directory
# Handles renaming if needed
Linux/macOS:
def find_move_delete_linux(downloaded, tool_name, delete, rename_to):
# Finds binary in extracted archive
# Sets executable permissions (chmod 777)
# Uses sudo for /usr/local/bin
# Moves to installation path
Version Tracking¶
Installed versions are tracked in ~/.config/machineconfig/install_versions/:
Each file contains the installed version string.
Checking Installation Status¶
from machineconfig.utils.installer_utils.installer_locator_utils import check_if_installed_already
verdict, current_ver, new_ver = check_if_installed_already(
exe_name="fd",
version="v9.0.0",
use_cache=False
)
# verdict: "✅ Up to date" | "❌ Outdated" | "⚠️ NotInstalled"
Bulk Installation¶
Install multiple packages in parallel:
from machineconfig.utils.installer_utils.installer_runner import install_bulk, get_installers
from machineconfig.utils.schemas.installer.installer_types import get_os_name, get_normalized_arch
# Get all installers for current platform
installers = get_installers(
os=get_os_name(),
arch=get_normalized_arch(),
which_cats=["termabc"] # or None for all
)
# Install with parallel processing
install_bulk(
installers_data=installers,
safe=False,
jobs=10, # Parallel workers
fresh=False # Don't clear version cache
)
VirusTotal Integration¶
The checks submodule provides security scanning for installed binaries.
Scanning Workflow¶
flowchart LR
A[Get Installed Apps] --> B[Scan with VirusTotal]
B --> C[Generate Report]
C --> D[CSV + Markdown Output]
Usage¶
from machineconfig.jobs.installer.checks.check_installations import main
# Run full scan
main()
# Outputs:
# - ~/.config/machineconfig/profile/records/{platform}/apps_metadata_report.csv
# - ~/.config/machineconfig/profile/records/{platform}/apps_engine_results_report.csv
Configuration¶
VirusTotal API token must be stored at:
Report Format¶
apps_metadata_report.csv
app_name,version,scan_time,app_path,app_url,scan_summary_available,notes
apps_engine_results_report.csv
app_name,engine_name,engine_category,engine_result
CLI Reference¶
devops install¶
Main installation command.
Arguments:
| Argument | Description |
|---|---|
WHICH |
Comma-separated package names or group name |
Options:
| Option | Short | Description |
|---|---|---|
--group |
-g |
Treat WHICH as a group name |
--interactive |
-i |
Interactive selection mode |
Examples:
# Single package
devops install btop
# Multiple packages
devops install btop,fd,bat,rg,fzf
# Package group
devops install termabc -g
# Interactive mode (with fzf/TV interface)
devops install -i
# Install from GitHub URL directly
devops install https://github.com/sharkdp/fd
# Install from direct binary URL
devops install https://example.com/tool-v1.0-linux-amd64.tar.gz
Interactive Mode Features¶
When using --interactive:
- Shows all available packages with installation status (✅/❌)
- Displays package descriptions
- Allows multi-select with TV/fzf interface
- Groups are prefixed with 📦 for easy identification
Adding New Packages¶
Step 1: Edit installer_data.json¶
{
"appName": "mytool",
"repoURL": "https://github.com/user/mytool",
"doc": "Description of what mytool does",
"fileNamePattern": {
"amd64": {
"linux": "mytool-{version}-linux-amd64.tar.gz",
"windows": "mytool-{version}-windows-amd64.zip",
"macos": "mytool-{version}-darwin-amd64.tar.gz"
},
"arm64": {
"linux": "mytool-{version}-linux-arm64.tar.gz",
"windows": null,
"macos": "mytool-{version}-darwin-arm64.tar.gz"
}
}
}
Step 2: Add to Package Groups (Optional)¶
Edit jobs/installer/package_groups.py:
Step 3: Create Custom Installer (If Needed)¶
For complex installations, create jobs/installer/python_scripts/mytool.py:
from typing import Optional
from machineconfig.utils.schemas.installer.installer_types import InstallerData
def main(installer_data: InstallerData, version: Optional[str]) -> None:
# Custom installation logic
pass
Troubleshooting¶
Common Issues¶
Package not found:
The system uses fuzzy matching to suggest alternatives.
GitHub rate limit:
Wait 60 minutes or authenticate with a GitHub token.
Permission denied on Linux:
The installer uses sudo for /usr/local/bin. Ensure sudo access.
Windows execution policy:
Run: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Debug Mode¶
Check installed versions cache:
Clear version cache for fresh install:
from machineconfig.utils.installer_utils.installer_runner import install_bulk
install_bulk(installers, fresh=True) # Clears cache
API Reference¶
Core Functions¶
# Main CLI entry point
from machineconfig.utils.installer_utils.installer_cli import main_installer_cli
# Install specific packages
from machineconfig.utils.installer_utils.installer_cli import install_clis
install_clis(clis_names=["btop", "fd", "bat"])
# Install package group
from machineconfig.utils.installer_utils.installer_cli import install_group
install_group(package_group="termabc")
# Interactive installation
from machineconfig.utils.installer_utils.installer_cli import install_interactively
install_interactively()
# Install if not present
from machineconfig.utils.installer_utils.installer_cli import install_if_missing
install_if_missing("git") # Returns True if available after call
Utility Functions¶
# Check if tool exists
from machineconfig.utils.installer_utils.installer_locator_utils import check_tool_exists
exists = check_tool_exists("fd")
# Get all installers for platform
from machineconfig.utils.installer_utils.installer_runner import get_installers
installers = get_installers(os="linux", arch="amd64", which_cats=None)
# Get installed CLI apps
from machineconfig.utils.installer_utils.installer_runner import get_installed_cli_apps
apps = get_installed_cli_apps()
# Install from GitHub URL
from machineconfig.utils.installer_utils.install_from_url import install_from_github_url
install_from_github_url("https://github.com/user/repo")
# Install from binary URL
from machineconfig.utils.installer_utils.install_from_url import install_from_binary_url
install_from_binary_url("https://example.com/tool.tar.gz")
Type Definitions¶
from machineconfig.utils.schemas.installer.installer_types import (
InstallerData, # Package definition
InstallerDataFiles, # installer_data.json structure
CPU_ARCHITECTURES, # "amd64" | "arm64"
OPERATING_SYSTEMS, # "windows" | "linux" | "macos"
get_os_name, # Get current OS
get_normalized_arch, # Get current architecture
)