more package support
This commit is contained in:
parent
a60562b7fc
commit
9737746923
5 changed files with 283 additions and 11 deletions
87
krayt/bundles.py
Normal file
87
krayt/bundles.py
Normal 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,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
@ -6,7 +6,7 @@ import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import time
|
import time
|
||||||
import typer
|
import typer
|
||||||
from typing import Any, Optional
|
from typing import Any, List, Optional
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
KRAYT_VERSION = "NIGHTLY"
|
KRAYT_VERSION = "NIGHTLY"
|
||||||
|
|
@ -324,6 +324,11 @@ def create_inspector_job(
|
||||||
volumes: list,
|
volumes: list,
|
||||||
image: str = "alpine:latest",
|
image: str = "alpine:latest",
|
||||||
imagepullsecret: Optional[str] = None,
|
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"""
|
"""Create a Krayt inspector job with the given mounts"""
|
||||||
timestamp = int(time.time())
|
timestamp = int(time.time())
|
||||||
|
|
|
||||||
166
krayt/package.py
Normal file
166
krayt/package.py
Normal 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])))
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{% if additional_packages %}
|
{% if additional_packages %}
|
||||||
detect_package_manager_and_install_command() {
|
detect_package_manager_and_install() {
|
||||||
if [ $# -eq 0 ]; then
|
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
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -34,19 +34,32 @@ detect_package_manager_and_install_command() {
|
||||||
return 2
|
return 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PACKAGES="$*"
|
echo "Using package manager: $PKG_MANAGER"
|
||||||
|
|
||||||
if [ -n "$UPDATE_CMD" ]; then
|
if [ -n "$UPDATE_CMD" ]; then
|
||||||
echo "$UPDATE_CMD
|
echo "Running package manager update..."
|
||||||
echo $INSTALL_CMD $PACKAGES"
|
eval "$UPDATE_CMD"
|
||||||
$UPDATE_CMD
|
fi
|
||||||
$INSTALL_CMD $PACKAGES
|
|
||||||
|
|
||||||
|
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
|
else
|
||||||
echo "$INSTALL_CMD $PACKAGES"
|
echo "✅ All requested packages installed successfully."
|
||||||
$INSTALL_CMD $PACKAGES
|
|
||||||
fi
|
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 %}
|
{% endif %}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ dependencies = [
|
||||||
"InquirerPy",
|
"InquirerPy",
|
||||||
"jinja2",
|
"jinja2",
|
||||||
"iterfzf",
|
"iterfzf",
|
||||||
|
"pydantic",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[project.authors]]
|
[[project.authors]]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue