werkdock load -i ARCHIVE reads the docker save manifest (legacy and OCI layout) or a plain OCI image layout, applies the layers in order into one rootfs with whiteout handling, and keeps the OCI config as the image metadata. Layer extraction is werkdock's own: every path is resolved inside the rootfs the way the sandbox sees it, following lower layers' symlinks and clamping .. at the root as a chroot does, so a hostile layer can rewrite the image but never the host. gzip layers in-process, zstd through the zstd binary. RepoTags name the image, each further tag is a hardlinked copy; a multi-arch index picks the host platform, otherwise the available ones are listed. Verified against docker 27 save archives of busybox:1.36 and alpine:3.20, run in the sandbox afterwards. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
50 lines
1.3 KiB
Go
50 lines
1.3 KiB
Go
package cli
|
|
|
|
import (
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"werkdock/internal/store"
|
|
)
|
|
|
|
// loadCmd is `docker load`: a `docker save` archive or an OCI image
|
|
// layout into the store, layers flattened, metadata kept (RFC 0004).
|
|
// --name still routes a plain rootfs archive to import, for the callers
|
|
// that predate `werkdock import` (Werkator), with a note.
|
|
func loadCmd(args []string) int {
|
|
fs := flag.NewFlagSet("load", flag.ContinueOnError)
|
|
fs.SetOutput(io.Discard)
|
|
var input, name string
|
|
fs.StringVar(&input, "i", "", "image archive to load")
|
|
fs.StringVar(&input, "input", "", "image archive to load")
|
|
fs.StringVar(&name, "name", "", "image reference for a rootfs archive (deprecated; use werkdock import)")
|
|
if err := fs.Parse(args); err != nil {
|
|
return fail(err)
|
|
}
|
|
if input == "" {
|
|
return fail(errors.New("load needs -i ARCHIVE"))
|
|
}
|
|
if len(fs.Args()) != 0 {
|
|
return fail(fmt.Errorf("unexpected argument %q", fs.Args()[0]))
|
|
}
|
|
if name != "" {
|
|
fmt.Fprintf(os.Stderr, "werkdock: load --name imports a rootfs archive; prefer: werkdock import %s %s\n", input, name)
|
|
return importArchive(input, name, store.ImageConfig{})
|
|
}
|
|
st, err := store.Default()
|
|
if err != nil {
|
|
return fail(err)
|
|
}
|
|
loaded, err := st.Load(input, "")
|
|
if err != nil {
|
|
return fail(err)
|
|
}
|
|
for _, ref := range loaded {
|
|
fmt.Printf("Loaded image: %s\n", ref)
|
|
}
|
|
return 0
|
|
}
|