-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: list output handler (#1176)
Refactor: - moved the output logic of `list` command to `ListHandler` to simplify list command code logic - added `streamPrinter` to print tree node in streaming fashion Test: - improved E2E Resolve part of #1151 --------- Signed-off-by: Junjie Gao <[email protected]>
- Loading branch information
Showing
17 changed files
with
304 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// Copyright The Notary Project 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 tree | ||
|
||
import ( | ||
notationregistry "github.com/notaryproject/notation-go/registry" | ||
"github.com/notaryproject/notation/cmd/notation/internal/display/output" | ||
ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||
) | ||
|
||
// ListHandler is a handler for rendering a list of signature digests in | ||
// streaming fashion. It implements the metadata.ListHandler interface. | ||
type ListHandler struct { | ||
printer *output.Printer | ||
|
||
// sprinter is a stream printer to print the signature digest nodes in | ||
// a streaming fashion | ||
sprinter *streamPrinter | ||
|
||
// headerNode contains the headers of the output | ||
// | ||
// example: | ||
// localhost:5000/net-monitor@sha256:b94d27b9934d3e08a52e52d7da7dabfac4efe37a5380ee9088f7ace2efcde9 | ||
// └── application/vnd.cncf.notary.signature | ||
headerNode *node | ||
|
||
// headerPrinted is a flag to indicate if the header has been printed | ||
headerPrinted bool | ||
} | ||
|
||
// NewListHandler creates a new ListHandler. | ||
func NewListHandler(printer *output.Printer) *ListHandler { | ||
return &ListHandler{ | ||
printer: printer, | ||
sprinter: newStreamPrinter(subTreePrefixLast, printer), | ||
} | ||
} | ||
|
||
// OnReferenceResolved sets the artifact reference and media type for the | ||
// handler. | ||
func (h *ListHandler) OnReferenceResolved(reference string) { | ||
h.headerNode = newNode(reference) | ||
h.headerNode.Add(notationregistry.ArtifactTypeNotation) | ||
} | ||
|
||
// OnSignatureListed adds the signature digest to be printed. | ||
func (h *ListHandler) OnSignatureListed(signatureManifest ocispec.Descriptor) error { | ||
// print the header | ||
if !h.headerPrinted { | ||
if err := h.headerNode.Print(h.printer); err != nil { | ||
return err | ||
} | ||
h.headerPrinted = true | ||
} | ||
return h.sprinter.PrintNode(newNode(signatureManifest.Digest.String())) | ||
} | ||
|
||
// Render completes the rendering of the list of signature digests. | ||
func (h *ListHandler) Render() error { | ||
if err := h.sprinter.Flush(); err != nil { | ||
return err | ||
} | ||
if !h.headerPrinted { | ||
return h.printer.Printf("%s has no associated signatures\n", h.headerNode.Value) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Copyright The Notary Project 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 tree | ||
|
||
import "io" | ||
|
||
// streamPrinter prints the tree nodes in a streaming fashion. | ||
type streamPrinter struct { | ||
w io.Writer | ||
prefix string | ||
prevNode *node | ||
} | ||
|
||
// newStreamPrinter creates a new stream printer. | ||
// | ||
// prefix is the prefix string that will be inherited by the nodes that are | ||
// printed. | ||
func newStreamPrinter(prefix string, w io.Writer) *streamPrinter { | ||
return &streamPrinter{ | ||
w: w, | ||
prefix: prefix, | ||
} | ||
} | ||
|
||
// PrintNode adds a new node to be ready to print. | ||
func (p *streamPrinter) PrintNode(node *node) error { | ||
if p.prevNode == nil { | ||
p.prevNode = node | ||
return nil | ||
} | ||
if err := print(p.w, p.prefix, treeItemPrefix, p.prefix+subTreePrefix, p.prevNode); err != nil { | ||
return err | ||
} | ||
p.prevNode = node | ||
return nil | ||
} | ||
|
||
// Flush prints the last node and completes the printing. | ||
func (p *streamPrinter) Flush() error { | ||
if p.prevNode != nil { | ||
// print the last node | ||
return print(p.w, p.prefix, treeItemPrefixLast, p.prefix+subTreePrefixLast, p.prevNode) | ||
} | ||
return nil | ||
} |
123 changes: 123 additions & 0 deletions
123
cmd/notation/internal/display/metadata/tree/printer_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// Copyright The Notary Project 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 tree | ||
|
||
import ( | ||
"bytes" | ||
"testing" | ||
) | ||
|
||
func TestStreamingPrinter(t *testing.T) { | ||
t.Run("empty output", func(t *testing.T) { | ||
expected := "" | ||
buff := &bytes.Buffer{} | ||
p := newStreamPrinter("", buff) | ||
p.Flush() | ||
|
||
if buff.String() != expected { | ||
t.Fatalf("expected %s, got %s", expected, buff.String()) | ||
} | ||
}) | ||
|
||
t.Run("one node", func(t *testing.T) { | ||
expected := "└── a\n" | ||
buff := &bytes.Buffer{} | ||
p := newStreamPrinter("", buff) | ||
p.PrintNode(newNode("a")) | ||
p.Flush() | ||
|
||
if buff.String() != expected { | ||
t.Fatalf("expected %s, got %s", expected, buff.String()) | ||
} | ||
}) | ||
|
||
t.Run("two nodes", func(t *testing.T) { | ||
expected := `├── a | ||
└── b | ||
` | ||
buff := &bytes.Buffer{} | ||
p := newStreamPrinter("", buff) | ||
p.PrintNode(newNode("a")) | ||
p.PrintNode(newNode("b")) | ||
p.Flush() | ||
|
||
if buff.String() != expected { | ||
t.Fatalf("expected %s, got %s", expected, buff.String()) | ||
} | ||
}) | ||
|
||
t.Run("two node with complex structure", func(t *testing.T) { | ||
expected := `├── a | ||
│ ├── b | ||
│ │ └── c | ||
│ └── d | ||
└── e | ||
├── f | ||
│ └── g | ||
└── h | ||
` | ||
buff := &bytes.Buffer{} | ||
p := newStreamPrinter("", buff) | ||
// create the tree | ||
a := newNode("a") | ||
b := a.Add("b") | ||
b.Add("c") | ||
a.Add("d") | ||
p.PrintNode(a) | ||
|
||
e := newNode("e") | ||
f := e.Add("f") | ||
f.Add("g") | ||
e.Add("h") | ||
p.PrintNode(e) | ||
|
||
p.Flush() | ||
|
||
if buff.String() != expected { | ||
t.Fatalf("expected %s, got %s", expected, buff.String()) | ||
} | ||
}) | ||
|
||
t.Run("two node with prefix", func(t *testing.T) { | ||
expected := ` │ ├── a | ||
│ │ ├── b | ||
│ │ │ └── c | ||
│ │ └── d | ||
│ └── e | ||
│ ├── f | ||
│ │ └── g | ||
│ └── h | ||
` | ||
buff := &bytes.Buffer{} | ||
p := newStreamPrinter(" │ ", buff) | ||
// create the tree | ||
a := newNode("a") | ||
b := a.Add("b") | ||
b.Add("c") | ||
a.Add("d") | ||
p.PrintNode(a) | ||
|
||
e := newNode("e") | ||
f := e.Add("f") | ||
f.Add("g") | ||
e.Add("h") | ||
p.PrintNode(e) | ||
|
||
p.Flush() | ||
|
||
if buff.String() != expected { | ||
t.Fatalf("expected %s, got %s", expected, buff.String()) | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.