mirror of
https://github.com/containers/skopeo.git
synced 2025-09-03 07:35:02 +00:00
Add --format option to skopeo inspect
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
20
vendor/github.com/containers/common/pkg/report/camelcase/LICENSE.md
generated
vendored
Normal file
20
vendor/github.com/containers/common/pkg/report/camelcase/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Fatih Arslan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
58
vendor/github.com/containers/common/pkg/report/camelcase/README.md
generated
vendored
Normal file
58
vendor/github.com/containers/common/pkg/report/camelcase/README.md
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
# CamelCase [](http://godoc.org/github.com/fatih/camelcase) [](https://travis-ci.org/fatih/camelcase)
|
||||
|
||||
CamelCase is a Golang (Go) package to split the words of a camelcase type
|
||||
string into a slice of words. It can be used to convert a camelcase word (lower
|
||||
or upper case) into any type of word.
|
||||
|
||||
## Splitting rules:
|
||||
|
||||
1. If string is not valid UTF-8, return it without splitting as
|
||||
single item array.
|
||||
2. Assign all unicode characters into one of 4 sets: lower case
|
||||
letters, upper case letters, numbers, and all other characters.
|
||||
3. Iterate through characters of string, introducing splits
|
||||
between adjacent characters that belong to different sets.
|
||||
4. Iterate through array of split strings, and if a given string
|
||||
is upper case:
|
||||
* if subsequent string is lower case:
|
||||
* move last character of upper case string to beginning of
|
||||
lower case string
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/fatih/camelcase
|
||||
```
|
||||
|
||||
## Usage and examples
|
||||
|
||||
```go
|
||||
splitted := camelcase.Split("GolangPackage")
|
||||
|
||||
fmt.Println(splitted[0], splitted[1]) // prints: "Golang", "Package"
|
||||
```
|
||||
|
||||
Both lower camel case and upper camel case are supported. For more info please
|
||||
check: [http://en.wikipedia.org/wiki/CamelCase](http://en.wikipedia.org/wiki/CamelCase)
|
||||
|
||||
Below are some example cases:
|
||||
|
||||
```
|
||||
"" => []
|
||||
"lowercase" => ["lowercase"]
|
||||
"Class" => ["Class"]
|
||||
"MyClass" => ["My", "Class"]
|
||||
"MyC" => ["My", "C"]
|
||||
"HTML" => ["HTML"]
|
||||
"PDFLoader" => ["PDF", "Loader"]
|
||||
"AString" => ["A", "String"]
|
||||
"SimpleXMLParser" => ["Simple", "XML", "Parser"]
|
||||
"vimRPCPlugin" => ["vim", "RPC", "Plugin"]
|
||||
"GL11Version" => ["GL", "11", "Version"]
|
||||
"99Bottles" => ["99", "Bottles"]
|
||||
"May5" => ["May", "5"]
|
||||
"BFG9000" => ["BFG", "9000"]
|
||||
"BöseÜberraschung" => ["Böse", "Überraschung"]
|
||||
"Two spaces" => ["Two", " ", "spaces"]
|
||||
"BadUTF8\xe2\xe2\xa1" => ["BadUTF8\xe2\xe2\xa1"]
|
||||
```
|
91
vendor/github.com/containers/common/pkg/report/camelcase/camelcase.go
generated
vendored
Normal file
91
vendor/github.com/containers/common/pkg/report/camelcase/camelcase.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
// Package camelcase is a micro package to split the words of a camelcase type
|
||||
// string into a slice of words.
|
||||
package camelcase
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Split splits the camelcase word and returns a list of words. It also
|
||||
// supports digits. Both lower camel case and upper camel case are supported.
|
||||
// For more info please check: http://en.wikipedia.org/wiki/CamelCase
|
||||
//
|
||||
// Examples
|
||||
//
|
||||
// "" => [""]
|
||||
// "lowercase" => ["lowercase"]
|
||||
// "Class" => ["Class"]
|
||||
// "MyClass" => ["My", "Class"]
|
||||
// "MyC" => ["My", "C"]
|
||||
// "HTML" => ["HTML"]
|
||||
// "PDFLoader" => ["PDF", "Loader"]
|
||||
// "AString" => ["A", "String"]
|
||||
// "SimpleXMLParser" => ["Simple", "XML", "Parser"]
|
||||
// "vimRPCPlugin" => ["vim", "RPC", "Plugin"]
|
||||
// "GL11Version" => ["GL", "11", "Version"]
|
||||
// "99Bottles" => ["99", "Bottles"]
|
||||
// "May5" => ["May", "5"]
|
||||
// "BFG9000" => ["BFG", "9000"]
|
||||
// "BöseÜberraschung" => ["Böse", "Überraschung"]
|
||||
// "Two spaces" => ["Two", " ", "spaces"]
|
||||
// "BadUTF8\xe2\xe2\xa1" => ["BadUTF8\xe2\xe2\xa1"]
|
||||
//
|
||||
// Splitting rules
|
||||
//
|
||||
// 1) If string is not valid UTF-8, return it without splitting as
|
||||
// single item array.
|
||||
// 2) Assign all unicode characters into one of 4 sets: lower case
|
||||
// letters, upper case letters, numbers, and all other characters.
|
||||
// 3) Iterate through characters of string, introducing splits
|
||||
// between adjacent characters that belong to different sets.
|
||||
// 4) Iterate through array of split strings, and if a given string
|
||||
// is upper case:
|
||||
// if subsequent string is lower case:
|
||||
// move last character of upper case string to beginning of
|
||||
// lower case string
|
||||
func Split(src string) (entries []string) {
|
||||
// don't split invalid utf8
|
||||
if !utf8.ValidString(src) {
|
||||
return []string{src}
|
||||
}
|
||||
entries = []string{}
|
||||
var runes [][]rune
|
||||
lastClass := 0
|
||||
class := 0
|
||||
// split into fields based on class of unicode character
|
||||
for _, r := range src {
|
||||
switch {
|
||||
case unicode.IsLower(r):
|
||||
class = 1
|
||||
case unicode.IsUpper(r):
|
||||
class = 2
|
||||
case unicode.IsDigit(r):
|
||||
class = 3
|
||||
default:
|
||||
class = 4
|
||||
}
|
||||
if class == lastClass {
|
||||
runes[len(runes)-1] = append(runes[len(runes)-1], r)
|
||||
} else {
|
||||
runes = append(runes, []rune{r})
|
||||
}
|
||||
lastClass = class
|
||||
}
|
||||
// handle upper case -> lower case sequences, e.g.
|
||||
// "PDFL", "oader" -> "PDF", "Loader"
|
||||
for i := 0; i < len(runes)-1; i++ {
|
||||
if unicode.IsUpper(runes[i][0]) && unicode.IsLower(runes[i+1][0]) {
|
||||
runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...)
|
||||
runes[i] = runes[i][:len(runes[i])-1]
|
||||
}
|
||||
}
|
||||
// construct []string from results
|
||||
for _, s := range runes {
|
||||
if len(s) > 0 {
|
||||
entries = append(entries, string(s))
|
||||
}
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
46
vendor/github.com/containers/common/pkg/report/doc.go
generated
vendored
Normal file
46
vendor/github.com/containers/common/pkg/report/doc.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Package report provides helper structs/methods/funcs for formatting output
|
||||
|
||||
To format output for an array of structs:
|
||||
|
||||
w := report.NewWriterDefault(os.Stdout)
|
||||
defer w.Flush()
|
||||
|
||||
headers := report.Headers(struct {
|
||||
ID string
|
||||
}{}, nil)
|
||||
t, _ := report.NewTemplate("command name").Parse("{{range .}}{{.ID}}{{end}}")
|
||||
t.Execute(t, headers)
|
||||
t.Execute(t, map[string]string{
|
||||
"ID":"fa85da03b40141899f3af3de6d27852b",
|
||||
})
|
||||
// t.IsTable() == false
|
||||
|
||||
or
|
||||
|
||||
w := report.NewWriterDefault(os.Stdout)
|
||||
defer w.Flush()
|
||||
|
||||
headers := report.Headers(struct {
|
||||
CID string
|
||||
}{}, map[string]string{
|
||||
"CID":"ID"})
|
||||
t, _ := report.NewTemplate("command name").Parse("table {{.CID}}")
|
||||
t.Execute(t, headers)
|
||||
t.Execute(t,map[string]string{
|
||||
"CID":"fa85da03b40141899f3af3de6d27852b",
|
||||
})
|
||||
// t.IsTable() == true
|
||||
|
||||
Helpers:
|
||||
|
||||
if report.IsJSON(cmd.Flag("format").Value.String()) {
|
||||
... process JSON and output
|
||||
}
|
||||
|
||||
and
|
||||
|
||||
|
||||
Note: Your code should not ignore errors
|
||||
*/
|
||||
package report
|
115
vendor/github.com/containers/common/pkg/report/template.go
generated
vendored
Normal file
115
vendor/github.com/containers/common/pkg/report/template.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
package report
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/containers/common/pkg/report/camelcase"
|
||||
)
|
||||
|
||||
// Template embeds template.Template to add functionality to methods
|
||||
type Template struct {
|
||||
*template.Template
|
||||
isTable bool
|
||||
}
|
||||
|
||||
// FuncMap is aliased from template.FuncMap
|
||||
type FuncMap template.FuncMap
|
||||
|
||||
// tableReplacer will remove 'table ' prefix and clean up tabs
|
||||
var tableReplacer = strings.NewReplacer(
|
||||
"table ", "",
|
||||
`\t`, "\t",
|
||||
`\n`, "\n",
|
||||
" ", "\t",
|
||||
)
|
||||
|
||||
// escapedReplacer will clean up escaped characters from CLI
|
||||
var escapedReplacer = strings.NewReplacer(
|
||||
`\t`, "\t",
|
||||
`\n`, "\n",
|
||||
)
|
||||
|
||||
// NormalizeFormat reads given go template format provided by CLI and munges it into what we need
|
||||
func NormalizeFormat(format string) string {
|
||||
var f string
|
||||
// two replacers used so we only remove the prefix keyword `table`
|
||||
if strings.HasPrefix(format, "table ") {
|
||||
f = tableReplacer.Replace(format)
|
||||
} else {
|
||||
f = escapedReplacer.Replace(format)
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(f, "\n") {
|
||||
f += "\n"
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// Headers queries the interface for field names.
|
||||
// Array of map is returned to support range templates
|
||||
// Note: unexported fields can be supported by adding field to overrides
|
||||
// Note: It is left to the developer to write out said headers
|
||||
// Podman commands use the general rules of:
|
||||
// 1) unchanged --format includes headers
|
||||
// 2) --format '{{.ID}" # no headers
|
||||
// 3) --format 'table {{.ID}}' # includes headers
|
||||
func Headers(object interface{}, overrides map[string]string) []map[string]string {
|
||||
value := reflect.ValueOf(object)
|
||||
if value.Kind() == reflect.Ptr {
|
||||
value = value.Elem()
|
||||
}
|
||||
|
||||
// Column header will be field name upper-cased.
|
||||
headers := make(map[string]string, value.NumField())
|
||||
for i := 0; i < value.Type().NumField(); i++ {
|
||||
field := value.Type().Field(i)
|
||||
// Recurse to find field names from promoted structs
|
||||
if field.Type.Kind() == reflect.Struct && field.Anonymous {
|
||||
h := Headers(reflect.New(field.Type).Interface(), nil)
|
||||
for k, v := range h[0] {
|
||||
headers[k] = v
|
||||
}
|
||||
continue
|
||||
}
|
||||
name := strings.Join(camelcase.Split(field.Name), " ")
|
||||
headers[field.Name] = strings.ToUpper(name)
|
||||
}
|
||||
|
||||
if len(overrides) > 0 {
|
||||
// Override column header as provided
|
||||
for k, v := range overrides {
|
||||
headers[k] = strings.ToUpper(v)
|
||||
}
|
||||
}
|
||||
return []map[string]string{headers}
|
||||
}
|
||||
|
||||
// NewTemplate creates a new template object
|
||||
func NewTemplate(name string) *Template {
|
||||
return &Template{template.New(name), false}
|
||||
}
|
||||
|
||||
// Parse parses text as a template body for t
|
||||
func (t *Template) Parse(text string) (*Template, error) {
|
||||
if strings.HasPrefix(text, "table ") {
|
||||
t.isTable = true
|
||||
text = "{{range .}}" + NormalizeFormat(text) + "{{end}}"
|
||||
} else {
|
||||
text = NormalizeFormat(text)
|
||||
}
|
||||
|
||||
tt, err := t.Template.Parse(text)
|
||||
return &Template{tt, t.isTable}, err
|
||||
}
|
||||
|
||||
// Funcs adds the elements of the argument map to the template's function map
|
||||
func (t *Template) Funcs(funcMap FuncMap) *Template {
|
||||
return &Template{t.Template.Funcs(template.FuncMap(funcMap)), t.isTable}
|
||||
}
|
||||
|
||||
// IsTable returns true if format string defines a "table"
|
||||
func (t *Template) IsTable() bool {
|
||||
return t.isTable
|
||||
}
|
13
vendor/github.com/containers/common/pkg/report/validate.go
generated
vendored
Normal file
13
vendor/github.com/containers/common/pkg/report/validate.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package report
|
||||
|
||||
import "regexp"
|
||||
|
||||
var jsonRegex = regexp.MustCompile(`^\s*(json|{{\s*json\s*(\.)?\s*}})\s*$`)
|
||||
|
||||
// JSONFormat test CLI --format string to be a JSON request
|
||||
// if report.IsJSON(cmd.Flag("format").Value.String()) {
|
||||
// ... process JSON and output
|
||||
// }
|
||||
func IsJSON(s string) bool {
|
||||
return jsonRegex.MatchString(s)
|
||||
}
|
27
vendor/github.com/containers/common/pkg/report/writer.go
generated
vendored
Normal file
27
vendor/github.com/containers/common/pkg/report/writer.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package report
|
||||
|
||||
import (
|
||||
"io"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
// Writer aliases tabwriter.Writer to provide Podman defaults
|
||||
type Writer struct {
|
||||
*tabwriter.Writer
|
||||
}
|
||||
|
||||
// NewWriter initializes a new report.Writer with given values
|
||||
func NewWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) (*Writer, error) {
|
||||
t := tabwriter.NewWriter(output, minwidth, tabwidth, padding, padchar, flags)
|
||||
return &Writer{t}, nil
|
||||
}
|
||||
|
||||
// NewWriterDefault initializes a new report.Writer with Podman defaults
|
||||
func NewWriterDefault(output io.Writer) (*Writer, error) {
|
||||
return NewWriter(output, 12, 2, 2, ' ', 0)
|
||||
}
|
||||
|
||||
// Flush any output left in buffers
|
||||
func (w *Writer) Flush() error {
|
||||
return w.Writer.Flush()
|
||||
}
|
Reference in New Issue
Block a user