Merge pull request #6242 from nalind/common-formats
Use containers/common's formats package instead of our own
This commit is contained in:
commit
9f6205610c
|
|
@ -8,8 +8,8 @@ import (
|
|||
|
||||
"github.com/containers/buildah"
|
||||
"github.com/containers/buildah/define"
|
||||
"github.com/containers/buildah/pkg/formats"
|
||||
"github.com/containers/buildah/util"
|
||||
"github.com/containers/common/pkg/formats"
|
||||
"github.com/containers/storage"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ import (
|
|||
"time"
|
||||
|
||||
buildahcli "github.com/containers/buildah/pkg/cli"
|
||||
"github.com/containers/buildah/pkg/formats"
|
||||
"github.com/containers/buildah/pkg/parse"
|
||||
"github.com/containers/common/libimage"
|
||||
"github.com/containers/common/pkg/formats"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import (
|
|||
"os"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"text/template"
|
||||
|
||||
"github.com/containers/buildah"
|
||||
"github.com/containers/buildah/define"
|
||||
"github.com/containers/common/pkg/formats"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
|
@ -71,7 +71,7 @@ func infoCmd(c *cobra.Command, iopts infoResults) error {
|
|||
} else if !matched {
|
||||
return fmt.Errorf("invalid format provided: %s", format)
|
||||
}
|
||||
t, err := template.New("format").Parse(format)
|
||||
t, err := formats.NewParse("info", format)
|
||||
if err != nil {
|
||||
return fmt.Errorf("template parsing error: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"text/template"
|
||||
|
||||
"github.com/containers/buildah"
|
||||
buildahcli "github.com/containers/buildah/pkg/cli"
|
||||
"github.com/containers/buildah/pkg/parse"
|
||||
"github.com/containers/common/pkg/formats"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
|
@ -113,7 +113,7 @@ func inspectCmd(c *cobra.Command, args []string, iopts inspectResults) error {
|
|||
} else if !matched {
|
||||
return fmt.Errorf("invalid format provided: %s", format)
|
||||
}
|
||||
t, err := template.New("format").Parse(format)
|
||||
t, err := formats.NewParse("inspect", format)
|
||||
if err != nil {
|
||||
return fmt.Errorf("template parsing error: %w", err)
|
||||
}
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -41,7 +41,6 @@ require (
|
|||
golang.org/x/sync v0.15.0
|
||||
golang.org/x/sys v0.33.0
|
||||
golang.org/x/term v0.32.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
tags.cncf.io/container-device-interface v1.0.1
|
||||
)
|
||||
|
||||
|
|
@ -156,5 +155,6 @@ require (
|
|||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/klog v1.0.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
tags.cncf.io/container-device-interface/specs-go v1.0.0 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
// The formats package is an API compatibility wrapper which merely calls into github.com/containers/common/pkg/formats. Newer code should instead call that package directly.
|
||||
package formats
|
||||
|
|
@ -1,166 +1,30 @@
|
|||
package formats
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
|
||||
"golang.org/x/term"
|
||||
"sigs.k8s.io/yaml"
|
||||
"github.com/containers/common/pkg/formats"
|
||||
)
|
||||
|
||||
const (
|
||||
// JSONString const to save on duplicate variable names
|
||||
JSONString = "json"
|
||||
JSONString = formats.JSONString
|
||||
// IDString const to save on duplicates for Go templates
|
||||
IDString = "{{.ID}}"
|
||||
|
||||
parsingErrorStr = "Template parsing error"
|
||||
IDString = formats.IDString
|
||||
)
|
||||
|
||||
// Writer interface for outputs
|
||||
type Writer interface {
|
||||
Out() error
|
||||
}
|
||||
type Writer = formats.Writer
|
||||
|
||||
// JSONStructArray for JSON output
|
||||
type JSONStructArray struct {
|
||||
Output []any
|
||||
}
|
||||
type JSONStructArray = formats.JSONStructArray
|
||||
|
||||
// StdoutTemplateArray for Go template output
|
||||
type StdoutTemplateArray struct {
|
||||
Output []any
|
||||
Template string
|
||||
Fields map[string]string
|
||||
}
|
||||
type StdoutTemplateArray = formats.StdoutTemplateArray
|
||||
|
||||
// JSONStruct for JSON output
|
||||
type JSONStruct struct {
|
||||
Output any
|
||||
}
|
||||
type JSONStruct = formats.JSONStruct
|
||||
|
||||
// StdoutTemplate for Go template output
|
||||
type StdoutTemplate struct {
|
||||
Output any
|
||||
Template string
|
||||
Fields map[string]string
|
||||
}
|
||||
type StdoutTemplate = formats.StdoutTemplate
|
||||
|
||||
// YAMLStruct for YAML output
|
||||
type YAMLStruct struct {
|
||||
Output any
|
||||
}
|
||||
|
||||
func setJSONFormatEncoder(isTerminal bool, w io.Writer) *json.Encoder {
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetIndent("", " ")
|
||||
if isTerminal {
|
||||
enc.SetEscapeHTML(false)
|
||||
}
|
||||
return enc
|
||||
}
|
||||
|
||||
// Out method for JSON Arrays
|
||||
func (j JSONStructArray) Out() error {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := setJSONFormatEncoder(term.IsTerminal(int(os.Stdout.Fd())), buf)
|
||||
if err := enc.Encode(j.Output); err != nil {
|
||||
return err
|
||||
}
|
||||
data := buf.Bytes()
|
||||
|
||||
// JSON returns a byte array with a literal null [110 117 108 108] in it
|
||||
// if it is passed empty data. We used bytes.Compare to see if that is
|
||||
// the case.
|
||||
if diff := bytes.Compare(data, []byte("null")); diff == 0 {
|
||||
data = []byte("[]")
|
||||
}
|
||||
|
||||
// If the we did get NULL back, we should spit out {} which is
|
||||
// at least valid JSON for the consumer.
|
||||
fmt.Printf("%s", data)
|
||||
humanNewLine()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Out method for Go templates
|
||||
func (t StdoutTemplateArray) Out() error {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
|
||||
if strings.HasPrefix(t.Template, "table") {
|
||||
// replace any spaces with tabs in template so that tabwriter can align it
|
||||
t.Template = strings.ReplaceAll(strings.TrimSpace(t.Template[5:]), " ", "\t")
|
||||
headerTmpl, err := template.New("header").Funcs(headerFunctions).Parse(t.Template)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v: %w", parsingErrorStr, err)
|
||||
}
|
||||
err = headerTmpl.Execute(w, t.Fields)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(w, "")
|
||||
}
|
||||
t.Template = strings.ReplaceAll(t.Template, " ", "\t")
|
||||
tmpl, err := template.New("image").Funcs(basicFunctions).Parse(t.Template)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v: %w", parsingErrorStr, err)
|
||||
}
|
||||
for _, raw := range t.Output {
|
||||
basicTmpl := tmpl.Funcs(basicFunctions)
|
||||
if err := basicTmpl.Execute(w, raw); err != nil {
|
||||
return fmt.Errorf("%v: %w", parsingErrorStr, err)
|
||||
}
|
||||
fmt.Fprintln(w, "")
|
||||
}
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
// Out method for JSON struct
|
||||
func (j JSONStruct) Out() error {
|
||||
data, err := json.MarshalIndent(j.Output, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s", data)
|
||||
humanNewLine()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Out method for Go templates
|
||||
func (t StdoutTemplate) Out() error {
|
||||
tmpl, err := template.New("image").Parse(t.Template)
|
||||
if err != nil {
|
||||
return fmt.Errorf("template parsing error: %w", err)
|
||||
}
|
||||
err = tmpl.Execute(os.Stdout, t.Output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
humanNewLine()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Out method for YAML
|
||||
func (y YAMLStruct) Out() error {
|
||||
var buf []byte
|
||||
var err error
|
||||
buf, err = yaml.Marshal(y.Output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s", string(buf))
|
||||
humanNewLine()
|
||||
return nil
|
||||
}
|
||||
|
||||
// humanNewLine prints a new line at the end of the output only if stdout is the terminal
|
||||
func humanNewLine() {
|
||||
if term.IsTerminal(int(os.Stdout.Fd())) {
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
type YAMLStruct = formats.YAMLStruct
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
package formats
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type ImageData struct {
|
||||
Author string `json:"Author"`
|
||||
}
|
||||
|
||||
func TestSetJSONFormatEncoder(t *testing.T) {
|
||||
t.Parallel()
|
||||
tt := []struct {
|
||||
name string
|
||||
imageData *ImageData
|
||||
expected string
|
||||
isTerminal bool
|
||||
}{
|
||||
{
|
||||
name: "HTML tags are not escaped",
|
||||
imageData: &ImageData{Author: "dave <dave@corp.io>"},
|
||||
expected: `"Author": "dave <dave@corp.io>"`,
|
||||
isTerminal: true,
|
||||
},
|
||||
{
|
||||
name: "HTML tags are escaped",
|
||||
imageData: &ImageData{Author: "dave <dave@corp.io>"},
|
||||
expected: `"Author": "dave \u003cdave@corp.io\u003e"`,
|
||||
isTerminal: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := setJSONFormatEncoder(tc.isTerminal, buf)
|
||||
if err := enc.Encode(tc.imageData); err != nil {
|
||||
t.Errorf("test %#v failed encoding: %s", tc.name, err)
|
||||
}
|
||||
if !strings.Contains(buf.String(), tc.expected) {
|
||||
t.Errorf("test %#v expected output to contain %#v. Output:\n%v\n", tc.name, tc.expected, buf.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +1,19 @@
|
|||
package formats
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/containers/common/pkg/formats"
|
||||
)
|
||||
|
||||
// basicFunctions are the set of initial
|
||||
// functions provided to every template.
|
||||
var basicFunctions = template.FuncMap{
|
||||
"json": func(v any) string {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := json.NewEncoder(buf)
|
||||
enc.SetEscapeHTML(false)
|
||||
_ = enc.Encode(v)
|
||||
// Remove the trailing new line added by the encoder
|
||||
return strings.TrimSpace(buf.String())
|
||||
},
|
||||
"split": strings.Split,
|
||||
"join": strings.Join,
|
||||
// strings.Title is deprecated since go 1.18
|
||||
// However for our use case it is still fine. The recommended replacement
|
||||
// is adding about 400kb binary size so lets keep using this for now.
|
||||
//nolint:staticcheck
|
||||
"title": strings.Title,
|
||||
"lower": strings.ToLower,
|
||||
"upper": strings.ToUpper,
|
||||
"pad": padWithSpace,
|
||||
"truncate": truncateWithLength,
|
||||
}
|
||||
|
||||
// HeaderFunctions are used to created headers of a table.
|
||||
// This is a replacement of basicFunctions for header generation
|
||||
// because we want the header to remain intact.
|
||||
// Some functions like `split` are irrelevant so not added.
|
||||
var headerFunctions = template.FuncMap{
|
||||
"json": func(v string) string {
|
||||
return v
|
||||
},
|
||||
"title": func(v string) string {
|
||||
return v
|
||||
},
|
||||
"lower": func(v string) string {
|
||||
return v
|
||||
},
|
||||
"upper": func(v string) string {
|
||||
return v
|
||||
},
|
||||
"truncate": func(v string, _ int) string {
|
||||
return v
|
||||
},
|
||||
}
|
||||
|
||||
// Parse creates a new anonymous template with the basic functions
|
||||
// and parses the given format.
|
||||
func Parse(format string) (*template.Template, error) {
|
||||
return NewParse("", format)
|
||||
return formats.Parse(format)
|
||||
}
|
||||
|
||||
// NewParse creates a new tagged template with the basic functions
|
||||
// and parses the given format.
|
||||
func NewParse(tag, format string) (*template.Template, error) {
|
||||
return template.New(tag).Funcs(basicFunctions).Parse(format)
|
||||
}
|
||||
|
||||
// padWithSpace adds whitespace to the input if the input is non-empty
|
||||
func padWithSpace(source string, prefix, suffix int) string {
|
||||
if source == "" {
|
||||
return source
|
||||
}
|
||||
return strings.Repeat(" ", prefix) + source + strings.Repeat(" ", suffix)
|
||||
}
|
||||
|
||||
// truncateWithLength truncates the source string up to the length provided by the input
|
||||
func truncateWithLength(source string, length int) string {
|
||||
if len(source) < length {
|
||||
return source
|
||||
}
|
||||
return source[:length]
|
||||
return formats.NewParse(tag, format)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ load helpers
|
|||
run_buildah inspect --type image --format '{{.OCIv1.Config}}' alpine-image
|
||||
inspect_after_commit=$output
|
||||
|
||||
# ...except that at some point in November 2019 buildah-inspect started
|
||||
# including version. Strip it out,
|
||||
# ...except that in #2510/#3036/#3829 we started adding a label with
|
||||
# buildah's version. Strip it out for comparison.
|
||||
run_buildah --version
|
||||
local -a output_fields=($output)
|
||||
buildah_version=${output_fields[2]}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,166 @@
|
|||
package formats
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
|
||||
terminal "golang.org/x/term"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
const (
|
||||
// JSONString const to save on duplicate variable names
|
||||
JSONString = "json"
|
||||
// IDString const to save on duplicates for Go templates
|
||||
IDString = "{{.ID}}"
|
||||
|
||||
parsingErrorStr = "Template parsing error"
|
||||
)
|
||||
|
||||
// Writer interface for outputs
|
||||
type Writer interface {
|
||||
Out() error
|
||||
}
|
||||
|
||||
// JSONStructArray for JSON output
|
||||
type JSONStructArray struct {
|
||||
Output []any
|
||||
}
|
||||
|
||||
// StdoutTemplateArray for Go template output
|
||||
type StdoutTemplateArray struct {
|
||||
Output []any
|
||||
Template string
|
||||
Fields map[string]string
|
||||
}
|
||||
|
||||
// JSONStruct for JSON output
|
||||
type JSONStruct struct {
|
||||
Output any
|
||||
}
|
||||
|
||||
// StdoutTemplate for Go template output
|
||||
type StdoutTemplate struct {
|
||||
Output any
|
||||
Template string
|
||||
Fields map[string]string
|
||||
}
|
||||
|
||||
// YAMLStruct for YAML output
|
||||
type YAMLStruct struct {
|
||||
Output any
|
||||
}
|
||||
|
||||
func setJSONFormatEncoder(isTerminal bool, w io.Writer) *json.Encoder {
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetIndent("", " ")
|
||||
if isTerminal {
|
||||
enc.SetEscapeHTML(false)
|
||||
}
|
||||
return enc
|
||||
}
|
||||
|
||||
// Out method for JSON Arrays
|
||||
func (j JSONStructArray) Out() error {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := setJSONFormatEncoder(terminal.IsTerminal(int(os.Stdout.Fd())), buf)
|
||||
if err := enc.Encode(j.Output); err != nil {
|
||||
return err
|
||||
}
|
||||
data := buf.Bytes()
|
||||
|
||||
// JSON returns a byte array with a literal null [110 117 108 108] in it
|
||||
// if it is passed empty data. We used bytes.Compare to see if that is
|
||||
// the case.
|
||||
if diff := bytes.Compare(data, []byte("null")); diff == 0 {
|
||||
data = []byte("[]")
|
||||
}
|
||||
|
||||
// If the we did get NULL back, we should spit out {} which is
|
||||
// at least valid JSON for the consumer.
|
||||
fmt.Printf("%s", data) //nolint:forbidigo
|
||||
humanNewLine()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Out method for Go templates
|
||||
func (t StdoutTemplateArray) Out() error {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
|
||||
if strings.HasPrefix(t.Template, "table") {
|
||||
// replace any spaces with tabs in template so that tabwriter can align it
|
||||
t.Template = strings.ReplaceAll(strings.TrimSpace(t.Template[5:]), " ", "\t")
|
||||
headerTmpl, err := template.New("header").Funcs(headerFunctions).Parse(t.Template)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", parsingErrorStr, err)
|
||||
}
|
||||
err = headerTmpl.Execute(w, t.Fields)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(w, "")
|
||||
}
|
||||
t.Template = strings.ReplaceAll(t.Template, " ", "\t")
|
||||
tmpl, err := template.New("image").Funcs(basicFunctions).Parse(t.Template)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", parsingErrorStr, err)
|
||||
}
|
||||
for _, raw := range t.Output {
|
||||
basicTmpl := tmpl.Funcs(basicFunctions)
|
||||
if err := basicTmpl.Execute(w, raw); err != nil {
|
||||
return fmt.Errorf("%s: %w", parsingErrorStr, err)
|
||||
}
|
||||
fmt.Fprintln(w, "")
|
||||
}
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
// Out method for JSON struct
|
||||
func (j JSONStruct) Out() error {
|
||||
data, err := json.MarshalIndent(j.Output, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s", data) //nolint:forbidigo
|
||||
humanNewLine()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Out method for Go templates
|
||||
func (t StdoutTemplate) Out() error {
|
||||
tmpl, err := template.New("image").Parse(t.Template)
|
||||
if err != nil {
|
||||
return fmt.Errorf("template parsing error: %w", err)
|
||||
}
|
||||
err = tmpl.Execute(os.Stdout, t.Output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
humanNewLine()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Out method for YAML
|
||||
func (y YAMLStruct) Out() error {
|
||||
var buf []byte
|
||||
var err error
|
||||
buf, err = yaml.Marshal(y.Output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s", string(buf)) //nolint:forbidigo
|
||||
humanNewLine()
|
||||
return nil
|
||||
}
|
||||
|
||||
// humanNewLine prints a new line at the end of the output only if stdout is the terminal
|
||||
func humanNewLine() {
|
||||
if terminal.IsTerminal(int(os.Stdout.Fd())) {
|
||||
fmt.Println() //nolint:forbidigo
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package formats
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// basicFunctions are the set of initial
|
||||
// functions provided to every template.
|
||||
var basicFunctions = template.FuncMap{
|
||||
"json": func(v any) string {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := json.NewEncoder(buf)
|
||||
enc.SetEscapeHTML(false)
|
||||
_ = enc.Encode(v)
|
||||
// Remove the trailing new line added by the encoder
|
||||
return strings.TrimSpace(buf.String())
|
||||
},
|
||||
"split": strings.Split,
|
||||
"join": strings.Join,
|
||||
"title": strings.Title, //nolint:staticcheck
|
||||
"lower": strings.ToLower,
|
||||
"upper": strings.ToUpper,
|
||||
"pad": padWithSpace,
|
||||
"truncate": truncateWithLength,
|
||||
}
|
||||
|
||||
// HeaderFunctions are used to created headers of a table.
|
||||
// This is a replacement of basicFunctions for header generation
|
||||
// because we want the header to remain intact.
|
||||
// Some functions like `split` are irrelevant so not added.
|
||||
var headerFunctions = template.FuncMap{
|
||||
"json": func(v string) string {
|
||||
return v
|
||||
},
|
||||
"title": func(v string) string {
|
||||
return v
|
||||
},
|
||||
"lower": func(v string) string {
|
||||
return v
|
||||
},
|
||||
"upper": func(v string) string {
|
||||
return v
|
||||
},
|
||||
"truncate": func(v string, _ int) string {
|
||||
return v
|
||||
},
|
||||
}
|
||||
|
||||
// Parse creates a new anonymous template with the basic functions
|
||||
// and parses the given format.
|
||||
func Parse(format string) (*template.Template, error) {
|
||||
return NewParse("", format)
|
||||
}
|
||||
|
||||
// NewParse creates a new tagged template with the basic functions
|
||||
// and parses the given format.
|
||||
func NewParse(tag, format string) (*template.Template, error) {
|
||||
return template.New(tag).Funcs(basicFunctions).Parse(format)
|
||||
}
|
||||
|
||||
// padWithSpace adds whitespace to the input if the input is non-empty
|
||||
func padWithSpace(source string, prefix, suffix int) string {
|
||||
if source == "" {
|
||||
return source
|
||||
}
|
||||
return strings.Repeat(" ", prefix) + source + strings.Repeat(" ", suffix)
|
||||
}
|
||||
|
||||
// truncateWithLength truncates the source string up to the length provided by the input
|
||||
func truncateWithLength(source string, length int) string {
|
||||
if len(source) < length {
|
||||
return source
|
||||
}
|
||||
return source[:length]
|
||||
}
|
||||
|
|
@ -131,6 +131,7 @@ github.com/containers/common/pkg/completion
|
|||
github.com/containers/common/pkg/config
|
||||
github.com/containers/common/pkg/download
|
||||
github.com/containers/common/pkg/filters
|
||||
github.com/containers/common/pkg/formats
|
||||
github.com/containers/common/pkg/hooks
|
||||
github.com/containers/common/pkg/hooks/0.1.0
|
||||
github.com/containers/common/pkg/hooks/1.0.0
|
||||
|
|
|
|||
Loading…
Reference in New Issue