package repocli import ( "context" "encoding/json" "errors" "fmt" "io" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) const ( MediaTypeOIIv1 = "application/vnd.oci.image.index.v1+json" MediatypeDDMLv2 = "application/vnd.docker.distribution.manifest.list.v2+json" MediatypeDDMv2 = "application/vnd.docker.distribution.manifest.v2+json" MediaTypeOIMv1 = "application/vnd.oci.image.manifest.v1+json" ) type Downloader struct { cli *Client } func NewDownloader(client *Client) *Downloader { return &Downloader{ cli: client, } } func (down *Downloader) Pull(ctx context.Context, rawref, dir, os, arch string) error { var err error ref, err := NewReference(rawref) if err != nil { return err } rawrepo := ref.Repo() tag := ref.Tag() exist, mime, man, err := down.cli.GetManifest(ctx, rawrepo, tag) if err != nil { return err } if !exist { err = errors.New("Manifest not found") return err } 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 { cond := descr.Platform.Architecture == arch cond = cond && descr.Platform.OS == os if cond { tag = descr.Digest.String() } } } } fmt.Printf("Tag: %s\n", tag) exist, mime, man, err = down.cli.GetManifest(ctx, rawrepo, tag) if err != nil { return err } fmt.Printf("Mime: %s\n", mime) if !exist { err = errors.New("Manifest not found") return err } 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 } "oci-layout" "index.json" layers := make([]ocispec.Descriptor, 0) layers = append(layers, manifest.Config) layers = append(layers, manifest.Layers...) for _, layer := range layers { digest := layer.Digest.String() exist, err := down.cli.GetBlob(ctx, rawrepo, io.Discard, digest) if err != nil { return err } if !exist { err = errors.New("Layer not found") return err } fmt.Printf("Layer type: %s\n", layer.MediaType) } return err }