From d7c97b87347ec98682762f1bc6f137b4a81569ab Mon Sep 17 00:00:00 2001 From: Priyanshu Verma Date: Tue, 10 Mar 2026 09:33:39 +0530 Subject: [PATCH 1/2] feat: pinned distro template Signed-off-by: Priyanshu Verma --- docs/template-spec.md | 12 +++++- install.sh | 12 ------ src/cli/mod.rs | 3 -- src/commands/create.rs | 84 ++++++++++++++++++++------------------- src/commands/enter.rs | 12 ------ src/commands/open.rs | 1 - src/container/meta.rs | 4 -- src/runtime/nspawn.rs | 8 ---- src/shell_config.rs | 9 ----- src/template/registry.rs | 5 --- src/template/spec.rs | 36 +++++++++++++++++ src/template/yaml_spec.rs | 14 +++++++ src/user.rs | 7 ---- tests/e2e.rs | 79 ------------------------------------ upgrade.sh | 10 ----- 15 files changed, 104 insertions(+), 192 deletions(-) diff --git a/docs/template-spec.md b/docs/template-spec.md index 611fe1b..4eeb45b 100644 --- a/docs/template-spec.md +++ b/docs/template-spec.md @@ -20,7 +20,7 @@ Every field is optional except `schema` and `name`. | `schema` | `string` | **yes** | Must be `dxon/v1` | | `name` | `string` | **yes** | Short identifier shown in the registry, no spaces | | `description` | `string` | no | One-line description of the environment | -| `base` | `string` | no | Suggested base distribution: `arch`, `debian`, or `alpine` | +| `base` | `string` | no | Pinned base distribution for this template: `arch`, `debian`, or `alpine` | | `packages` | `map>` | no | Per-distro package lists installed before steps run | | `env` | `map` | no | Environment variables set inside the container | | `run` | `list` | no | Commands run after all steps complete | @@ -44,6 +44,16 @@ dXon selects the list matching the chosen distribution and installs those packag Supported keys: `arch`, `debian`, `alpine`. +If your template is intentionally distro-specific, set `base` and only define that distro key in `packages`. + +```yaml +base: debian +packages: + debian: [curl, git, ca-certificates] +``` + +When `base` is set, `dxon create --template ...` automatically uses that distro. + --- ## `env` — environment variables diff --git a/install.sh b/install.sh index 428f7b4..502224a 100755 --- a/install.sh +++ b/install.sh @@ -1,7 +1,4 @@ #!/usr/bin/env sh -# dXon install script -# Usage: curl -sSfL https://raw.githubusercontent.com/P8labs/dxon/master/install.sh | sh -# Or: wget -qO- https://raw.githubusercontent.com/P8labs/dxon/master/install.sh | sh set -e @@ -9,7 +6,6 @@ REPO="P8labs/dxon" BINARY="dxon" INSTALL_DIR="${DXON_INSTALL_DIR:-/usr/local/bin}" -# ── helpers ──────────────────────────────────────────────────────────────────── info() { printf '\033[0;34m info\033[0m %s\n' "$*"; } ok() { printf '\033[0;32m ok\033[0m %s\n' "$*"; } @@ -22,7 +18,6 @@ need_cmd() { fi } -# ── detect OS ────────────────────────────────────────────────────────────────── detect_os() { OS="$(uname -s 2>/dev/null | tr '[:upper:]' '[:lower:]')" @@ -33,7 +28,6 @@ detect_os() { esac } -# ── detect architecture ──────────────────────────────────────────────────────── detect_arch() { ARCH="$(uname -m 2>/dev/null)" @@ -45,7 +39,6 @@ detect_arch() { esac } -# ── fetch latest release tag ─────────────────────────────────────────────────── latest_version() { if command -v curl >/dev/null 2>&1; then @@ -63,7 +56,6 @@ latest_version() { fi } -# ── download binary ──────────────────────────────────────────────────────────── download() { ASSET="${BINARY}-${VERSION}-${OS}-${ARCH}" @@ -86,7 +78,6 @@ download() { echo "$TMP" } -# ── install binary ───────────────────────────────────────────download/v0.3.0/dxon-linux-x86_64────────────────── install_bin() { TMPFILE="$1" @@ -106,7 +97,6 @@ install_bin() { fi } -# ── check systemd-nspawn ──────────────────────────────────────────────────────── check_nspawn() { if ! command -v systemd-nspawn >/dev/null 2>&1; then @@ -120,13 +110,11 @@ check_nspawn() { fi } -# ── main ─────────────────────────────────────────────────────────────────────── main() { detect_os detect_arch - # Allow pinning a version via env var if [ -n "$DXON_VERSION" ]; then VERSION="$DXON_VERSION" else diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 13c7b6a..24c435e 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -29,11 +29,8 @@ pub enum Commands { packages: Vec, #[arg(long, short = 'y')] trust: bool, - /// Shell to install: bash, zsh, fish. #[arg(long, value_name = "SHELL")] shell: Option, - /// Copy or bind-mount host shell config into the container. - /// Valid values: copy, bind. #[arg(long, value_name = "MODE")] shell_config: Option, }, diff --git a/src/commands/create.rs b/src/commands/create.rs index ace9370..244e2f8 100644 --- a/src/commands/create.rs +++ b/src/commands/create.rs @@ -46,36 +46,6 @@ pub fn run(store: &ContainerStore, cfg: &mut Config, args: CreateArgs) -> Result return Err(DxonError::ContainerExists(name).into()); } - let distro_choices = &["arch", "debian", "alpine"]; - - let distro_str: String = match args.distro { - Some(d) => d, - None => { - let default_idx = cfg - .default_distro - .as_deref() - .and_then(|d| distro_choices.iter().position(|&c| c == d)) - .unwrap_or(0); - - let idx = Select::with_theme(&theme) - .with_prompt("Base distribution") - .items(distro_choices) - .default(default_idx) - .interact()?; - distro_choices[idx].to_string() - } - }; - let distro = Distro::parse(&distro_str)?; - - let (bootstrap_tool, hint) = host.bootstrap_tool_for(&distro_str); - if !user::command_available(bootstrap_tool) { - return Err(DxonError::MissingTool { - tool: bootstrap_tool.to_string(), - hint: format!("on {}: {hint}", host.pretty_name), - } - .into()); - } - let (tmpl, tmpl_name): (Option, Option) = match args.template { Some(ref t) => { let (loaded, source) = template::resolve(t, cfg.effective_registry_url())?; @@ -112,6 +82,49 @@ pub fn run(store: &ContainerStore, cfg: &mut Config, args: CreateArgs) -> Result } }; + let distro_choices = &["arch", "debian", "alpine"]; + let template_distro = tmpl.as_ref().and_then(|t| t.pinned_distro()); + + let distro_str: String = match (args.distro, template_distro) { + (Some(requested), Some(pinned)) => { + if requested != pinned { + anyhow::bail!( + "template '{}' is pinned to distro '{}' but '--distro {}' was provided", + tmpl_name.as_deref().unwrap_or("