From e7ffb6597c423c4797ede129e7c7f49f467bc2f7 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Thu, 4 Jul 2024 19:21:18 +0800 Subject: [PATCH] refactor: add display handler for `cp`, `tag` and `manifest push` (#1439) Signed-off-by: Billy Zha --- cmd/oras/internal/display/handler.go | 15 +++++++ .../internal/display/metadata/interface.go | 10 +++++ .../internal/display/metadata/text/copy.go | 39 +++++++++++++++++++ .../display/metadata/text/manifest_push.go | 39 +++++++++++++++++++ .../internal/display/metadata/text/push.go | 2 +- .../internal/display/metadata/text/tag.go | 9 +++-- cmd/oras/root/cp.go | 6 +-- cmd/oras/root/manifest/push.go | 6 +-- cmd/oras/root/tag.go | 5 ++- internal/listener/tag.go | 6 +++ 10 files changed, 125 insertions(+), 12 deletions(-) create mode 100644 cmd/oras/internal/display/metadata/text/copy.go create mode 100644 cmd/oras/internal/display/metadata/text/manifest_push.go diff --git a/cmd/oras/internal/display/handler.go b/cmd/oras/internal/display/handler.go index f6f6000ec..22be8d5ad 100644 --- a/cmd/oras/internal/display/handler.go +++ b/cmd/oras/internal/display/handler.go @@ -162,3 +162,18 @@ func NewManifestFetchHandler(out io.Writer, format option.Format, outputDescript } return metadataHandler, contentHandler, nil } + +// NewTagHandler returns a tag handler. +func NewTagHandler(printer *output.Printer, target option.Target) metadata.TagHandler { + return text.NewTagHandler(printer, target) +} + +// NewManifestPushHandler returns a manifest push handler. +func NewManifestPushHandler(printer *output.Printer) metadata.ManifestPushHandler { + return text.NewManifestPushHandler(printer) +} + +// NewCopyHandler returns a copy handler. +func NewCopyHandler(printer *output.Printer) metadata.CopyHandler { + return text.NewCopyHandler(printer) +} diff --git a/cmd/oras/internal/display/metadata/interface.go b/cmd/oras/internal/display/metadata/interface.go index f56f09f07..aacc91309 100644 --- a/cmd/oras/internal/display/metadata/interface.go +++ b/cmd/oras/internal/display/metadata/interface.go @@ -72,3 +72,13 @@ type TagHandler interface { OnTagging(desc ocispec.Descriptor, tag string) error TaggedHandler } + +// ManifestPushHandler handles metadata output for manifest push events. +type ManifestPushHandler interface { + TaggedHandler +} + +// CopyHandler handles metadata output for cp events. +type CopyHandler interface { + TaggedHandler +} diff --git a/cmd/oras/internal/display/metadata/text/copy.go b/cmd/oras/internal/display/metadata/text/copy.go new file mode 100644 index 000000000..a21d5aac4 --- /dev/null +++ b/cmd/oras/internal/display/metadata/text/copy.go @@ -0,0 +1,39 @@ +/* +Copyright The ORAS Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package text + +import ( + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "oras.land/oras/cmd/oras/internal/display/metadata" + "oras.land/oras/cmd/oras/internal/output" +) + +// CopyHandler handles text metadata output for cp events. +type CopyHandler struct { + printer *output.Printer +} + +// NewCopyHandler returns a new handler for cp events. +func NewCopyHandler(printer *output.Printer) metadata.CopyHandler { + return &CopyHandler{ + printer: printer, + } +} + +// OnTagged implements metadata.TaggedHandler. +func (h *CopyHandler) OnTagged(_ ocispec.Descriptor, tag string) error { + return h.printer.Println("Tagged", tag) +} diff --git a/cmd/oras/internal/display/metadata/text/manifest_push.go b/cmd/oras/internal/display/metadata/text/manifest_push.go new file mode 100644 index 000000000..743ba7ee2 --- /dev/null +++ b/cmd/oras/internal/display/metadata/text/manifest_push.go @@ -0,0 +1,39 @@ +/* +Copyright The ORAS Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package text + +import ( + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "oras.land/oras/cmd/oras/internal/display/metadata" + "oras.land/oras/cmd/oras/internal/output" +) + +// ManifestPushHandler handles text metadata output for manifest push events. +type ManifestPushHandler struct { + printer *output.Printer +} + +// NewManifestPushHandler returns a new handler for manifest push events. +func NewManifestPushHandler(printer *output.Printer) metadata.ManifestPushHandler { + return &ManifestPushHandler{ + printer: printer, + } +} + +// OnTagged implements metadata.TaggedHandler. +func (h *ManifestPushHandler) OnTagged(_ ocispec.Descriptor, tag string) error { + return h.printer.Println("Tagged", tag) +} diff --git a/cmd/oras/internal/display/metadata/text/push.go b/cmd/oras/internal/display/metadata/text/push.go index b90852ff5..b84b510a3 100644 --- a/cmd/oras/internal/display/metadata/text/push.go +++ b/cmd/oras/internal/display/metadata/text/push.go @@ -37,7 +37,7 @@ func NewPushHandler(printer *output.Printer) metadata.PushHandler { } } -// OnTagged implements metadata.TextTagHandler. +// OnTagged implements metadata.TaggedHandler. func (h *PushHandler) OnTagged(_ ocispec.Descriptor, tag string) error { h.tagLock.Lock() defer h.tagLock.Unlock() diff --git a/cmd/oras/internal/display/metadata/text/tag.go b/cmd/oras/internal/display/metadata/text/tag.go index eb1332054..c001a70db 100644 --- a/cmd/oras/internal/display/metadata/text/tag.go +++ b/cmd/oras/internal/display/metadata/text/tag.go @@ -16,10 +16,13 @@ limitations under the License. package text import ( + "fmt" + "sync" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "oras.land/oras/cmd/oras/internal/display/metadata" + "oras.land/oras/cmd/oras/internal/option" "oras.land/oras/cmd/oras/internal/output" - "sync" ) // TagHandler handles text metadata output for tag events. @@ -30,10 +33,10 @@ type TagHandler struct { } // NewTagHandler returns a new handler for tag events. -func NewTagHandler(printer *output.Printer, refPrefix string) metadata.TagHandler { +func NewTagHandler(printer *output.Printer, target option.Target) metadata.TagHandler { return &TagHandler{ printer: printer, - refPrefix: refPrefix, + refPrefix: fmt.Sprintf("[%s] %s", target.Type, target.Path), } } diff --git a/cmd/oras/root/cp.go b/cmd/oras/root/cp.go index 963bb901d..3a9ab2ef4 100644 --- a/cmd/oras/root/cp.go +++ b/cmd/oras/root/cp.go @@ -33,7 +33,7 @@ import ( "oras.land/oras-go/v2/registry/remote/auth" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" - "oras.land/oras/cmd/oras/internal/display/metadata/text" + "oras.land/oras/cmd/oras/internal/display" "oras.land/oras/cmd/oras/internal/display/status/track" oerrors "oras.land/oras/cmd/oras/internal/errors" "oras.land/oras/cmd/oras/internal/option" @@ -142,8 +142,8 @@ func runCopy(cmd *cobra.Command, opts *copyOptions) error { if len(opts.extraRefs) != 0 { tagNOpts := oras.DefaultTagNOptions tagNOpts.Concurrency = opts.concurrency - tagHandler := text.NewTagHandler(opts.Printer, "") - tagListener := listener.NewTagListener(dst, nil, tagHandler.OnTagged) + handler := display.NewCopyHandler(opts.Printer) + tagListener := listener.NewTaggedListener(dst, handler.OnTagged) if _, err = oras.TagN(ctx, tagListener, opts.To.Reference, opts.extraRefs, tagNOpts); err != nil { return err } diff --git a/cmd/oras/root/manifest/push.go b/cmd/oras/root/manifest/push.go index 93e3ae8f6..78f61ece8 100644 --- a/cmd/oras/root/manifest/push.go +++ b/cmd/oras/root/manifest/push.go @@ -30,7 +30,7 @@ import ( "oras.land/oras-go/v2/registry/remote" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" - "oras.land/oras/cmd/oras/internal/display/metadata/text" + "oras.land/oras/cmd/oras/internal/display" oerrors "oras.land/oras/cmd/oras/internal/errors" "oras.land/oras/cmd/oras/internal/manifest" "oras.land/oras/cmd/oras/internal/option" @@ -190,8 +190,8 @@ func pushManifest(cmd *cobra.Command, opts pushOptions) error { } _ = opts.Println("Pushed", opts.AnnotatedReference()) if len(opts.extraRefs) != 0 { - tagHandler := text.NewTagHandler(opts.Printer, "") - tagListener := listener.NewTagListener(target, nil, tagHandler.OnTagged) + handler := display.NewManifestPushHandler(opts.Printer) + tagListener := listener.NewTaggedListener(target, handler.OnTagged) if _, err = oras.TagBytesN(ctx, tagListener, mediaType, contentBytes, opts.extraRefs, tagBytesNOpts); err != nil { return err } diff --git a/cmd/oras/root/tag.go b/cmd/oras/root/tag.go index 031ea0546..556214411 100644 --- a/cmd/oras/root/tag.go +++ b/cmd/oras/root/tag.go @@ -18,7 +18,8 @@ package root import ( "errors" "fmt" - "oras.land/oras/cmd/oras/internal/display/metadata/text" + + "oras.land/oras/cmd/oras/internal/display" "oras.land/oras/internal/listener" "github.com/spf13/cobra" @@ -115,7 +116,7 @@ func tagManifest(cmd *cobra.Command, opts *tagOptions) error { tagNOpts := oras.DefaultTagNOptions tagNOpts.Concurrency = opts.concurrency - tagHandler := text.NewTagHandler(opts.Printer, fmt.Sprintf("[%s] %s", opts.Type, opts.Path)) + tagHandler := display.NewTagHandler(opts.Printer, opts.Target) tagListener := listener.NewTagListener(target, tagHandler.OnTagging, tagHandler.OnTagged) _, err = oras.TagN( ctx, diff --git a/internal/listener/tag.go b/internal/listener/tag.go index 6de571745..e7a17f658 100644 --- a/internal/listener/tag.go +++ b/internal/listener/tag.go @@ -41,6 +41,12 @@ func NewTagListener(target oras.Target, onTagging, onTagged func(desc ocispec.De } } +// NewTaggedListener creates a wrapper type for printing all tagged statuses. +// It can only be used for oras.TagBytes and oras.TagBytesN. +func NewTaggedListener(target oras.Target, onTagged func(desc ocispec.Descriptor, tag string) error) oras.Target { + return NewTagListener(target, nil, onTagged) +} + type tagListenerForRepository struct { registry.Repository onTagging func(desc ocispec.Descriptor, tag string) error