From 3b159ddb06cac0e24cf8a1cdfa6c21ca42e45e13 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Thu, 5 Dec 2024 08:04:18 +0000 Subject: [PATCH 1/2] docs: add experimental mark for examples Signed-off-by: Billy Zha --- cmd/oras/root/attach.go | 53 ++++++++++++++------------------- cmd/oras/root/discover.go | 4 +-- cmd/oras/root/manifest/fetch.go | 4 +-- cmd/oras/root/pull.go | 4 +-- cmd/oras/root/push.go | 6 ++-- 5 files changed, 32 insertions(+), 39 deletions(-) diff --git a/cmd/oras/root/attach.go b/cmd/oras/root/attach.go index d6eb6f788..596e98ec1 100644 --- a/cmd/oras/root/attach.go +++ b/cmd/oras/root/attach.go @@ -44,13 +44,12 @@ type attachOptions struct { artifactType string concurrency int - verbose bool } func attachCmd() *cobra.Command { var opts attachOptions cmd := &cobra.Command{ - Use: "attach [flags] --artifact-type= {:|@} {[:]|--annotation =} [...]", + Use: "attach [flags] --artifact-type= {:|@} [:] [...]", Short: "[Preview] Attach files to an existing artifact", Long: `[Preview] Attach files to an existing artifact @@ -78,10 +77,10 @@ Example - Attach an artifact with manifest annotations: Example - Attach file 'hi.txt' and add manifest annotations: oras attach --artifact-type doc/example --annotation "key=val" localhost:5000/hello:v1 hi.txt -Example - Attach file 'hi.txt' and format output in JSON: +Example - [Experimental] Attach file 'hi.txt' and format output in JSON: oras attach --artifact-type doc/example localhost:5000/hello:v1 hi.txt --format json -Example - Attach file 'hi.txt' and format output with Go template: +Example - [Experimental] Attach file 'hi.txt' and format output with Go template: oras attach --artifact-type doc/example localhost:5000/hello:v1 hi.txt --format go-template --template "{{.digest}}" Example - Attach file 'hi.txt' and export the pushed manifest to 'manifest.json': @@ -94,41 +93,38 @@ Example - Attach file to the manifest tagged 'v1' in an OCI image layout folder PreRunE: func(cmd *cobra.Command, args []string) error { opts.RawReference = args[0] opts.FileRefs = args[1:] - err := option.Parse(cmd, &opts) - if err == nil { - if err = opts.EnsureReferenceNotEmpty(cmd, true); err == nil { - return nil - } - } - if len(opts.FileRefs) == 0 { - // no file argument provided - if err, ok := err.(*oerrors.Error); ok && err.OperationType == oerrors.OperationTypeParseArtifactReference { - // invalid reference - err.Recommendation = fmt.Sprintf("Are you missing an artifact reference to attach to? %s", err.Recommendation) - } + if err := option.Parse(cmd, &opts); err != nil { + return err } - return err + return nil }, RunE: func(cmd *cobra.Command, args []string) error { - opts.Printer.Verbose = opts.verbose return runAttach(cmd, &opts) }, } cmd.Flags().StringVarP(&opts.artifactType, "artifact-type", "", "", "artifact type") cmd.Flags().IntVarP(&opts.concurrency, "concurrency", "", 5, "concurrency level") - cmd.Flags().BoolVarP(&opts.verbose, "verbose", "v", false, "print status output for unnamed blobs") opts.FlagDescription = "[Preview] attach to an arch-specific subject" _ = cmd.MarkFlagRequired("artifact-type") opts.EnableDistributionSpecFlag() - opts.SetTypes(option.FormatTypeText, option.FormatTypeJSON, option.FormatTypeGoTemplate) + opts.AllowedTypes = []*option.FormatType{option.FormatTypeJSON, option.FormatTypeGoTemplate} option.ApplyFlags(&opts, cmd.Flags()) return oerrors.Command(cmd, &opts.Target) } func runAttach(cmd *cobra.Command, opts *attachOptions) error { ctx, logger := command.GetLogger(cmd, &opts.Common) - if len(opts.FileRefs) == 0 && len(opts.Annotations[option.AnnotationManifest]) == 0 { + displayStatus, displayMetadata, err := display.NewAttachHandler(cmd.OutOrStdout(), opts.Format, opts.TTY, opts.Verbose) + if err != nil { + return err + } + + annotations, err := opts.LoadManifestAnnotations() + if err != nil { + return err + } + if len(opts.FileRefs) == 0 && len(annotations[option.AnnotationManifest]) == 0 { return &oerrors.Error{ Err: errors.New(`neither file nor annotation provided in the command`), Usage: fmt.Sprintf("%s %s", cmd.Parent().CommandPath(), cmd.Use), @@ -147,6 +143,9 @@ func runAttach(cmd *cobra.Command, opts *attachOptions) error { if err != nil { return err } + if err := opts.EnsureReferenceNotEmpty(cmd, true); err != nil { + return err + } // add both pull and push scope hints for dst repository // to save potential push-scope token requests during copy ctx = registryutil.WithScopeHint(ctx, dst, auth.ActionPull, auth.ActionPush) @@ -156,11 +155,7 @@ func runAttach(cmd *cobra.Command, opts *attachOptions) error { if err != nil { return fmt.Errorf("failed to resolve %s: %w", opts.Reference, err) } - displayStatus, displayMetadata, err := display.NewAttachHandler(opts.Printer, opts.Format, opts.TTY, store) - if err != nil { - return err - } - descs, err := loadFiles(ctx, store, opts.Annotations, opts.FileRefs, displayStatus) + descs, err := loadFiles(ctx, store, annotations, opts.FileRefs, displayStatus) if err != nil { return err } @@ -172,13 +167,11 @@ func runAttach(cmd *cobra.Command, opts *attachOptions) error { } graphCopyOptions := oras.DefaultCopyGraphOptions graphCopyOptions.Concurrency = opts.concurrency - graphCopyOptions.OnCopySkipped = displayStatus.OnCopySkipped - graphCopyOptions.PreCopy = displayStatus.PreCopy - graphCopyOptions.PostCopy = displayStatus.PostCopy + displayStatus.UpdateCopyOptions(&graphCopyOptions, store) packOpts := oras.PackManifestOptions{ Subject: &subject, - ManifestAnnotations: opts.Annotations[option.AnnotationManifest], + ManifestAnnotations: annotations[option.AnnotationManifest], Layers: descs, } pack := func() (ocispec.Descriptor, error) { diff --git a/cmd/oras/root/discover.go b/cmd/oras/root/discover.go index afdd0da46..e65817b57 100644 --- a/cmd/oras/root/discover.go +++ b/cmd/oras/root/discover.go @@ -61,10 +61,10 @@ Example - Discover referrers via referrers API: Example - Discover referrers via tag scheme: oras discover --distribution-spec v1.1-referrers-tag localhost:5000/hello:v1 -Example - Discover referrers and display in a table view: +Example - [Experimental] Discover referrers and display in a table view: oras discover localhost:5000/hello:v1 --format table -Example - Discover referrers and format output with Go template: +Example - [Experimental] Discover referrers and format output with Go template: oras discover localhost:5000/hello:v1 --format go-template --template "{{.manifests}}" Example - Discover all the referrers of manifest with annotations, displayed in a tree view: diff --git a/cmd/oras/root/manifest/fetch.go b/cmd/oras/root/manifest/fetch.go index f7a8d7281..f924d8a47 100644 --- a/cmd/oras/root/manifest/fetch.go +++ b/cmd/oras/root/manifest/fetch.go @@ -55,10 +55,10 @@ Example - Fetch raw manifest from a registry: Example - Fetch the descriptor of a manifest from a registry: oras manifest fetch --descriptor localhost:5000/hello:v1 -Example - Fetch the manifest digest from a registry similar to the resolve command: +Example - [Experimental] Fetch the manifest digest from a registry similar to the resolve command: oras manifest fetch --format go-template --template '{{ .digest }}' localhost:5000/hello:v1 -Example - Fetch manifest and output metadata encoded in JSON: +Example - [Experimental] Fetch manifest and output metadata encoded in JSON: oras manifest fetch localhost:5000/hello:v1 --format json Example - Fetch manifest from a registry with specified media type: diff --git a/cmd/oras/root/pull.go b/cmd/oras/root/pull.go index d5beef3f3..10bccb060 100644 --- a/cmd/oras/root/pull.go +++ b/cmd/oras/root/pull.go @@ -84,10 +84,10 @@ Example - Pull files from a registry with certain platform: Example - Pull all files with concurrency level tuned: oras pull --concurrency 6 localhost:5000/hello:v1 -Example - Pull files and format output in JSON: +Example - [Experimental] Pull files and format output in JSON: oras pull localhost:5000/hello:v1 --format json -Example - Pull files and format output with Go template: +Example - [Experimental] Pull files and format output with Go template: oras pull localhost:5000/hello:v1 --format go-template="{{.reference}}" Example - Pull artifact files from an OCI image layout folder 'layout-dir': diff --git a/cmd/oras/root/push.go b/cmd/oras/root/push.go index f34bcc0fa..b75c8661b 100644 --- a/cmd/oras/root/push.go +++ b/cmd/oras/root/push.go @@ -86,10 +86,10 @@ Example - Push file "hi.txt" with config type "application/vnd.me.config": Example - Push file "hi.txt" with the custom manifest config "config.json" of the custom media type "application/vnd.me.config": oras push --config config.json:application/vnd.me.config localhost:5000/hello:v1 hi.txt -Example - Push file "hi.txt" and format output in JSON: +Example - [Experimental] Push file "hi.txt" and format output in JSON: oras push localhost:5000/hello:v1 hi.txt --format json -Example - Push file "hi.txt" and format output with Go template: +Example - [Experimental] Push file "hi.txt" and format output with Go template: oras push localhost:5000/hello:v1 hi.txt --format go-template="{{.digest}}" Example - Push file to the insecure registry: @@ -104,7 +104,7 @@ Example - Push repository with manifest annotations: Example - Push repository with manifest annotation file: oras push --annotation-file annotation.json localhost:5000/hello:v1 -Example - Push artifact to repository with platform: +Example - [Experimental] Push artifact to repository with platform: oras push --artifact-platform linux/arm/v5 localhost:5000/hello:v1 Example - Push file "hi.txt" with multiple tags: From a52e9742ce35d5abe544c1aabd6f183048f64eac Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Thu, 5 Dec 2024 08:10:52 +0000 Subject: [PATCH 2/2] fix attach Signed-off-by: Billy Zha --- cmd/oras/root/attach.go | 49 +++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/cmd/oras/root/attach.go b/cmd/oras/root/attach.go index 596e98ec1..90508a2f4 100644 --- a/cmd/oras/root/attach.go +++ b/cmd/oras/root/attach.go @@ -44,12 +44,13 @@ type attachOptions struct { artifactType string concurrency int + verbose bool } func attachCmd() *cobra.Command { var opts attachOptions cmd := &cobra.Command{ - Use: "attach [flags] --artifact-type= {:|@} [:] [...]", + Use: "attach [flags] --artifact-type= {:|@} {[:]|--annotation =} [...]", Short: "[Preview] Attach files to an existing artifact", Long: `[Preview] Attach files to an existing artifact @@ -93,38 +94,41 @@ Example - Attach file to the manifest tagged 'v1' in an OCI image layout folder PreRunE: func(cmd *cobra.Command, args []string) error { opts.RawReference = args[0] opts.FileRefs = args[1:] - if err := option.Parse(cmd, &opts); err != nil { - return err + err := option.Parse(cmd, &opts) + if err == nil { + if err = opts.EnsureReferenceNotEmpty(cmd, true); err == nil { + return nil + } + } + if len(opts.FileRefs) == 0 { + // no file argument provided + if err, ok := err.(*oerrors.Error); ok && err.OperationType == oerrors.OperationTypeParseArtifactReference { + // invalid reference + err.Recommendation = fmt.Sprintf("Are you missing an artifact reference to attach to? %s", err.Recommendation) + } } - return nil + return err }, RunE: func(cmd *cobra.Command, args []string) error { + opts.Printer.Verbose = opts.verbose return runAttach(cmd, &opts) }, } cmd.Flags().StringVarP(&opts.artifactType, "artifact-type", "", "", "artifact type") cmd.Flags().IntVarP(&opts.concurrency, "concurrency", "", 5, "concurrency level") + cmd.Flags().BoolVarP(&opts.verbose, "verbose", "v", false, "print status output for unnamed blobs") opts.FlagDescription = "[Preview] attach to an arch-specific subject" _ = cmd.MarkFlagRequired("artifact-type") opts.EnableDistributionSpecFlag() - opts.AllowedTypes = []*option.FormatType{option.FormatTypeJSON, option.FormatTypeGoTemplate} + opts.SetTypes(option.FormatTypeText, option.FormatTypeJSON, option.FormatTypeGoTemplate) option.ApplyFlags(&opts, cmd.Flags()) return oerrors.Command(cmd, &opts.Target) } func runAttach(cmd *cobra.Command, opts *attachOptions) error { ctx, logger := command.GetLogger(cmd, &opts.Common) - displayStatus, displayMetadata, err := display.NewAttachHandler(cmd.OutOrStdout(), opts.Format, opts.TTY, opts.Verbose) - if err != nil { - return err - } - - annotations, err := opts.LoadManifestAnnotations() - if err != nil { - return err - } - if len(opts.FileRefs) == 0 && len(annotations[option.AnnotationManifest]) == 0 { + if len(opts.FileRefs) == 0 && len(opts.Annotations[option.AnnotationManifest]) == 0 { return &oerrors.Error{ Err: errors.New(`neither file nor annotation provided in the command`), Usage: fmt.Sprintf("%s %s", cmd.Parent().CommandPath(), cmd.Use), @@ -143,9 +147,6 @@ func runAttach(cmd *cobra.Command, opts *attachOptions) error { if err != nil { return err } - if err := opts.EnsureReferenceNotEmpty(cmd, true); err != nil { - return err - } // add both pull and push scope hints for dst repository // to save potential push-scope token requests during copy ctx = registryutil.WithScopeHint(ctx, dst, auth.ActionPull, auth.ActionPush) @@ -155,7 +156,11 @@ func runAttach(cmd *cobra.Command, opts *attachOptions) error { if err != nil { return fmt.Errorf("failed to resolve %s: %w", opts.Reference, err) } - descs, err := loadFiles(ctx, store, annotations, opts.FileRefs, displayStatus) + displayStatus, displayMetadata, err := display.NewAttachHandler(opts.Printer, opts.Format, opts.TTY, store) + if err != nil { + return err + } + descs, err := loadFiles(ctx, store, opts.Annotations, opts.FileRefs, displayStatus) if err != nil { return err } @@ -167,11 +172,13 @@ func runAttach(cmd *cobra.Command, opts *attachOptions) error { } graphCopyOptions := oras.DefaultCopyGraphOptions graphCopyOptions.Concurrency = opts.concurrency - displayStatus.UpdateCopyOptions(&graphCopyOptions, store) + graphCopyOptions.OnCopySkipped = displayStatus.OnCopySkipped + graphCopyOptions.PreCopy = displayStatus.PreCopy + graphCopyOptions.PostCopy = displayStatus.PostCopy packOpts := oras.PackManifestOptions{ Subject: &subject, - ManifestAnnotations: annotations[option.AnnotationManifest], + ManifestAnnotations: opts.Annotations[option.AnnotationManifest], Layers: descs, } pack := func() (ocispec.Descriptor, error) {