/* * Copyright 2026 Oleg Borodin * * */ package repocli import ( "context" "encoding/json" "errors" "os" "runtime" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) type Loader struct { cli *Client } func NewLoader(client *Client) *Loader { return &Loader{ cli: client, } } func (down *Loader) Pull(ctx context.Context, rawref, dir, osname, arch, variant string) error { var err error if osname == "" { osname = runtime.GOOS } if arch == "" { arch = runtime.GOARCH } ref, err := NewReferer(rawref) if err != nil { return err } rawrepo := ref.RawRepo() accepts := []string{ MediaTypeDDMLv2, MediaTypeDDMv2, MediaTypeOIMv1, MediaTypeOIIv1, } exist, mime, man, digstr, err := down.cli.GetRawManifest(ctx, ref.Raw(), accepts) if err != nil { return err } if !exist { err = errors.New("Manifest not found") return err } tag := ref.Tag() if mime == MediaTypeOIIv1 || mime == MediaTypeDDMLv2 { var index ocispec.Index err = json.Unmarshal(man, &index) if err != nil { return err } for _, descr := range index.Manifests { if descr.Platform != nil { var cond bool cond = descr.Platform.Architecture == arch cond = cond && descr.Platform.OS == osname if variant != "" { cond = cond && descr.Platform.Variant == variant } if cond { tag = descr.Digest.String() digstr = descr.Digest.String() break } } } if tag == "" { err = errors.New("Manifest for required arch and OS not found") return err } accepts := []string{ MediaTypeDDMv2, MediaTypeOIMv1, } _, mime, man, digstr, err = down.cli.GetRawManifest(ctx, ref.RawWithTag(tag), accepts) if err != nil { return err } } else if mime != MediaTypeOIMv1 && mime != MediaTypeDDMv2 { err = errors.New("Unknown manifest media type") return err } var manifest ocispec.Manifest err = json.Unmarshal(man, &manifest) if err != nil { return err } // Write image manifest imager := NewEmptyImager(dir) err = imager.WriteManifest(ctx, digstr, mime, man) if err != nil { return err } layers := make([]ocispec.Descriptor, 0) layers = append(layers, manifest.Config) layers = append(layers, manifest.Layers...) for _, layer := range layers { wrapfunc := func() error { tmpfile, err := os.CreateTemp(dir, "*.bin") if err != nil { return err } defer tmpfile.Close() tmpname := tmpfile.Name() defer os.Remove(tmpname) digstr := layer.Digest.String() exist, err := down.cli.GetBlob(ctx, rawrepo, tmpfile, digstr) if err != nil { return err } if !exist { err = errors.New("Layer not found") return err } tmpfile.Seek(0, 0) size := layer.Size err = imager.WriteLayer(ctx, digstr, size, tmpfile) if err != nil { return err } return err } err = wrapfunc() if err != nil { return err } } return err }