From 45a3de27d4ded712758f1a77cc518f33ce9b09be Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 09:24:38 +0800 Subject: [PATCH 01/29] Add discover command Signed-off-by: Billy Zha --- cmd/oras/discover.go | 173 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 cmd/oras/discover.go diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go new file mode 100644 index 000000000..ab8c1021c --- /dev/null +++ b/cmd/oras/discover.go @@ -0,0 +1,173 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "os" + "strings" + + "oras.land/oras-go/v2/registry/remote" + "oras.land/oras/cmd/oras/internal/option" + + "github.com/containerd/containerd/reference" + "github.com/need-being/go-tree" + digest "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1" + "github.com/spf13/cobra" +) + +type discoverOptions struct { + option.Common + option.Remote + + targetRef string + artifactType string + outputType string +} + +func discoverCmd() *cobra.Command { + var opts discoverOptions + cmd := &cobra.Command{ + Use: "discover [options] ", + Short: "discover artifacts from remote registry", + Long: `discover artifacts from remote registry + +Example - Discover artifacts of type "" linked with the specified reference: + oras discover --artifact-type application/vnd.cncf.notary.v2 localhost:5000/hello:latest +`, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + opts.targetRef = args[0] + return runDiscover(opts) + }, + } + + cmd.Flags().StringVarP(&opts.artifactType, "artifact-type", "", "", "artifact type") + cmd.Flags().StringVarP(&opts.outputType, "output", "o", "table", fmt.Sprintf("Format in which to display references (%s, %s, or %s). tree format will show all references including nested", "table", "json", "tree")) + option.ApplyFlags(&opts, cmd.Flags()) + return cmd +} + +func runDiscover(opts discoverOptions) error { + ctx, _ := opts.SetLoggerLevel() + repo, err := opts.NewRepository(opts.targetRef, opts.Common) + if err != nil { + return err + } + + // discover artifacts + root := tree.New(opts.targetRef) + desc, err := repo.Resolve(ctx, repo.Reference.Reference) + if err != nil { + return err + } + desc, refs, err := getAllReferences(ctx, repo, desc, opts.artifactType, root, opts.outputType == "tree") + if err != nil { + return err + } + + switch opts.outputType { + case "tree": + tree.Print(root) + case "json": + printDiscoveredReferencesJSON(desc, *refs) + default: + fmt.Println("Discovered", len(*refs), "artifacts referencing", opts.targetRef) + fmt.Println("Digest:", desc.Digest) + + if len(*refs) != 0 { + fmt.Println() + printDiscoveredReferencesTable(*refs, opts.Verbose) + } + } + return nil +} + +func getAllReferences(ctx context.Context, repo *remote.Repository, desc ocispec.Descriptor, artifactType string, node *tree.Node, queryGraph bool) (ocispec.Descriptor, *[]artifactspec.Descriptor, error) { + var results []artifactspec.Descriptor + err := repo.Referrers(ctx, desc, func(referrers []artifactspec.Descriptor) error { + for _, r := range referrers { + if artifactType == "" || artifactType == r.ArtifactType { + results = append(results, r) + if queryGraph { + // Find all referrers + referrerNode := node.AddPath(r.ArtifactType, r.Digest) + _, nestedReferrers, err := getAllReferences( + ctx, repo, + ocispec.Descriptor{ + Digest: r.Digest, + Size: r.Size, + MediaType: r.MediaType, + }, + artifactType, referrerNode, queryGraph) + if err != nil { + return err + } + results = append(results, *nestedReferrers...) + } + } + } + return nil + }) + if err != nil { + if err == reference.ErrObjectRequired { + return ocispec.Descriptor{}, nil, fmt.Errorf("image reference format is invalid. Please specify ") + } + return ocispec.Descriptor{}, nil, err + } + return desc, &results, nil +} + +func printDiscoveredReferencesTable(refs []artifactspec.Descriptor, verbose bool) { + typeNameTitle := "Artifact Type" + typeNameLength := len(typeNameTitle) + for _, ref := range refs { + if length := len(ref.ArtifactType); length > typeNameLength { + typeNameLength = length + } + } + + print := func(key string, value interface{}) { + fmt.Println(key, strings.Repeat(" ", typeNameLength-len(key)+1), value) + } + + print(typeNameTitle, "Digest") + for _, ref := range refs { + print(ref.ArtifactType, ref.Digest) + if verbose { + printJSON(ref) + } + } +} + +func printDiscoveredReferencesJSON(desc ocispec.Descriptor, refs []artifactspec.Descriptor) { + type reference struct { + Digest digest.Digest `json:"digest"` + Artifact string `json:"artifactType"` + } + output := struct { + Digest digest.Digest `json:"digest"` + References []reference `json:"references"` + }{ + Digest: desc.Digest, + References: make([]reference, len(refs)), + } + + for i, ref := range refs { + output.References[i] = reference{ + Digest: ref.Digest, + Artifact: ref.ArtifactType, + } + } + + printJSON(output) +} + +func printJSON(object interface{}) { + encoder := json.NewEncoder(os.Stdout) + encoder.SetEscapeHTML(false) + encoder.SetIndent("", " ") + encoder.Encode(object) +} From a625b291b9869f16c5df2e4a0baa7c7f28bdb6d0 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 12:28:58 +0800 Subject: [PATCH 02/29] Add discover command Signed-off-by: Billy Zha --- cmd/oras/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/oras/main.go b/cmd/oras/main.go index 927a101c1..1579f4a35 100644 --- a/cmd/oras/main.go +++ b/cmd/oras/main.go @@ -11,7 +11,7 @@ func main() { Use: "oras [command]", SilenceUsage: true, } - cmd.AddCommand(pullCmd(), pushCmd(), loginCmd(), logoutCmd(), versionCmd()) + cmd.AddCommand(pullCmd(), pushCmd(), loginCmd(), logoutCmd(), versionCmd(), discoverCmd()) if err := cmd.Execute(); err != nil { os.Exit(1) } From 146353bace45e825ad2b9976e02cd20fa0f06319 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 13:38:42 +0800 Subject: [PATCH 03/29] Remove containerd dependency Signed-off-by: Billy Zha --- cmd/oras/discover.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index ab8c1021c..291c182b1 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -10,7 +10,6 @@ import ( "oras.land/oras-go/v2/registry/remote" "oras.land/oras/cmd/oras/internal/option" - "github.com/containerd/containerd/reference" "github.com/need-being/go-tree" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -112,9 +111,6 @@ func getAllReferences(ctx context.Context, repo *remote.Repository, desc ocispec return nil }) if err != nil { - if err == reference.ErrObjectRequired { - return ocispec.Descriptor{}, nil, fmt.Errorf("image reference format is invalid. Please specify ") - } return ocispec.Descriptor{}, nil, err } return desc, &results, nil From 9d85d939126c6038c50514109e031a91f41fb856 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 13:42:34 +0800 Subject: [PATCH 04/29] Update module info Signed-off-by: Billy Zha --- go.mod | 9 +++++++-- go.sum | 18 +++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 72631ccd4..9c591b9a8 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,10 @@ go 1.18 require ( github.com/docker/cli v20.10.17+incompatible github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 + github.com/need-being/go-tree v0.1.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 + github.com/oras-project/artifacts-spec v1.0.0-draft.1.1 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.5.0 github.com/spf13/pflag v1.0.5 @@ -17,9 +19,12 @@ require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/docker/docker v20.10.17+incompatible // indirect github.com/docker/docker-credential-helpers v0.6.4 // indirect + github.com/google/go-cmp v0.5.6 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/oras-project/artifacts-spec v1.0.0-draft.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/stretchr/testify v1.7.0 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gotest.tools/v3 v3.0.3 // indirect ) diff --git a/go.sum b/go.sum index ffa699109..f7962b01d 100644 --- a/go.sum +++ b/go.sum @@ -14,12 +14,15 @@ github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05 github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/need-being/go-tree v0.1.0 h1:blQrtD006cFm97UDeMUfixwPc9o06A6c+uLaUskdNNw= +github.com/need-being/go-tree v0.1.0/go.mod h1:UOHUchuOm+lxM+EtvQ9h/IO88hK/ke7FHai4oGhhEoI= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= @@ -41,8 +44,9 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -51,16 +55,20 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= oras.land/oras-go/v2 v2.0.0-alpha h1:Uwso3p1KMTmm7YheWBkGNjf8xqXZ2AYxMfxu1DoQiH0= oras.land/oras-go/v2 v2.0.0-alpha/go.mod h1:0IQiLwHUJuMs0+QYGavaeQWw5FD4ABD/RP5YamXT/sc= From 63e962e9410bb8aa41d1cc27c2b561a7bdf710da Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 13:49:07 +0800 Subject: [PATCH 05/29] Add command line examples Signed-off-by: Billy Zha --- cmd/oras/discover.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 291c182b1..7875e8807 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -31,10 +31,16 @@ func discoverCmd() *cobra.Command { cmd := &cobra.Command{ Use: "discover [options] ", Short: "discover artifacts from remote registry", - Long: `discover artifacts from remote registry + Long: `discover artifacts from remote regislatesttry -Example - Discover artifacts of type "" linked with the specified reference: - oras discover --artifact-type application/vnd.cncf.notary.v2 localhost:5000/hello:latest +Example - Discover all the artifacts linked with the specified reference: + oras discover localhost:5000/hello + +Example - Discover all the artifacts linked with the specified reference in a tree view: + oras discover localhost:5000/hello -o tree + +Example - Discover artifacts of type test-artifact test-artifact linked with the specified reference: + oras discover --artifact test-artifact localhost:5000/hello `, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { From a8e1984916bd99ed3a03f22070bc3db53884d186 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 13:57:02 +0800 Subject: [PATCH 06/29] Code clean Signed-off-by: Billy Zha --- cmd/oras/discover.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 7875e8807..962ae77be 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -31,7 +31,7 @@ func discoverCmd() *cobra.Command { cmd := &cobra.Command{ Use: "discover [options] ", Short: "discover artifacts from remote registry", - Long: `discover artifacts from remote regislatesttry + Long: `discover artifacts from remote registry Example - Discover all the artifacts linked with the specified reference: oras discover localhost:5000/hello From ffcee8cbd2481f5e8d0c44ed18d8e0eabfb9baca Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 14:00:42 +0800 Subject: [PATCH 07/29] Code clean Signed-off-by: Billy Zha --- cmd/oras/discover.go | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 962ae77be..d93d38d31 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -96,22 +96,23 @@ func getAllReferences(ctx context.Context, repo *remote.Repository, desc ocispec for _, r := range referrers { if artifactType == "" || artifactType == r.ArtifactType { results = append(results, r) - if queryGraph { - // Find all referrers - referrerNode := node.AddPath(r.ArtifactType, r.Digest) - _, nestedReferrers, err := getAllReferences( - ctx, repo, - ocispec.Descriptor{ - Digest: r.Digest, - Size: r.Size, - MediaType: r.MediaType, - }, - artifactType, referrerNode, queryGraph) - if err != nil { - return err - } - results = append(results, *nestedReferrers...) + if !queryGraph { + continue } + // Find all referrers + referrerNode := node.AddPath(r.ArtifactType, r.Digest) + _, nestedReferrers, err := getAllReferences( + ctx, repo, + ocispec.Descriptor{ + Digest: r.Digest, + Size: r.Size, + MediaType: r.MediaType, + }, + artifactType, referrerNode, queryGraph) + if err != nil { + return err + } + results = append(results, *nestedReferrers...) } } return nil From 829daf8a2b94b89ea60f37a16734522264e6191b Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 09:24:38 +0800 Subject: [PATCH 08/29] Add discover command Signed-off-by: Billy Zha --- cmd/oras/discover.go | 173 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 cmd/oras/discover.go diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go new file mode 100644 index 000000000..ab8c1021c --- /dev/null +++ b/cmd/oras/discover.go @@ -0,0 +1,173 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "os" + "strings" + + "oras.land/oras-go/v2/registry/remote" + "oras.land/oras/cmd/oras/internal/option" + + "github.com/containerd/containerd/reference" + "github.com/need-being/go-tree" + digest "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1" + "github.com/spf13/cobra" +) + +type discoverOptions struct { + option.Common + option.Remote + + targetRef string + artifactType string + outputType string +} + +func discoverCmd() *cobra.Command { + var opts discoverOptions + cmd := &cobra.Command{ + Use: "discover [options] ", + Short: "discover artifacts from remote registry", + Long: `discover artifacts from remote registry + +Example - Discover artifacts of type "" linked with the specified reference: + oras discover --artifact-type application/vnd.cncf.notary.v2 localhost:5000/hello:latest +`, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + opts.targetRef = args[0] + return runDiscover(opts) + }, + } + + cmd.Flags().StringVarP(&opts.artifactType, "artifact-type", "", "", "artifact type") + cmd.Flags().StringVarP(&opts.outputType, "output", "o", "table", fmt.Sprintf("Format in which to display references (%s, %s, or %s). tree format will show all references including nested", "table", "json", "tree")) + option.ApplyFlags(&opts, cmd.Flags()) + return cmd +} + +func runDiscover(opts discoverOptions) error { + ctx, _ := opts.SetLoggerLevel() + repo, err := opts.NewRepository(opts.targetRef, opts.Common) + if err != nil { + return err + } + + // discover artifacts + root := tree.New(opts.targetRef) + desc, err := repo.Resolve(ctx, repo.Reference.Reference) + if err != nil { + return err + } + desc, refs, err := getAllReferences(ctx, repo, desc, opts.artifactType, root, opts.outputType == "tree") + if err != nil { + return err + } + + switch opts.outputType { + case "tree": + tree.Print(root) + case "json": + printDiscoveredReferencesJSON(desc, *refs) + default: + fmt.Println("Discovered", len(*refs), "artifacts referencing", opts.targetRef) + fmt.Println("Digest:", desc.Digest) + + if len(*refs) != 0 { + fmt.Println() + printDiscoveredReferencesTable(*refs, opts.Verbose) + } + } + return nil +} + +func getAllReferences(ctx context.Context, repo *remote.Repository, desc ocispec.Descriptor, artifactType string, node *tree.Node, queryGraph bool) (ocispec.Descriptor, *[]artifactspec.Descriptor, error) { + var results []artifactspec.Descriptor + err := repo.Referrers(ctx, desc, func(referrers []artifactspec.Descriptor) error { + for _, r := range referrers { + if artifactType == "" || artifactType == r.ArtifactType { + results = append(results, r) + if queryGraph { + // Find all referrers + referrerNode := node.AddPath(r.ArtifactType, r.Digest) + _, nestedReferrers, err := getAllReferences( + ctx, repo, + ocispec.Descriptor{ + Digest: r.Digest, + Size: r.Size, + MediaType: r.MediaType, + }, + artifactType, referrerNode, queryGraph) + if err != nil { + return err + } + results = append(results, *nestedReferrers...) + } + } + } + return nil + }) + if err != nil { + if err == reference.ErrObjectRequired { + return ocispec.Descriptor{}, nil, fmt.Errorf("image reference format is invalid. Please specify ") + } + return ocispec.Descriptor{}, nil, err + } + return desc, &results, nil +} + +func printDiscoveredReferencesTable(refs []artifactspec.Descriptor, verbose bool) { + typeNameTitle := "Artifact Type" + typeNameLength := len(typeNameTitle) + for _, ref := range refs { + if length := len(ref.ArtifactType); length > typeNameLength { + typeNameLength = length + } + } + + print := func(key string, value interface{}) { + fmt.Println(key, strings.Repeat(" ", typeNameLength-len(key)+1), value) + } + + print(typeNameTitle, "Digest") + for _, ref := range refs { + print(ref.ArtifactType, ref.Digest) + if verbose { + printJSON(ref) + } + } +} + +func printDiscoveredReferencesJSON(desc ocispec.Descriptor, refs []artifactspec.Descriptor) { + type reference struct { + Digest digest.Digest `json:"digest"` + Artifact string `json:"artifactType"` + } + output := struct { + Digest digest.Digest `json:"digest"` + References []reference `json:"references"` + }{ + Digest: desc.Digest, + References: make([]reference, len(refs)), + } + + for i, ref := range refs { + output.References[i] = reference{ + Digest: ref.Digest, + Artifact: ref.ArtifactType, + } + } + + printJSON(output) +} + +func printJSON(object interface{}) { + encoder := json.NewEncoder(os.Stdout) + encoder.SetEscapeHTML(false) + encoder.SetIndent("", " ") + encoder.Encode(object) +} From 6c060584ad24bb64521631998ff1b9478edab435 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 12:28:58 +0800 Subject: [PATCH 09/29] Add discover command Signed-off-by: Billy Zha --- cmd/oras/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/oras/main.go b/cmd/oras/main.go index 927a101c1..1579f4a35 100644 --- a/cmd/oras/main.go +++ b/cmd/oras/main.go @@ -11,7 +11,7 @@ func main() { Use: "oras [command]", SilenceUsage: true, } - cmd.AddCommand(pullCmd(), pushCmd(), loginCmd(), logoutCmd(), versionCmd()) + cmd.AddCommand(pullCmd(), pushCmd(), loginCmd(), logoutCmd(), versionCmd(), discoverCmd()) if err := cmd.Execute(); err != nil { os.Exit(1) } From 31c9903dc94f655104ca6dd792c17cdb24b39303 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 13:38:42 +0800 Subject: [PATCH 10/29] Remove containerd dependency Signed-off-by: Billy Zha --- cmd/oras/discover.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index ab8c1021c..291c182b1 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -10,7 +10,6 @@ import ( "oras.land/oras-go/v2/registry/remote" "oras.land/oras/cmd/oras/internal/option" - "github.com/containerd/containerd/reference" "github.com/need-being/go-tree" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -112,9 +111,6 @@ func getAllReferences(ctx context.Context, repo *remote.Repository, desc ocispec return nil }) if err != nil { - if err == reference.ErrObjectRequired { - return ocispec.Descriptor{}, nil, fmt.Errorf("image reference format is invalid. Please specify ") - } return ocispec.Descriptor{}, nil, err } return desc, &results, nil From eb5ac00e793ddf31f36f0dbc7fe920661e786465 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 13:42:34 +0800 Subject: [PATCH 11/29] Update module info Signed-off-by: Billy Zha --- go.mod | 9 +++++++-- go.sum | 18 +++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 72631ccd4..9c591b9a8 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,10 @@ go 1.18 require ( github.com/docker/cli v20.10.17+incompatible github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 + github.com/need-being/go-tree v0.1.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 + github.com/oras-project/artifacts-spec v1.0.0-draft.1.1 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.5.0 github.com/spf13/pflag v1.0.5 @@ -17,9 +19,12 @@ require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/docker/docker v20.10.17+incompatible // indirect github.com/docker/docker-credential-helpers v0.6.4 // indirect + github.com/google/go-cmp v0.5.6 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/oras-project/artifacts-spec v1.0.0-draft.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/stretchr/testify v1.7.0 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gotest.tools/v3 v3.0.3 // indirect ) diff --git a/go.sum b/go.sum index ffa699109..f7962b01d 100644 --- a/go.sum +++ b/go.sum @@ -14,12 +14,15 @@ github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05 github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/need-being/go-tree v0.1.0 h1:blQrtD006cFm97UDeMUfixwPc9o06A6c+uLaUskdNNw= +github.com/need-being/go-tree v0.1.0/go.mod h1:UOHUchuOm+lxM+EtvQ9h/IO88hK/ke7FHai4oGhhEoI= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= @@ -41,8 +44,9 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -51,16 +55,20 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= oras.land/oras-go/v2 v2.0.0-alpha h1:Uwso3p1KMTmm7YheWBkGNjf8xqXZ2AYxMfxu1DoQiH0= oras.land/oras-go/v2 v2.0.0-alpha/go.mod h1:0IQiLwHUJuMs0+QYGavaeQWw5FD4ABD/RP5YamXT/sc= From 0a7fb5ca1fe613ad89698d501e07574e4284f3e5 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 13:49:07 +0800 Subject: [PATCH 12/29] Add command line examples Signed-off-by: Billy Zha --- cmd/oras/discover.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 291c182b1..7875e8807 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -31,10 +31,16 @@ func discoverCmd() *cobra.Command { cmd := &cobra.Command{ Use: "discover [options] ", Short: "discover artifacts from remote registry", - Long: `discover artifacts from remote registry + Long: `discover artifacts from remote regislatesttry -Example - Discover artifacts of type "" linked with the specified reference: - oras discover --artifact-type application/vnd.cncf.notary.v2 localhost:5000/hello:latest +Example - Discover all the artifacts linked with the specified reference: + oras discover localhost:5000/hello + +Example - Discover all the artifacts linked with the specified reference in a tree view: + oras discover localhost:5000/hello -o tree + +Example - Discover artifacts of type test-artifact test-artifact linked with the specified reference: + oras discover --artifact test-artifact localhost:5000/hello `, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { From d3921bbdd50e2334c6d3c863c70e6cc33083466a Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 13:57:02 +0800 Subject: [PATCH 13/29] Code clean Signed-off-by: Billy Zha --- cmd/oras/discover.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 7875e8807..962ae77be 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -31,7 +31,7 @@ func discoverCmd() *cobra.Command { cmd := &cobra.Command{ Use: "discover [options] ", Short: "discover artifacts from remote registry", - Long: `discover artifacts from remote regislatesttry + Long: `discover artifacts from remote registry Example - Discover all the artifacts linked with the specified reference: oras discover localhost:5000/hello From 91505b0b28359b31f629dda48c5250040e6c35e5 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Jun 2022 14:00:42 +0800 Subject: [PATCH 14/29] Code clean Signed-off-by: Billy Zha --- cmd/oras/discover.go | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 962ae77be..d93d38d31 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -96,22 +96,23 @@ func getAllReferences(ctx context.Context, repo *remote.Repository, desc ocispec for _, r := range referrers { if artifactType == "" || artifactType == r.ArtifactType { results = append(results, r) - if queryGraph { - // Find all referrers - referrerNode := node.AddPath(r.ArtifactType, r.Digest) - _, nestedReferrers, err := getAllReferences( - ctx, repo, - ocispec.Descriptor{ - Digest: r.Digest, - Size: r.Size, - MediaType: r.MediaType, - }, - artifactType, referrerNode, queryGraph) - if err != nil { - return err - } - results = append(results, *nestedReferrers...) + if !queryGraph { + continue } + // Find all referrers + referrerNode := node.AddPath(r.ArtifactType, r.Digest) + _, nestedReferrers, err := getAllReferences( + ctx, repo, + ocispec.Descriptor{ + Digest: r.Digest, + Size: r.Size, + MediaType: r.MediaType, + }, + artifactType, referrerNode, queryGraph) + if err != nil { + return err + } + results = append(results, *nestedReferrers...) } } return nil From b3b47d2d5a6cd222b9e502ec486fa1afd11a3835 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Wed, 29 Jun 2022 13:59:04 +0800 Subject: [PATCH 15/29] Add exprimental command logging Signed-off-by: Billy Zha --- cmd/oras/discover.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index d93d38d31..d9e6889ca 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -43,6 +43,9 @@ Example - Discover artifacts of type test-artifact test-artifact linked with the oras discover --artifact test-artifact localhost:5000/hello `, Args: cobra.ExactArgs(1), + PreRun: func(cmd *cobra.Command, args []string) { + fmt.Println("Command discover is experimental and under development.") + }, RunE: func(cmd *cobra.Command, args []string) error { opts.targetRef = args[0] return runDiscover(opts) From 120b776842bff1250b255a9b5cc448e5013d77cf Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Wed, 29 Jun 2022 16:01:48 +0800 Subject: [PATCH 16/29] Update module Signed-off-by: Billy Zha --- go.mod | 8 ++------ go.sum | 20 +++++++------------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 9c591b9a8..e516e43ef 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/need-being/go-tree v0.1.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 - github.com/oras-project/artifacts-spec v1.0.0-draft.1.1 + github.com/oras-project/artifacts-spec v1.0.0-rc.1 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.5.0 github.com/spf13/pflag v1.0.5 @@ -19,12 +19,8 @@ require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/docker/docker v20.10.17+incompatible // indirect github.com/docker/docker-credential-helpers v0.6.4 // indirect - github.com/google/go-cmp v0.5.6 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/stretchr/testify v1.7.0 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - gotest.tools/v3 v3.0.3 // indirect + golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect ) diff --git a/go.sum b/go.sum index f7962b01d..3087cd053 100644 --- a/go.sum +++ b/go.sum @@ -14,9 +14,8 @@ github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05 github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= @@ -27,8 +26,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/oras-project/artifacts-spec v1.0.0-draft.1.1 h1:2YMUDyDH0glYA4gNG/zEg9HNVzgGX8kr/NBLR9AQkLQ= -github.com/oras-project/artifacts-spec v1.0.0-draft.1.1/go.mod h1:Xch2aLzSwtkhbFFN6LUzTfLtukYvMMdXJ4oZ8O7BOdc= +github.com/oras-project/artifacts-spec v1.0.0-rc.1 h1:bCHf9mPbrgiNwQFyVzBX79BYZVAl0OUrmvICZOCOwts= +github.com/oras-project/artifacts-spec v1.0.0-rc.1/go.mod h1:Xch2aLzSwtkhbFFN6LUzTfLtukYvMMdXJ4oZ8O7BOdc= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -44,9 +43,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -55,20 +53,16 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= oras.land/oras-go/v2 v2.0.0-alpha h1:Uwso3p1KMTmm7YheWBkGNjf8xqXZ2AYxMfxu1DoQiH0= oras.land/oras-go/v2 v2.0.0-alpha/go.mod h1:0IQiLwHUJuMs0+QYGavaeQWw5FD4ABD/RP5YamXT/sc= From 35a777a9f8b59c9089406c048d20e08e1d7081ec Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Thu, 30 Jun 2022 09:12:40 +0800 Subject: [PATCH 17/29] Resolve partial comments Signed-off-by: Billy Zha --- cmd/oras/discover.go | 58 +++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index d9e6889ca..e27b8515c 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -1,3 +1,18 @@ +/* +Copyright The ORAS Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package main import ( @@ -44,7 +59,7 @@ Example - Discover artifacts of type test-artifact test-artifact linked with the `, Args: cobra.ExactArgs(1), PreRun: func(cmd *cobra.Command, args []string) { - fmt.Println("Command discover is experimental and under development.") + fmt.Println("Command discover is in preview and might have breaking changes coming.") }, RunE: func(cmd *cobra.Command, args []string) error { opts.targetRef = args[0] @@ -53,7 +68,7 @@ Example - Discover artifacts of type test-artifact test-artifact linked with the } cmd.Flags().StringVarP(&opts.artifactType, "artifact-type", "", "", "artifact type") - cmd.Flags().StringVarP(&opts.outputType, "output", "o", "table", fmt.Sprintf("Format in which to display references (%s, %s, or %s). tree format will show all references including nested", "table", "json", "tree")) + cmd.Flags().StringVarP(&opts.outputType, "output", "o", "table", "format in which to display references (table, json, or tree). tree format will show all references including nested") option.ApplyFlags(&opts, cmd.Flags()) return cmd } @@ -67,7 +82,7 @@ func runDiscover(opts discoverOptions) error { // discover artifacts root := tree.New(opts.targetRef) - desc, err := repo.Resolve(ctx, repo.Reference.Reference) + desc, err := repo.Resolve(ctx, repo.Reference.ReferenceOrDefault()) if err != nil { return err } @@ -80,20 +95,20 @@ func runDiscover(opts discoverOptions) error { case "tree": tree.Print(root) case "json": - printDiscoveredReferencesJSON(desc, *refs) + printDiscoveredReferencesJSON(desc, refs) default: - fmt.Println("Discovered", len(*refs), "artifacts referencing", opts.targetRef) + fmt.Println("Discovered", len(refs), "artifacts referencing", opts.targetRef) fmt.Println("Digest:", desc.Digest) - if len(*refs) != 0 { + if len(refs) != 0 { fmt.Println() - printDiscoveredReferencesTable(*refs, opts.Verbose) + printDiscoveredReferencesTable(refs, opts.Verbose) } } return nil } -func getAllReferences(ctx context.Context, repo *remote.Repository, desc ocispec.Descriptor, artifactType string, node *tree.Node, queryGraph bool) (ocispec.Descriptor, *[]artifactspec.Descriptor, error) { +func getAllReferences(ctx context.Context, repo *remote.Repository, desc ocispec.Descriptor, artifactType string, node *tree.Node, queryGraph bool) (ocispec.Descriptor, []artifactspec.Descriptor, error) { var results []artifactspec.Descriptor err := repo.Referrers(ctx, desc, func(referrers []artifactspec.Descriptor) error { for _, r := range referrers { @@ -115,7 +130,7 @@ func getAllReferences(ctx context.Context, repo *remote.Repository, desc ocispec if err != nil { return err } - results = append(results, *nestedReferrers...) + results = append(results, nestedReferrers...) } } return nil @@ -123,7 +138,7 @@ func getAllReferences(ctx context.Context, repo *remote.Repository, desc ocispec if err != nil { return ocispec.Descriptor{}, nil, err } - return desc, &results, nil + return desc, results, nil } func printDiscoveredReferencesTable(refs []artifactspec.Descriptor, verbose bool) { @@ -149,22 +164,25 @@ func printDiscoveredReferencesTable(refs []artifactspec.Descriptor, verbose bool } func printDiscoveredReferencesJSON(desc ocispec.Descriptor, refs []artifactspec.Descriptor) { - type reference struct { - Digest digest.Digest `json:"digest"` - Artifact string `json:"artifactType"` + type referrerDesc struct { + Digest digest.Digest `json:"digest"` + MediaType string `json:"mediaType"` + Artifact string `json:"artifactType"` + Size int64 `json:"size"` } output := struct { - Digest digest.Digest `json:"digest"` - References []reference `json:"references"` + // https://github.com/oras-project/artifacts-spec/blob/main/manifest-referrers-api.md#artifact-referrers-api-results + Referrers []referrerDesc `json:"referrers"` }{ - Digest: desc.Digest, - References: make([]reference, len(refs)), + Referrers: make([]referrerDesc, len(refs)), } for i, ref := range refs { - output.References[i] = reference{ - Digest: ref.Digest, - Artifact: ref.ArtifactType, + output.Referrers[i] = referrerDesc{ + Digest: ref.Digest, + Artifact: ref.ArtifactType, + Size: ref.Size, + MediaType: ref.MediaType, } } From 3c961dfdb587d4079a232d29ebbf7a5bc62fb65d Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Thu, 30 Jun 2022 11:24:42 +0800 Subject: [PATCH 18/29] Use oras-go to do artifact filtering Signed-off-by: Billy Zha --- cmd/oras/discover.go | 38 ++++++++++++++++++-------------------- go.mod | 2 +- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index e27b8515c..7ffed75ad 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -110,28 +110,26 @@ func runDiscover(opts discoverOptions) error { func getAllReferences(ctx context.Context, repo *remote.Repository, desc ocispec.Descriptor, artifactType string, node *tree.Node, queryGraph bool) (ocispec.Descriptor, []artifactspec.Descriptor, error) { var results []artifactspec.Descriptor - err := repo.Referrers(ctx, desc, func(referrers []artifactspec.Descriptor) error { + err := repo.Referrers(ctx, desc, artifactType, func(referrers []artifactspec.Descriptor) error { for _, r := range referrers { - if artifactType == "" || artifactType == r.ArtifactType { - results = append(results, r) - if !queryGraph { - continue - } - // Find all referrers - referrerNode := node.AddPath(r.ArtifactType, r.Digest) - _, nestedReferrers, err := getAllReferences( - ctx, repo, - ocispec.Descriptor{ - Digest: r.Digest, - Size: r.Size, - MediaType: r.MediaType, - }, - artifactType, referrerNode, queryGraph) - if err != nil { - return err - } - results = append(results, nestedReferrers...) + results = append(results, r) + if !queryGraph { + continue } + // Find all referrers + referrerNode := node.AddPath(r.ArtifactType, r.Digest) + _, nestedReferrers, err := getAllReferences( + ctx, repo, + ocispec.Descriptor{ + Digest: r.Digest, + Size: r.Size, + MediaType: r.MediaType, + }, + artifactType, referrerNode, queryGraph) + if err != nil { + return err + } + results = append(results, nestedReferrers...) } return nil }) diff --git a/go.mod b/go.mod index e516e43ef..5b9013905 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.5.0 github.com/spf13/pflag v1.0.5 - oras.land/oras-go/v2 v2.0.0-alpha + oras.land/oras-go/v2 v2.0.0-20220629060154-3f83f0c01a01 ) require ( From 69aefd7315fc4e2202a3bde9f90860114313fdec Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Thu, 30 Jun 2022 13:21:29 +0800 Subject: [PATCH 19/29] Refactoring Signed-off-by: Billy Zha --- cmd/oras/discover.go | 61 ++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 7ffed75ad..1b9c461f4 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -86,7 +86,12 @@ func runDiscover(opts discoverOptions) error { if err != nil { return err } - desc, refs, err := getAllReferences(ctx, repo, desc, opts.artifactType, root, opts.outputType == "tree") + var refs []artifactspec.Descriptor + if opts.outputType == "tree" { + refs, err = fetchAllReferrers(ctx, repo, desc, opts.artifactType, root) + } else { + refs, err = fetchReferrers(ctx, repo, desc, opts.artifactType) + } if err != nil { return err } @@ -99,7 +104,6 @@ func runDiscover(opts discoverOptions) error { default: fmt.Println("Discovered", len(refs), "artifacts referencing", opts.targetRef) fmt.Println("Digest:", desc.Digest) - if len(refs) != 0 { fmt.Println() printDiscoveredReferencesTable(refs, opts.Verbose) @@ -108,35 +112,42 @@ func runDiscover(opts discoverOptions) error { return nil } -func getAllReferences(ctx context.Context, repo *remote.Repository, desc ocispec.Descriptor, artifactType string, node *tree.Node, queryGraph bool) (ocispec.Descriptor, []artifactspec.Descriptor, error) { +func fetchReferrers(ctx context.Context, repo *remote.Repository, desc ocispec.Descriptor, artifactType string) ([]artifactspec.Descriptor, error) { var results []artifactspec.Descriptor err := repo.Referrers(ctx, desc, artifactType, func(referrers []artifactspec.Descriptor) error { - for _, r := range referrers { - results = append(results, r) - if !queryGraph { - continue - } - // Find all referrers - referrerNode := node.AddPath(r.ArtifactType, r.Digest) - _, nestedReferrers, err := getAllReferences( - ctx, repo, - ocispec.Descriptor{ - Digest: r.Digest, - Size: r.Size, - MediaType: r.MediaType, - }, - artifactType, referrerNode, queryGraph) - if err != nil { - return err - } - results = append(results, nestedReferrers...) - } + results = referrers return nil }) if err != nil { - return ocispec.Descriptor{}, nil, err + return nil, err + } + return results, nil +} + +func fetchAllReferrers(ctx context.Context, repo *remote.Repository, desc ocispec.Descriptor, artifactType string, node *tree.Node) ([]artifactspec.Descriptor, error) { + var results []artifactspec.Descriptor + results, err := fetchReferrers(ctx, repo, desc, artifactType) + if err != nil { + return nil, err + } + + for _, r := range results { + // Find all indirect referrers + referrerNode := node.AddPath(r.ArtifactType, r.Digest) + nestedReferrers, err := fetchAllReferrers( + ctx, repo, + ocispec.Descriptor{ + Digest: r.Digest, + Size: r.Size, + MediaType: r.MediaType, + }, + artifactType, referrerNode) + if err != nil { + return nil, err + } + results = append(results, nestedReferrers...) } - return desc, results, nil + return results, nil } func printDiscoveredReferencesTable(refs []artifactspec.Descriptor, verbose bool) { From f7924f6744505b14f156e9984f8aaf0d541c208e Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Thu, 30 Jun 2022 13:39:28 +0800 Subject: [PATCH 20/29] Add go.sum Signed-off-by: Billy Zha --- go.sum | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.sum b/go.sum index 3087cd053..828de050f 100644 --- a/go.sum +++ b/go.sum @@ -64,5 +64,5 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -oras.land/oras-go/v2 v2.0.0-alpha h1:Uwso3p1KMTmm7YheWBkGNjf8xqXZ2AYxMfxu1DoQiH0= -oras.land/oras-go/v2 v2.0.0-alpha/go.mod h1:0IQiLwHUJuMs0+QYGavaeQWw5FD4ABD/RP5YamXT/sc= +oras.land/oras-go/v2 v2.0.0-20220629060154-3f83f0c01a01 h1:jUTJqQr+wPBDESDdRuv9Vm4xRztjhJgzYrdvRtt9HVQ= +oras.land/oras-go/v2 v2.0.0-20220629060154-3f83f0c01a01/go.mod h1:0IQiLwHUJuMs0+QYGavaeQWw5FD4ABD/RP5YamXT/sc= From 5834cb24ca6bea06e2fb4a9b4ba13d2d2ddda79b Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Thu, 30 Jun 2022 13:55:14 +0800 Subject: [PATCH 21/29] Resolve all comments Signed-off-by: Billy Zha --- cmd/oras/discover.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 1b9c461f4..5d02e5f56 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -44,9 +44,10 @@ type discoverOptions struct { func discoverCmd() *cobra.Command { var opts discoverOptions cmd := &cobra.Command{ - Use: "discover [options] ", - Short: "discover artifacts from remote registry", - Long: `discover artifacts from remote registry + Hidden: true, + Use: "discover [options] ", + Short: "Discover artifacts from remote registry", + Long: `Discover artifacts from remote registry Example - Discover all the artifacts linked with the specified reference: oras discover localhost:5000/hello From 1aa0ee59703f2f823d80651a75840cddeb607179 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Thu, 30 Jun 2022 21:36:43 +0800 Subject: [PATCH 22/29] Support pagination Signed-off-by: Billy Zha --- cmd/oras/discover.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 5d02e5f56..2100ec364 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -116,7 +116,7 @@ func runDiscover(opts discoverOptions) error { func fetchReferrers(ctx context.Context, repo *remote.Repository, desc ocispec.Descriptor, artifactType string) ([]artifactspec.Descriptor, error) { var results []artifactspec.Descriptor err := repo.Referrers(ctx, desc, artifactType, func(referrers []artifactspec.Descriptor) error { - results = referrers + results = append(results, referrers...) return nil }) if err != nil { From 681c5e12499de091401e371e55484c65c3cf1473 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Thu, 30 Jun 2022 21:40:48 +0800 Subject: [PATCH 23/29] Resolve comments Signed-off-by: Billy Zha --- cmd/oras/discover.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 2100ec364..ebda8834b 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -105,7 +105,7 @@ func runDiscover(opts discoverOptions) error { default: fmt.Println("Discovered", len(refs), "artifacts referencing", opts.targetRef) fmt.Println("Digest:", desc.Digest) - if len(refs) != 0 { + if len(refs) > 0 { fmt.Println() printDiscoveredReferencesTable(refs, opts.Verbose) } From e098eff6d512e639de5adebbe7af12915cbe726c Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Thu, 30 Jun 2022 22:29:35 +0800 Subject: [PATCH 24/29] Reword Signed-off-by: Billy Zha --- cmd/oras/discover.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index ebda8834b..7a44d96b3 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -46,16 +46,16 @@ func discoverCmd() *cobra.Command { cmd := &cobra.Command{ Hidden: true, Use: "discover [options] ", - Short: "Discover artifacts from remote registry", - Long: `Discover artifacts from remote registry + Short: "Discover referrers of a manifest in the remote registry", + Long: `Discover referrers of a manifest in the remote registry -Example - Discover all the artifacts linked with the specified reference: +Example - Discover direct referrers of manifest 'hello:latest' in registry 'localhost:5000': oras discover localhost:5000/hello -Example - Discover all the artifacts linked with the specified reference in a tree view: +Example - Discover all the referrers of manifest 'hello:latest' in registry 'localhost:5000' in a tree view: oras discover localhost:5000/hello -o tree -Example - Discover artifacts of type test-artifact test-artifact linked with the specified reference: +Example - Discover referrers with type 'test-artifact' of manifest 'hello:latest' in registry 'localhost:5000': oras discover --artifact test-artifact localhost:5000/hello `, Args: cobra.ExactArgs(1), @@ -69,7 +69,7 @@ Example - Discover artifacts of type test-artifact test-artifact linked with the } cmd.Flags().StringVarP(&opts.artifactType, "artifact-type", "", "", "artifact type") - cmd.Flags().StringVarP(&opts.outputType, "output", "o", "table", "format in which to display references (table, json, or tree). tree format will show all references including nested") + cmd.Flags().StringVarP(&opts.outputType, "output", "o", "table", "format in which to display referrers (table, json, or tree). tree format will also show indirect referrers") option.ApplyFlags(&opts, cmd.Flags()) return cmd } From 7fb6be4c27c13a4857e4a3167eb64cbe970b2878 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Fri, 1 Jul 2022 10:13:35 +0800 Subject: [PATCH 25/29] Resolve comments Signed-off-by: Billy Zha --- cmd/oras/discover.go | 47 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 7a44d96b3..20ca665c0 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -82,33 +82,34 @@ func runDiscover(opts discoverOptions) error { } // discover artifacts - root := tree.New(opts.targetRef) desc, err := repo.Resolve(ctx, repo.Reference.ReferenceOrDefault()) if err != nil { return err } - var refs []artifactspec.Descriptor + if opts.outputType == "tree" { - refs, err = fetchAllReferrers(ctx, repo, desc, opts.artifactType, root) - } else { - refs, err = fetchReferrers(ctx, repo, desc, opts.artifactType) + root := tree.New(opts.targetRef) + err = fetchAllReferrers(ctx, repo, desc, opts.artifactType, root) + if err != nil { + return err + } + return tree.Print(root) } + + refs, err := fetchReferrers(ctx, repo, desc, opts.artifactType) if err != nil { return err } - - switch opts.outputType { - case "tree": - tree.Print(root) - case "json": + if opts.outputType == "json" { printDiscoveredReferencesJSON(desc, refs) - default: - fmt.Println("Discovered", len(refs), "artifacts referencing", opts.targetRef) - fmt.Println("Digest:", desc.Digest) - if len(refs) > 0 { - fmt.Println() - printDiscoveredReferencesTable(refs, opts.Verbose) - } + return nil + } + + fmt.Println("Discovered", len(refs), "artifacts referencing", opts.targetRef) + fmt.Println("Digest:", desc.Digest) + if len(refs) > 0 { + fmt.Println() + printDiscoveredReferencesTable(refs, opts.Verbose) } return nil } @@ -125,17 +126,16 @@ func fetchReferrers(ctx context.Context, repo *remote.Repository, desc ocispec.D return results, nil } -func fetchAllReferrers(ctx context.Context, repo *remote.Repository, desc ocispec.Descriptor, artifactType string, node *tree.Node) ([]artifactspec.Descriptor, error) { - var results []artifactspec.Descriptor +func fetchAllReferrers(ctx context.Context, repo *remote.Repository, desc ocispec.Descriptor, artifactType string, node *tree.Node) error { results, err := fetchReferrers(ctx, repo, desc, artifactType) if err != nil { - return nil, err + return err } for _, r := range results { // Find all indirect referrers referrerNode := node.AddPath(r.ArtifactType, r.Digest) - nestedReferrers, err := fetchAllReferrers( + err := fetchAllReferrers( ctx, repo, ocispec.Descriptor{ Digest: r.Digest, @@ -144,11 +144,10 @@ func fetchAllReferrers(ctx context.Context, repo *remote.Repository, desc ocispe }, artifactType, referrerNode) if err != nil { - return nil, err + return err } - results = append(results, nestedReferrers...) } - return results, nil + return nil } func printDiscoveredReferencesTable(refs []artifactspec.Descriptor, verbose bool) { From 3ebdbca7f7fbee0e01b0063261ee7a2ac4974676 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Fri, 1 Jul 2022 10:20:26 +0800 Subject: [PATCH 26/29] Resolve more comments Signed-off-by: Billy Zha --- cmd/oras/discover.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 20ca665c0..39023f621 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -101,8 +101,7 @@ func runDiscover(opts discoverOptions) error { return err } if opts.outputType == "json" { - printDiscoveredReferencesJSON(desc, refs) - return nil + return printDiscoveredReferencesJSON(desc, refs) } fmt.Println("Discovered", len(refs), "artifacts referencing", opts.targetRef) @@ -172,7 +171,7 @@ func printDiscoveredReferencesTable(refs []artifactspec.Descriptor, verbose bool } } -func printDiscoveredReferencesJSON(desc ocispec.Descriptor, refs []artifactspec.Descriptor) { +func printDiscoveredReferencesJSON(desc ocispec.Descriptor, refs []artifactspec.Descriptor) error { type referrerDesc struct { Digest digest.Digest `json:"digest"` MediaType string `json:"mediaType"` @@ -180,7 +179,7 @@ func printDiscoveredReferencesJSON(desc ocispec.Descriptor, refs []artifactspec. Size int64 `json:"size"` } output := struct { - // https://github.com/oras-project/artifacts-spec/blob/main/manifest-referrers-api.md#artifact-referrers-api-results + // Reference: https://github.com/oras-project/artifacts-spec/blob/v1.0.0-rc.1/manifest-referrers-api.md#artifact-referrers-api-results Referrers []referrerDesc `json:"referrers"` }{ Referrers: make([]referrerDesc, len(refs)), @@ -195,12 +194,12 @@ func printDiscoveredReferencesJSON(desc ocispec.Descriptor, refs []artifactspec. } } - printJSON(output) + return printJSON(output) } -func printJSON(object interface{}) { +func printJSON(object interface{}) error { encoder := json.NewEncoder(os.Stdout) encoder.SetEscapeHTML(false) encoder.SetIndent("", " ") - encoder.Encode(object) + return encoder.Encode(object) } From 53855491ea658206d44991dbe5b0682efff238d9 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Fri, 1 Jul 2022 10:25:49 +0800 Subject: [PATCH 27/29] Add default prompt Signed-off-by: Billy Zha --- cmd/oras/discover.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 39023f621..38f5ad8b9 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -82,7 +82,11 @@ func runDiscover(opts discoverOptions) error { } // discover artifacts - desc, err := repo.Resolve(ctx, repo.Reference.ReferenceOrDefault()) + ref := repo.Reference.ReferenceOrDefault() + if ref != repo.Reference.Reference { + fmt.Println("Using default tag:", ref) + } + desc, err := repo.Resolve(ctx, ref) if err != nil { return err } From 1530d8a28943ec307ae90b35d3b3c48084ecbe29 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Fri, 1 Jul 2022 16:48:24 +0800 Subject: [PATCH 28/29] Add preview warning Signed-off-by: Billy Zha --- cmd/oras/discover.go | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 38f5ad8b9..6b2ff8767 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -44,10 +44,11 @@ type discoverOptions struct { func discoverCmd() *cobra.Command { var opts discoverOptions cmd := &cobra.Command{ - Hidden: true, - Use: "discover [options] ", - Short: "Discover referrers of a manifest in the remote registry", - Long: `Discover referrers of a manifest in the remote registry + Use: "discover [options] ", + Short: "[Preview] Discover referrers of a manifest in the remote registry", + Long: `[Preview] Discover referrers of a manifest in the remote registry + +** This command is in preview and under development. ** Example - Discover direct referrers of manifest 'hello:latest' in registry 'localhost:5000': oras discover localhost:5000/hello @@ -59,9 +60,6 @@ Example - Discover referrers with type 'test-artifact' of manifest 'hello:latest oras discover --artifact test-artifact localhost:5000/hello `, Args: cobra.ExactArgs(1), - PreRun: func(cmd *cobra.Command, args []string) { - fmt.Println("Command discover is in preview and might have breaking changes coming.") - }, RunE: func(cmd *cobra.Command, args []string) error { opts.targetRef = args[0] return runDiscover(opts) @@ -105,14 +103,14 @@ func runDiscover(opts discoverOptions) error { return err } if opts.outputType == "json" { - return printDiscoveredReferencesJSON(desc, refs) + return printDiscoveredReferrersJSON(desc, refs) } fmt.Println("Discovered", len(refs), "artifacts referencing", opts.targetRef) fmt.Println("Digest:", desc.Digest) if len(refs) > 0 { fmt.Println() - printDiscoveredReferencesTable(refs, opts.Verbose) + printDiscoveredReferrersTable(refs, opts.Verbose) } return nil } @@ -153,7 +151,7 @@ func fetchAllReferrers(ctx context.Context, repo *remote.Repository, desc ocispe return nil } -func printDiscoveredReferencesTable(refs []artifactspec.Descriptor, verbose bool) { +func printDiscoveredReferrersTable(refs []artifactspec.Descriptor, verbose bool) { typeNameTitle := "Artifact Type" typeNameLength := len(typeNameTitle) for _, ref := range refs { @@ -175,7 +173,9 @@ func printDiscoveredReferencesTable(refs []artifactspec.Descriptor, verbose bool } } -func printDiscoveredReferencesJSON(desc ocispec.Descriptor, refs []artifactspec.Descriptor) error { +// printDiscoveredReferrersJSON prints referrer list in JSON equivalent to the +// API result: https://github.com/oras-project/artifacts-spec/blob/v1.0.0-rc.1/manifest-referrers-api.md#artifact-referrers-api-results +func printDiscoveredReferrersJSON(desc ocispec.Descriptor, refs []artifactspec.Descriptor) error { type referrerDesc struct { Digest digest.Digest `json:"digest"` MediaType string `json:"mediaType"` @@ -183,7 +183,6 @@ func printDiscoveredReferencesJSON(desc ocispec.Descriptor, refs []artifactspec. Size int64 `json:"size"` } output := struct { - // Reference: https://github.com/oras-project/artifacts-spec/blob/v1.0.0-rc.1/manifest-referrers-api.md#artifact-referrers-api-results Referrers []referrerDesc `json:"referrers"` }{ Referrers: make([]referrerDesc, len(refs)), From fc8a6a005a7395e9a455dd40568c3c820f409725 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Fri, 1 Jul 2022 17:03:05 +0800 Subject: [PATCH 29/29] Add latest tag support Signed-off-by: Billy Zha --- cmd/oras/discover.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/oras/discover.go b/cmd/oras/discover.go index 6b2ff8767..ba05f2cbb 100644 --- a/cmd/oras/discover.go +++ b/cmd/oras/discover.go @@ -83,6 +83,7 @@ func runDiscover(opts discoverOptions) error { ref := repo.Reference.ReferenceOrDefault() if ref != repo.Reference.Reference { fmt.Println("Using default tag:", ref) + repo.Reference.Reference = ref } desc, err := repo.Resolve(ctx, ref) if err != nil { @@ -90,7 +91,7 @@ func runDiscover(opts discoverOptions) error { } if opts.outputType == "tree" { - root := tree.New(opts.targetRef) + root := tree.New(repo.Reference.String()) err = fetchAllReferrers(ctx, repo, desc, opts.artifactType, root) if err != nil { return err @@ -106,7 +107,7 @@ func runDiscover(opts discoverOptions) error { return printDiscoveredReferrersJSON(desc, refs) } - fmt.Println("Discovered", len(refs), "artifacts referencing", opts.targetRef) + fmt.Println("Discovered", len(refs), "artifacts referencing", repo.Reference) fmt.Println("Digest:", desc.Digest) if len(refs) > 0 { fmt.Println()