summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/podman/common/createparse.go2
-rw-r--r--cmd/podman/common/specgen.go2
-rw-r--r--cmd/podman/containers/diff.go9
-rw-r--r--cmd/podman/containers/ps.go2
-rw-r--r--cmd/podman/images/list.go74
-rw-r--r--cmd/podman/parse/json.go3
-rw-r--r--cmd/podman/parse/json_test.go25
-rw-r--r--cmd/podman/report/format.go68
-rw-r--r--cmd/podman/report/format_test.go35
-rw-r--r--cmd/podman/root.go137
10 files changed, 241 insertions, 116 deletions
diff --git a/cmd/podman/common/createparse.go b/cmd/podman/common/createparse.go
index 059f9050f..09ee5aa0c 100644
--- a/cmd/podman/common/createparse.go
+++ b/cmd/podman/common/createparse.go
@@ -10,7 +10,7 @@ import (
func (c *ContainerCLIOpts) validate() error {
var ()
if c.Rm && c.Restart != "" && c.Restart != "no" {
- return errors.Errorf("the --rm option conflicts with --restart")
+ return errors.Errorf(`the --rm option conflicts with --restart, when the restartPolicy is not "" and "no"`)
}
if _, err := util.ValidatePullType(c.Pull); err != nil {
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index e7b88eb3f..84ae70b6a 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -233,7 +233,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
// validate flags as needed
if err := c.validate(); err != nil {
- return nil
+ return err
}
s.User = c.User
diff --git a/cmd/podman/containers/diff.go b/cmd/podman/containers/diff.go
index 227c13f4c..a3ca6edf9 100644
--- a/cmd/podman/containers/diff.go
+++ b/cmd/podman/containers/diff.go
@@ -1,6 +1,7 @@
package containers
import (
+ "github.com/containers/podman/v2/cmd/podman/parse"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/report"
"github.com/containers/podman/v2/cmd/podman/validate"
@@ -52,11 +53,11 @@ func diff(cmd *cobra.Command, args []string) error {
return err
}
- switch diffOpts.Format {
- case "":
- return report.ChangesToTable(results)
- case "json":
+ switch {
+ case parse.MatchesJSONFormat(diffOpts.Format):
return report.ChangesToJSON(results)
+ case diffOpts.Format == "":
+ return report.ChangesToTable(results)
default:
return errors.New("only supported value for '--format' is 'json'")
}
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index a78b35c08..c4c8b60f3 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -240,7 +240,7 @@ func ps(cmd *cobra.Command, args []string) error {
func createPsOut() (string, string) {
var row string
if listOpts.Namespace {
- headers := "CONTAINER ID\tNAMES\tPID\tCGROUPNS\tIPC\tMNT\tNET\tPIDN\tUSERNS\tUTS\n"
+ headers := "CONTAINER ID\tNAMES\tPID\tCGROUPNS\tIPC\tMNT\tNET\tPIDNS\tUSERNS\tUTS\n"
row := "{{.ID}}\t{{.Names}}\t{{.Pid}}\t{{.Namespaces.Cgroup}}\t{{.Namespaces.IPC}}\t{{.Namespaces.MNT}}\t{{.Namespaces.NET}}\t{{.Namespaces.PIDNS}}\t{{.Namespaces.User}}\t{{.Namespaces.UTS}}\n"
return headers, row
}
diff --git a/cmd/podman/images/list.go b/cmd/podman/images/list.go
index ffb341fc4..239da9d28 100644
--- a/cmd/podman/images/list.go
+++ b/cmd/podman/images/list.go
@@ -11,7 +11,9 @@ import (
"unicode"
"github.com/containers/image/v5/docker/reference"
+ "github.com/containers/podman/v2/cmd/podman/parse"
"github.com/containers/podman/v2/cmd/podman/registry"
+ "github.com/containers/podman/v2/cmd/podman/report"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/docker/go-units"
"github.com/pkg/errors"
@@ -106,9 +108,12 @@ func images(cmd *cobra.Command, args []string) error {
switch {
case listFlag.quiet:
return writeID(imgs)
- case cmd.Flag("format").Changed && listFlag.format == "json":
+ case parse.MatchesJSONFormat(listFlag.format):
return writeJSON(imgs)
default:
+ if cmd.Flag("format").Changed {
+ listFlag.noHeading = true // V1 compatibility
+ }
return writeTemplate(imgs)
}
}
@@ -156,25 +161,29 @@ func writeJSON(images []imageReporter) error {
}
func writeTemplate(imgs []imageReporter) error {
- var (
- hdr, row string
- )
- if len(listFlag.format) < 1 {
- hdr, row = imageListFormat(listFlag)
+ hdrs := report.Headers(imageReporter{}, map[string]string{
+ "ID": "IMAGE ID",
+ "ReadOnly": "R/O",
+ })
+
+ var row string
+ if listFlag.format == "" {
+ row = lsFormatFromFlags(listFlag)
} else {
- row = listFlag.format
- if !strings.HasSuffix(row, "\n") {
- row += "\n"
- }
+ row = report.NormalizeFormat(listFlag.format)
}
- format := hdr + "{{range . }}" + row + "{{end}}"
- tmpl, err := template.New("list").Parse(format)
- if err != nil {
- return err
- }
- tmpl = template.Must(tmpl, nil)
+
+ format := "{{range . }}" + row + "{{end}}"
+ tmpl := template.Must(template.New("list").Parse(format))
w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
defer w.Flush()
+
+ if !listFlag.noHeading {
+ if err := tmpl.Execute(w, hdrs); err != nil {
+ return err
+ }
+ }
+
return tmpl.Execute(w, imgs)
}
@@ -276,40 +285,27 @@ func sortFunc(key string, data []imageReporter) func(i, j int) bool {
}
}
-func imageListFormat(flags listFlagType) (string, string) {
- // Defaults
- hdr := "REPOSITORY\tTAG"
- row := "{{.Repository}}\t{{if .Tag}}{{.Tag}}{{else}}<none>{{end}}"
+func lsFormatFromFlags(flags listFlagType) string {
+ row := []string{
+ "{{if .Repository}}{{.Repository}}{{else}}<none>{{end}}",
+ "{{if .Tag}}{{.Tag}}{{else}}<none>{{end}}",
+ }
if flags.digests {
- hdr += "\tDIGEST"
- row += "\t{{.Digest}}"
+ row = append(row, "{{.Digest}}")
}
- hdr += "\tIMAGE ID"
- row += "\t{{.ID}}"
-
- hdr += "\tCREATED\tSIZE"
- row += "\t{{.Created}}\t{{.Size}}"
+ row = append(row, "{{.ID}}", "{{.Created}}", "{{.Size}}")
if flags.history {
- hdr += "\tHISTORY"
- row += "\t{{if .History}}{{.History}}{{else}}<none>{{end}}"
+ row = append(row, "{{if .History}}{{.History}}{{else}}<none>{{end}}")
}
if flags.readOnly {
- hdr += "\tReadOnly"
- row += "\t{{.ReadOnly}}"
- }
-
- if flags.noHeading {
- hdr = ""
- } else {
- hdr += "\n"
+ row = append(row, "{{.ReadOnly}}")
}
- row += "\n"
- return hdr, row
+ return strings.Join(row, "\t") + "\n"
}
type imageReporter struct {
diff --git a/cmd/podman/parse/json.go b/cmd/podman/parse/json.go
index 95a6633b8..40ac415db 100644
--- a/cmd/podman/parse/json.go
+++ b/cmd/podman/parse/json.go
@@ -2,8 +2,9 @@ package parse
import "regexp"
-var jsonFormatRegex = regexp.MustCompile(`^(\s*json\s*|\s*{{\s*json\s*\.\s*}}\s*)$`)
+var jsonFormatRegex = regexp.MustCompile(`^\s*(json|{{\s*json\s*( \.)?\s*}})\s*$`)
+// MatchesJSONFormat test CLI --format string to be a JSON request
func MatchesJSONFormat(s string) bool {
return jsonFormatRegex.Match([]byte(s))
}
diff --git a/cmd/podman/parse/json_test.go b/cmd/podman/parse/json_test.go
index 5cad185fd..ec3b5664b 100644
--- a/cmd/podman/parse/json_test.go
+++ b/cmd/podman/parse/json_test.go
@@ -1,6 +1,8 @@
package parse
import (
+ "fmt"
+ "strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -13,18 +15,31 @@ func TestMatchesJSONFormat(t *testing.T) {
}{
{"json", true},
{" json", true},
- {"json ", true},
+ {" json ", true},
{" json ", true},
+ {"{{json}}", true},
+ {"{{json }}", true},
{"{{json .}}", true},
{"{{ json .}}", true},
- {"{{json . }}", true},
- {" {{ json . }} ", true},
- {"{{json }}", false},
- {"{{json .", false},
+ {"{{ json . }}", true},
+ {" {{ json . }} ", true},
+ {"{{ json .", false},
{"json . }}", false},
+ {"{{.ID }} json .", false},
+ {"json .", false},
+ {"{{json.}}", false},
}
for _, tt := range tests {
assert.Equal(t, tt.expected, MatchesJSONFormat(tt.input))
}
+
+ for _, tc := range tests {
+ tc := tc
+ label := "MatchesJSONFormat/" + strings.ReplaceAll(tc.input, " ", "_")
+ t.Run(label, func(t *testing.T) {
+ t.Parallel()
+ assert.Equal(t, tc.expected, MatchesJSONFormat(tc.input), fmt.Sprintf("Scanning %q failed", tc.input))
+ })
+ }
}
diff --git a/cmd/podman/report/format.go b/cmd/podman/report/format.go
new file mode 100644
index 000000000..32d92bec5
--- /dev/null
+++ b/cmd/podman/report/format.go
@@ -0,0 +1,68 @@
+package report
+
+import (
+ "reflect"
+ "strings"
+)
+
+// 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 {
+ f := format
+ // two replacers used so we only remove the prefix keyword `table`
+ if strings.HasPrefix(f, "table ") {
+ f = tableReplacer.Replace(f)
+ } else {
+ f = escapedReplacer.Replace(format)
+ }
+
+ if !strings.HasSuffix(f, "\n") {
+ f += "\n"
+ }
+
+ return f
+}
+
+// Headers queries the interface for field names
+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
+ }
+ headers[field.Name] = strings.ToUpper(field.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}
+}
diff --git a/cmd/podman/report/format_test.go b/cmd/podman/report/format_test.go
new file mode 100644
index 000000000..7dd62e899
--- /dev/null
+++ b/cmd/podman/report/format_test.go
@@ -0,0 +1,35 @@
+package report
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestNormalizeFormat(t *testing.T) {
+ cases := []struct {
+ format string
+ expected string
+ }{
+ {"table {{.ID}}", "{{.ID}}\n"},
+ {"table {{.ID}} {{.C}}", "{{.ID}}\t{{.C}}\n"},
+ {"{{.ID}}", "{{.ID}}\n"},
+ {"{{.ID}}\n", "{{.ID}}\n"},
+ {"{{.ID}} {{.C}}", "{{.ID}} {{.C}}\n"},
+ {"\t{{.ID}}", "\t{{.ID}}\n"},
+ {`\t` + "{{.ID}}", "\t{{.ID}}\n"},
+ {"table {{.ID}}\t{{.C}}", "{{.ID}}\t{{.C}}\n"},
+ {"{{.ID}} table {{.C}}", "{{.ID}} table {{.C}}\n"},
+ }
+ for _, tc := range cases {
+ tc := tc
+
+ label := strings.ReplaceAll(tc.format, " ", "<sp>")
+ t.Run("NormalizeFormat/"+label, func(t *testing.T) {
+ t.Parallel()
+ actual := NormalizeFormat(tc.format)
+ if actual != tc.expected {
+ t.Errorf("Expected %q, actual %q", tc.expected, actual)
+ }
+ })
+ }
+}
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 6424ec12e..1e73f7540 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -154,34 +154,35 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
}
}
- if cmd.Flag("cpu-profile").Changed {
- f, err := os.Create(cfg.CPUProfile)
- if err != nil {
- return errors.Wrapf(err, "unable to create cpu profiling file %s",
- cfg.CPUProfile)
- }
- if err := pprof.StartCPUProfile(f); err != nil {
- return err
+ if !registry.IsRemote() {
+ if cmd.Flag("cpu-profile").Changed {
+ f, err := os.Create(cfg.CPUProfile)
+ if err != nil {
+ return errors.Wrapf(err, "unable to create cpu profiling file %s",
+ cfg.CPUProfile)
+ }
+ if err := pprof.StartCPUProfile(f); err != nil {
+ return err
+ }
}
- }
- if cmd.Flag("trace").Changed {
- tracer, closer := tracing.Init("podman")
- opentracing.SetGlobalTracer(tracer)
- cfg.SpanCloser = closer
+ if cmd.Flag("trace").Changed {
+ tracer, closer := tracing.Init("podman")
+ opentracing.SetGlobalTracer(tracer)
+ cfg.SpanCloser = closer
- cfg.Span = tracer.StartSpan("before-context")
- cfg.SpanCtx = opentracing.ContextWithSpan(registry.Context(), cfg.Span)
- opentracing.StartSpanFromContext(cfg.SpanCtx, cmd.Name())
- }
+ cfg.Span = tracer.StartSpan("before-context")
+ cfg.SpanCtx = opentracing.ContextWithSpan(registry.Context(), cfg.Span)
+ opentracing.StartSpanFromContext(cfg.SpanCtx, cmd.Name())
+ }
- if cfg.MaxWorks <= 0 {
- return errors.Errorf("maximum workers must be set to a positive number (got %d)", cfg.MaxWorks)
- }
- if err := parallel.SetMaxThreads(uint(cfg.MaxWorks)); err != nil {
- return err
+ if cfg.MaxWorks <= 0 {
+ return errors.Errorf("maximum workers must be set to a positive number (got %d)", cfg.MaxWorks)
+ }
+ if err := parallel.SetMaxThreads(uint(cfg.MaxWorks)); err != nil {
+ return err
+ }
}
-
// Setup Rootless environment, IFF:
// 1) in ABI mode
// 2) running as non-root
@@ -206,12 +207,14 @@ func persistentPostRunE(cmd *cobra.Command, args []string) error {
}
cfg := registry.PodmanConfig()
- if cmd.Flag("cpu-profile").Changed {
- pprof.StopCPUProfile()
- }
- if cmd.Flag("trace").Changed {
- cfg.Span.Finish()
- cfg.SpanCloser.Close()
+ if !registry.IsRemote() {
+ if cmd.Flag("cpu-profile").Changed {
+ pprof.StopCPUProfile()
+ }
+ if cmd.Flag("trace").Changed {
+ cfg.Span.Finish()
+ cfg.SpanCloser.Close()
+ }
}
registry.ImageEngine().Shutdown(registry.Context())
@@ -249,51 +252,57 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) {
srv, uri, ident := resolveDestination()
lFlags := cmd.Flags()
- lFlags.BoolVarP(&opts.Remote, "remote", "r", false, "Access remote Podman service (default false)")
lFlags.StringVarP(&opts.Engine.ActiveService, "connection", "c", srv, "Connection to use for remote Podman service")
lFlags.StringVar(&opts.URI, "url", uri, "URL to access Podman service (CONTAINER_HOST)")
lFlags.StringVar(&opts.Identity, "identity", ident, "path to SSH identity file, (CONTAINER_SSHKEY)")
+ lFlags.BoolVarP(&opts.Remote, "remote", "r", false, "Access remote Podman service (default false)")
pFlags := cmd.PersistentFlags()
- pFlags.StringVar(&cfg.Engine.CgroupManager, "cgroup-manager", cfg.Engine.CgroupManager, "Cgroup manager to use (\"cgroupfs\"|\"systemd\")")
- pFlags.StringVar(&opts.CPUProfile, "cpu-profile", "", "Path for the cpu profiling results")
- pFlags.StringVar(&opts.ConmonPath, "conmon", "", "Path of the conmon binary")
- pFlags.StringVar(&cfg.Engine.NetworkCmdPath, "network-cmd-path", cfg.Engine.NetworkCmdPath, "Path to the command for configuring the network")
- pFlags.StringVar(&cfg.Network.NetworkConfigDir, "cni-config-dir", cfg.Network.NetworkConfigDir, "Path of the configuration directory for CNI networks")
- pFlags.StringVar(&cfg.Containers.DefaultMountsFile, "default-mounts-file", cfg.Containers.DefaultMountsFile, "Path to default mounts file")
- pFlags.StringVar(&cfg.Engine.EventsLogger, "events-backend", cfg.Engine.EventsLogger, `Events backend to use ("file"|"journald"|"none")`)
- pFlags.StringSliceVar(&cfg.Engine.HooksDir, "hooks-dir", cfg.Engine.HooksDir, "Set the OCI hooks directory path (may be set multiple times)")
- pFlags.IntVar(&opts.MaxWorks, "max-workers", (runtime.NumCPU()*3)+1, "The maximum number of workers for parallel operations")
- pFlags.StringVar(&cfg.Engine.Namespace, "namespace", cfg.Engine.Namespace, "Set the libpod namespace, used to create separate views of the containers and pods on the system")
- pFlags.StringVar(&cfg.Engine.StaticDir, "root", "", "Path to the root directory in which data, including images, is stored")
- pFlags.StringVar(&opts.RegistriesConf, "registries-conf", "", "Path to a registries.conf to use for image processing")
- pFlags.StringVar(&opts.Runroot, "runroot", "", "Path to the 'run directory' where all state information is stored")
- pFlags.StringVar(&opts.RuntimePath, "runtime", "", "Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc")
- // -s is deprecated due to conflict with -s on subcommands
- pFlags.StringVar(&opts.StorageDriver, "storage-driver", "", "Select which storage driver is used to manage storage of images and containers (default is overlay)")
- pFlags.StringArrayVar(&opts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver")
-
- pFlags.StringVar(&opts.Engine.TmpDir, "tmpdir", "", "Path to the tmp directory for libpod state content.\n\nNote: use the environment variable 'TMPDIR' to change the temporary storage location for container images, '/var/tmp'.\n")
- pFlags.BoolVar(&opts.Trace, "trace", false, "Enable opentracing output (default false)")
-
+ if registry.IsRemote() {
+ if err := lFlags.MarkHidden("remote"); err != nil {
+ logrus.Warnf("unable to mark --remote flag as hidden: %s", err.Error())
+ }
+ opts.Remote = true
+ } else {
+ pFlags.StringVar(&cfg.Engine.CgroupManager, "cgroup-manager", cfg.Engine.CgroupManager, "Cgroup manager to use (\"cgroupfs\"|\"systemd\")")
+ pFlags.StringVar(&opts.CPUProfile, "cpu-profile", "", "Path for the cpu profiling results")
+ pFlags.StringVar(&opts.ConmonPath, "conmon", "", "Path of the conmon binary")
+ pFlags.StringVar(&cfg.Engine.NetworkCmdPath, "network-cmd-path", cfg.Engine.NetworkCmdPath, "Path to the command for configuring the network")
+ pFlags.StringVar(&cfg.Network.NetworkConfigDir, "cni-config-dir", cfg.Network.NetworkConfigDir, "Path of the configuration directory for CNI networks")
+ pFlags.StringVar(&cfg.Containers.DefaultMountsFile, "default-mounts-file", cfg.Containers.DefaultMountsFile, "Path to default mounts file")
+ pFlags.StringVar(&cfg.Engine.EventsLogger, "events-backend", cfg.Engine.EventsLogger, `Events backend to use ("file"|"journald"|"none")`)
+ pFlags.StringSliceVar(&cfg.Engine.HooksDir, "hooks-dir", cfg.Engine.HooksDir, "Set the OCI hooks directory path (may be set multiple times)")
+ pFlags.IntVar(&opts.MaxWorks, "max-workers", (runtime.NumCPU()*3)+1, "The maximum number of workers for parallel operations")
+ pFlags.StringVar(&cfg.Engine.Namespace, "namespace", cfg.Engine.Namespace, "Set the libpod namespace, used to create separate views of the containers and pods on the system")
+ pFlags.StringVar(&cfg.Engine.StaticDir, "root", "", "Path to the root directory in which data, including images, is stored")
+ pFlags.StringVar(&opts.RegistriesConf, "registries-conf", "", "Path to a registries.conf to use for image processing")
+ pFlags.StringVar(&opts.Runroot, "runroot", "", "Path to the 'run directory' where all state information is stored")
+ pFlags.StringVar(&opts.RuntimePath, "runtime", "", "Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc")
+ // -s is deprecated due to conflict with -s on subcommands
+ pFlags.StringVar(&opts.StorageDriver, "storage-driver", "", "Select which storage driver is used to manage storage of images and containers (default is overlay)")
+ pFlags.StringArrayVar(&opts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver")
+
+ pFlags.StringVar(&opts.Engine.TmpDir, "tmpdir", "", "Path to the tmp directory for libpod state content.\n\nNote: use the environment variable 'TMPDIR' to change the temporary storage location for container images, '/var/tmp'.\n")
+ pFlags.BoolVar(&opts.Trace, "trace", false, "Enable opentracing output (default false)")
+
+ // Hide these flags for both ABI and Tunneling
+ for _, f := range []string{
+ "cpu-profile",
+ "default-mounts-file",
+ "max-workers",
+ "registries-conf",
+ "trace",
+ } {
+ if err := pFlags.MarkHidden(f); err != nil {
+ logrus.Warnf("unable to mark %s flag as hidden: %s", f, err.Error())
+ }
+ }
+ }
// Override default --help information of `--help` global flag
var dummyHelp bool
pFlags.BoolVar(&dummyHelp, "help", false, "Help for podman")
pFlags.StringVar(&logLevel, "log-level", logLevel, fmt.Sprintf("Log messages above specified level (%s)", strings.Join(logLevels, ", ")))
- // Hide these flags for both ABI and Tunneling
- for _, f := range []string{
- "cpu-profile",
- "default-mounts-file",
- "max-workers",
- "registries-conf",
- "trace",
- } {
- if err := pFlags.MarkHidden(f); err != nil {
- logrus.Warnf("unable to mark %s flag as hidden: %s", f, err.Error())
- }
- }
-
// Only create these flags for ABI connections
if !registry.IsRemote() {
pFlags.StringArrayVar(&opts.RuntimeFlags, "runtime-flag", []string{}, "add global flags for the container runtime")