package controller import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "net/url" "nf-repo/internal/interfaces" "nf-repo/internal/model" "nf-repo/internal/opt" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/remote" ) func PullRepo(ctx context.Context, repo string, tag string, proxy string, mh interfaces.ManifestHandler, bh interfaces.BlobHandler, ) (*v1.Manifest, error) { if repo == "" || tag == "" { return nil, fmt.Errorf("invalid repo or tag") } var ( err error transport = &http.Transport{} puller *remote.Puller tn name.Tag des *remote.Descriptor img v1.Image manifest *v1.Manifest bs []byte mhash model.Hash target = fmt.Sprintf("%s:%s", repo, tag) ) if opt.Proxy != nil { transport.Proxy = http.ProxyURL(opt.Proxy) } if proxy != "" { var pu *url.URL if pu, err = url.Parse(proxy); err != nil { return nil, err } transport.Proxy = http.ProxyURL(pu) } if puller, err = remote.NewPuller( remote.WithTransport(transport), ); err != nil { return nil, err } if tn, err = name.NewTag(target); err != nil { return nil, err } if des, err = puller.Get(ctx, tn); err != nil { return nil, err } if img, err = des.Image(); err != nil { return nil, err } if manifest, err = img.Manifest(); err != nil { return nil, err } total := model.ManifestCountSize(manifest) size := 0 _ = total var ( tly v1.Layer tdigest v1.Hash treader io.ReadCloser ) if tly, err = img.LayerByDigest(manifest.Config.Digest); err != nil { return nil, err } if tdigest, err = tly.Digest(); err != nil { return nil, err } if treader, err = tly.Uncompressed(); err != nil { return nil, err } defer treader.Close() if err = bh.Put( ctx, target, model.Hash{Algorithm: tdigest.Algorithm, Hex: tdigest.Hex}, treader, ); err != nil { return nil, err } size = size + int(manifest.Config.Size) if bs, err = json.Marshal(manifest); err != nil { return nil, err } if mhash, _, err = model.SHA256(bytes.NewReader(bs)); err != nil { return nil, err } for idx := range manifest.Layers { var ( reader io.ReadCloser lyHash v1.Hash ly v1.Layer ) lyHash = manifest.Layers[idx].Digest if ly, err = img.LayerByDigest(manifest.Layers[idx].Digest); err != nil { return nil, err } if reader, err = ly.Compressed(); err != nil { return nil, err } defer reader.Close() if err = bh.Put(ctx, repo, model.Hash{Algorithm: lyHash.Algorithm, Hex: lyHash.Hex}, reader); err != nil { return nil, err } size = size + int(manifest.Layers[idx].Size) } if re := mh.Put(ctx, repo, tag, mhash.String(), &model.RepoSimpleManifest{ ContentType: string(manifest.MediaType), Blob: bs, }); re != nil { return nil, err } return manifest, nil }