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

feat: remove empty artifact CLI message and show hints for pulling OCI image layout #1157

Merged
merged 1 commit into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/oras/internal/display/progress/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (s *status) String(width int) (string, string) {
// bar + wrapper(2) + space(1) + speed + "/s"(2) + wrapper(2) = len(bar) + len(speed) + 7
lenLeft = barLength + speedLength + 7
} else {
left = fmt.Sprintf(" %s %s", s.prompt, name)
left = fmt.Sprintf(" %s %s", s.prompt, name)
}
// mark(1) + space(1) + prompt + space(1) + name = len(prompt) + len(name) + 3
lenLeft += utf8.RuneCountInString(s.prompt) + utf8.RuneCountInString(name) + 3
Expand Down
2 changes: 1 addition & 1 deletion cmd/oras/internal/display/progress/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func Test_status_String(t *testing.T) {
descriptor: s.descriptor,
})
statusStr, digestStr = s.String(120)
if err := testutils.OrderedMatch(statusStr+digestStr, "", s.prompt, s.descriptor.MediaType, "2/2 B", "100.00%", s.descriptor.Digest.String()); err != nil {
if err := testutils.OrderedMatch(statusStr+digestStr, "", s.prompt, s.descriptor.MediaType, "2/2 B", "100.00%", s.descriptor.Digest.String()); err != nil {
t.Error(err)
}
}
Expand Down
32 changes: 17 additions & 15 deletions cmd/oras/root/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,40 +130,44 @@ func runPull(ctx context.Context, opts pullOptions) error {
dst.AllowPathTraversalOnWrite = opts.PathTraversal
dst.DisableOverwrite = opts.KeepOldFiles

desc, pulledEmpty, err := doPull(ctx, src, dst, copyOptions, &opts)
desc, skippedLayers, err := doPull(ctx, src, dst, copyOptions, &opts)
if err != nil {
if errors.Is(err, file.ErrPathTraversalDisallowed) {
err = fmt.Errorf("%s: %w", "use flag --allow-path-traversal to allow insecurely pulling files outside of working directory", err)
}
return err
}
if pulledEmpty {
fmt.Println("Downloaded empty artifact")

// suggest oras copy for pulling layers without annotation
if skippedLayers > 0 {
fmt.Printf("Skipped pulling layers without file name in %q\n", ocispec.AnnotationTitle)
fmt.Printf("Use 'oras copy %s --to-oci-layout <layout-dir>' to pull all layers.\n", opts.RawReference)
qweeah marked this conversation as resolved.
Show resolved Hide resolved
} else {
fmt.Println("Pulled", opts.AnnotatedReference())
fmt.Println("Digest:", desc.Digest)
}
fmt.Println("Pulled", opts.AnnotatedReference())
fmt.Println("Digest:", desc.Digest)
return nil
}

func doPull(ctx context.Context, src oras.ReadOnlyTarget, dst oras.GraphTarget, opts oras.CopyOptions, po *pullOptions) (ocispec.Descriptor, bool, error) {
func doPull(ctx context.Context, src oras.ReadOnlyTarget, dst oras.GraphTarget, opts oras.CopyOptions, po *pullOptions) (ocispec.Descriptor, int, error) {
var configPath, configMediaType string
var err error
if po.ManifestConfigRef != "" {
configPath, configMediaType, err = fileref.Parse(po.ManifestConfigRef, "")
if err != nil {
return ocispec.Descriptor{}, false, err
return ocispec.Descriptor{}, 0, err
}
}

var tracked track.GraphTarget
dst, tracked, err = getTrackedTarget(dst, po.TTY, "Downloading", "Downloaded ")
dst, tracked, err = getTrackedTarget(dst, po.TTY, "Downloading", "Pulled ")
if err != nil {
return ocispec.Descriptor{}, false, err
return ocispec.Descriptor{}, 0, err
}
if tracked != nil {
defer tracked.Close()
}

skippedLayers := 0
var printed sync.Map
var getConfigOnce sync.Once
opts.FindSuccessors = func(ctx context.Context, fetcher content.Fetcher, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
Expand Down Expand Up @@ -215,6 +219,7 @@ func doPull(ctx context.Context, src oras.ReadOnlyTarget, dst oras.GraphTarget,
var ret []ocispec.Descriptor
for _, s := range nodes {
if s.Annotations[ocispec.AnnotationTitle] == "" {
skippedLayers++
ss, err := content.Successors(ctx, fetcher, s)
if err != nil {
return nil, err
Expand All @@ -233,7 +238,6 @@ func doPull(ctx context.Context, src oras.ReadOnlyTarget, dst oras.GraphTarget,
return ret, nil
}

pulledEmpty := true
opts.PreCopy = func(ctx context.Context, desc ocispec.Descriptor) error {
if _, ok := printed.LoadOrStore(generateContentKey(desc), true); ok {
return nil
Expand Down Expand Up @@ -264,17 +268,15 @@ func doPull(ctx context.Context, src oras.ReadOnlyTarget, dst oras.GraphTarget,
return nil
}
name = desc.MediaType
} else {
// named content downloaded
pulledEmpty = false
skippedLayers++
}
printed.Store(generateContentKey(desc), true)
return display.Print("Downloaded ", display.ShortDigest(desc), name)
}

// Copy
desc, err := oras.Copy(ctx, src, po.Reference, dst, po.Reference, opts)
return desc, pulledEmpty, err
return desc, skippedLayers, err
}

// generateContentKey generates a unique key for each content descriptor, using
Expand Down