docs: document the library/CLI output split
The library is terminal-silent: diagnostics through the log facade, progress through Progress sinks. The CLI owns all rendering.
This commit is contained in:
@@ -18,7 +18,7 @@ ecr fedora # any Docker Hub image
|
|||||||
|
|
||||||
## Library
|
## Library
|
||||||
|
|
||||||
`ecr` is a cargo workspace: `crates/ecr` is the library crate (package `ecr`), `crates/ecr-cli` the thin command-line front-end. Rust consumers can use the library directly — resolve an image, download it through the content cache, and run commands with a fully caller-controlled environment, bind targets and architecture:
|
`ecr` is a cargo workspace: `crates/ecr` is the library crate (package `ecr`), `crates/ecr-cli` the thin command-line front-end. The library never writes to the terminal: diagnostics go through the `log` crate, and downloads, extraction and initramfs creation report progress through a caller-supplied `Progress` sink (pass `&NoProgress` for silence, or implement the trait to render your own UI). Rust consumers can use the library directly — resolve an image, download it through the content cache, and run commands with a fully caller-controlled environment, bind targets and architecture:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -26,11 +26,11 @@ ecr = { git = "https://github.com/…" } # or a path / registry source
|
|||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use ecr::{chroot, BindTarget, ExecOptions, PrepareRequest, RootfsCache};
|
use ecr::{chroot, BindTarget, ExecOptions, NoProgress, PrepareRequest, RootfsCache};
|
||||||
|
|
||||||
// Download alpine through the cache (~/.cache/ecr) and extract to a scratch dir
|
// Download alpine through the cache (~/.cache/ecr) and extract to a scratch dir
|
||||||
let cache = RootfsCache::new(RootfsCache::default_dir()?);
|
let cache = RootfsCache::new(RootfsCache::default_dir()?);
|
||||||
let rootfs = cache.prepare(&PrepareRequest::new("alpine:3.23"))?;
|
let rootfs = cache.prepare(&PrepareRequest::new("alpine:3.23"), &NoProgress)?;
|
||||||
|
|
||||||
// Caller-composed envp, explicit bind targets, target architecture
|
// Caller-composed envp, explicit bind targets, target architecture
|
||||||
let code = rootfs.exec(&ExecOptions {
|
let code = rootfs.exec(&ExecOptions {
|
||||||
@@ -53,7 +53,7 @@ rootfs.persist()?; // write the rootfs back into the cache (see below)
|
|||||||
Prepare once, provision once, amortize every later run — including runs from other processes sharing the same cache directory:
|
Prepare once, provision once, amortize every later run — including runs from other processes sharing the same cache directory:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let rootfs = cache.prepare_provisioned(&PrepareRequest::new("alpine:3.23"), |rootfs| {
|
let rootfs = cache.prepare_provisioned(&PrepareRequest::new("alpine:3.23"), &NoProgress, |rootfs| {
|
||||||
// runs at most once per cache entry
|
// runs at most once per cache entry
|
||||||
rootfs.exec(&ExecOptions {
|
rootfs.exec(&ExecOptions {
|
||||||
command: vec!["apk".into(), "add".into(), "curl".into()],
|
command: vec!["apk".into(), "add".into(), "curl".into()],
|
||||||
|
|||||||
@@ -10,7 +10,13 @@ Cargo workspace with two crates:
|
|||||||
- `crates/ecr-cli` — the CLI front-end (package `ecr-cli`, binary `ecr`).
|
- `crates/ecr-cli` — the CLI front-end (package `ecr-cli`, binary `ecr`).
|
||||||
Parses flags, maps them onto the library API, propagates exit codes.
|
Parses flags, maps them onto the library API, propagates exit codes.
|
||||||
|
|
||||||
The library must not depend on CLI types (`clap` is a CLI-only dependency).
|
The library must not depend on CLI types (`clap` is a CLI-only
|
||||||
|
dependency), and it never writes to the terminal: diagnostics go
|
||||||
|
through the `log` facade, and long-running operations (downloads,
|
||||||
|
extraction, initramfs creation) report progress through an
|
||||||
|
`ecr::progress::Progress` sink (`NoProgress` discards everything).
|
||||||
|
All terminal output — the logger driven by `-v`, the bars and
|
||||||
|
spinners (indicatif) — is owned by `crates/ecr-cli`.
|
||||||
|
|
||||||
## Library API
|
## Library API
|
||||||
|
|
||||||
@@ -18,12 +24,13 @@ The library must not depend on CLI types (`clap` is a CLI-only dependency).
|
|||||||
|
|
||||||
- `RootfsCache::new(dir)` / `RootfsCache::default_dir()` — the image tarball
|
- `RootfsCache::new(dir)` / `RootfsCache::default_dir()` — the image tarball
|
||||||
cache (default `~/.cache/ecr`).
|
cache (default `~/.cache/ecr`).
|
||||||
- `cache.prepare(&PrepareRequest)` — parse the image reference, resolve
|
- `cache.prepare(&req, &progress)` — parse the image reference, resolve
|
||||||
floating version aliases ("latest", "lts", "edge") to a concrete version
|
floating version aliases ("latest", "lts", "edge") to a concrete version
|
||||||
before computing the cache key, run the OCI `:latest` digest freshness
|
before computing the cache key, run the OCI `:latest` digest freshness
|
||||||
check, download through the cache when needed, and extract into a scratch
|
check, download through the cache when needed, and extract into a scratch
|
||||||
directory. Returns a `PreparedRootfs` (TempDir-backed; dropped on drop).
|
directory. Returns a `PreparedRootfs` (TempDir-backed; dropped on drop).
|
||||||
- `cache.prepare_provisioned(&req, provision)` — hot-cell amortization: on a
|
- `cache.prepare_provisioned(&req, &progress, provision)` — hot-cell
|
||||||
|
amortization: on a
|
||||||
cache hit with a `.provisioned` sidecar the entry is extracted as-is (no
|
cache hit with a `.provisioned` sidecar the entry is extracted as-is (no
|
||||||
freshness check, no provisioning); otherwise the rootfs is prepared,
|
freshness check, no provisioning); otherwise the rootfs is prepared,
|
||||||
`provision(&PreparedRootfs)` runs once, and `persist` writes the result
|
`provision(&PreparedRootfs)` runs once, and `persist` writes the result
|
||||||
@@ -58,6 +65,17 @@ the bind targets; `in_rootfs(rootfs, target)` maps in-chroot paths and
|
|||||||
rejects escaping targets. Overlay upper/work directories are temp dirs the
|
rejects escaping targets. Overlay upper/work directories are temp dirs the
|
||||||
caller must keep alive (returned by `setup_mounts`).
|
caller must keep alive (returned by `setup_mounts`).
|
||||||
|
|
||||||
|
### Progress and logging (`ecr::progress`)
|
||||||
|
|
||||||
|
- `Progress` — sink trait for sequential operations: `begin(label, unit,
|
||||||
|
total)` starts the next operation (implicitly ending the previous one),
|
||||||
|
`advance(n)` counts completed units, `finish` ends it. Consumers
|
||||||
|
implement it to render UI; `NoProgress` discards every event.
|
||||||
|
- Diagnostics go through `log`: `debug` for narration (URLs, layer info,
|
||||||
|
extraction steps), `warn` for recoverable conditions (unreadable
|
||||||
|
entries, failed best-effort setup). Nothing is emitted unless the
|
||||||
|
consumer installs a logger.
|
||||||
|
|
||||||
## Synopsis
|
## Synopsis
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user