diff --git a/cmd/oras/internal/command/logger.go b/cmd/oras/internal/command/logger.go index 5492ea3d8..1d5c54e2c 100644 --- a/cmd/oras/internal/command/logger.go +++ b/cmd/oras/internal/command/logger.go @@ -26,7 +26,7 @@ import ( // GetLogger returns a new FieldLogger and an associated Context derived from command context. func GetLogger(cmd *cobra.Command, opts *option.Common) (context.Context, logrus.FieldLogger) { - ctx, logger := trace.NewLogger(cmd.Context(), opts.Debug, opts.Verbose) + ctx, logger := trace.NewLogger(cmd.Context(), opts.Debug) cmd.SetContext(ctx) return ctx, logger } diff --git a/cmd/oras/internal/display/handler_test.go b/cmd/oras/internal/display/handler_test.go index f1016e6f0..e02d1cfca 100644 --- a/cmd/oras/internal/display/handler_test.go +++ b/cmd/oras/internal/display/handler_test.go @@ -16,17 +16,18 @@ limitations under the License. package display import ( - "oras.land/oras/internal/testutils" "os" "testing" + "oras.land/oras/internal/testutils" + "oras.land/oras/cmd/oras/internal/option" "oras.land/oras/cmd/oras/internal/output" ) func TestNewPushHandler(t *testing.T) { mockFetcher := testutils.NewMockFetcher() - printer := output.NewPrinter(os.Stdout, os.Stderr, false) + printer := output.NewPrinter(os.Stdout, os.Stderr) _, _, err := NewPushHandler(printer, option.Format{Type: option.FormatTypeText.Name}, os.Stdout, mockFetcher.Fetcher) if err != nil { t.Errorf("NewPushHandler() error = %v, want nil", err) @@ -35,7 +36,7 @@ func TestNewPushHandler(t *testing.T) { func TestNewAttachHandler(t *testing.T) { mockFetcher := testutils.NewMockFetcher() - printer := output.NewPrinter(os.Stdout, os.Stderr, false) + printer := output.NewPrinter(os.Stdout, os.Stderr) _, _, err := NewAttachHandler(printer, option.Format{Type: option.FormatTypeText.Name}, os.Stdout, mockFetcher.Fetcher) if err != nil { t.Errorf("NewAttachHandler() error = %v, want nil", err) @@ -43,7 +44,7 @@ func TestNewAttachHandler(t *testing.T) { } func TestNewPullHandler(t *testing.T) { - printer := output.NewPrinter(os.Stdout, os.Stderr, false) + printer := output.NewPrinter(os.Stdout, os.Stderr) _, _, err := NewPullHandler(printer, option.Format{Type: option.FormatTypeText.Name}, "", os.Stdout) if err != nil { t.Errorf("NewPullHandler() error = %v, want nil", err) diff --git a/cmd/oras/internal/display/metadata/text/push_test.go b/cmd/oras/internal/display/metadata/text/push_test.go index c72a0a3e5..960de4134 100644 --- a/cmd/oras/internal/display/metadata/text/push_test.go +++ b/cmd/oras/internal/display/metadata/text/push_test.go @@ -65,7 +65,7 @@ func TestPushHandler_OnCompleted(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - printer := output.NewPrinter(tt.out, os.Stderr, false) + printer := output.NewPrinter(tt.out, os.Stderr) p := &PushHandler{ printer: printer, } diff --git a/cmd/oras/internal/display/status/text_test.go b/cmd/oras/internal/display/status/text_test.go index 223bc69da..85d354771 100644 --- a/cmd/oras/internal/display/status/text_test.go +++ b/cmd/oras/internal/display/status/text_test.go @@ -39,7 +39,7 @@ func TestMain(m *testing.M) { mockFetcher = testutils.NewMockFetcher() ctx = context.Background() builder = &strings.Builder{} - printer = output.NewPrinter(builder, os.Stderr, false) + printer = output.NewPrinter(builder, os.Stderr) bogus = ocispec.Descriptor{MediaType: ocispec.MediaTypeImageManifest} os.Exit(m.Run()) } @@ -204,14 +204,14 @@ func TestTextManifestIndexUpdateHandler_OnManifestAdded(t *testing.T) { }{ { name: "ref is a digest", - printer: output.NewPrinter(os.Stdout, os.Stderr, false), + printer: output.NewPrinter(os.Stdout, os.Stderr), ref: "sha256:fd6ed2f36b5465244d5dc86cb4e7df0ab8a9d24adc57825099f522fe009a22bb", desc: ocispec.Descriptor{MediaType: "test", Digest: "sha256:fd6ed2f36b5465244d5dc86cb4e7df0ab8a9d24adc57825099f522fe009a22bb", Size: 25}, wantErr: false, }, { name: "ref is not a digest", - printer: output.NewPrinter(os.Stdout, os.Stderr, false), + printer: output.NewPrinter(os.Stdout, os.Stderr), ref: "v1", desc: ocispec.Descriptor{MediaType: "test", Digest: "sha256:fd6ed2f36b5465244d5dc86cb4e7df0ab8a9d24adc57825099f522fe009a22bb", Size: 25}, wantErr: false, @@ -239,14 +239,14 @@ func TestTextManifestIndexUpdateHandler_OnIndexMerged(t *testing.T) { }{ { name: "ref is a digest", - printer: output.NewPrinter(os.Stdout, os.Stderr, false), + printer: output.NewPrinter(os.Stdout, os.Stderr), ref: "sha256:fd6ed2f36b5465244d5dc86cb4e7df0ab8a9d24adc57825099f522fe009a22bb", desc: ocispec.Descriptor{MediaType: "test", Digest: "sha256:fd6ed2f36b5465244d5dc86cb4e7df0ab8a9d24adc57825099f522fe009a22bb", Size: 25}, wantErr: false, }, { name: "ref is not a digest", - printer: output.NewPrinter(os.Stdout, os.Stderr, false), + printer: output.NewPrinter(os.Stdout, os.Stderr), ref: "v1", desc: ocispec.Descriptor{MediaType: "test", Digest: "sha256:fd6ed2f36b5465244d5dc86cb4e7df0ab8a9d24adc57825099f522fe009a22bb", Size: 25}, wantErr: false, diff --git a/cmd/oras/internal/option/common.go b/cmd/oras/internal/option/common.go index 3fa6cefde..5713dd7b8 100644 --- a/cmd/oras/internal/option/common.go +++ b/cmd/oras/internal/option/common.go @@ -28,23 +28,22 @@ const NoTTYFlag = "no-tty" // Common option struct. type Common struct { - Debug bool - Verbose bool + Printer *output.Printer TTY *os.File - *output.Printer + Debug bool + noTTY bool } // ApplyFlags applies flags to a command flag set. func (opts *Common) ApplyFlags(fs *pflag.FlagSet) { fs.BoolVarP(&opts.Debug, "debug", "d", false, "output debug logs (implies --no-tty)") - fs.BoolVarP(&opts.Verbose, "verbose", "v", false, "verbose output") fs.BoolVarP(&opts.noTTY, NoTTYFlag, "", false, "[Preview] do not show progress output") } // Parse gets target options from user input. func (opts *Common) Parse(cmd *cobra.Command) error { - opts.Printer = output.NewPrinter(cmd.OutOrStdout(), cmd.OutOrStderr(), opts.Verbose) + opts.Printer = output.NewPrinter(cmd.OutOrStdout(), cmd.OutOrStderr()) // use STDERR as TTY output since STDOUT is reserved for pipeable output return opts.parseTTY(os.Stderr) } diff --git a/cmd/oras/internal/output/print.go b/cmd/oras/internal/output/print.go index d7e486866..bdc4e8c1f 100644 --- a/cmd/oras/internal/output/print.go +++ b/cmd/oras/internal/output/print.go @@ -27,15 +27,16 @@ import ( // Printer prints for status handlers. type Printer struct { - out io.Writer - err io.Writer - verbose bool - lock sync.Mutex + Verbose bool + + out io.Writer + err io.Writer + lock sync.Mutex } // NewPrinter creates a new Printer. -func NewPrinter(out io.Writer, err io.Writer, verbose bool) *Printer { - return &Printer{out: out, err: err, verbose: verbose} +func NewPrinter(out io.Writer, err io.Writer) *Printer { + return &Printer{out: out, err: err} } // Write implements the io.Writer interface. @@ -73,7 +74,7 @@ func (p *Printer) Printf(format string, a ...any) error { // PrintVerbose prints when verbose is true. func (p *Printer) PrintVerbose(a ...any) error { - if !p.verbose { + if !p.Verbose { return nil } return p.Println(a...) diff --git a/cmd/oras/internal/output/print_test.go b/cmd/oras/internal/output/print_test.go index 24ff6eb85..38466f20e 100644 --- a/cmd/oras/internal/output/print_test.go +++ b/cmd/oras/internal/output/print_test.go @@ -43,7 +43,7 @@ func (mw *mockWriter) String() string { func TestPrinter_Println(t *testing.T) { mockWriter := &mockWriter{} - printer := NewPrinter(mockWriter, os.Stderr, false) + printer := NewPrinter(mockWriter, os.Stderr) err := printer.Println("boom") if mockWriter.errorCount != 1 { t.Error("Expected one error actual <" + strconv.Itoa(mockWriter.errorCount) + ">") @@ -62,7 +62,7 @@ func TestPrinter_Println(t *testing.T) { func TestPrinter_PrintVerbose_noError(t *testing.T) { builder := &strings.Builder{} - printer := NewPrinter(builder, os.Stderr, false) + printer := NewPrinter(builder, os.Stderr) expected := "normal\nthing one\n" err := printer.Println("normal") @@ -85,7 +85,8 @@ func TestPrinter_PrintVerbose_noError(t *testing.T) { func TestPrinter_PrintVerbose(t *testing.T) { builder := &strings.Builder{} - printer := NewPrinter(builder, os.Stderr, true) + printer := NewPrinter(builder, os.Stderr) + printer.Verbose = true expected := "normal\nverbose\n" err := printer.Println("normal") diff --git a/cmd/oras/root/attach.go b/cmd/oras/root/attach.go index 1531927d5..d6eb6f788 100644 --- a/cmd/oras/root/attach.go +++ b/cmd/oras/root/attach.go @@ -44,6 +44,7 @@ type attachOptions struct { artifactType string concurrency int + verbose bool } func attachCmd() *cobra.Command { @@ -109,12 +110,14 @@ Example - Attach file to the manifest tagged 'v1' in an OCI image layout folder 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() diff --git a/cmd/oras/root/blob/delete.go b/cmd/oras/root/blob/delete.go index 69d75a45a..f17debd8d 100644 --- a/cmd/oras/root/blob/delete.go +++ b/cmd/oras/root/blob/delete.go @@ -89,7 +89,7 @@ func deleteBlob(cmd *cobra.Command, opts *deleteBlobOptions) (err error) { if errors.Is(err, errdef.ErrNotFound) { if opts.Force && !opts.OutputDescriptor { // ignore nonexistent - _ = opts.Println("Missing", opts.RawReference) + _ = opts.Printer.Println("Missing", opts.RawReference) return nil } return fmt.Errorf("%s: the specified blob does not exist", opts.RawReference) @@ -118,7 +118,7 @@ func deleteBlob(cmd *cobra.Command, opts *deleteBlobOptions) (err error) { return opts.Output(os.Stdout, descJSON) } - _ = opts.Println("Deleted", opts.AnnotatedReference()) + _ = opts.Printer.Println("Deleted", opts.AnnotatedReference()) return nil } diff --git a/cmd/oras/root/blob/push.go b/cmd/oras/root/blob/push.go index 6bb126357..9dbc80b34 100644 --- a/cmd/oras/root/blob/push.go +++ b/cmd/oras/root/blob/push.go @@ -42,6 +42,7 @@ type pushBlobOptions struct { fileRef string mediaType string size int64 + verbose bool } func pushCmd() *cobra.Command { @@ -87,16 +88,17 @@ Example - Push blob 'hi.txt' into an OCI image layout folder 'layout-dir': return errors.New("`--size` must be provided if the blob is read from stdin") } } - opts.Verbose = opts.Verbose && !opts.OutputDescriptor return option.Parse(cmd, &opts) }, RunE: func(cmd *cobra.Command, args []string) error { + opts.Printer.Verbose = opts.verbose && !opts.OutputDescriptor return pushBlob(cmd, &opts) }, } cmd.Flags().Int64VarP(&opts.size, "size", "", -1, "provide the blob size") cmd.Flags().StringVarP(&opts.mediaType, "media-type", "", ocispec.MediaTypeImageLayer, "specify the returned media type in the descriptor if --descriptor is used") + cmd.Flags().BoolVarP(&opts.verbose, "verbose", "v", false, "print status output for unnamed blobs") option.ApplyFlags(&opts, cmd.Flags()) return oerrors.Command(cmd, &opts.Target) } @@ -121,7 +123,7 @@ func pushBlob(cmd *cobra.Command, opts *pushBlobOptions) (err error) { return err } if exists { - err = opts.PrintStatus(desc, "Exists") + err = opts.Printer.PrintStatus(desc, "Exists") } else { err = opts.doPush(ctx, opts.Printer, target, desc, rc) } @@ -137,8 +139,8 @@ func pushBlob(cmd *cobra.Command, opts *pushBlobOptions) (err error) { return opts.Output(os.Stdout, descJSON) } - _ = opts.Println("Pushed", opts.AnnotatedReference()) - _ = opts.Println("Digest:", desc.Digest) + _ = opts.Printer.Println("Pushed", opts.AnnotatedReference()) + _ = opts.Printer.Println("Digest:", desc.Digest) return nil } diff --git a/cmd/oras/root/blob/push_test.go b/cmd/oras/root/blob/push_test.go index 154f3ae61..358fe966b 100644 --- a/cmd/oras/root/blob/push_test.go +++ b/cmd/oras/root/blob/push_test.go @@ -20,10 +20,11 @@ package blob import ( "bytes" "context" - "oras.land/oras/cmd/oras/internal/output" "os" "testing" + "oras.land/oras/cmd/oras/internal/output" + "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "oras.land/oras-go/v2/content/memory" @@ -40,7 +41,7 @@ func Test_pushBlobOptions_doPush(t *testing.T) { src := memory.New() content := []byte("test") r := bytes.NewReader(content) - printer := output.NewPrinter(os.Stdout, os.Stderr, false) + printer := output.NewPrinter(os.Stdout, os.Stderr) desc := ocispec.Descriptor{ MediaType: "application/octet-stream", Digest: digest.FromBytes(content), diff --git a/cmd/oras/root/cp.go b/cmd/oras/root/cp.go index 8cf5ac250..931613891 100644 --- a/cmd/oras/root/cp.go +++ b/cmd/oras/root/cp.go @@ -53,6 +53,7 @@ type copyOptions struct { recursive bool concurrency int extraRefs []string + verbose bool } func copyCmd() *cobra.Command { @@ -100,11 +101,13 @@ Example - Copy an artifact with multiple tags with concurrency tuned: return option.Parse(cmd, &opts) }, RunE: func(cmd *cobra.Command, args []string) error { + opts.Printer.Verbose = opts.verbose return runCopy(cmd, &opts) }, } cmd.Flags().BoolVarP(&opts.recursive, "recursive", "r", false, "[Preview] recursively copy the artifact and its referrer artifacts") cmd.Flags().IntVarP(&opts.concurrency, "concurrency", "", 3, "concurrency level") + cmd.Flags().BoolVarP(&opts.verbose, "verbose", "v", false, "print status output for unnamed blobs") opts.EnableDistributionSpecFlag() option.ApplyFlags(&opts, cmd.Flags()) return oerrors.Command(cmd, &opts.BinaryTarget) @@ -139,7 +142,7 @@ func runCopy(cmd *cobra.Command, opts *copyOptions) error { // correct source digest opts.From.RawReference = fmt.Sprintf("%s@%s", opts.From.Path, desc.Digest.String()) } - _ = opts.Println("Copied", opts.From.AnnotatedReference(), "=>", opts.To.AnnotatedReference()) + _ = opts.Printer.Println("Copied", opts.From.AnnotatedReference(), "=>", opts.To.AnnotatedReference()) if len(opts.extraRefs) != 0 { tagNOpts := oras.DefaultTagNOptions @@ -150,7 +153,7 @@ func runCopy(cmd *cobra.Command, opts *copyOptions) error { } } - _ = opts.Println("Digest:", desc.Digest) + _ = opts.Printer.Println("Digest:", desc.Digest) return nil } diff --git a/cmd/oras/root/cp_test.go b/cmd/oras/root/cp_test.go index c02ef5ea1..f625f5669 100644 --- a/cmd/oras/root/cp_test.go +++ b/cmd/oras/root/cp_test.go @@ -24,12 +24,13 @@ import ( "net/http" "net/http/httptest" "net/url" - "oras.land/oras/cmd/oras/internal/display/status" - "oras.land/oras/cmd/oras/internal/output" "os" "strings" "testing" + "oras.land/oras/cmd/oras/internal/display/status" + "oras.land/oras/cmd/oras/internal/output" + "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "oras.land/oras-go/v2/content/memory" @@ -129,11 +130,11 @@ func Test_doCopy(t *testing.T) { defer slave.Close() var opts copyOptions opts.TTY = slave - opts.Verbose = true opts.From.Reference = memDesc.Digest.String() dst := memory.New() builder := &strings.Builder{} - printer := output.NewPrinter(builder, os.Stderr, opts.Verbose) + printer := output.NewPrinter(builder, os.Stderr) + printer.Verbose = true handler := status.NewTextCopyHandler(printer, dst) // test _, err = doCopy(context.Background(), handler, memStore, dst, &opts) @@ -155,10 +156,10 @@ func Test_doCopy_skipped(t *testing.T) { defer slave.Close() var opts copyOptions opts.TTY = slave - opts.Verbose = true opts.From.Reference = memDesc.Digest.String() builder := &strings.Builder{} - printer := output.NewPrinter(builder, os.Stderr, opts.Verbose) + printer := output.NewPrinter(builder, os.Stderr) + printer.Verbose = true handler := status.NewTextCopyHandler(printer, memStore) // test @@ -181,7 +182,6 @@ func Test_doCopy_mounted(t *testing.T) { defer slave.Close() var opts copyOptions opts.TTY = slave - opts.Verbose = true opts.From.Reference = manifestDigest // mocked repositories from, err := remote.NewRepository(fmt.Sprintf("%s/%s", host, repoFrom)) @@ -195,7 +195,8 @@ func Test_doCopy_mounted(t *testing.T) { } to.PlainHTTP = true builder := &strings.Builder{} - printer := output.NewPrinter(builder, os.Stderr, opts.Verbose) + printer := output.NewPrinter(builder, os.Stderr) + printer.Verbose = true handler := status.NewTextCopyHandler(printer, to) // test diff --git a/cmd/oras/root/discover.go b/cmd/oras/root/discover.go index 34d3bccb0..afdd0da46 100644 --- a/cmd/oras/root/discover.go +++ b/cmd/oras/root/discover.go @@ -40,6 +40,7 @@ type discoverOptions struct { option.Format artifactType string + verbose bool } func discoverCmd() *cobra.Command { @@ -101,6 +102,7 @@ Example - Discover referrers of the manifest tagged 'v1' in an OCI image layout cmd.Flags().StringVarP(&opts.artifactType, "artifact-type", "", "", "artifact type") cmd.Flags().StringVarP(&opts.Format.FormatFlag, "output", "o", "tree", "[Deprecated] format in which to display referrers (table, json, or tree). tree format will also show indirect referrers") + cmd.Flags().BoolVarP(&opts.verbose, "verbose", "v", false, "display full metadata of referrers") opts.SetTypes( option.FormatTypeTree, option.FormatTypeTable, @@ -130,7 +132,7 @@ func runDiscover(cmd *cobra.Command, opts *discoverOptions) error { return err } - handler, err := display.NewDiscoverHandler(opts.Printer, opts.Format, opts.Path, opts.RawReference, desc, opts.Verbose) + handler, err := display.NewDiscoverHandler(opts.Printer, opts.Format, opts.Path, opts.RawReference, desc, opts.verbose) if err != nil { return err } diff --git a/cmd/oras/root/login.go b/cmd/oras/root/login.go index 340c52b9e..52f8a1c12 100644 --- a/cmd/oras/root/login.go +++ b/cmd/oras/root/login.go @@ -118,7 +118,7 @@ func runLogin(cmd *cobra.Command, opts loginOptions) (err error) { if err = credentials.Login(ctx, store, remote, opts.Credential()); err != nil { return err } - _ = opts.Println("Login Succeeded") + _ = opts.Printer.Println("Login Succeeded") return nil } diff --git a/cmd/oras/root/manifest/delete.go b/cmd/oras/root/manifest/delete.go index 12bcf7aad..085ec62f6 100644 --- a/cmd/oras/root/manifest/delete.go +++ b/cmd/oras/root/manifest/delete.go @@ -98,7 +98,7 @@ func deleteManifest(cmd *cobra.Command, opts *deleteOptions) error { if errors.Is(err, errdef.ErrNotFound) { if opts.Force && !opts.OutputDescriptor { // ignore nonexistent - _ = opts.Println("Missing", opts.RawReference) + _ = opts.Printer.Println("Missing", opts.RawReference) return nil } return fmt.Errorf("%s: the specified manifest does not exist", opts.RawReference) @@ -127,7 +127,7 @@ func deleteManifest(cmd *cobra.Command, opts *deleteOptions) error { return opts.Output(os.Stdout, descJSON) } - _ = opts.Println("Deleted", opts.AnnotatedReference()) + _ = opts.Printer.Println("Deleted", opts.AnnotatedReference()) return nil } diff --git a/cmd/oras/root/manifest/index/update.go b/cmd/oras/root/manifest/index/update.go index e82204519..ab24f0a39 100644 --- a/cmd/oras/root/manifest/index/update.go +++ b/cmd/oras/root/manifest/index/update.go @@ -102,7 +102,7 @@ Example - Update an index and output the index to stdout, auto push will be disa func updateIndex(cmd *cobra.Command, opts updateOptions) error { // if no update flag is used, do nothing if !updateFlagsUsed(cmd.Flags()) { - opts.Println("Nothing to update as no change is requested") + opts.Printer.Println("Nothing to update as no change is requested") return nil } ctx, logger := command.GetLogger(cmd, &opts.Common) diff --git a/cmd/oras/root/manifest/push.go b/cmd/oras/root/manifest/push.go index 78f61ece8..2de0d5348 100644 --- a/cmd/oras/root/manifest/push.go +++ b/cmd/oras/root/manifest/push.go @@ -48,6 +48,7 @@ type pushOptions struct { extraRefs []string fileRef string mediaType string + verbose bool } func pushCmd() *cobra.Command { @@ -96,10 +97,10 @@ Example - Push a manifest to an OCI image layout folder 'layout-dir' and tag wit refs := strings.Split(args[0], ",") opts.RawReference = refs[0] opts.extraRefs = refs[1:] - opts.Verbose = opts.Verbose && !opts.OutputDescriptor return option.Parse(cmd, &opts) }, RunE: func(cmd *cobra.Command, args []string) error { + opts.Printer.Verbose = opts.verbose && !opts.OutputDescriptor return pushManifest(cmd, opts) }, } @@ -108,6 +109,7 @@ Example - Push a manifest to an OCI image layout folder 'layout-dir' and tag wit option.ApplyFlags(&opts, cmd.Flags()) cmd.Flags().StringVarP(&opts.mediaType, "media-type", "", "", "media type of manifest") cmd.Flags().IntVarP(&opts.concurrency, "concurrency", "", 5, "concurrency level") + cmd.Flags().BoolVarP(&opts.verbose, "verbose", "v", false, "print status output for unnamed blobs") return oerrors.Command(cmd, &opts.Target) } @@ -157,17 +159,17 @@ func pushManifest(cmd *cobra.Command, opts pushOptions) error { return err } if match { - if err := opts.PrintStatus(desc, "Exists"); err != nil { + if err := opts.Printer.PrintStatus(desc, "Exists"); err != nil { return err } } else { - if err = opts.PrintStatus(desc, "Uploading"); err != nil { + if err = opts.Printer.PrintStatus(desc, "Uploading"); err != nil { return err } if _, err := oras.TagBytes(ctx, target, mediaType, contentBytes, ref); err != nil { return err } - if err = opts.PrintStatus(desc, "Uploaded "); err != nil { + if err = opts.Printer.PrintStatus(desc, "Uploaded "); err != nil { return err } } @@ -188,7 +190,7 @@ func pushManifest(cmd *cobra.Command, opts pushOptions) error { } return opts.Output(os.Stdout, descJSON) } - _ = opts.Println("Pushed", opts.AnnotatedReference()) + _ = opts.Printer.Println("Pushed", opts.AnnotatedReference()) if len(opts.extraRefs) != 0 { handler := display.NewManifestPushHandler(opts.Printer) tagListener := listener.NewTaggedListener(target, handler.OnTagged) @@ -197,7 +199,7 @@ func pushManifest(cmd *cobra.Command, opts pushOptions) error { } } - _ = opts.Println("Digest:", desc.Digest) + _ = opts.Printer.Println("Digest:", desc.Digest) return nil } diff --git a/cmd/oras/root/pull.go b/cmd/oras/root/pull.go index 6ab3a3dff..d5beef3f3 100644 --- a/cmd/oras/root/pull.go +++ b/cmd/oras/root/pull.go @@ -52,6 +52,7 @@ type pullOptions struct { PathTraversal bool Output string ManifestConfigRef string + verbose bool } func pullCmd() *cobra.Command { @@ -101,6 +102,7 @@ Example - Pull artifact files from an OCI layout archive 'layout.tar': return option.Parse(cmd, &opts) }, RunE: func(cmd *cobra.Command, args []string) error { + opts.Printer.Verbose = opts.verbose return runPull(cmd, &opts) }, } @@ -111,6 +113,7 @@ Example - Pull artifact files from an OCI layout archive 'layout.tar': cmd.Flags().StringVarP(&opts.Output, "output", "o", ".", "output directory") cmd.Flags().StringVarP(&opts.ManifestConfigRef, "config", "", "", "output manifest config file") cmd.Flags().IntVarP(&opts.concurrency, "concurrency", "", 3, "concurrency level") + cmd.Flags().BoolVarP(&opts.verbose, "verbose", "v", false, "print status output for unnamed blobs") opts.SetTypes(option.FormatTypeText, option.FormatTypeJSON, option.FormatTypeGoTemplate) option.ApplyFlags(&opts, cmd.Flags()) return oerrors.Command(cmd, &opts.Target) diff --git a/cmd/oras/root/push.go b/cmd/oras/root/push.go index b5ae07e14..f34bcc0fa 100644 --- a/cmd/oras/root/push.go +++ b/cmd/oras/root/push.go @@ -52,6 +52,7 @@ type pushOptions struct { manifestConfigRef string artifactType string concurrency int + verbose bool } func pushCmd() *cobra.Command { @@ -157,12 +158,14 @@ Example - Push file "hi.txt" into an OCI image layout folder 'layout-dir' with t return nil }, RunE: func(cmd *cobra.Command, args []string) error { + opts.Printer.Verbose = opts.verbose return runPush(cmd, &opts) }, } cmd.Flags().StringVarP(&opts.manifestConfigRef, "config", "", "", "`path` of image config file") 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.SetTypes(option.FormatTypeText, option.FormatTypeJSON, option.FormatTypeGoTemplate) option.ApplyFlags(&opts, cmd.Flags()) return oerrors.Command(cmd, &opts.Target) diff --git a/cmd/oras/root/repo/ls.go b/cmd/oras/root/repo/ls.go index 1ee6221b3..501ee050b 100644 --- a/cmd/oras/root/repo/ls.go +++ b/cmd/oras/root/repo/ls.go @@ -80,7 +80,7 @@ func listRepository(cmd *cobra.Command, opts *repositoryOptions) error { err = reg.Repositories(ctx, opts.last, func(repos []string) error { for _, repo := range repos { if subRepo, found := strings.CutPrefix(repo, opts.namespace); found { - _ = opts.Println(subRepo) + _ = opts.Printer.Println(subRepo) } } return nil diff --git a/cmd/oras/root/repo/tags.go b/cmd/oras/root/repo/tags.go index 5986bf410..5d32ce906 100644 --- a/cmd/oras/root/repo/tags.go +++ b/cmd/oras/root/repo/tags.go @@ -105,7 +105,7 @@ func showTags(cmd *cobra.Command, opts *showTagsOptions) error { } if filter != "" { if tag == opts.Reference { - _ = opts.Println(tag) + _ = opts.Printer.Println(tag) continue } desc, err := finder.Resolve(ctx, tag) @@ -116,7 +116,7 @@ func showTags(cmd *cobra.Command, opts *showTagsOptions) error { continue } } - _ = opts.Println(tag) + _ = opts.Printer.Println(tag) } return nil }) diff --git a/cmd/oras/root/resolve.go b/cmd/oras/root/resolve.go index 649b10e5c..6ccab0f01 100644 --- a/cmd/oras/root/resolve.go +++ b/cmd/oras/root/resolve.go @@ -79,9 +79,9 @@ func runResolve(cmd *cobra.Command, opts *resolveOptions) error { } if opts.fullRef { - _ = opts.Printf("%s@%s\n", opts.Path, desc.Digest) + _ = opts.Printer.Printf("%s@%s\n", opts.Path, desc.Digest) } else { - _ = opts.Println(desc.Digest.String()) + _ = opts.Printer.Println(desc.Digest.String()) } return nil diff --git a/cmd/oras/root/version.go b/cmd/oras/root/version.go index 908f46f56..fb4f510ec 100644 --- a/cmd/oras/root/version.go +++ b/cmd/oras/root/version.go @@ -46,7 +46,7 @@ Example - print version: return nil }, RunE: func(cmd *cobra.Command, args []string) error { - printer := output.NewPrinter(cmd.OutOrStdout(), cmd.ErrOrStderr(), false) + printer := output.NewPrinter(cmd.OutOrStdout(), cmd.ErrOrStderr()) return runVersion(printer) }, } diff --git a/internal/trace/context.go b/internal/trace/context.go index d1299e6f1..d55c3812d 100644 --- a/internal/trace/context.go +++ b/internal/trace/context.go @@ -27,12 +27,10 @@ type contextKey int const loggerKey contextKey = iota // NewLogger returns a logger. -func NewLogger(ctx context.Context, debug bool, verbose bool) (context.Context, logrus.FieldLogger) { +func NewLogger(ctx context.Context, debug bool) (context.Context, logrus.FieldLogger) { var logLevel logrus.Level if debug { logLevel = logrus.DebugLevel - } else if verbose { - logLevel = logrus.InfoLevel } else { logLevel = logrus.WarnLevel } diff --git a/test/e2e/suite/command/repo.go b/test/e2e/suite/command/repo.go index 8bc924498..46f2a2f64 100644 --- a/test/e2e/suite/command/repo.go +++ b/test/e2e/suite/command/repo.go @@ -134,12 +134,12 @@ var _ = Describe("1.1 registry users:", func() { WithDescription("prepare: copy tag with different digest"). Exec() // test - viaTag := ORAS("repo", "tags", "-v", RegistryRef(ZOTHost, repo, foobar.Tag)). + viaTag := ORAS("repo", "tags", RegistryRef(ZOTHost, repo, foobar.Tag)). MatchKeyWords(tags...). MatchErrKeyWords(feature.Experimental.Mark, foobar.Digest).Exec().Out Expect(viaTag).ShouldNot(gbytes.Say(multi_arch.Tag)) - viaDigest := ORAS("repo", "tags", "-v", RegistryRef(ZOTHost, repo, foobar.Digest)). + viaDigest := ORAS("repo", "tags", RegistryRef(ZOTHost, repo, foobar.Digest)). MatchKeyWords(tags...). MatchErrKeyWords(feature.Experimental.Mark, foobar.Digest).Exec().Out Expect(viaDigest).ShouldNot(gbytes.Say(multi_arch.Tag)) @@ -189,12 +189,12 @@ var _ = Describe("OCI image layout users:", func() { tags := []string{foobar.Tag, "bax", "bay", "baz"} root := prepare(ImageRepo, foobar.Tag, tags...) // test - viaTag := ORAS("repo", "tags", "-v", LayoutRef(root, foobar.Tag), Flags.Layout). + viaTag := ORAS("repo", "tags", LayoutRef(root, foobar.Tag), Flags.Layout). WithDescription("via tag"). MatchKeyWords(tags...). MatchErrKeyWords(feature.Experimental.Mark, foobar.Digest).Exec().Out Expect(viaTag).ShouldNot(gbytes.Say(multi_arch.Tag)) - viaDigest := ORAS("repo", "tags", "-v", LayoutRef(root, foobar.Digest), Flags.Layout). + viaDigest := ORAS("repo", "tags", LayoutRef(root, foobar.Digest), Flags.Layout). WithDescription("via digest"). MatchKeyWords(tags...). MatchErrKeyWords(feature.Experimental.Mark, foobar.Digest).Exec().Out