Skip to content

Commit

Permalink
refactor: use command output in status output (#1314)
Browse files Browse the repository at this point in the history
Signed-off-by: Billy Zha <jinzha1@microsoft.com>
  • Loading branch information
qweeah authored Mar 29, 2024
1 parent 093ed14 commit bf18775
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 41 deletions.
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)
}

0 comments on commit bf18775

Please sign in to comment.