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: add digest hint in oras tag logs #853

Merged
merged 14 commits into from
Mar 6, 2023
2 changes: 1 addition & 1 deletion cmd/oras/cp.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func runCopy(opts copyOptions) error {
if len(opts.extraRefs) != 0 {
tagNOpts := oras.DefaultTagNOptions
tagNOpts.Concurrency = opts.concurrency
if _, err = oras.TagN(ctx, display.NewTagManifestStatusPrinter(dst), opts.To.Reference, opts.extraRefs, tagNOpts); err != nil {
if _, err = oras.TagN(ctx, display.NewTagStatusPrinter(dst), opts.To.Reference, opts.extraRefs, tagNOpts); err != nil {
return err
}
}
Expand Down
52 changes: 50 additions & 2 deletions cmd/oras/internal/display/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"io"
"sync"
"sync/atomic"

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"oras.land/oras-go/v2"
Expand Down Expand Up @@ -75,8 +76,8 @@ func PrintSuccessorStatus(ctx context.Context, desc ocispec.Descriptor, status s
return nil
}

// NewTagManifestStatusPrinter creates a wrapper type for printing tag status.
func NewTagManifestStatusPrinter(target oras.Target) oras.Target {
// 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,
Expand All @@ -87,8 +88,29 @@ func NewTagManifestStatusPrinter(target oras.Target) oras.Target {
}
}

qweeah marked this conversation as resolved.
Show resolved Hide resolved
// NewTagStatusHintPrinter creates a wrapper type for printing
// tag status and hint.
func NewTagStatusHintPrinter(target oras.Target, hintFunc func(ocispec.Descriptor) string) oras.Target {
var b atomic.Bool
b.Store(true)
qweeah marked this conversation as resolved.
Show resolved Hide resolved
if repo, ok := target.(registry.Repository); ok {
return &tagManifestStatusForRepo{
Repository: repo,
needHint: &b,
hintFunc: hintFunc,
}
}
return &tagManifestStatusForTarget{
Target: target,
needHint: &b,
hintFunc: hintFunc,
}
}

type tagManifestStatusForRepo struct {
registry.Repository
needHint *atomic.Bool
hintFunc func(ocispec.Descriptor) string
}

// PushReference overrides Repository.PushReference method to print off which tag(s) were added successfully.
Expand All @@ -99,8 +121,22 @@ func (p *tagManifestStatusForRepo) PushReference(ctx context.Context, expected o
return Print("Tagged", reference)
}

// FetchReference fetches the content identified by the reference.
func (p *tagManifestStatusForRepo) FetchReference(ctx context.Context, reference string) (ocispec.Descriptor, io.ReadCloser, error) {
desc, rc, err := p.Repository.FetchReference(ctx, reference)
if err == nil && p.hintFunc != nil && p.needHint != nil {
needHint := p.needHint.Swap(false)
if needHint {
Print(p.hintFunc(desc))
}
}
return desc, rc, err
}

type tagManifestStatusForTarget struct {
oras.Target
needHint *atomic.Bool
hintFunc func(ocispec.Descriptor) string
}

// Tag tags a descriptor with a reference string.
Expand All @@ -110,3 +146,15 @@ func (p *tagManifestStatusForTarget) Tag(ctx context.Context, desc ocispec.Descr
}
return Print("Tagged", reference)
}

// Resolve resolves a reference to a descriptor.
func (p *tagManifestStatusForTarget) Resolve(ctx context.Context, reference string) (ocispec.Descriptor, error) {
desc, err := p.Target.Resolve(ctx, reference)
if err == nil && p.hintFunc != nil && p.needHint != nil {
needHint := p.needHint.Swap(false)
if needHint {
Print(p.hintFunc(desc))
}
}
return desc, err
}
2 changes: 1 addition & 1 deletion cmd/oras/manifest/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func pushManifest(opts pushOptions) error {
}
display.Print("Pushed", opts.AnnotatedReference())
if len(opts.extraRefs) != 0 {
if _, err = oras.TagBytesN(ctx, display.NewTagManifestStatusPrinter(target), mediaType, contentBytes, opts.extraRefs, tagBytesNOpts); err != nil {
if _, err = oras.TagBytesN(ctx, display.NewTagStatusPrinter(target), mediaType, contentBytes, opts.extraRefs, tagBytesNOpts); err != nil {
return err
}
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/oras/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func runPush(opts pushOptions) error {
}
tagBytesNOpts := oras.DefaultTagBytesNOptions
tagBytesNOpts.Concurrency = opts.concurrency
if _, err = oras.TagBytesN(ctx, display.NewTagManifestStatusPrinter(dst), root.MediaType, contentBytes, opts.extraRefs, tagBytesNOpts); err != nil {
if _, err = oras.TagBytesN(ctx, display.NewTagStatusPrinter(dst), root.MediaType, contentBytes, opts.extraRefs, tagBytesNOpts); err != nil {
return err
}
}
Expand Down
7 changes: 6 additions & 1 deletion cmd/oras/tag/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ limitations under the License.
package tag

import (
"fmt"

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/spf13/cobra"
"oras.land/oras-go/v2"
"oras.land/oras/cmd/oras/internal/display"
Expand Down Expand Up @@ -82,6 +85,8 @@ func tagManifest(opts tagOptions) error {

tagNOpts := oras.DefaultTagNOptions
tagNOpts.Concurrency = opts.concurrency
_, err = oras.TagN(ctx, display.NewTagManifestStatusPrinter(target), opts.Reference, opts.targetRefs, tagNOpts)
_, err = oras.TagN(ctx, display.NewTagStatusHintPrinter(target, func(d ocispec.Descriptor) string {
return fmt.Sprintf("Tagging [%s] %s@%s", opts.Type, opts.Path, d.Digest)
}), opts.Reference, opts.targetRefs, tagNOpts)
return err
}
14 changes: 8 additions & 6 deletions test/e2e/suite/command/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ limitations under the License.
package command

import (
"fmt"

. "github.com/onsi/ginkgo/v2"
"oras.land/oras/test/e2e/internal/testdata/multi_arch"
. "oras.land/oras/test/e2e/internal/utils"
Expand All @@ -35,22 +37,22 @@ var _ = Describe("ORAS beginners:", func() {
})

var _ = Describe("Common registry users:", func() {
var tagAndValidate = func(reg string, repo string, tagOrDigest string, tags ...string) {
ORAS(append([]string{"tag", Reference(reg, repo, tagOrDigest)}, tags...)...).MatchKeyWords(tags...).Exec()
var tagAndValidate = func(reg string, repo string, tagOrDigest string, digest string, tags ...string) {
ORAS(append([]string{"tag", Reference(reg, repo, tagOrDigest)}, tags...)...).MatchKeyWords(append(tags, fmt.Sprintf("Tagging [registry] %s", Reference(reg, repo, digest)))...).Exec()
ORAS("repo", "tags", Reference(reg, repo, "")).MatchKeyWords(tags...).Exec()
}
When("running `tag`", func() {
It("should add a tag to an existent manifest when providing tag reference", func() {
tagAndValidate(Host, ImageRepo, multi_arch.Tag, "tag-via-tag")
tagAndValidate(Host, ImageRepo, multi_arch.Tag, multi_arch.Digest, "tag-via-tag")
})
It("should add a tag to an existent manifest when providing digest reference", func() {
tagAndValidate(Host, ImageRepo, multi_arch.Digest, "tag-via-digest")
tagAndValidate(Host, ImageRepo, multi_arch.Digest, multi_arch.Digest, "tag-via-digest")
})
It("should add multiple tags to an existent manifest when providing digest reference", func() {
tagAndValidate(Host, ImageRepo, multi_arch.Digest, "tag1-via-digest", "tag2-via-digest", "tag3-via-digest")
tagAndValidate(Host, ImageRepo, multi_arch.Digest, multi_arch.Digest, "tag1-via-digest", "tag2-via-digest", "tag3-via-digest")
})
It("should add multiple tags to an existent manifest when providing tag reference", func() {
tagAndValidate(Host, ImageRepo, multi_arch.Tag, "tag1-via-tag", "tag1-via-tag", "tag1-via-tag")
tagAndValidate(Host, ImageRepo, multi_arch.Tag, multi_arch.Digest, "tag1-via-tag", "tag1-via-tag", "tag1-via-tag")
})
})
})