mirror of
https://github.com/vhaudiquet/ecrou.git
synced 2026-11-12 22:22:44 +00:00
feat(cli): provision layers from a spec file
A provision command baked by hand - `ecrou provision alpine -- apk add ...` - cannot be reviewed or shared: the artifact worth keeping is a diff in git, not a shell history line. A spec file is that diff. `ecrou provision --spec image.yaml` parses base, packages and a run block, derives the provisioning script from the base's own package manager (apt, apk, dnf, discovered at provision time on the running machine), and bakes the result into a cache entry keyed by the spec's content hash: the same file never provisions twice, an edited file never reuses the old layer, and the key hashes the raw bytes so the layer is stable across ecrou versions. `--layer NAME` names the entry, and `ecrou run --layer NAME` boots it directly - no image resolution, no download; the layer is whatever the provision call persisted under that name. A keyed entry has no tarball of its own, so the base downloads only on the first provisioning and every later run extracts the finished layer.
This commit is contained in:
1 parent
dad5f61833
commit
878ce29b8d
7 files changed
+455
-31
No files matched your search
@@ -27,9 +27,20 @@ pub enum Command {
|
||||
/// command installed. Cached entries are reused as-is; --no-cache
|
||||
/// re-downloads and re-provisions.
|
||||
Provision {
|
||||
/// Distribution name or OCI image reference
|
||||
image: String,
|
||||
/// Ignore the cache and download a fresh image
|
||||
/// Distribution name or OCI image reference; the spec's `base`
|
||||
/// when omitted and the spec carries one
|
||||
image: Option<String>,
|
||||
/// A provisioning spec file (YAML: base, packages, run) — the
|
||||
/// layer it describes is keyed by the file's content, so the
|
||||
/// same spec never provisions twice and a changed spec never
|
||||
/// reuses an old layer
|
||||
#[arg(long)]
|
||||
spec: Option<std::path::PathBuf>,
|
||||
/// Name the provisioned layer, so runs can boot it by name
|
||||
/// (`run --layer NAME`) without re-deriving anything
|
||||
#[arg(long)]
|
||||
layer: Option<String>,
|
||||
/// Ignore the cache: re-download the base and re-provision
|
||||
#[arg(long)]
|
||||
no_cache: bool,
|
||||
/// The provisioning command. An argument vector after `--` is
|
||||
@@ -44,8 +55,10 @@ pub enum Command {
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct RunArgs {
|
||||
/// Distribution name or OCI image reference
|
||||
pub image: String,
|
||||
/// Distribution name or OCI image reference; not needed with
|
||||
/// `--layer`, which boots a provisioned cache entry
|
||||
#[arg(required_unless_present = "layer")]
|
||||
pub image: Option<String>,
|
||||
/// Command to run in the machine; the image's default shell when
|
||||
/// omitted. An argument vector after `--` is taken literally; a
|
||||
/// single quoted line runs through the image's shell.
|
||||
@@ -73,6 +86,10 @@ pub struct RunArgs {
|
||||
/// Ignore the cache and download a fresh image
|
||||
#[arg(long)]
|
||||
pub no_cache: bool,
|
||||
/// Boot a named provisioned layer (see `provision --layer`)
|
||||
/// instead of resolving an image
|
||||
#[arg(long)]
|
||||
pub layer: Option<String>,
|
||||
}
|
||||
|
||||
/// Parse one `HOST:GUEST[:ro]` share specification. The guest path must
|
||||
|
||||
Reference in new issue
Block a user