forked from containers/common
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor report package to be more compatible
* Add additional replacer for ('\', 'n') -> "\n" * New type Formatter embeds Template and writer/tabwriter handling * tabwriter.Init() is exposed to allow updating the tabwriter settings Note: If template origin is OriginPodman or has "table" keyword prefix output will be filtered through tabwriter. Otherwise, output will be rendered using given writer. Note: Once all podman commands have been updated a follow on PR will remove the old report.Template and report.Writer code. See containers/podman#10974 Signed-off-by: Jhon Honce <[email protected]>
- Loading branch information
Showing
5 changed files
with
373 additions
and
18 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package report | ||
|
||
import ( | ||
"io" | ||
"strings" | ||
"text/tabwriter" | ||
"text/template" | ||
) | ||
|
||
// Flusher is the interface that wraps the Flush method. | ||
type Flusher interface { | ||
Flush() error | ||
} | ||
|
||
// NopFlusher represents a type which flush operation is nop. | ||
type NopFlusher struct{} | ||
|
||
// Flush is a nop operation. | ||
func (f *NopFlusher) Flush() (err error) { return } | ||
|
||
type Origin int | ||
|
||
const ( | ||
OriginUnknown Origin = iota | ||
OriginPodman | ||
OriginUser | ||
) | ||
|
||
func (o Origin) String() string { | ||
switch o { | ||
case OriginPodman: | ||
return "OriginPodman" | ||
case OriginUser: | ||
return "OriginUser" | ||
default: | ||
return "OriginUnknown" | ||
} | ||
} | ||
|
||
// Formatter holds the configured Writer and parsed Template, additional state fields are | ||
// maintained to assist in the podman command report writing. | ||
type Formatter struct { | ||
io.Writer // Destination for formatted output | ||
Flusher // Flush any buffered formatted output | ||
*template.Template // Go text/template for formatting output | ||
RenderTable bool // Does template have "table" keyword | ||
RenderHeaders bool // default behavior for given template is to include headers | ||
Origin Origin // Source of go template. OriginUser or OriginPodman | ||
text string | ||
} | ||
|
||
// Parse parses golang template returning a formatter | ||
// | ||
// - OriginPodman implies text is a template from podman code. Output will | ||
// be filtered through a tabwriter. | ||
// | ||
// - OriginUser implies text is a template from a user. If template includes | ||
// keyword "table" output will be filtered through a tabwriter. | ||
func (f *Formatter) Parse(origin Origin, text string) (*Formatter, error) { | ||
f.Origin = origin | ||
|
||
if strings.HasPrefix(text, "table ") { | ||
f.RenderTable = true | ||
text = "{{range .}}" + NormalizeFormat(text) + "{{end -}}" | ||
} else { | ||
text = NormalizeFormat(text) | ||
} | ||
f.text = text | ||
|
||
if f.RenderTable || origin == OriginPodman { | ||
tw := tabwriter.NewWriter(f.Writer, 12, 2, 2, ' ', tabwriter.StripEscape) | ||
f.Writer = tw | ||
f.Flusher = tw | ||
f.RenderHeaders = true | ||
} | ||
|
||
tmpl, err := f.Template.Funcs(template.FuncMap(DefaultFuncs)).Parse(text) | ||
if err != nil { | ||
return f, err | ||
} | ||
f.Template = tmpl | ||
return f, nil | ||
} | ||
|
||
// Funcs adds the elements of the argument map to the template's function map. | ||
// A default template function will be replaced if there is a key collision. | ||
func (f *Formatter) Funcs(funcMap template.FuncMap) *Formatter { | ||
m := make(template.FuncMap, len(DefaultFuncs)+len(funcMap)) | ||
for k, v := range DefaultFuncs { | ||
m[k] = v | ||
} | ||
for k, v := range funcMap { | ||
m[k] = v | ||
} | ||
f.Template = f.Template.Funcs(funcMap) | ||
return f | ||
} | ||
|
||
// Init either resets the given tabwriter with new values or wraps w in tabwriter with given values | ||
func (f *Formatter) Init(w io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Formatter { | ||
flags |= tabwriter.StripEscape | ||
|
||
if tw, ok := f.Writer.(*tabwriter.Writer); ok { | ||
tw = tw.Init(w, minwidth, tabwidth, padding, padchar, flags) | ||
f.Writer = tw | ||
f.Flusher = tw | ||
} else { | ||
tw = tabwriter.NewWriter(w, minwidth, tabwidth, padding, padchar, flags) | ||
f.Writer = tw | ||
f.Flusher = tw | ||
} | ||
return f | ||
} | ||
|
||
// Execute applies a parsed template to the specified data object, | ||
// and writes the output to f.Writer. | ||
func (f *Formatter) Execute(data interface{}) error { | ||
return f.Template.Execute(f.Writer, data) | ||
} | ||
|
||
// New allocates a new, undefined Formatter with the given name and Writer | ||
func New(output io.Writer, name string) *Formatter { | ||
f := new(Formatter) | ||
|
||
f.Flusher = new(NopFlusher) | ||
if flusher, ok := output.(Flusher); ok { | ||
f.Flusher = flusher | ||
} | ||
|
||
f.Template = template.New(name) | ||
f.Writer = output | ||
return f | ||
} |
Oops, something went wrong.