Skip to content

Commit

Permalink
refactor: Create text copy handler (#1441)
Browse files Browse the repository at this point in the history
Signed-off-by: Terry Howe <[email protected]>
  • Loading branch information
Terry Howe authored Jul 23, 2024
1 parent 7a88524 commit 5067a9a
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 28 deletions.
7 changes: 4 additions & 3 deletions cmd/oras/internal/display/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"os"

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
fetcher "oras.land/oras-go/v2/content"

"oras.land/oras/cmd/oras/internal/display/content"
"oras.land/oras/cmd/oras/internal/display/metadata"
Expand Down Expand Up @@ -173,7 +174,7 @@ func NewManifestPushHandler(printer *output.Printer) metadata.ManifestPushHandle
return text.NewManifestPushHandler(printer)
}

// NewCopyHandler returns a copy handler.
func NewCopyHandler(printer *output.Printer) metadata.CopyHandler {
return text.NewCopyHandler(printer)
// NewCopyHandler returns copy handlers.
func NewCopyHandler(printer *output.Printer, fetcher fetcher.Fetcher) (status.CopyHandler, metadata.CopyHandler) {
return status.NewTextCopyHandler(printer, fetcher), text.NewCopyHandler(printer)
}
9 changes: 9 additions & 0 deletions cmd/oras/internal/display/status/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.
package status

import (
"context"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"oras.land/oras-go/v2"
"oras.land/oras-go/v2/content"
Expand Down Expand Up @@ -51,3 +52,11 @@ type PullHandler interface {
// OnNodeSkipped is called when a node is skipped.
OnNodeSkipped(desc ocispec.Descriptor) error
}

// CopyHandler handles status output for cp command.
type CopyHandler interface {
OnCopySkipped(ctx context.Context, desc ocispec.Descriptor) error
PreCopy(ctx context.Context, desc ocispec.Descriptor) error
PostCopy(ctx context.Context, desc ocispec.Descriptor) error
OnMounted(ctx context.Context, desc ocispec.Descriptor) error
}
42 changes: 42 additions & 0 deletions cmd/oras/internal/display/status/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,45 @@ func NewTextPullHandler(printer *output.Printer) PullHandler {
printer: printer,
}
}

// TextCopyHandler handles text status output for push events.
type TextCopyHandler struct {
printer *output.Printer
committed *sync.Map
fetcher content.Fetcher
}

// NewTextCopyHandler returns a new handler for push command.
func NewTextCopyHandler(printer *output.Printer, fetcher content.Fetcher) CopyHandler {
return &TextCopyHandler{
printer: printer,
fetcher: fetcher,
committed: &sync.Map{},
}
}

// OnCopySkipped is called when an object already exists.
func (ch *TextCopyHandler) OnCopySkipped(_ context.Context, desc ocispec.Descriptor) error {
ch.committed.Store(desc.Digest.String(), desc.Annotations[ocispec.AnnotationTitle])
return ch.printer.PrintStatus(desc, copyPromptExists)
}

// PreCopy implements PreCopy of CopyHandler.
func (ch *TextCopyHandler) PreCopy(_ context.Context, desc ocispec.Descriptor) error {
return ch.printer.PrintStatus(desc, copyPromptCopying)
}

// PostCopy implements PostCopy of CopyHandler.
func (ch *TextCopyHandler) PostCopy(ctx context.Context, desc ocispec.Descriptor) error {
ch.committed.Store(desc.Digest.String(), desc.Annotations[ocispec.AnnotationTitle])
if err := output.PrintSuccessorStatus(ctx, desc, ch.fetcher, ch.committed, ch.printer.StatusPrinter(copyPromptSkipped)); err != nil {
return err
}
return ch.printer.PrintStatus(desc, copyPromptCopied)
}

// OnMounted implements OnMounted of CopyHandler.
func (ch *TextCopyHandler) OnMounted(_ context.Context, desc ocispec.Descriptor) error {
ch.committed.Store(desc.Digest.String(), desc.Annotations[ocispec.AnnotationTitle])
return ch.printer.PrintStatus(desc, copyPromptMounted)
}
9 changes: 9 additions & 0 deletions cmd/oras/internal/display/status/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,12 @@ const (
PushPromptSkipped = "Skipped "
PushPromptExists = "Exists "
)

// Prompts for cp events.
const (
copyPromptExists = "Exists "
copyPromptCopying = "Copying"
copyPromptCopied = "Copied "
copyPromptSkipped = "Skipped"
copyPromptMounted = "Mounted"
)
31 changes: 9 additions & 22 deletions cmd/oras/root/cp.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"context"
"encoding/json"
"fmt"
"oras.land/oras/cmd/oras/internal/display/status"
"slices"
"strings"
"sync"
Expand Down Expand Up @@ -127,8 +128,9 @@ func runCopy(cmd *cobra.Command, opts *copyOptions) error {
return err
}
ctx = registryutil.WithScopeHint(ctx, dst, auth.ActionPull, auth.ActionPush)
copyHandler, handler := display.NewCopyHandler(opts.Printer, dst)

desc, err := doCopy(ctx, opts.Printer, src, dst, opts)
desc, err := doCopy(ctx, copyHandler, src, dst, opts)
if err != nil {
return err
}
Expand All @@ -142,7 +144,6 @@ func runCopy(cmd *cobra.Command, opts *copyOptions) error {
if len(opts.extraRefs) != 0 {
tagNOpts := oras.DefaultTagNOptions
tagNOpts.Concurrency = opts.concurrency
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
Expand All @@ -154,7 +155,7 @@ func runCopy(cmd *cobra.Command, opts *copyOptions) error {
return nil
}

func doCopy(ctx context.Context, printer *output.Printer, src oras.ReadOnlyGraphTarget, dst oras.GraphTarget, opts *copyOptions) (ocispec.Descriptor, error) {
func doCopy(ctx context.Context, copyHandler status.CopyHandler, src oras.ReadOnlyGraphTarget, dst oras.GraphTarget, opts *copyOptions) (ocispec.Descriptor, error) {
// Prepare copy options
committed := &sync.Map{}
extendedCopyOptions := oras.DefaultExtendedCopyOptions
Expand All @@ -178,25 +179,11 @@ func doCopy(ctx context.Context, printer *output.Printer, src oras.ReadOnlyGraph
}
}
if opts.TTY == nil {
// none TTY output
extendedCopyOptions.OnCopySkipped = func(ctx context.Context, desc ocispec.Descriptor) error {
committed.Store(desc.Digest.String(), desc.Annotations[ocispec.AnnotationTitle])
return printer.PrintStatus(desc, promptExists)
}
extendedCopyOptions.PreCopy = func(ctx context.Context, desc ocispec.Descriptor) error {
return printer.PrintStatus(desc, promptCopying)
}
extendedCopyOptions.PostCopy = func(ctx context.Context, desc ocispec.Descriptor) error {
committed.Store(desc.Digest.String(), desc.Annotations[ocispec.AnnotationTitle])
if err := output.PrintSuccessorStatus(ctx, desc, dst, committed, printer.StatusPrinter(promptSkipped)); err != nil {
return err
}
return printer.PrintStatus(desc, promptCopied)
}
extendedCopyOptions.OnMounted = func(ctx context.Context, desc ocispec.Descriptor) error {
committed.Store(desc.Digest.String(), desc.Annotations[ocispec.AnnotationTitle])
return printer.PrintStatus(desc, promptMounted)
}
// no TTY output
extendedCopyOptions.OnCopySkipped = copyHandler.OnCopySkipped
extendedCopyOptions.PreCopy = copyHandler.PreCopy
extendedCopyOptions.PostCopy = copyHandler.PostCopy
extendedCopyOptions.OnMounted = copyHandler.OnMounted
} else {
// TTY output
tracked, err := track.NewTarget(dst, promptCopying, promptCopied, opts.TTY)
Expand Down
12 changes: 9 additions & 3 deletions cmd/oras/root/cp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ 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"
Expand Down Expand Up @@ -133,8 +134,9 @@ func Test_doCopy(t *testing.T) {
dst := memory.New()
builder := &strings.Builder{}
printer := output.NewPrinter(builder, os.Stderr, opts.Verbose)
handler := status.NewTextCopyHandler(printer, dst)
// test
_, err = doCopy(context.Background(), printer, memStore, dst, &opts)
_, err = doCopy(context.Background(), handler, memStore, dst, &opts)
if err != nil {
t.Fatal(err)
}
Expand All @@ -157,8 +159,10 @@ func Test_doCopy_skipped(t *testing.T) {
opts.From.Reference = memDesc.Digest.String()
builder := &strings.Builder{}
printer := output.NewPrinter(builder, os.Stderr, opts.Verbose)
handler := status.NewTextCopyHandler(printer, memStore)

// test
_, err = doCopy(context.Background(), printer, memStore, memStore, &opts)
_, err = doCopy(context.Background(), handler, memStore, memStore, &opts)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -192,8 +196,10 @@ func Test_doCopy_mounted(t *testing.T) {
to.PlainHTTP = true
builder := &strings.Builder{}
printer := output.NewPrinter(builder, os.Stderr, opts.Verbose)
handler := status.NewTextCopyHandler(printer, to)

// test
_, err = doCopy(context.Background(), printer, from, to, &opts)
_, err = doCopy(context.Background(), handler, from, to, &opts)
if err != nil {
t.Fatal(err)
}
Expand Down

0 comments on commit 5067a9a

Please sign in to comment.