more package support

This commit is contained in:
Waylon S. Walker 2025-04-09 09:15:00 -05:00
parent a60562b7fc
commit 9737746923
5 changed files with 283 additions and 11 deletions

87
krayt/bundles.py Normal file
View file

@ -0,0 +1,87 @@
"""
Bundles of packages available in most package managers.
"""
basics = [
"curl",
"wget",
"jq",
"yq",
"bash",
"coreutils",
]
pretty = [
*basics
"starship",
"atuin",
"bash",
"zsh",
"fish",
"bat",
"eza",
]
networking = [
*basics
"mtr",
"bind-tools",
"aws-cli",
"curl",
"wget",
"iperf3",
"nmap",
"traceroute",
"netcat-openbsd",
]
database = [
*basics
"sqlite",
"sqlite-dev",
"sqlite-libs",
"postgresql",
"mysql",
"mariadb",
"redis",
"mongodb",
]
storage = [
*basics
"ncdu",
"dust",
"file",
"hexyl",
"ripgrep",
"fd",
"fzf",
"difftastic",
]
search = [
*basics
"ripgrep",
"fd",
"fzf",
"difftastic",
]
monitoring = [
*basics
"htop",
"bottom",
"mtr",
]
all = list(
set(
[
*basics,
*pretty,
*networking,
*database,
*storage,
*search,
*monitoring,
]
)
)

View file

@ -6,7 +6,7 @@ import os
from pathlib import Path
import time
import typer
from typing import Any, Optional
from typing import Any, List, Optional
import yaml
KRAYT_VERSION = "NIGHTLY"
@ -324,6 +324,11 @@ def create_inspector_job(
volumes: list,
image: str = "alpine:latest",
imagepullsecret: Optional[str] = None,
additional_packages: Optional[List[str]] = None,
pre_init_scripts: Optional[List[str]] = None,
post_init_scripts: Optional[List[str]] = None,
pre_init_hooks: Optional[List[str]] = None,
post_init_hooks: Optional[List[str]] = None,
):
"""Create a Krayt inspector job with the given mounts"""
timestamp = int(time.time())

166
krayt/package.py Normal file
View file

