From 4b4bba25debda36eed7447cacf77b2742aef0612 Mon Sep 17 00:00:00 2001 From: Horiodino Date: Sun, 5 Jan 2025 15:48:44 +0530 Subject: [PATCH] added --format tree-full flag Signed-off-by: Horiodino --- cmd/oras/internal/display/handler.go | 3 + .../display/metadata/fulltree/discover.go | 92 +++++++++++++++++++ cmd/oras/internal/option/format.go | 5 + cmd/oras/root/discover.go | 1 + 4 files changed, 101 insertions(+) create mode 100644 cmd/oras/internal/display/metadata/fulltree/discover.go diff --git a/cmd/oras/internal/display/handler.go b/cmd/oras/internal/display/handler.go index 56bb9700c..b243287d6 100644 --- a/cmd/oras/internal/display/handler.go +++ b/cmd/oras/internal/display/handler.go @@ -25,6 +25,7 @@ import ( "oras.land/oras/cmd/oras/internal/display/content" "oras.land/oras/cmd/oras/internal/display/metadata" "oras.land/oras/cmd/oras/internal/display/metadata/descriptor" + "oras.land/oras/cmd/oras/internal/display/metadata/fulltree" "oras.land/oras/cmd/oras/internal/display/metadata/json" "oras.land/oras/cmd/oras/internal/display/metadata/table" "oras.land/oras/cmd/oras/internal/display/metadata/template" @@ -117,6 +118,8 @@ func NewDiscoverHandler(out io.Writer, format option.Format, path string, rawRef switch format.Type { case option.FormatTypeTree.Name: handler = tree.NewDiscoverHandler(out, path, desc, verbose) + case option.FormatTypeTreeFull.Name: + handler = fulltree.NewDiscoverHandler(out, path, desc, verbose) case option.FormatTypeTable.Name: handler = table.NewDiscoverHandler(out, rawReference, desc, verbose) case option.FormatTypeJSON.Name: diff --git a/cmd/oras/internal/display/metadata/fulltree/discover.go b/cmd/oras/internal/display/metadata/fulltree/discover.go new file mode 100644 index 000000000..c3fef4391 --- /dev/null +++ b/cmd/oras/internal/display/metadata/fulltree/discover.go @@ -0,0 +1,92 @@ +package fulltree + +/* +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. +*/ + +import ( + "fmt" + "io" + "strings" + + "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "oras.land/oras/cmd/oras/internal/display/metadata" + "oras.land/oras/internal/tree" +) + +// discoverHandler handles json metadata output for discover events. +type discoverHandler struct { + out io.Writer + path string + root *tree.Node + nodes map[digest.Digest]*tree.Node + verbose bool +} + +// NewDiscoverHandler creates a new handler for discover events. +func NewDiscoverHandler(out io.Writer, path string, root ocispec.Descriptor, verbose bool) metadata.DiscoverHandler { + treeRoot := tree.New(fmt.Sprintf("%s@%s", path, root.Digest)) + return &discoverHandler{ + out: out, + path: path, + root: treeRoot, + nodes: map[digest.Digest]*tree.Node{ + root.Digest: treeRoot, + }, + verbose: verbose, + } +} + +// MultiLevelSupported implements metadata.DiscoverHandler. +func (h *discoverHandler) MultiLevelSupported() bool { + return true +} + +// OnDiscovered implements metadata.DiscoverHandler. +func (h *discoverHandler) OnDiscovered(referrer, subject ocispec.Descriptor) error { + node, ok := h.nodes[subject.Digest] + if !ok { + return fmt.Errorf("unexpected subject descriptor: %v", subject) + } + + referrerNode := node.AddPath(fmt.Sprintf("ArtifactType: %s", referrer.ArtifactType), fmt.Sprintf("Digest: %s", referrer.Digest)) + + referrerNode.AddPath(fmt.Sprintf("MediaType: %s", referrer.MediaType)) + referrerNode.AddPath(fmt.Sprintf("Size: %d bytes", referrer.Size)) + if len(referrer.URLs) > 0 { + referrerNode.AddPath(fmt.Sprintf("URLs: %s", strings.Join(referrer.URLs, ", "))) + } + if len(referrer.Data) > 0 { + referrerNode.AddPath(fmt.Sprintf("Data: %s", string(referrer.Data))) + } + if referrer.Platform != nil { + referrerNode.AddPath(fmt.Sprintf("Platform: OS=%s, Architecture=%s, OSVersion=%s, Variant=%s", + referrer.Platform.OS, referrer.Platform.Architecture, referrer.Platform.OSVersion, referrer.Platform.Variant)) + if len(referrer.Platform.OSFeatures) > 0 { + referrerNode.AddPath(fmt.Sprintf("Platform OSFeatures: %s", strings.Join(referrer.Platform.OSFeatures, ", "))) + } + } + for k, v := range referrer.Annotations { + referrerNode.AddPath(fmt.Sprintf("Annotation: %s = %s", k, v)) + } + + h.nodes[referrer.Digest] = referrerNode + return nil +} + +// OnCompleted implements metadata.DiscoverHandler. +func (h *discoverHandler) OnCompleted() error { + return tree.NewPrinter(h.out).Print(h.root) +} diff --git a/cmd/oras/internal/option/format.go b/cmd/oras/internal/option/format.go index 76acdc105..bb47ffb93 100644 --- a/cmd/oras/internal/option/format.go +++ b/cmd/oras/internal/option/format.go @@ -68,6 +68,11 @@ var ( Name: "text", Usage: "Print in text format", } + + FormatTypeTreeFull = &FormatType{ + Name: "tree-full", + Usage: "Display a full tree view with detailed metadata output", + } ) // Format contains input and parsed options for formatted output flags. diff --git a/cmd/oras/root/discover.go b/cmd/oras/root/discover.go index e65817b57..36fb3673b 100644 --- a/cmd/oras/root/discover.go +++ b/cmd/oras/root/discover.go @@ -105,6 +105,7 @@ Example - Discover referrers of the manifest tagged 'v1' in an OCI image layout cmd.Flags().BoolVarP(&opts.verbose, "verbose", "v", false, "display full metadata of referrers") opts.SetTypes( option.FormatTypeTree, + option.FormatTypeTreeFull.WithUsage("Display a full tree view including indirect referrers with metadata"), option.FormatTypeTable, option.FormatTypeJSON.WithUsage("Get direct referrers and output in JSON format"), option.FormatTypeGoTemplate.WithUsage("Print direct referrers using the given Go template"),