github.com/Racer159/jackal@v0.32.7-0.20240401174413-0bd2339e4f2e/src/pkg/zoci/push.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: 2021-Present The Jackal Authors 3 4 // Package zoci contains functions for interacting with Jackal packages stored in OCI registries. 5 package zoci 6 7 import ( 8 "context" 9 "fmt" 10 11 "github.com/Racer159/jackal/src/pkg/layout" 12 "github.com/Racer159/jackal/src/pkg/message" 13 "github.com/Racer159/jackal/src/types" 14 "github.com/defenseunicorns/pkg/helpers" 15 "github.com/defenseunicorns/pkg/oci" 16 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 17 "oras.land/oras-go/v2" 18 "oras.land/oras-go/v2/content/file" 19 ) 20 21 // PublishPackage publishes the jackal package to the remote repository. 22 func (r *Remote) PublishPackage(ctx context.Context, pkg *types.JackalPackage, paths *layout.PackagePaths, concurrency int) error { 23 src, err := file.New(paths.Base) 24 if err != nil { 25 return err 26 } 27 defer src.Close() 28 29 r.Log().Info(fmt.Sprintf("Publishing package to %s", r.Repo().Reference)) 30 spinner := message.NewProgressSpinner("") 31 defer spinner.Stop() 32 33 // Get all of the layers in the package 34 var descs []ocispec.Descriptor 35 for name, path := range paths.Files() { 36 spinner.Updatef("Preparing layer %s", helpers.First30last30(name)) 37 38 mediaType := JackalLayerMediaTypeBlob 39 40 desc, err := src.Add(ctx, name, mediaType, path) 41 if err != nil { 42 return err 43 } 44 descs = append(descs, desc) 45 } 46 spinner.Successf("Prepared all layers") 47 48 copyOpts := r.GetDefaultCopyOpts() 49 copyOpts.Concurrency = concurrency 50 total := oci.SumDescsSize(descs) 51 52 annotations := annotationsFromMetadata(&pkg.Metadata) 53 54 // assumes referrers API is not supported since OCI artifact 55 // media type is not supported 56 r.Repo().SetReferrersCapability(false) 57 58 // push the manifest config 59 manifestConfigDesc, err := r.CreateAndPushManifestConfig(ctx, annotations, JackalConfigMediaType) 60 if err != nil { 61 return err 62 } 63 root, err := r.PackAndTagManifest(ctx, src, descs, manifestConfigDesc, annotations) 64 if err != nil { 65 return err 66 } 67 68 total += manifestConfigDesc.Size 69 70 progressBar := message.NewProgressBar(total, fmt.Sprintf("Publishing %s:%s", r.Repo().Reference.Repository, r.Repo().Reference.Reference)) 71 defer progressBar.Stop() 72 r.SetProgressWriter(progressBar) 73 defer r.ClearProgressWriter() 74 75 publishedDesc, err := oras.Copy(ctx, src, root.Digest.String(), r.Repo(), "", copyOpts) 76 if err != nil { 77 return err 78 } 79 80 if err := r.UpdateIndex(ctx, r.Repo().Reference.Reference, publishedDesc); err != nil { 81 return err 82 } 83 84 progressBar.Successf("Published %s [%s]", r.Repo().Reference, JackalLayerMediaTypeBlob) 85 return nil 86 } 87 88 func annotationsFromMetadata(metadata *types.JackalMetadata) map[string]string { 89 annotations := map[string]string{ 90 ocispec.AnnotationTitle: metadata.Name, 91 ocispec.AnnotationDescription: metadata.Description, 92 } 93 94 if url := metadata.URL; url != "" { 95 annotations[ocispec.AnnotationURL] = url 96 } 97 if authors := metadata.Authors; authors != "" { 98 annotations[ocispec.AnnotationAuthors] = authors 99 } 100 if documentation := metadata.Documentation; documentation != "" { 101 annotations[ocispec.AnnotationDocumentation] = documentation 102 } 103 if source := metadata.Source; source != "" { 104 annotations[ocispec.AnnotationSource] = source 105 } 106 if vendor := metadata.Vendor; vendor != "" { 107 annotations[ocispec.AnnotationVendor] = vendor 108 } 109 110 return annotations 111 }