@ -0,0 +1,166 @@
from more_itertools import unique_everseen
from pydantic import BaseModel, BeforeValidator, model_validator
from typing import Annotated, List, Literal, Optional
from typing_extensions import Self
SUPPORTED_KINDS = {
"system",
"uv",
"installer",
"i",
"curlbash",
"curlsh",
"brew",
"cargo",
"pipx",
"npm",
"go",
"gh",
}
def validate_kind(v):
if v not in SUPPORTED_KINDS:
raise ValueError(
f"Unknown installer kind: {v}\n Supported kinds: {SUPPORTED_KINDS}\n "
)
return v
class Package(BaseModel):
"""
Represents a package to be installed, either via system package manager
or an alternative installer like uv, installer.sh, brew, etc.
"""
kind: Annotated[
Literal[
"system",
"uv",
"i",
"curlsh",
"brew",
"cargo",
"pipx",
"npm",
"go",
"gh",
],
BeforeValidator(validate_kind),
] = "system"
dependencies: Optional[List[str]] = None
value: str
@classmethod
def from_raw(cls, raw: str) -> "Package":
"""
Parse a raw input string like 'uv:copier' into a Package(kind='uv', value='copier')
"""
if ":" in raw:
prefix, value = raw.split(":", 1)
return cls(kind=prefix.strip(), value=value.strip())
else:
return cls(kind="system", value=raw.strip())
@model_validator(mode="after")
def validate_dependencies(self) -> Self:
if self.dependencies:
return self
else:
if self.kind == "system":
return self
dependencies = []
if self.kind in ["uv", "i", "installer", "curlbash", "curlsh", "gh"]:
dependencies.extend(
[
Package.from_raw("curl"),
]
)
if self.kind == "brew":
dependencies.extend(
[
Package.from_raw("brew"),
Package.from_raw("git"),
]
)
if self.kind == "cargo":
dependencies.extend(
[
Package.from_raw("cargo"),
]
)
if self.kind == "pipx":
dependencies.extend(
[
Package.from_raw("pipx"),
]
)
if self.kind == "npm":
dependencies.extend(
[
Package.from_raw("npm"),
]
)
if self.kind == "go":
dependencies.extend(
[
Package.from_raw("go"),
]
)
self.dependencies = dependencies
return self
def __str__(self):
return f"{self.kind}:{self.value}" if self.kind != "system" else self.value
def is_system(self) -> bool:
return self.kind == "system"
def install_command(self) -> str:
"""
Generate the bash install command snippet for this package.
"""
if self.kind == "system":
return f"detect_package_manager_and_install {self.value}"
elif self.kind == "uv":
return f"uv tool install {self.value}"
elif self.kind in ["i", "installer", "gh"]:
return f"curl -fsSL https://i.jpillora.com/{self.value} | sh"
elif self.kind == "curlsh":
return f"curl -fsSL {self.value} | sh"
elif self.kind == "curlbash":
return f"curl -fsSL {self.value} | bash"
elif self.kind == "brew":
return f"brew install {self.value}"
elif self.kind == "cargo":
return f"cargo install {self.value}"
elif self.kind == "pipx":
return f"pipx install {self.value}"
elif self.kind == "npm":
return f"npm install -g {self.value}"
elif self.kind == "go":
return f"go install {self.value}@latest"
else:
raise ValueError(f"Unknown install method for kind={self.kind}")
if __name__ == "__main__":
raw_inputs = [
"curl",
"wget",
"uv:copier",
"i:sharkdp/fd",
"curlsh:https://example.com/install.sh",
"brew:bat",
]
packages = [Package.from_raw(raw) for raw in raw_inputs]
dependencies = []
for package in packages:
if package.dependencies:
dependencies.extend(
[dependency.install_command() for dependency in package.dependencies]
)
installs = [package.install_command() for package in packages]
print("\n".join(install for install in unique_everseen([*dependencies, *installs])))

View file

@ -1,7 +1,7 @@
{% if additional_packages %}
detect_package_manager_and_install_command() {
detect_package_manager_and_install() {
if [ $# -eq 0 ]; then
echo "Usage: detect_package_manager_and_install_command <package1> [package2] [...]"
echo "Usage: detect_package_manager_and_install <package1> [package2] [...]"
return 1
fi
@ -34,19 +34,32 @@ detect_package_manager_and_install_command() {
return 2
fi
PACKAGES="$*"
echo "Using package manager: $PKG_MANAGER"
if [ -n "$UPDATE_CMD" ]; then
echo "$UPDATE_CMD
echo $INSTALL_CMD $PACKAGES"
$UPDATE_CMD
$INSTALL_CMD $PACKAGES
echo "Running package manager update..."
eval "$UPDATE_CMD"
fi
FAILED_PKGS=()
for pkg in "$@"; do
echo "Installing package: $pkg"
if ! eval "$INSTALL_CMD $pkg"; then
echo "⚠️ Warning: Failed to install package: $pkg"
FAILED_PKGS+=("$pkg")
fi
done
if [ ${#FAILED_PKGS[@]} -ne 0 ]; then
echo "⚠️ The following packages failed to install:"
for failed_pkg in "${FAILED_PKGS[@]}"; do
echo " - $failed_pkg"
done
else
echo "$INSTALL_CMD $PACKAGES"
$INSTALL_CMD $PACKAGES
echo "✅ All requested packages installed successfully."
fi
}
detect_package_manager_and_install_command {% for package in additional_packages %}{{ package | trim }}{% if not loop.last %} {% endif %}{% endfor %}
detect_package_manager_and_install {% for package in additional_packages %}{{ package | trim }}{% if not loop.last %} {% endif %}{% endfor %}
{% endif %}

View file

@ -31,6 +31,7 @@ dependencies = [
"InquirerPy",
"jinja2",
"iterfzf",
"pydantic",
]
[[project.authors]]