Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions docs/dev-tools/mise-oci.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ jq = "1.8.1"
1. **Base image layers** (e.g. `debian:bookworm-slim`) — copied through from
the registry unchanged, so registry dedup kicks in.
2. **mise binary** at `/usr/local/bin/mise` (skip with `--no-mise`).
3. **One layer per tool**, each rooted at
3. **Configured apt or apk `[bootstrap.packages]`**, if any, installed into the
base rootfs and emitted as one package layer.
4. **One layer per tool**, each rooted at
`/mise/installs/<plugin>/<version>/`. Annotated with
`dev.mise.tool.short` and `dev.mise.tool.version`.
4. **Configured apt `[bootstrap.packages]`**, if any, installed into the base
rootfs and emitted as one package layer.
5. **Configured `[dotfiles]`**, if any, baked as image files.
6. **Synthesized `/etc/mise/config.toml`** referencing `/mise` as the data
directory.
Expand Down Expand Up @@ -309,11 +309,19 @@ Pass `--include-global` to also include `[bootstrap.packages]` and
"~/.config/app/config.toml" = { source = "config.toml", mode = "template" }
```

For packages, OCI builds currently support `apt:` entries with a Debian/Ubuntu
base image. mise unpacks the base image into a temporary rootfs, calls the
host `apt-get` to install into that rootfs, then emits the filesystem changes
as one OCI layer annotated with `dev.mise.system.packages=apt`. Other system
package managers are rejected for OCI builds for now.
For packages, OCI builds support `apt:` entries with a Debian/Ubuntu base image
and `apk:` entries with an Alpine/Wolfi base image. mise unpacks the base image
into a temporary rootfs, calls the matching host package manager to install into
that rootfs, then emits the filesystem changes as one OCI layer annotated with
`dev.mise.system.packages=apt` or `dev.mise.system.packages=apk`. A build may
use only the package manager matching its base image; mixing `apt:` and `apk:`
entries is rejected.

The host must provide `apt-get` and `dpkg` for apt layers, or `apk` for apk
layers. Apk package scripts execute inside a chroot, so apk layers currently
require a Linux host running mise as root. `--no-cache` is passed to apk and
transient package-manager cache and log files are removed before the layer is
created.

For image builds, `symlink` and `symlink-each` entries are copied as file
content. Host symlinks would usually point back to the checkout path and be
Expand Down
6 changes: 6 additions & 0 deletions e2e/oci/test_oci_build_slow
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ cat >mise.toml <<EOF
EOF
assert_fail "mise oci build -o ./out-system-packages --from scratch" "requires an apt-based base image"

cat >mise.toml <<EOF
[bootstrap.packages]
"apk:curl" = "latest"
EOF
assert_fail "mise oci build -o ./out-system-packages --from scratch" "requires an apk-based base image"

# --- 12. No project config + no --include-global → clear error ---
# Error message is shared between build/run/push, so it must NOT name a
# specific subcommand (just "mise oci").
Expand Down
13 changes: 8 additions & 5 deletions src/oci/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,17 +451,20 @@ impl Builder {
}

if let Some(blob) = &system_packages_layer {
layout.write_blob_with_digest(&blob.digest, &blob.bytes)?;
layout.write_blob_with_digest(&blob.blob.digest, &blob.blob.bytes)?;
let mut annotations = IndexMap::new();
annotations.insert("dev.mise.system.packages".to_string(), "apt".to_string());
annotations.insert(
"dev.mise.system.packages".to_string(),
blob.manager.to_string(),
);
manifest_layers.push(Descriptor {
media_type: manifest::MEDIA_TYPE_OCI_LAYER_GZIP.to_string(),
size: blob.size,
digest: blob.digest.clone(),
size: blob.blob.size,
digest: blob.blob.digest.clone(),
annotations,
platform: None,
});
all_diff_ids.push(blob.diff_id.clone());
all_diff_ids.push(blob.blob.diff_id.clone());
}

for entry in &tool_layers {
Expand Down
Loading
Loading