Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use command output in status output #1314

Merged
merged 12 commits into from
Mar 29, 2024
Merged
4 changes: 2 additions & 2 deletions cmd/oras/internal/display/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func NewPushHandler(format string, tty *os.File, out io.Writer, verbose bool) (s
if tty != nil {
statusHandler = status.NewTTYPushHandler(tty)
} else if format == "" {
statusHandler = status.NewTextPushHandler(verbose)
statusHandler = status.NewTextPushHandler(out, verbose)
} else {
statusHandler = status.NewDiscardHandler()
}
Expand All @@ -56,7 +56,7 @@ func NewAttachHandler(format string, tty *os.File, out io.Writer, verbose bool)
if tty != nil {
statusHandler = status.NewTTYAttachHandler(tty)
} else if format == "" {
statusHandler = status.NewTextAttachHandler(verbose)
statusHandler = status.NewTextAttachHandler(out, verbose)
} else {
statusHandler = status.NewDiscardHandler()
}
Expand Down
83 changes: 56 additions & 27 deletions cmd/oras/internal/display/status/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"context"
"fmt"
"io"
"os"
"sync"

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
Expand All @@ -27,28 +28,30 @@ import (
"oras.land/oras-go/v2/registry"
)

var printLock sync.Mutex

// PrintFunc is the function type returned by StatusPrinter.
type PrintFunc func(ocispec.Descriptor) error

// Print objects to display concurrent-safely.
func Print(a ...any) error {
printLock.Lock()
defer printLock.Unlock()
_, err := fmt.Println(a...)
return err
// Printer prints for status handlers.
type Printer struct {
out io.Writer
lock sync.Mutex
}

// StatusPrinter returns a tracking function for transfer status.
func StatusPrinter(status string, verbose bool) PrintFunc {
return func(desc ocispec.Descriptor) error {
return PrintStatus(desc, status, verbose)
}
// NewPrinter creates a new Printer.
func NewPrinter(out io.Writer) *Printer {
return &Printer{out: out}
}

// Println prints objects concurrent-safely with newline.
func (p *Printer) Println(a ...any) error {
p.lock.Lock()
defer p.lock.Unlock()
_, err := fmt.Fprintln(p.out, a...)
return err
}

// PrintStatus prints transfer status.
func PrintStatus(desc ocispec.Descriptor, status string, verbose bool) error {
func (p *Printer) PrintStatus(desc ocispec.Descriptor, status string, verbose bool) error {
name, ok := desc.Annotations[ocispec.AnnotationTitle]
if !ok {
// no status for unnamed content
Expand All @@ -57,7 +60,14 @@ func PrintStatus(desc ocispec.Descriptor, status string, verbose bool) error {
}
name = desc.MediaType
}
return Print(status, ShortDigest(desc), name)
return p.Println(status, ShortDigest(desc), name)
}

// StatusPrinter returns a tracking function for transfer status.
func (p *Printer) StatusPrinter(status string, verbose bool) PrintFunc {
return func(desc ocispec.Descriptor) error {
return p.PrintStatus(desc, status, verbose)
}
}

// PrintSuccessorStatus prints transfer status of successors.
Expand All @@ -78,18 +88,6 @@ func PrintSuccessorStatus(ctx context.Context, desc ocispec.Descriptor, fetcher
return nil
}

// NewTagStatusPrinter creates a wrapper type for printing tag status.
func NewTagStatusPrinter(target oras.Target) oras.Target {
if repo, ok := target.(registry.Repository); ok {
return &tagManifestStatusForRepo{
Repository: repo,
}
}
return &tagManifestStatusForTarget{
Target: target,
}
}

// NewTagStatusHintPrinter creates a wrapper type for printing
// tag status and hint.
func NewTagStatusHintPrinter(target oras.Target, refPrefix string) oras.Target {
Expand Down Expand Up @@ -148,3 +146,34 @@ func (p *tagManifestStatusForTarget) Tag(ctx context.Context, desc ocispec.Descr
}
return Print("Tagged", reference)
}

// NewTagStatusPrinter creates a wrapper type for printing tag status.
func NewTagStatusPrinter(target oras.Target) oras.Target {
if repo, ok := target.(registry.Repository); ok {
return &tagManifestStatusForRepo{
Repository: repo,
}
}
return &tagManifestStatusForTarget{
Target: target,
}
}

// printer is used by the code being deprecated. Related functions should be
// removed when no-longer referenced.
var printer = NewPrinter(os.Stdout)

// Print objects to display concurrent-safely.
func Print(a ...any) error {
return printer.Println(a...)
}

// StatusPrinter returns a tracking function for transfer status.
func StatusPrinter(status string, verbose bool) PrintFunc {
return printer.StatusPrinter(status, verbose)
}

// PrintStatus prints transfer status.
func PrintStatus(desc ocispec.Descriptor, status string, verbose bool) error {
return printer.PrintStatus(desc, status, verbose)
}
24 changes: 12 additions & 12 deletions cmd/oras/internal/display/status/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ package status

import (
"context"
"fmt"
"io"
"sync"

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
Expand All @@ -28,12 +28,14 @@ import (
// TextPushHandler handles text status output for push events.
type TextPushHandler struct {
verbose bool
printer *Printer
}

// NewTextPushHandler returns a new handler for push command.
func NewTextPushHandler(verbose bool) PushHandler {
func NewTextPushHandler(out io.Writer, verbose bool) PushHandler {
return &TextPushHandler{
verbose: verbose,
printer: NewPrinter(out),
}
}

Expand All @@ -42,14 +44,12 @@ func (ph *TextPushHandler) OnFileLoading(name string) error {
if !ph.verbose {
return nil
}
_, err := fmt.Println("Preparing", name)
return err
return ph.printer.Println("Preparing", name)
}

// OnEmptyArtifact is called when an empty artifact is being uploaded.
func (ph *TextPushHandler) OnEmptyArtifact() error {
_, err := fmt.Println("Uploading empty artifact")
return err
return ph.printer.Println("Uploading empty artifact")
}

// TrackTarget returns a tracked target.
Expand All @@ -68,21 +68,21 @@ func (ph *TextPushHandler) UpdateCopyOptions(opts *oras.CopyGraphOptions, fetche
committed := &sync.Map{}
opts.OnCopySkipped = func(ctx context.Context, desc ocispec.Descriptor) error {
committed.Store(desc.Digest.String(), desc.Annotations[ocispec.AnnotationTitle])
return PrintStatus(desc, promptExists, ph.verbose)
return ph.printer.PrintStatus(desc, promptExists, ph.verbose)
}
opts.PreCopy = func(ctx context.Context, desc ocispec.Descriptor) error {
return PrintStatus(desc, promptUploading, ph.verbose)
return ph.printer.PrintStatus(desc, promptUploading, ph.verbose)
}
opts.PostCopy = func(ctx context.Context, desc ocispec.Descriptor) error {
committed.Store(desc.Digest.String(), desc.Annotations[ocispec.AnnotationTitle])
if err := PrintSuccessorStatus(ctx, desc, fetcher, committed, StatusPrinter(promptSkipped, ph.verbose)); err != nil {
if err := PrintSuccessorStatus(ctx, desc, fetcher, committed, ph.printer.StatusPrinter(promptSkipped, ph.verbose)); err != nil {
return err
}
return PrintStatus(desc, promptUploaded, ph.verbose)
return ph.printer.PrintStatus(desc, promptUploaded, ph.verbose)
}
}

// NewTextAttachHandler returns a new handler for attach command.
func NewTextAttachHandler(verbose bool) AttachHandler {
return NewTextPushHandler(verbose)
func NewTextAttachHandler(out io.Writer, verbose bool) AttachHandler {
return NewTextPushHandler(out, verbose)
}
Loading