mirror of
https://github.com/containerd/containerd.git
synced 2026-11-06 05:17:02 +00:00
migrate to github.com/urfave/cli/v3
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
179 files changed
+8906
-10554
No files matched your search
@@ -34,7 +34,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/pkg/namespaces"
|
||||
"github.com/containerd/containerd/v2/pkg/oci"
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var densityCommand = &cli.Command{
|
||||
@@ -47,7 +47,7 @@ var densityCommand = &cli.Command{
|
||||
Value: 10,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
pids []uint32
|
||||
count = cmd.Int("count")
|
||||
@@ -72,16 +72,16 @@ var densityCommand = &cli.Command{
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
ctx := namespaces.WithNamespace(context.Background(), "density")
|
||||
ctx = namespaces.WithNamespace(ctx, "density")
|
||||
if err := cleanup(ctx, client); err != nil {
|
||||
return err
|
||||
}
|
||||
log.L.Infof("pulling %s", cfg.Image)
|
||||
log.G(ctx).Infof("pulling %s", cfg.Image)
|
||||
image, err := client.Pull(ctx, cfg.Image, containerd.WithPullUnpack, containerd.WithPullSnapshotter(cfg.Snapshotter))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.L.Info("generating spec from image")
|
||||
log.G(ctx).Info("generating spec from image")
|
||||
|
||||
s := make(chan os.Signal, 1)
|
||||
signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)
|
||||
|
||||
@@ -36,7 +36,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/version"
|
||||
"github.com/containerd/log"
|
||||
metrics "github.com/docker/go-metrics"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -65,8 +65,8 @@ func init() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cli.VersionPrinter = func(cmd *cli.Context) {
|
||||
fmt.Println(cmd.App.Name, version.Package, cmd.App.Version)
|
||||
cli.VersionPrinter = func(cmd *cli.Command) {
|
||||
_, _ = fmt.Fprintln(cmd.Root().Writer, cmd.Name, version.Package, cmd.Version)
|
||||
}
|
||||
|
||||
// Override the default flag descriptions for '--version' and '--help'
|
||||
@@ -76,14 +76,14 @@ func init() {
|
||||
Aliases: []string{"v"},
|
||||
Usage: "Print the version",
|
||||
|
||||
DisableDefaultText: true,
|
||||
HideDefault: true,
|
||||
}
|
||||
cli.HelpFlag = &cli.BoolFlag{
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Show help",
|
||||
|
||||
DisableDefaultText: true,
|
||||
HideDefault: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ func main() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
|
||||
ctx := context.Background()
|
||||
app := &cli.App{
|
||||
app := &cli.Command{
|
||||
Name: "containerd-stress",
|
||||
Description: "stress test a containerd daemon",
|
||||
Version: version.Version,
|
||||
@@ -206,23 +206,23 @@ func main() {
|
||||
Value: "overlayfs",
|
||||
},
|
||||
},
|
||||
Before: func(cmd *cli.Context) error {
|
||||
Before: func(ctx context.Context, cmd *cli.Command) (context.Context, error) {
|
||||
if cmd.Bool("json") {
|
||||
if err := log.SetLevel(log.WarnLevel); err != nil {
|
||||
return err
|
||||
return ctx, err
|
||||
}
|
||||
}
|
||||
if cmd.Bool("debug") {
|
||||
if err := log.SetLevel(log.DebugLevel); err != nil {
|
||||
return err
|
||||
return ctx, err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return ctx, nil
|
||||
},
|
||||
Commands: []*cli.Command{
|
||||
densityCommand,
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
cfg := config{
|
||||
Address: cmd.String("address"),
|
||||
Duration: cmd.Duration("duration"),
|
||||
@@ -246,7 +246,7 @@ func main() {
|
||||
return test(cfg)
|
||||
},
|
||||
}
|
||||
if err := app.RunContext(ctx, os.Args); err != nil {
|
||||
if err := app.Run(ctx, os.Args); err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "containerd-stress:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -480,10 +480,10 @@ func cleanup(ctx context.Context, client *containerd.Client) error {
|
||||
for _, c := range containers {
|
||||
task, err := c.Task(ctx, nil)
|
||||
if err == nil {
|
||||
task.Delete(ctx, containerd.WithProcessKill)
|
||||
_, _ = task.Delete(ctx, containerd.WithProcessKill)
|
||||
}
|
||||
if err := c.Delete(ctx, containerd.WithSnapshotCleanup); err != nil {
|
||||
if derr := c.Delete(ctx); derr == nil {
|
||||
if dErr := c.Delete(ctx); dErr == nil {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
|
||||
@@ -33,7 +33,7 @@ import (
|
||||
"github.com/containerd/plugin/registry"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func outputConfig(ctx context.Context, config *srvconfig.Config) error {
|
||||
@@ -85,12 +85,11 @@ func defaultConfig() *srvconfig.Config {
|
||||
var configCommand = &cli.Command{
|
||||
Name: "config",
|
||||
Usage: "Information on the containerd config",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
{
|
||||
Name: "default",
|
||||
Usage: "See the output of the default config",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return outputConfig(ctx, defaultConfig())
|
||||
},
|
||||
},
|
||||
@@ -108,9 +107,8 @@ var configCommand = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func dumpConfig(cmd *cli.Context) error {
|
||||
func dumpConfig(ctx context.Context, cmd *cli.Command) error {
|
||||
config := defaultConfig()
|
||||
ctx := cmd.Context
|
||||
|
||||
g := registry.Graph(func(*plugin.Registration) bool { return false })
|
||||
plugins := func() iter.Seq[plugin.Registration] {
|
||||
|
||||
@@ -40,7 +40,7 @@ import (
|
||||
"github.com/containerd/plugin"
|
||||
"github.com/containerd/plugin/registry"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
@@ -58,8 +58,8 @@ func init() {
|
||||
// Discard grpc logs so that they don't mess with our stdio
|
||||
grpclog.SetLoggerV2(grpclog.NewLoggerV2(io.Discard, io.Discard, io.Discard))
|
||||
|
||||
cli.VersionPrinter = func(cmd *cli.Context) {
|
||||
fmt.Println(cmd.App.Name, version.Package, cmd.App.Version, version.Revision)
|
||||
cli.VersionPrinter = func(cmd *cli.Command) {
|
||||
_, _ = fmt.Fprintln(cmd.Root().Writer, cmd.Name, version.Package, cmd.Version, version.Revision)
|
||||
}
|
||||
|
||||
// Override the default flag descriptions for '--version' and '--help'
|
||||
@@ -69,20 +69,20 @@ func init() {
|
||||
Aliases: []string{"v"},
|
||||
Usage: "Print the version",
|
||||
|
||||
DisableDefaultText: true,
|
||||
HideDefault: true,
|
||||
}
|
||||
cli.HelpFlag = &cli.BoolFlag{
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Show help",
|
||||
|
||||
DisableDefaultText: true,
|
||||
HideDefault: true,
|
||||
}
|
||||
}
|
||||
|
||||
// App returns a *cli.App instance.
|
||||
func App() *cli.App {
|
||||
return &cli.App{
|
||||
// App returns a *cli.Command instance.
|
||||
func App() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "containerd",
|
||||
Version: version.Version,
|
||||
Usage: usage,
|
||||
@@ -128,9 +128,9 @@ can be used and modified as necessary as a custom configuration.`,
|
||||
publishCommand,
|
||||
ociHook,
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
if args := cmd.Args(); args.First() != "" {
|
||||
return cli.ShowCommandHelp(cmd, args.First())
|
||||
return cli.ShowCommandHelp(ctx, cmd, args.First())
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -140,7 +140,7 @@ can be used and modified as necessary as a custom configuration.`,
|
||||
config = defaultConfig()
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithCancel(cmd.Context)
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
// Only try to load the config if it either exists, or the user explicitly
|
||||
@@ -281,7 +281,7 @@ can be used and modified as necessary as a custom configuration.`,
|
||||
}
|
||||
}
|
||||
|
||||
func applyFlags(cmd *cli.Context, config *srvconfig.Config) error {
|
||||
func applyFlags(cmd *cli.Command, config *srvconfig.Config) error {
|
||||
// the order for config vs flag values is that flags will always override
|
||||
// the config values if they are set
|
||||
if err := setLogLevel(cmd, config); err != nil {
|
||||
@@ -350,7 +350,7 @@ func applyFlags(cmd *cli.Context, config *srvconfig.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setLogLevel(cmd *cli.Context, config *srvconfig.Config) error {
|
||||
func setLogLevel(cmd *cli.Command, config *srvconfig.Config) error {
|
||||
l := cmd.String("log-level")
|
||||
if l == "" {
|
||||
l = config.Debug.Level
|
||||
@@ -392,7 +392,7 @@ func dumpStacks(writeToFile bool) {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
f.WriteString(string(buf))
|
||||
_, _ = f.WriteString(string(buf))
|
||||
log.L.Infof("goroutine stack dump written to %s", name)
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package command
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
@@ -27,13 +28,13 @@ import (
|
||||
|
||||
"github.com/containerd/containerd/v2/pkg/oci"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var ociHook = &cli.Command{
|
||||
Name: "oci-hook",
|
||||
Usage: "Provides a base for OCI runtime hooks to allow arguments to be injected.",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
state, err := loadHookState(os.Stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
eventsapi "github.com/containerd/containerd/api/services/events/v1"
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/errdefs/pkg/errgrpc"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/backoff"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
@@ -51,8 +51,8 @@ var publishCommand = &cli.Command{
|
||||
Usage: "Topic of the event",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := namespaces.WithNamespace(cmd.Context, cmd.String("namespace"))
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
ctx = namespaces.WithNamespace(ctx, cmd.String("namespace"))
|
||||
topic := cmd.String("topic")
|
||||
if topic == "" {
|
||||
return fmt.Errorf("topic required to publish event: %w", errdefs.ErrInvalidArgument)
|
||||
|
||||
@@ -20,7 +20,7 @@ package command
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/v2/cmd/containerd/server"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// serviceFlags returns an array of flags for configuring containerd to run
|
||||
@@ -30,7 +30,7 @@ func serviceFlags() []cli.Flag {
|
||||
}
|
||||
|
||||
// applyPlatformFlags applies platform-specific flags.
|
||||
func applyPlatformFlags(*cli.Context) {}
|
||||
func applyPlatformFlags(*cli.Command) {}
|
||||
|
||||
// registerUnregisterService is only relevant on Windows.
|
||||
func registerUnregisterService(root string) (bool, error) {
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/cmd/containerd/server"
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/debug"
|
||||
@@ -79,7 +79,7 @@ func serviceFlags() []cli.Flag {
|
||||
}
|
||||
|
||||
// applyPlatformFlags applies platform-specific flags.
|
||||
func applyPlatformFlags(cmd *cli.Context) {
|
||||
func applyPlatformFlags(cmd *cli.Command) {
|
||||
serviceNameFlag = cmd.String("service-name")
|
||||
if serviceNameFlag == "" {
|
||||
serviceNameFlag = defaultServiceName
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
if err := command.App().RunContext(ctx, os.Args); err != nil {
|
||||
if err := command.App().Run(ctx, os.Args); err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "containerd:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
+14
-13
@@ -17,11 +17,12 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands/containers"
|
||||
@@ -55,8 +56,8 @@ func init() {
|
||||
// Discard grpc logs so that they don't mess with our stdio
|
||||
grpclog.SetLoggerV2(grpclog.NewLoggerV2(io.Discard, io.Discard, io.Discard))
|
||||
|
||||
cli.VersionPrinter = func(cmd *cli.Context) {
|
||||
fmt.Println(cmd.App.Name, version.Package, cmd.App.Version)
|
||||
cli.VersionPrinter = func(cmd *cli.Command) {
|
||||
_, _ = fmt.Fprintln(cmd.Root().Writer, cmd.Name, version.Package, cmd.Version)
|
||||
}
|
||||
|
||||
// Override the default flag descriptions for '--version' and '--help'
|
||||
@@ -66,20 +67,20 @@ func init() {
|
||||
Aliases: []string{"v"},
|
||||
Usage: "Print the version",
|
||||
|
||||
DisableDefaultText: true,
|
||||
HideDefault: true,
|
||||
}
|
||||
cli.HelpFlag = &cli.BoolFlag{
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Show help",
|
||||
|
||||
DisableDefaultText: true,
|
||||
HideDefault: true,
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a *cli.App instance.
|
||||
func New() *cli.App {
|
||||
return &cli.App{
|
||||
func New() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "ctr",
|
||||
Version: version.Version,
|
||||
Description: `
|
||||
@@ -97,7 +98,7 @@ stable from release to release of the containerd project.`,
|
||||
containerd CLI
|
||||
`,
|
||||
DisableSliceFlagSeparator: true,
|
||||
EnableBashCompletion: true,
|
||||
EnableShellCompletion: true,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "debug",
|
||||
@@ -108,7 +109,7 @@ containerd CLI
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Address for containerd's GRPC server",
|
||||
Value: defaults.DefaultAddress,
|
||||
EnvVars: []string{"CONTAINERD_ADDRESS"},
|
||||
Sources: cli.EnvVars("CONTAINERD_ADDRESS"),
|
||||
},
|
||||
&cli.DurationFlag{
|
||||
Name: "timeout",
|
||||
@@ -123,7 +124,7 @@ containerd CLI
|
||||
Aliases: []string{"n"},
|
||||
Usage: "Namespace to use with commands",
|
||||
Value: namespaces.Default,
|
||||
EnvVars: []string{namespaces.NamespaceEnvVar},
|
||||
Sources: cli.EnvVars(namespaces.NamespaceEnvVar),
|
||||
},
|
||||
},
|
||||
Commands: append([]*cli.Command{
|
||||
@@ -145,11 +146,11 @@ containerd CLI
|
||||
info.Command,
|
||||
deprecations.Command,
|
||||
}, extraCmds...),
|
||||
Before: func(cmd *cli.Context) error {
|
||||
Before: func(ctx context.Context, cmd *cli.Command) (context.Context, error) {
|
||||
if cmd.Bool("debug") {
|
||||
return log.SetLevel(log.DebugLevel)
|
||||
return ctx, log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
return nil
|
||||
return ctx, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/pkg/epoch"
|
||||
"github.com/containerd/containerd/v2/pkg/namespaces"
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// AppContext returns the context for a command. Should only be called once per
|
||||
@@ -34,7 +34,7 @@ import (
|
||||
//
|
||||
// This will ensure the namespace is picked up and set the timeout, if one is
|
||||
// defined.
|
||||
func AppContext(ctx context.Context, cmd *cli.Context) (context.Context, context.CancelFunc) {
|
||||
func AppContext(ctx context.Context, cmd *cli.Command) (context.Context, context.CancelFunc) {
|
||||
var (
|
||||
timeout = cmd.Duration("timeout")
|
||||
namespace = cmd.String("namespace")
|
||||
@@ -56,7 +56,7 @@ func AppContext(ctx context.Context, cmd *cli.Context) (context.Context, context
|
||||
}
|
||||
|
||||
// NewClient returns a new containerd client
|
||||
func NewClient(ctx context.Context, cmd *cli.Context, opts ...containerd.Opt) (*containerd.Client, context.Context, context.CancelFunc, error) {
|
||||
func NewClient(ctx context.Context, cmd *cli.Command, opts ...containerd.Opt) (*containerd.Client, context.Context, context.CancelFunc, error) {
|
||||
timeoutOpt := containerd.WithTimeout(cmd.Duration("connect-timeout"))
|
||||
opts = append(opts, timeoutOpt)
|
||||
socketPath := cmd.String("address")
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/defaults"
|
||||
"github.com/containerd/containerd/v2/pkg/atomicfile"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -35,7 +35,7 @@ var (
|
||||
&cli.StringFlag{
|
||||
Name: "snapshotter",
|
||||
Usage: "Snapshotter name. Empty value stands for the default value.",
|
||||
EnvVars: []string{"CONTAINERD_SNAPSHOTTER"},
|
||||
Sources: cli.EnvVars("CONTAINERD_SNAPSHOTTER"),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ var (
|
||||
)
|
||||
|
||||
// ObjectWithLabelArgs returns the first arg and a LabelArgs object
|
||||
func ObjectWithLabelArgs(cmd *cli.Context) (string, map[string]string) {
|
||||
func ObjectWithLabelArgs(cmd *cli.Command) (string, map[string]string) {
|
||||
var (
|
||||
first = cmd.Args().First()
|
||||
labelStrings = cmd.Args().Tail()
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
"github.com/containerd/containerd/api/types/runc/options"
|
||||
runtimeoptions "github.com/containerd/containerd/api/types/runtimeoptions/v1"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -59,7 +59,7 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
func getRuncOptions(cmd *cli.Context) (*options.Options, error) {
|
||||
func getRuncOptions(cmd *cli.Command) (*options.Options, error) {
|
||||
runtimeOpts := &options.Options{}
|
||||
if runcBinary := cmd.String("runc-binary"); runcBinary != "" {
|
||||
runtimeOpts.BinaryName = runcBinary
|
||||
@@ -78,7 +78,7 @@ func getRuncOptions(cmd *cli.Context) (*options.Options, error) {
|
||||
return runtimeOpts, nil
|
||||
}
|
||||
|
||||
func RuntimeOptions(cmd *cli.Context) (any, error) {
|
||||
func RuntimeOptions(cmd *cli.Command) (any, error) {
|
||||
// validate first
|
||||
if (cmd.String("runc-binary") != "" || cmd.Bool("runc-systemd-cgroup")) &&
|
||||
cmd.String("runtime") != "io.containerd.runc.v2" {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -37,6 +37,6 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
func RuntimeOptions(cmd *cli.Context) (any, error) {
|
||||
func RuntimeOptions(cmd *cli.Command) (any, error) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -17,13 +17,14 @@
|
||||
package containers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
containerd "github.com/containerd/containerd/v2/client"
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var checkpointCommand = &cli.Command{
|
||||
@@ -44,8 +45,7 @@ var checkpointCommand = &cli.Command{
|
||||
Usage: "Checkpoint container task",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
id := cmd.Args().First()
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/typeurl/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command is the cli command for managing containers
|
||||
@@ -39,7 +39,7 @@ var Command = &cli.Command{
|
||||
Name: "containers",
|
||||
Usage: "Manage containers",
|
||||
Aliases: []string{"c", "container"},
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
createCommand,
|
||||
deleteCommand,
|
||||
infoCommand,
|
||||
@@ -55,8 +55,7 @@ var createCommand = &cli.Command{
|
||||
Usage: "Create container",
|
||||
ArgsUsage: "[flags] Image|RootFS CONTAINER [COMMAND] [ARG...]",
|
||||
Flags: append(commands.RuntimeFlags, append(append(commands.SnapshotterFlags, []cli.Flag{commands.SnapshotterLabels}...), commands.ContainerFlags...)...),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
id string
|
||||
ref string
|
||||
@@ -103,8 +102,7 @@ var listCommand = &cli.Command{
|
||||
Usage: "Print only the container id",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
filters = cmd.Args().Slice()
|
||||
quiet = cmd.Bool("quiet")
|
||||
@@ -158,8 +156,7 @@ var deleteCommand = &cli.Command{
|
||||
Usage: "Do not clean up snapshot with container",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var exitErr error
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
@@ -215,8 +212,7 @@ var setLabelsCommand = &cli.Command{
|
||||
ArgsUsage: "[flags] CONTAINER [<key>=<value>, ...]",
|
||||
Description: "set and clear labels for a container",
|
||||
Flags: []cli.Flag{},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
containerID, labels := commands.ObjectWithLabelArgs(cmd)
|
||||
if containerID == "" {
|
||||
return fmt.Errorf("container id must be provided: %w", errdefs.ErrInvalidArgument)
|
||||
@@ -258,8 +254,7 @@ var infoCommand = &cli.Command{
|
||||
Usage: "Only display the spec",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
id := cmd.Args().First()
|
||||
if id == "" {
|
||||
return fmt.Errorf("container id must be provided: %w", errdefs.ErrInvalidArgument)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package containers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/containerd/console"
|
||||
@@ -26,7 +27,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/pkg/cio"
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var restoreCommand = &cli.Command{
|
||||
@@ -43,8 +44,7 @@ var restoreCommand = &cli.Command{
|
||||
Usage: "Restore the runtime and memory data from the checkpoint",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
id := cmd.Args().First()
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package content
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -35,7 +36,7 @@ import (
|
||||
units "github.com/docker/go-units"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -43,7 +44,7 @@ var (
|
||||
Command = &cli.Command{
|
||||
Name: "content",
|
||||
Usage: "Manage content",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
activeIngestCommand,
|
||||
deleteCommand,
|
||||
editCommand,
|
||||
@@ -64,8 +65,7 @@ var (
|
||||
Usage: "Get the data for an object",
|
||||
ArgsUsage: "[<digest>, ...]",
|
||||
Description: "display the image object",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
dgst, err := digest.Parse(cmd.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -104,8 +104,7 @@ var (
|
||||
Usage: "Verify content against expected digest",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
ref = cmd.Args().First()
|
||||
expectedSize = cmd.Int64("expected-size")
|
||||
@@ -142,7 +141,7 @@ var (
|
||||
Name: "timeout",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "Total timeout for fetch",
|
||||
EnvVars: []string{"CONTAINERD_FETCH_TIMEOUT"},
|
||||
Sources: cli.EnvVars("CONTAINERD_FETCH_TIMEOUT"),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "root",
|
||||
@@ -150,8 +149,7 @@ var (
|
||||
Value: "/tmp/content", // TODO(stevvooe): for now, just use the PWD/.content
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
match := cmd.Args().First()
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
@@ -189,8 +187,7 @@ var (
|
||||
Usage: "Print only the blob digest",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
quiet = cmd.Bool("quiet")
|
||||
args = cmd.Args().Slice()
|
||||
@@ -243,8 +240,7 @@ var (
|
||||
Usage: "Add labels to content",
|
||||
ArgsUsage: "<digest> [<label>=<value> ...]",
|
||||
Description: "labels blobs in the content store",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
object, labels := commands.ObjectWithLabelArgs(cmd)
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
@@ -306,11 +302,10 @@ var (
|
||||
&cli.StringFlag{
|
||||
Name: "editor",
|
||||
Usage: "Select editor (vim, emacs, etc.)",
|
||||
EnvVars: []string{"EDITOR"},
|
||||
Sources: cli.EnvVars("EDITOR"),
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
validate = cmd.String("validate")
|
||||
object = cmd.Args().First()
|
||||
@@ -370,8 +365,7 @@ var (
|
||||
ArgsUsage: "[<digest>, ...]",
|
||||
Description: `Delete one or more blobs permanently. Successfully deleted
|
||||
blobs are printed to stdout.`,
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
args = cmd.Args().Slice()
|
||||
exitError error
|
||||
@@ -419,8 +413,7 @@ var (
|
||||
ArgsUsage: "[flags] <remote> <object> [<hint>, ...]",
|
||||
Description: `Fetch objects by identifier from a remote.`,
|
||||
Flags: commands.RegistryFlags,
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
ctx, cancel := commands.AppContext(ctx, cmd)
|
||||
defer cancel()
|
||||
|
||||
@@ -465,12 +458,11 @@ var (
|
||||
Usage: "Specify target mediatype for request header",
|
||||
},
|
||||
}...),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
digests := cmd.Args().Tail()
|
||||
if len(digests) == 0 {
|
||||
return errors.New("must specify digests")
|
||||
}
|
||||
ctx := cmd.Context
|
||||
ctx, cancel := commands.AppContext(ctx, cmd)
|
||||
defer cancel()
|
||||
|
||||
@@ -519,8 +511,7 @@ var (
|
||||
ArgsUsage: "[flags] <remote> <object> <type>",
|
||||
Description: `Push objects by identifier to a remote.`,
|
||||
Flags: commands.RegistryFlags,
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
ref = cmd.Args().Get(0)
|
||||
object = cmd.Args().Get(1)
|
||||
@@ -600,7 +591,7 @@ func edit(editor string, rd io.Reader) (_ io.ReadCloser, retErr error) {
|
||||
}
|
||||
}()
|
||||
_, err = io.Copy(tmp, rd)
|
||||
tmp.Close()
|
||||
_ = tmp.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ import (
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var fetchCommand = &cli.Command{
|
||||
@@ -76,8 +76,7 @@ pull content that will later be used with 'ctr run' or 'ctr images unpack'.`,
|
||||
Usage: "Pull all metadata including manifests and configs",
|
||||
},
|
||||
),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -115,7 +114,7 @@ type FetchConfig struct {
|
||||
}
|
||||
|
||||
// NewFetchConfig returns the default FetchConfig from cli flags
|
||||
func NewFetchConfig(ctx context.Context, cmd *cli.Context) (*FetchConfig, error) {
|
||||
func NewFetchConfig(ctx context.Context, cmd *cli.Command) (*FetchConfig, error) {
|
||||
resolver, err := commands.GetResolver(ctx, cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package content
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
@@ -25,7 +26,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/core/content"
|
||||
"github.com/containerd/containerd/v2/core/leases"
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -47,7 +48,7 @@ var pruneFlags = []cli.Flag{
|
||||
var pruneCommand = &cli.Command{
|
||||
Name: "prune",
|
||||
Usage: "Prunes content from the content store",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
pruneReferencesCommand,
|
||||
},
|
||||
}
|
||||
@@ -56,8 +57,7 @@ var pruneReferencesCommand = &cli.Command{
|
||||
Name: "references",
|
||||
Usage: "Prunes preference labels from the content store (layers only by default)",
|
||||
Flags: pruneFlags,
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
package deprecations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
api "github.com/containerd/containerd/api/services/introspection/v1"
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
@@ -32,7 +33,7 @@ import (
|
||||
// Command is the parent for all commands under "deprecations"
|
||||
var Command = &cli.Command{
|
||||
Name: "deprecations",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
listCommand,
|
||||
},
|
||||
}
|
||||
@@ -45,8 +46,7 @@ var listCommand = &cli.Command{
|
||||
Usage: "output format to use (Examples: 'default', 'json')",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
// Suppress automatic warnings, since we print the warnings by ourselves.
|
||||
_ = os.Setenv("CONTAINERD_SUPPRESS_DEPRECATION_WARNINGS", "1")
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
@@ -24,7 +25,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/core/events"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/typeurl/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
// Register grpc event types
|
||||
_ "github.com/containerd/containerd/api/events"
|
||||
@@ -35,8 +36,7 @@ var Command = &cli.Command{
|
||||
Name: "events",
|
||||
Aliases: []string{"event"},
|
||||
Usage: "Display containerd events",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/platforms"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/v2/core/content"
|
||||
@@ -69,8 +69,7 @@ dmverity_mode=on, which rejects cache hits that lack a sidecar.`,
|
||||
Usage: "Generate a dm-verity hash tree and .dmverity sidecar for each blob (Linux only)",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
ref := cmd.Args().Get(0)
|
||||
cacheDir := cmd.Args().Get(1)
|
||||
if ref == "" || cacheDir == "" {
|
||||
@@ -111,7 +110,7 @@ dmverity_mode=on, which rejects cache hits that lack a sidecar.`,
|
||||
}
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(cmd.App.Writer, cacheDir)
|
||||
_, _ = fmt.Fprintln(cmd.Writer, cacheDir)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
@@ -26,7 +27,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/core/images/converter/erofs"
|
||||
"github.com/containerd/containerd/v2/core/images/converter/uncompress"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var convertCommand = &cli.Command{
|
||||
@@ -75,8 +76,7 @@ When '--all-platforms' is given all images in a manifest list must be available.
|
||||
Usage: "Exports content from all platforms",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var convertOpts []converter.Opt
|
||||
srcRef := cmd.Args().Get(0)
|
||||
targetRef := cmd.Args().Get(1)
|
||||
@@ -134,7 +134,7 @@ When '--all-platforms' is given all images in a manifest list must be available.
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(cmd.App.Writer, newImg.Target.Digest.String())
|
||||
_, _ = fmt.Fprintln(cmd.Writer, newImg.Target.Digest.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -17,12 +17,13 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/v2/core/images/archive"
|
||||
@@ -65,8 +66,7 @@ When '--all-platforms' is given all images in a manifest list must be available.
|
||||
Usage: "Run export locally rather than through transfer API",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
out = cmd.Args().First()
|
||||
images = cmd.Args().Tail()
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -30,7 +31,7 @@ import (
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command is the cli command for managing images
|
||||
@@ -38,7 +39,7 @@ var Command = &cli.Command{
|
||||
Name: "images",
|
||||
Aliases: []string{"image", "i"},
|
||||
Usage: "Manage images",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
checkCommand,
|
||||
exportCommand,
|
||||
importCommand,
|
||||
@@ -71,8 +72,7 @@ var listCommand = &cli.Command{
|
||||
Usage: "Print only the image refs",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
filters = cmd.Args().Slice()
|
||||
quiet = cmd.Bool("quiet")
|
||||
@@ -156,8 +156,7 @@ var setLabelsCommand = &cli.Command{
|
||||
Usage: "Replace all labels",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
replaceAll = cmd.Bool("replace-all")
|
||||
name, labels = commands.ObjectWithLabelArgs(cmd)
|
||||
@@ -217,8 +216,7 @@ var checkCommand = &cli.Command{
|
||||
Usage: "Print only the ready image refs (fully downloaded and unpacked)",
|
||||
},
|
||||
}, commands.SnapshotterFlags...),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
exitErr error
|
||||
quiet = cmd.Bool("quiet")
|
||||
@@ -332,8 +330,7 @@ var removeCommand = &cli.Command{
|
||||
Usage: "Synchronously remove image and all associated resources",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -378,8 +375,7 @@ var pruneCommand = &cli.Command{
|
||||
},
|
||||
// adapted from `nerdctl`:
|
||||
// https://github.com/containerd/nerdctl/blob/272dc9c29fc1434839d3ec63194d7efa24d7c0ef/cmd/nerdctl/image_prune.go#L86
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,13 +17,14 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
containerd "github.com/containerd/containerd/v2/client"
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
@@ -105,8 +106,7 @@ If foobar.tar contains an OCI ref named "latest" and anonymous ref "sha256:deadb
|
||||
},
|
||||
}, append(commands.SnapshotterFlags, commands.LabelFlag)...),
|
||||
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
in = cmd.Args().First()
|
||||
opts []containerd.ImportOpt
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/v2/pkg/display"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var inspectCommand = &cli.Command{
|
||||
@@ -36,8 +37,7 @@ var inspectCommand = &cli.Command{
|
||||
Usage: "Show JSON content",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
@@ -26,7 +27,7 @@ import (
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
containerd "github.com/containerd/containerd/v2/client"
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
@@ -65,8 +66,7 @@ When you are done, use the unmount command.
|
||||
Value: 1 * time.Hour,
|
||||
},
|
||||
),
|
||||
Action: func(cmd *cli.Context) (retErr error) {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) (retErr error) {
|
||||
var (
|
||||
ref = cmd.Args().First()
|
||||
target = cmd.Args().Get(1)
|
||||
@@ -162,7 +162,7 @@ When you are done, use the unmount command.
|
||||
if target != "" {
|
||||
if err := mount.All(mounts, target); err != nil {
|
||||
if err := s.Remove(ctx, key); err != nil && !errdefs.IsNotFound(err) {
|
||||
fmt.Fprintln(cmd.App.ErrWriter, "Error cleaning up snapshot after mount error:", err)
|
||||
_, _ = fmt.Fprintln(cmd.ErrWriter, "Error cleaning up snapshot after mount error:", err)
|
||||
}
|
||||
return fmt.Errorf("failed to mount %v: %w", mounts, err)
|
||||
}
|
||||
@@ -172,7 +172,7 @@ When you are done, use the unmount command.
|
||||
return fmt.Errorf("cannot handle returned mounts: %v", mounts)
|
||||
}
|
||||
|
||||
fmt.Fprintln(cmd.App.Writer, target)
|
||||
_, _ = fmt.Fprintln(cmd.Writer, target)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -38,7 +38,7 @@ import (
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var pullCommand = &cli.Command{
|
||||
@@ -89,8 +89,7 @@ command. As part of this process, we do the following:
|
||||
Usage: "Synchronize the underlying filesystem containing files when unpack images, false by default",
|
||||
},
|
||||
),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
ref := cmd.Args().First()
|
||||
if ref == "" {
|
||||
return errors.New("please provide an image reference to pull")
|
||||
|
||||
@@ -40,7 +40,7 @@ import (
|
||||
"github.com/containerd/platforms"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@@ -77,8 +77,7 @@ var pushCommand = &cli.Command{
|
||||
Name: "allow-non-distributable-blobs",
|
||||
Usage: "Allow pushing blobs that are marked as non-distributable",
|
||||
}),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
ref = cmd.Args().First()
|
||||
local = cmd.Args().Get(1)
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/v2/core/transfer/image"
|
||||
@@ -47,8 +48,7 @@ var tagCommand = &cli.Command{
|
||||
Usage: "Skip the strict check for reference names",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
ref := cmd.Args().First()
|
||||
if ref == "" {
|
||||
return errors.New("please provide an image reference to tag from")
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
@@ -24,7 +25,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/core/leases"
|
||||
"github.com/containerd/containerd/v2/core/mount"
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var unmountCommand = &cli.Command{
|
||||
@@ -38,8 +39,7 @@ var unmountCommand = &cli.Command{
|
||||
Usage: "Remove the snapshot after a successful unmount",
|
||||
},
|
||||
),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
target := cmd.Args().First()
|
||||
if target == "" {
|
||||
return errors.New("please provide a target path to unmount from")
|
||||
@@ -66,7 +66,7 @@ var unmountCommand = &cli.Command{
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintln(cmd.App.Writer, target)
|
||||
_, _ = fmt.Fprintln(cmd.Writer, target)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -28,7 +29,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/pkg/progress"
|
||||
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var usageCommand = &cli.Command{
|
||||
@@ -36,8 +37,7 @@ var usageCommand = &cli.Command{
|
||||
Usage: "Display usage of snapshots for a given image ref",
|
||||
ArgsUsage: "[flags] <ref>",
|
||||
Flags: commands.SnapshotterFlags,
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
ref := cmd.Args().First()
|
||||
if ref == "" {
|
||||
return errors.New("please provide an image reference to mount")
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
api "github.com/containerd/containerd/api/services/introspection/v1"
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
type Info struct {
|
||||
@@ -30,8 +32,7 @@ type Info struct {
|
||||
var Command = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "Print the server info",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
package install
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
containerd "github.com/containerd/containerd/v2/client"
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command to install binary packages
|
||||
@@ -44,8 +46,7 @@ var Command = &cli.Command{
|
||||
Usage: "Set an optional install path other than the managed opt directory",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package leases
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
@@ -26,14 +27,14 @@ import (
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/v2/core/leases"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command is the cli command for managing content
|
||||
var Command = &cli.Command{
|
||||
Name: "leases",
|
||||
Usage: "Manage leases",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
listCommand,
|
||||
createCommand,
|
||||
deleteCommand,
|
||||
@@ -54,8 +55,7 @@ var listCommand = &cli.Command{
|
||||
Usage: "Print only the blob digest",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
filters = cmd.Args().Slice()
|
||||
quiet = cmd.Bool("quiet")
|
||||
@@ -118,8 +118,7 @@ var createCommand = &cli.Command{
|
||||
Value: 24 * time.Hour,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
labelstr := cmd.Args().Slice()
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
@@ -168,8 +167,7 @@ var deleteCommand = &cli.Command{
|
||||
Usage: "Synchronously remove leases and all unreferenced resources",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
lids := cmd.Args().Slice()
|
||||
if len(lids) == 0 {
|
||||
return cli.ShowSubcommandHelp(cmd)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package namespaces
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -27,7 +28,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command is the cli command for managing namespaces
|
||||
@@ -35,7 +36,7 @@ var Command = &cli.Command{
|
||||
Name: "namespaces",
|
||||
Aliases: []string{"namespace", "ns"},
|
||||
Usage: "Manage namespaces",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
createCommand,
|
||||
listCommand,
|
||||
removeCommand,
|
||||
@@ -49,8 +50,7 @@ var createCommand = &cli.Command{
|
||||
Usage: "Create a new namespace",
|
||||
ArgsUsage: "<name> [<key>=<value>]",
|
||||
Description: "create a new namespace. it must be unique",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
namespace, labels := commands.ObjectWithLabelArgs(cmd)
|
||||
if namespace == "" {
|
||||
return errors.New("please specify a namespace")
|
||||
@@ -70,8 +70,7 @@ var setLabelsCommand = &cli.Command{
|
||||
Usage: "Set and clear labels for a namespace",
|
||||
ArgsUsage: "<name> [<key>=<value>, ...]",
|
||||
Description: "set and clear labels for a namespace. empty value clears the label",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
namespace, labels := commands.ObjectWithLabelArgs(cmd)
|
||||
if namespace == "" {
|
||||
return errors.New("please specify a namespace")
|
||||
@@ -104,8 +103,7 @@ var listCommand = &cli.Command{
|
||||
Usage: "Print only the namespace name",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -158,8 +156,7 @@ var removeCommand = &cli.Command{
|
||||
Usage: "Delete the namespace's cgroup",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -19,10 +19,10 @@ package namespaces
|
||||
import (
|
||||
"github.com/containerd/containerd/v2/core/runtime/opts"
|
||||
"github.com/containerd/containerd/v2/pkg/namespaces"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func deleteOpts(cmd *cli.Context) []namespaces.DeleteOpts {
|
||||
func deleteOpts(cmd *cli.Command) []namespaces.DeleteOpts {
|
||||
var delOpts []namespaces.DeleteOpts
|
||||
if cmd.Bool("cgroup") {
|
||||
delOpts = append(delOpts, opts.WithNamespaceCgroupDeletion)
|
||||
|
||||
@@ -20,9 +20,9 @@ package namespaces
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/v2/pkg/namespaces"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func deleteOpts(cmd *cli.Context) []namespaces.DeleteOpts {
|
||||
func deleteOpts(cmd *cli.Command) []namespaces.DeleteOpts {
|
||||
return nil
|
||||
}
|
||||
@@ -17,9 +17,10 @@
|
||||
package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/v2/core/containers"
|
||||
@@ -31,7 +32,7 @@ import (
|
||||
var Command = &cli.Command{
|
||||
Name: "oci",
|
||||
Usage: "OCI tools",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
defaultSpecCommand,
|
||||
},
|
||||
}
|
||||
@@ -45,8 +46,7 @@ var defaultSpecCommand = &cli.Command{
|
||||
Usage: "Platform of the spec to print (Examples: 'linux/arm64', 'windows/amd64')",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
ctx, cancel := commands.AppContext(ctx, cmd)
|
||||
defer cancel()
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -29,7 +30,7 @@ import (
|
||||
"github.com/containerd/platforms"
|
||||
pluginutils "github.com/containerd/plugin"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
@@ -38,7 +39,7 @@ var Command = &cli.Command{
|
||||
Name: "plugins",
|
||||
Aliases: []string{"plugin"},
|
||||
Usage: "Provides information about containerd plugins",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
listCommand,
|
||||
inspectRuntimeCommand,
|
||||
},
|
||||
@@ -60,8 +61,7 @@ var listCommand = &cli.Command{
|
||||
Usage: "Print detailed information about each plugin",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
quiet = cmd.Bool("quiet")
|
||||
detailed = cmd.Bool("detailed")
|
||||
@@ -173,8 +173,7 @@ var inspectRuntimeCommand = &cli.Command{
|
||||
Usage: "Display runtime info",
|
||||
ArgsUsage: "[flags]",
|
||||
Flags: commands.RuntimeFlags,
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
rt := cmd.String("runtime")
|
||||
rtOptions, err := commands.RuntimeOptions(cmd)
|
||||
if err != nil {
|
||||
@@ -193,7 +192,7 @@ var inspectRuntimeCommand = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fmt.Fprintln(cmd.App.Writer, string(j))
|
||||
_, err = fmt.Fprintln(cmd.Writer, string(j))
|
||||
return err
|
||||
},
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
package pprof
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -24,7 +25,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/v2/defaults"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
type pprofDialer struct {
|
||||
@@ -44,7 +45,7 @@ var Command = &cli.Command{
|
||||
Value: defaults.DefaultDebugAddress,
|
||||
},
|
||||
},
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
pprofBlockCommand,
|
||||
pprofGoroutinesCommand,
|
||||
pprofHeapCommand,
|
||||
@@ -64,7 +65,7 @@ var pprofGoroutinesCommand = &cli.Command{
|
||||
Value: 2,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return GoroutineProfile(cmd, getPProfClient)
|
||||
},
|
||||
}
|
||||
@@ -79,7 +80,7 @@ var pprofHeapCommand = &cli.Command{
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return HeapProfile(cmd, getPProfClient)
|
||||
},
|
||||
}
|
||||
@@ -100,7 +101,7 @@ var pprofProfileCommand = &cli.Command{
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return CPUProfile(cmd, getPProfClient)
|
||||
},
|
||||
}
|
||||
@@ -121,7 +122,7 @@ var pprofTraceCommand = &cli.Command{
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return TraceProfile(cmd, getPProfClient)
|
||||
},
|
||||
}
|
||||
@@ -136,7 +137,7 @@ var pprofBlockCommand = &cli.Command{
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return BlockProfile(cmd, getPProfClient)
|
||||
},
|
||||
}
|
||||
@@ -151,16 +152,16 @@ var pprofThreadcreateCommand = &cli.Command{
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return ThreadcreateProfile(cmd, getPProfClient)
|
||||
},
|
||||
}
|
||||
|
||||
// Client is a func that returns a http client for a pprof server
|
||||
type Client func(cmd *cli.Context) (*http.Client, error)
|
||||
type Client func(cmd *cli.Command) (*http.Client, error)
|
||||
|
||||
// GoroutineProfile dumps goroutine stack dump
|
||||
func GoroutineProfile(cmd *cli.Context, clientFunc Client) error {
|
||||
func GoroutineProfile(cmd *cli.Command, clientFunc Client) error {
|
||||
client, err := clientFunc(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -176,7 +177,7 @@ func GoroutineProfile(cmd *cli.Context, clientFunc Client) error {
|
||||
}
|
||||
|
||||
// HeapProfile dumps the heap profile
|
||||
func HeapProfile(cmd *cli.Context, clientFunc Client) error {
|
||||
func HeapProfile(cmd *cli.Command, clientFunc Client) error {
|
||||
client, err := clientFunc(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -192,7 +193,7 @@ func HeapProfile(cmd *cli.Context, clientFunc Client) error {
|
||||
}
|
||||
|
||||
// CPUProfile dumps CPU profile
|
||||
func CPUProfile(cmd *cli.Context, clientFunc Client) error {
|
||||
func CPUProfile(cmd *cli.Command, clientFunc Client) error {
|
||||
client, err := clientFunc(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -209,7 +210,7 @@ func CPUProfile(cmd *cli.Context, clientFunc Client) error {
|
||||
}
|
||||
|
||||
// TraceProfile collects execution trace
|
||||
func TraceProfile(cmd *cli.Context, clientFunc Client) error {
|
||||
func TraceProfile(cmd *cli.Command, clientFunc Client) error {
|
||||
client, err := clientFunc(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -227,7 +228,7 @@ func TraceProfile(cmd *cli.Context, clientFunc Client) error {
|
||||
}
|
||||
|
||||
// BlockProfile collects goroutine blocking profile
|
||||
func BlockProfile(cmd *cli.Context, clientFunc Client) error {
|
||||
func BlockProfile(cmd *cli.Command, clientFunc Client) error {
|
||||
client, err := clientFunc(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -243,7 +244,7 @@ func BlockProfile(cmd *cli.Context, clientFunc Client) error {
|
||||
}
|
||||
|
||||
// ThreadcreateProfile collects goroutine thread creating profile
|
||||
func ThreadcreateProfile(cmd *cli.Context, clientFunc Client) error {
|
||||
func ThreadcreateProfile(cmd *cli.Command, clientFunc Client) error {
|
||||
client, err := clientFunc(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -258,7 +259,7 @@ func ThreadcreateProfile(cmd *cli.Context, clientFunc Client) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func getPProfClient(cmd *cli.Context) (*http.Client, error) {
|
||||
func getPProfClient(cmd *cli.Command) (*http.Client, error) {
|
||||
dialer := getPProfDialer(cmd.String("debug-socket"))
|
||||
|
||||
tr := &http.Transport{
|
||||
|
||||
@@ -33,7 +33,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/core/remotes/docker/config"
|
||||
"github.com/containerd/containerd/v2/core/transfer/registry"
|
||||
"github.com/containerd/containerd/v2/pkg/httpdbg"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// PushTracker returns a new InMemoryTracker which tracks the ref status
|
||||
@@ -55,7 +55,7 @@ func passwordPrompt() (string, error) {
|
||||
}
|
||||
|
||||
// GetResolver prepares the resolver from the environment and options
|
||||
func GetResolver(ctx context.Context, cmd *cli.Context) (remotes.Resolver, error) {
|
||||
func GetResolver(ctx context.Context, cmd *cli.Command) (remotes.Resolver, error) {
|
||||
username := cmd.String("user")
|
||||
var secret string
|
||||
if i := strings.IndexByte(username, ':'); i > 0 {
|
||||
@@ -111,7 +111,7 @@ func GetResolver(ctx context.Context, cmd *cli.Context) (remotes.Resolver, error
|
||||
return docker.NewResolver(options), nil
|
||||
}
|
||||
|
||||
func resolverDefaultTLS(cmd *cli.Context) (*tls.Config, error) {
|
||||
func resolverDefaultTLS(cmd *cli.Command) (*tls.Config, error) {
|
||||
tlsConfig := &tls.Config{}
|
||||
|
||||
if cmd.Bool("skip-verify") {
|
||||
@@ -158,7 +158,7 @@ type staticCredentials struct {
|
||||
}
|
||||
|
||||
// NewStaticCredentials gets credentials from passing in cli context
|
||||
func NewStaticCredentials(ctx context.Context, cmd *cli.Context, ref string) (registry.CredentialHelper, error) {
|
||||
func NewStaticCredentials(ctx context.Context, cmd *cli.Command, ref string) (registry.CredentialHelper, error) {
|
||||
username := cmd.String("user")
|
||||
var secret string
|
||||
if i := strings.IndexByte(username, ':'); i > 0 {
|
||||
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
"github.com/containerd/console"
|
||||
gocni "github.com/containerd/go-cni"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
@@ -43,7 +43,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/pkg/oci"
|
||||
)
|
||||
|
||||
func withMounts(cmd *cli.Context) oci.SpecOpts {
|
||||
func withMounts(cmd *cli.Command) oci.SpecOpts {
|
||||
return func(ctx context.Context, client oci.Client, container *containers.Container, s *specs.Spec) error {
|
||||
mounts := make([]specs.Mount, 0)
|
||||
dests := make([]string, 0)
|
||||
@@ -143,8 +143,7 @@ var Command = &cli.Command{
|
||||
append(commands.RuntimeFlags,
|
||||
append(append(commands.SnapshotterFlags, []cli.Flag{commands.SnapshotterLabels}...),
|
||||
commands.ContainerFlags...)...)...)...),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
err error
|
||||
id string
|
||||
|
||||
@@ -43,7 +43,7 @@ import (
|
||||
|
||||
"github.com/intel/goresctrl/pkg/blockio"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
"tags.cncf.io/container-device-interface/pkg/cdi"
|
||||
"tags.cncf.io/container-device-interface/pkg/parser"
|
||||
)
|
||||
@@ -90,7 +90,7 @@ var platformRunFlags = []cli.Flag{
|
||||
}
|
||||
|
||||
// NewContainer creates a new container
|
||||
func NewContainer(ctx context.Context, client *containerd.Client, cmd *cli.Context) (containerd.Container, error) {
|
||||
func NewContainer(ctx context.Context, client *containerd.Client, cmd *cli.Command) (containerd.Container, error) {
|
||||
var (
|
||||
id string
|
||||
config = cmd.IsSet("config")
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/pkg/oci"
|
||||
"github.com/containerd/log"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var platformRunFlags = []cli.Flag{
|
||||
@@ -46,7 +46,7 @@ var platformRunFlags = []cli.Flag{
|
||||
}
|
||||
|
||||
// NewContainer creates a new container
|
||||
func NewContainer(ctx context.Context, client *containerd.Client, cmd *cli.Context) (containerd.Container, error) {
|
||||
func NewContainer(ctx context.Context, client *containerd.Client, cmd *cli.Command) (containerd.Container, error) {
|
||||
var (
|
||||
id string
|
||||
opts []oci.SpecOpts
|
||||
@@ -126,6 +126,7 @@ func NewContainer(ctx context.Context, client *containerd.Client, cmd *cli.Conte
|
||||
|
||||
con := console.Current()
|
||||
size, err := con.Size()
|
||||
_ = con.Close()
|
||||
if err != nil {
|
||||
log.L.WithError(err).Error("console size")
|
||||
}
|
||||
@@ -184,8 +185,7 @@ func NewContainer(ctx context.Context, client *containerd.Client, cmd *cli.Conte
|
||||
Debug: cmd.Bool("debug"),
|
||||
}
|
||||
if cmd.IsSet("scrub-logs") {
|
||||
scrubLogs := cmd.Bool("scrub-logs")
|
||||
opts.ScrubLogs = &scrubLogs
|
||||
opts.ScrubLogs = new(cmd.Bool("scrub-logs"))
|
||||
}
|
||||
runtimeOpts = opts
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package sandboxes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -28,7 +29,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/pkg/oci"
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command is a set of subcommands to manage runtimes with sandbox support
|
||||
@@ -36,7 +37,7 @@ var Command = &cli.Command{
|
||||
Name: "sandboxes",
|
||||
Aliases: []string{"sandbox", "sb", "s"},
|
||||
Usage: "Manage sandboxes",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
runCommand,
|
||||
listCommand,
|
||||
removeCommand,
|
||||
@@ -56,8 +57,7 @@ var runCommand = &cli.Command{
|
||||
Value: defaults.DefaultRuntime,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
if cmd.NArg() != 2 {
|
||||
return cli.ShowSubcommandHelp(cmd)
|
||||
}
|
||||
@@ -110,8 +110,7 @@ var listCommand = &cli.Command{
|
||||
Usage: "The list of filters to apply when querying sandboxes from the store",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -159,8 +158,7 @@ var removeCommand = &cli.Command{
|
||||
Usage: "Ignore shutdown errors when removing sandbox",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -202,8 +200,7 @@ var infoCommand = &cli.Command{
|
||||
Aliases: []string{"i"},
|
||||
Usage: "Get info about a sandbox",
|
||||
ArgsUsage: "<sandbox id>",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -29,13 +29,13 @@ import (
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands/pprof"
|
||||
"github.com/containerd/containerd/v2/pkg/namespaces"
|
||||
"github.com/containerd/containerd/v2/pkg/shim"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var pprofCommand = &cli.Command{
|
||||
Name: "pprof",
|
||||
Usage: "Provide golang pprof outputs for containerd-shim",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
pprofBlockCommand,
|
||||
pprofGoroutinesCommand,
|
||||
pprofHeapCommand,
|
||||
@@ -55,7 +55,7 @@ var pprofGoroutinesCommand = &cli.Command{
|
||||
Value: 2,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return pprof.GoroutineProfile(cmd, getPProfClient)
|
||||
},
|
||||
}
|
||||
@@ -70,7 +70,7 @@ var pprofHeapCommand = &cli.Command{
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return pprof.HeapProfile(cmd, getPProfClient)
|
||||
},
|
||||
}
|
||||
@@ -91,7 +91,7 @@ var pprofProfileCommand = &cli.Command{
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return pprof.CPUProfile(cmd, getPProfClient)
|
||||
},
|
||||
}
|
||||
@@ -112,7 +112,7 @@ var pprofTraceCommand = &cli.Command{
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return pprof.TraceProfile(cmd, getPProfClient)
|
||||
},
|
||||
}
|
||||
@@ -127,7 +127,7 @@ var pprofBlockCommand = &cli.Command{
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return pprof.BlockProfile(cmd, getPProfClient)
|
||||
},
|
||||
}
|
||||
@@ -142,12 +142,12 @@ var pprofThreadcreateCommand = &cli.Command{
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return pprof.ThreadcreateProfile(cmd, getPProfClient)
|
||||
},
|
||||
}
|
||||
|
||||
func getPProfClient(cmd *cli.Context) (*http.Client, error) {
|
||||
func getPProfClient(cmd *cli.Command) (*http.Client, error) {
|
||||
id := cmd.String("id")
|
||||
if id == "" {
|
||||
return nil, errors.New("container id must be provided")
|
||||
|
||||
@@ -34,7 +34,7 @@ import (
|
||||
"github.com/containerd/ttrpc"
|
||||
"github.com/containerd/typeurl/v2"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/v2/pkg/namespaces"
|
||||
@@ -76,7 +76,7 @@ var Command = &cli.Command{
|
||||
Usage: "shim address (default: computed from shim ID)",
|
||||
},
|
||||
},
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
deleteCommand,
|
||||
execCommand,
|
||||
startCommand,
|
||||
@@ -89,7 +89,7 @@ var Command = &cli.Command{
|
||||
var startCommand = &cli.Command{
|
||||
Name: "start",
|
||||
Usage: "Start a container with a task",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
service, err := getTaskService(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -104,7 +104,7 @@ var startCommand = &cli.Command{
|
||||
var deleteCommand = &cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "Delete a container with a task",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
service, err := getTaskService(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -128,7 +128,7 @@ var shutdownCommand = &cli.Command{
|
||||
Name: "api-version",
|
||||
Usage: "shim API version {2,3}",
|
||||
Value: 3,
|
||||
Action: func(cmd *cli.Context, v int) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command, v int) error {
|
||||
if v != 2 && v != 3 {
|
||||
return fmt.Errorf("api-version must be 2 or 3")
|
||||
}
|
||||
@@ -136,7 +136,7 @@ var shutdownCommand = &cli.Command{
|
||||
},
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
switch cmd.Int("api-version") {
|
||||
case 2:
|
||||
service, err := getTaskServiceV2(cmd)
|
||||
@@ -174,7 +174,7 @@ var stateCommand = &cli.Command{
|
||||
Name: "api-version",
|
||||
Usage: "shim API version {2,3}",
|
||||
Value: 3,
|
||||
Action: func(cmd *cli.Context, v int) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command, v int) error {
|
||||
if v != 2 && v != 3 {
|
||||
return fmt.Errorf("api-version must be 2 or 3")
|
||||
}
|
||||
@@ -182,7 +182,7 @@ var stateCommand = &cli.Command{
|
||||
},
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
id := cmd.String("task-id")
|
||||
if id == "" {
|
||||
id = cmd.String("id")
|
||||
@@ -241,16 +241,12 @@ var execCommand = &cli.Command{
|
||||
Usage: "Runtime spec",
|
||||
},
|
||||
),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
service, err := getTaskService(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
id = cmd.Args().First()
|
||||
ctx = context.Background()
|
||||
)
|
||||
|
||||
id := cmd.Args().First()
|
||||
if id == "" {
|
||||
return errors.New("exec id must be provided")
|
||||
}
|
||||
@@ -318,14 +314,14 @@ var execCommand = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func getTaskService(cmd *cli.Context) (task.TTRPCTaskService, error) {
|
||||
func getTaskService(cmd *cli.Command) (task.TTRPCTaskService, error) {
|
||||
client, err := getTTRPCClient(cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return task.NewTTRPCTaskClient(client), nil
|
||||
}
|
||||
func getTaskServiceV2(cmd *cli.Context) (taskv2.TTRPCTaskService, error) {
|
||||
func getTaskServiceV2(cmd *cli.Command) (taskv2.TTRPCTaskService, error) {
|
||||
client, err := getTTRPCClient(cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -333,7 +329,7 @@ func getTaskServiceV2(cmd *cli.Context) (taskv2.TTRPCTaskService, error) {
|
||||
return taskv2.NewTTRPCTaskClient(client), nil
|
||||
}
|
||||
|
||||
func getTTRPCClient(cmd *cli.Context) (*ttrpc.Client, error) {
|
||||
func getTTRPCClient(cmd *cli.Command) (*ttrpc.Client, error) {
|
||||
id := cmd.String("id")
|
||||
shimAddress := cmd.String("shim-address")
|
||||
if id == "" && shimAddress == "" {
|
||||
|
||||
@@ -32,7 +32,7 @@ import (
|
||||
"github.com/containerd/log"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
containerd "github.com/containerd/containerd/v2/client"
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
@@ -50,7 +50,7 @@ var Command = &cli.Command{
|
||||
Aliases: []string{"snapshot"},
|
||||
Usage: "Manage snapshots",
|
||||
Flags: commands.SnapshotterFlags,
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
commitCommand,
|
||||
diffCommand,
|
||||
infoCommand,
|
||||
@@ -70,8 +70,7 @@ var listCommand = &cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List snapshots",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -115,8 +114,7 @@ var diffCommand = &cli.Command{
|
||||
Usage: "Keep diff content. up to creator to delete it.",
|
||||
},
|
||||
}, commands.LabelFlag),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
idA = cmd.Args().First()
|
||||
idB = cmd.Args().Get(1)
|
||||
@@ -209,8 +207,7 @@ var usageCommand = &cli.Command{
|
||||
Usage: "Display size in bytes",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var displaySize func(int64) string
|
||||
if cmd.Bool("b") {
|
||||
displaySize = func(s int64) string {
|
||||
@@ -261,8 +258,7 @@ var removeCommand = &cli.Command{
|
||||
Aliases: []string{"del", "remove", "rm"},
|
||||
ArgsUsage: "<key> [<key>, ...]",
|
||||
Usage: "Remove snapshots",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -295,8 +291,7 @@ var prepareCommand = &cli.Command{
|
||||
Usage: "Print out snapshot mounts as JSON",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
if narg := cmd.NArg(); narg < 1 || narg > 2 {
|
||||
return cli.ShowSubcommandHelp(cmd)
|
||||
}
|
||||
@@ -348,8 +343,7 @@ var viewCommand = &cli.Command{
|
||||
Usage: "Print out snapshot mounts as JSON",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
if narg := cmd.NArg(); narg < 1 || narg > 2 {
|
||||
return cli.ShowSubcommandHelp(cmd)
|
||||
}
|
||||
@@ -393,8 +387,7 @@ var mountCommand = &cli.Command{
|
||||
Usage: "Mounts the snapshot mounts as a temp mount and returns a bind mount",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
if cmd.NArg() != 2 {
|
||||
return cli.ShowSubcommandHelp(cmd)
|
||||
}
|
||||
@@ -436,8 +429,7 @@ var commitCommand = &cli.Command{
|
||||
Name: "commit",
|
||||
Usage: "Commit an active snapshot into the provided name",
|
||||
ArgsUsage: "<key> <active>",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
if cmd.NArg() != 2 {
|
||||
return cli.ShowSubcommandHelp(cmd)
|
||||
}
|
||||
@@ -461,8 +453,7 @@ var commitCommand = &cli.Command{
|
||||
var treeCommand = &cli.Command{
|
||||
Name: "tree",
|
||||
Usage: "Display tree view of snapshot branches",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -491,8 +482,7 @@ var infoCommand = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "Get info about a snapshot",
|
||||
ArgsUsage: "<key>",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
if cmd.NArg() != 1 {
|
||||
return cli.ShowSubcommandHelp(cmd)
|
||||
}
|
||||
@@ -520,8 +510,7 @@ var setLabelCommand = &cli.Command{
|
||||
Usage: "Add labels to content",
|
||||
ArgsUsage: "<name> [<label>=<value> ...]",
|
||||
Description: "labels snapshots in the snapshotter",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -575,8 +564,7 @@ var unpackCommand = &cli.Command{
|
||||
Usage: "Synchronize the underlying filesystem containing files when unpack images, false by default",
|
||||
},
|
||||
}, commands.SnapshotterFlags...),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
dgst, err := digest.Parse(cmd.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,19 +17,20 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/v2/pkg/cio"
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var attachCommand = &cli.Command{
|
||||
Name: "attach",
|
||||
Usage: "Attach to the IO of a running container",
|
||||
ArgsUsage: "CONTAINER",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,13 +17,14 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/containerd/containerd/api/types/runc/options"
|
||||
containerd "github.com/containerd/containerd/v2/client"
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var checkpointCommand = &cli.Command{
|
||||
@@ -44,8 +45,7 @@ var checkpointCommand = &cli.Command{
|
||||
Usage: "Path to criu work files and logs",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
id := cmd.Args().First()
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
@@ -80,7 +80,7 @@ var checkpointCommand = &cli.Command{
|
||||
}
|
||||
|
||||
// withCheckpointOpts only suitable for runc runtime now
|
||||
func withCheckpointOpts(rt string, cmd *cli.Context) containerd.CheckpointTaskOpts {
|
||||
func withCheckpointOpts(rt string, cmd *cli.Command) containerd.CheckpointTaskOpts {
|
||||
return func(r *containerd.CheckpointTaskInfo) error {
|
||||
imagePath := cmd.String("image-path")
|
||||
workPath := cmd.String("work-path")
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/v2/pkg/cio"
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var deleteCommand = &cli.Command{
|
||||
@@ -42,8 +42,7 @@ var deleteCommand = &cli.Command{
|
||||
Usage: "Process ID to kill",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/url"
|
||||
@@ -28,7 +29,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/pkg/cio"
|
||||
"github.com/containerd/containerd/v2/pkg/oci"
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var execCommand = &cli.Command{
|
||||
@@ -68,8 +69,7 @@ var execCommand = &cli.Command{
|
||||
Usage: "User id or name",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
id = cmd.Args().First()
|
||||
args = cmd.Args().Tail()
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/typeurl/v2"
|
||||
"github.com/moby/sys/signal"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
const defaultSignal = "SIGTERM"
|
||||
@@ -82,8 +82,7 @@ var killCommand = &cli.Command{
|
||||
Usage: "Send signal to all processes inside the container",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
id := cmd.Args().First()
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
|
||||
@@ -17,13 +17,14 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
tasks "github.com/containerd/containerd/api/services/tasks/v1"
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var listCommand = &cli.Command{
|
||||
@@ -38,8 +39,7 @@ var listCommand = &cli.Command{
|
||||
Usage: "Print only the task id",
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -28,7 +29,7 @@ import (
|
||||
v2 "github.com/containerd/cgroups/v3/cgroup2/stats"
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/typeurl/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -49,8 +50,7 @@ var metricsCommand = &cli.Command{
|
||||
Value: formatTable,
|
||||
},
|
||||
},
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,16 +17,17 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var pauseCommand = &cli.Command{
|
||||
Name: "pause",
|
||||
Usage: "Pause an existing container",
|
||||
ArgsUsage: "CONTAINER",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -24,15 +25,14 @@ import (
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/typeurl/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var psCommand = &cli.Command{
|
||||
Name: "ps",
|
||||
Usage: "List processes for container",
|
||||
ArgsUsage: "CONTAINER",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
id := cmd.Args().First()
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
|
||||
@@ -17,16 +17,17 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var resumeCommand = &cli.Command{
|
||||
Name: "resume",
|
||||
Usage: "Resume a paused container",
|
||||
ArgsUsage: "CONTAINER",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
client, ctx, cancel, err := commands.NewClient(ctx, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/containerd/console"
|
||||
@@ -25,7 +26,7 @@ import (
|
||||
"github.com/containerd/containerd/v2/pkg/cio"
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var startCommand = &cli.Command{
|
||||
@@ -55,8 +56,7 @@ var startCommand = &cli.Command{
|
||||
Usage: "Detach from the task after it has started execution",
|
||||
},
|
||||
}...),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var (
|
||||
id = cmd.Args().Get(0)
|
||||
detach = cmd.Bool("detach")
|
||||
|
||||
@@ -19,7 +19,7 @@ package tasks
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
type resizer interface {
|
||||
@@ -31,7 +31,7 @@ var Command = &cli.Command{
|
||||
Name: "tasks",
|
||||
Usage: "Manage tasks",
|
||||
Aliases: []string{"t", "task"},
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
attachCommand,
|
||||
checkpointCommand,
|
||||
deleteCommand,
|
||||
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
containerd "github.com/containerd/containerd/v2/client"
|
||||
"github.com/containerd/containerd/v2/pkg/cio"
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@@ -115,13 +115,13 @@ func NewTask(ctx context.Context, client *containerd.Client, container container
|
||||
return nil, err
|
||||
}
|
||||
stdinC.closer = func() {
|
||||
t.CloseIO(ctx, containerd.WithStdinCloser)
|
||||
_ = t.CloseIO(ctx, containerd.WithStdinCloser)
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// GetNewTaskOpts resolves containerd.NewTaskOpts from cli.Context
|
||||
func GetNewTaskOpts(cmd *cli.Context) []containerd.NewTaskOpts {
|
||||
func GetNewTaskOpts(cmd *cli.Command) []containerd.NewTaskOpts {
|
||||
if cmd.Bool("no-pivot") {
|
||||
return []containerd.NewTaskOpts{containerd.WithNoPivotRoot}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
containerd "github.com/containerd/containerd/v2/client"
|
||||
"github.com/containerd/containerd/v2/pkg/cio"
|
||||
"github.com/containerd/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var platformStartFlags = []cli.Flag{}
|
||||
@@ -83,6 +83,6 @@ func NewTask(ctx context.Context, client *containerd.Client, container container
|
||||
}
|
||||
|
||||
// GetNewTaskOpts resolves containerd.NewTaskOpts from cli.Context
|
||||
func GetNewTaskOpts(_ *cli.Context) []containerd.NewTaskOpts {
|
||||
func GetNewTaskOpts(_ *cli.Command) []containerd.NewTaskOpts {
|
||||
return nil
|
||||
}
|
||||
@@ -17,20 +17,20 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/v2/version"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command is a cli command to output the client and containerd server version
|
||||
var Command = &cli.Command{
|
||||
Name: "version",
|
||||
Usage: "Print the client and server versions",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
ctx := cmd.Context
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
if cmd.NArg() != 0 {
|
||||
return fmt.Errorf("extra arguments: %v", cmd.Args())
|
||||
}
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ import (
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
if err := app.New().RunContext(ctx, os.Args); err != nil {
|
||||
if err := app.New().Run(ctx, os.Args); err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "ctr:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@ import (
|
||||
|
||||
"github.com/containerd/containerd/v2/cmd/containerd/command"
|
||||
"github.com/containerd/containerd/v2/cmd/ctr/app"
|
||||
"github.com/urfave/cli/v2"
|
||||
docs "github.com/urfave/cli-docs/v3"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -37,7 +38,7 @@ func main() {
|
||||
|
||||
func run() error {
|
||||
flag.Parse()
|
||||
apps := map[string]*cli.App{
|
||||
apps := map[string]*cli.Command{
|
||||
"containerd": command.App(),
|
||||
"ctr": app.New(),
|
||||
}
|
||||
@@ -55,7 +56,7 @@ func run() error {
|
||||
|
||||
// clear out the usage as we use banners that do not display in man pages
|
||||
appName.Usage = ""
|
||||
data, err := appName.ToMan()
|
||||
data, err := docs.ToMan(appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -62,7 +62,8 @@ require (
|
||||
github.com/sirupsen/logrus v1.10.2
|
||||
github.com/stretchr/testify v1.12.1
|
||||
github.com/tchap/go-patricia/v2 v2.3.3
|
||||
github.com/urfave/cli/v2 v2.27.7
|
||||
github.com/urfave/cli-docs/v3 v3.1.0
|
||||
github.com/urfave/cli/v3 v3.11.0
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
github.com/vishvananda/netns v0.0.5
|
||||
go.etcd.io/bbolt v1.5.0
|
||||
@@ -136,7 +137,6 @@ require (
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect
|
||||
github.com/tetratelabs/wazero v1.11.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.46.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.11.0 // indirect
|
||||
|
||||
@@ -278,16 +278,16 @@ github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhg
|
||||
github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
|
||||
github.com/tetratelabs/wazero v1.11.0 h1:+gKemEuKCTevU4d7ZTzlsvgd1uaToIDtlQlmNbwqYhA=
|
||||
github.com/tetratelabs/wazero v1.11.0/go.mod h1:eV28rsN8Q+xwjogd7f4/Pp4xFxO7uOGbLcD/LzB1wiU=
|
||||
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
|
||||
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
|
||||
github.com/urfave/cli-docs/v3 v3.1.0 h1:Sa5xm19IpE5gpm6tZzXdfjdFxn67PnEsE4dpXF7vsKw=
|
||||
github.com/urfave/cli-docs/v3 v3.1.0/go.mod h1:59d+5Hz1h6GSGJ10cvcEkbIe3j233t4XDqI72UIx7to=
|
||||
github.com/urfave/cli/v3 v3.11.0 h1:P/euJp99kb9p0tlVY+iYTLYYTAQlfl0hR2gUO1Img1Q=
|
||||
github.com/urfave/cli/v3 v3.11.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
|
||||
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
|
||||
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
|
||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.etcd.io/bbolt v1.5.0 h1:S7GAl7Fxv12yohbwFfIbQCGDWbQbtDGPET4P/bD4lxU=
|
||||
go.etcd.io/bbolt v1.5.0/go.mod h1:mkltfYE5aUHQxUct9N9V+Kp7aSjFqjgrhcXIS70Lrdk=
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
*.gotmpl text eol=lf
|
||||
Generated
-3
@@ -4,11 +4,8 @@
|
||||
.*envrc
|
||||
.envrc
|
||||
.idea
|
||||
# goimports is installed here if not available
|
||||
/.local/
|
||||
/site/
|
||||
coverage.txt
|
||||
internal/*/built-example
|
||||
vendor
|
||||
/cmd/urfave-cli-genflags/urfave-cli-genflags
|
||||
*.exe
|
||||
vendor/github.com/urfave/cli/v2/.golangci.yaml → vendor/github.com/urfave/cli-docs/v3/.golangci.yaml
Generated
Vendored
+1
@@ -1,4 +1,5 @@
|
||||
# https://golangci-lint.run/usage/configuration/
|
||||
linters:
|
||||
enable:
|
||||
- makezero
|
||||
- misspell
|
||||
Generated
Vendored
File renamed without changes.
Generated
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 urfave/cli maintainers
|
||||
Copyright (c) 2023 urfave/cli maintainers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
.PHONY: all
|
||||
all: vet test show-cover
|
||||
|
||||
.PHONY: vet
|
||||
vet:
|
||||
go vet -v ./...
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test -v -cover -coverprofile=coverage.txt ./...
|
||||
|
||||
.PHONY: show-cover
|
||||
show-cover:
|
||||
go tool cover -func=coverage.txt
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
# Welcome to urfave/cli-docs/v3
|
||||
|
||||
[](https://github.com/urfave/cli-docs/actions/workflows/main.yml)
|
||||
[](https://pkg.go.dev/github.com/urfave/cli-docs/v3)
|
||||
[](https://goreportcard.com/report/github.com/urfave/cli-docs/v3)
|
||||
|
||||
urfave/cli-docs/v3 is an extended documentation library for use with urfave/cli/v3.
|
||||
|
||||
## Start using
|
||||
|
||||
1. Add the dependency to your project
|
||||
|
||||
```sh
|
||||
go get github.com/urfave/cli-docs/v3@latest
|
||||
```
|
||||
|
||||
2. Add it as import
|
||||
|
||||
```diff
|
||||
import (
|
||||
+ docs "github.com/urfave/cli-docs/v3"
|
||||
)
|
||||
```
|
||||
|
||||
3. Now use it e.g. to generate markdown document from a command
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
docs "github.com/urfave/cli-docs/v3"
|
||||
cli "github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := &cli.Command{
|
||||
Name: "greet",
|
||||
Usage: "say a greeting",
|
||||
Action: func(ctx context.Context, c *cli.Command) error {
|
||||
fmt.Println("Greetings")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
md, err := docs.ToMarkdown(app)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fi, err := os.Create("cli-docs.md")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fi.Close()
|
||||
if _, err := fi.WriteString("# CLI\n\n" + md); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This will create a file `cli-docs.md` with content:
|
||||
|
||||
````md
|
||||
# CLI
|
||||
|
||||
# NAME
|
||||
|
||||
greet - say a greeting
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
greet
|
||||
|
||||
**Usage**:
|
||||
|
||||
```
|
||||
greet [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...]
|
||||
```
|
||||
|
||||
````
|
||||
+590
@@ -0,0 +1,590 @@
|
||||
package docs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/cpuguy83/go-md2man/v2/md2man"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed markdown.md.gotmpl
|
||||
MarkdownDocTemplate string
|
||||
|
||||
//go:embed markdown_tabular.md.gotmpl
|
||||
MarkdownTabularDocTemplate string
|
||||
|
||||
isTracingOn = os.Getenv("URFAVE_CLI_TRACING") == "on"
|
||||
)
|
||||
|
||||
func tracef(format string, a ...any) {
|
||||
if !isTracingOn {
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(format, "\n") {
|
||||
format = format + "\n"
|
||||
}
|
||||
|
||||
pc, file, line, _ := runtime.Caller(1)
|
||||
cf := runtime.FuncForPC(pc)
|
||||
|
||||
fmt.Fprintf(
|
||||
os.Stderr,
|
||||
strings.Join([]string{
|
||||
"## URFAVE CLI TRACE ",
|
||||
file,
|
||||
":",
|
||||
fmt.Sprintf("%v", line),
|
||||
" ",
|
||||
fmt.Sprintf("(%s)", cf.Name()),
|
||||
" ",
|
||||
format,
|
||||
}, ""),
|
||||
a...,
|
||||
)
|
||||
}
|
||||
|
||||
// ToTabularMarkdown creates a tabular markdown documentation for
|
||||
// the `*cli.Command`. The function errors if either parsing or
|
||||
// writing of the string fails.
|
||||
func ToTabularMarkdown(cmd *cli.Command, appPath string) (string, error) {
|
||||
if appPath == "" {
|
||||
appPath = "app"
|
||||
}
|
||||
|
||||
const name = "cli"
|
||||
|
||||
t, err := template.New(name).Funcs(template.FuncMap{
|
||||
"join": strings.Join,
|
||||
}).Parse(MarkdownTabularDocTemplate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var (
|
||||
w bytes.Buffer
|
||||
tt tabularTemplate
|
||||
)
|
||||
|
||||
if err = t.ExecuteTemplate(&w, name, cliTabularAppTemplate{
|
||||
AppPath: appPath,
|
||||
Name: cmd.Name,
|
||||
Description: tt.PrepareMultilineString(cmd.Description),
|
||||
Usage: tt.PrepareMultilineString(cmd.Usage),
|
||||
UsageText: strings.FieldsFunc(cmd.UsageText, func(r rune) bool { return r == '\n' }),
|
||||
ArgsUsage: tt.PrepareMultilineString(cmd.ArgsUsage),
|
||||
GlobalFlags: tt.PrepareFlags(cmd.VisibleFlags()),
|
||||
Commands: tt.PrepareCommands(cmd.VisibleCommands(), appPath, "", 0),
|
||||
}); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tt.Prettify(w.String()), nil
|
||||
}
|
||||
|
||||
// ToTabularToFileBetweenTags creates a tabular markdown documentation for the `*App` and updates the file between
|
||||
// the tags in the file. The function errors if either parsing or writing of the string fails.
|
||||
func ToTabularToFileBetweenTags(cmd *cli.Command, appPath, filePath string, startEndTags ...string) error {
|
||||
var start, end = "<!--GENERATED:CLI_DOCS-->", "<!--/GENERATED:CLI_DOCS-->" // default tags
|
||||
|
||||
if len(startEndTags) == 2 {
|
||||
start, end = startEndTags[0], startEndTags[1]
|
||||
}
|
||||
|
||||
// read original file content
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// generate markdown
|
||||
md, err := ToTabularMarkdown(cmd, appPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// prepare regexp to replace content between start and end tags
|
||||
re, err := regexp.Compile("(?s)" + regexp.QuoteMeta(start) + "(.*?)" + regexp.QuoteMeta(end))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const comment = "<!-- Documentation inside this block generated by github.com/urfave/cli-docs/v3; DO NOT EDIT -->"
|
||||
|
||||
// replace content between start and end tags
|
||||
updated := re.ReplaceAll(content, []byte(strings.Join([]string{start, comment, md, end}, "\n")))
|
||||
|
||||
// write updated content to file
|
||||
if err = os.WriteFile(filePath, updated, 0664); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToMarkdown creates a markdown string for the `*cli.Command`
|
||||
// The function errors if either parsing or writing of the string fails.
|
||||
func ToMarkdown(cmd *cli.Command) (string, error) {
|
||||
var w bytes.Buffer
|
||||
if err := writeDocTemplate(cmd, &w, 0); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return w.String(), nil
|
||||
}
|
||||
|
||||
// ToMan creates a man page string with section number for the
|
||||
// `*cli.Command` The function errors if either parsing or writing
|
||||
// of the string fails.
|
||||
func ToManWithSection(cmd *cli.Command, sectionNumber int) (string, error) {
|
||||
var w bytes.Buffer
|
||||
if err := writeDocTemplate(cmd, &w, sectionNumber); err != nil {
|
||||
return "", err
|
||||
}
|
||||
man := md2man.Render(w.Bytes())
|
||||
return string(man), nil
|
||||
}
|
||||
|
||||
// ToMan creates a man page string for the `*cli.Command`
|
||||
// The function errors if either parsing or writing of the string fails.
|
||||
func ToMan(cmd *cli.Command) (string, error) {
|
||||
man, err := ToManWithSection(cmd, 8)
|
||||
return man, err
|
||||
}
|
||||
|
||||
type cliCommandTemplate struct {
|
||||
Command *cli.Command
|
||||
SectionNum int
|
||||
Commands []string
|
||||
GlobalArgs []string
|
||||
SynopsisArgs []string
|
||||
}
|
||||
|
||||
func writeDocTemplate(cmd *cli.Command, w io.Writer, sectionNum int) error {
|
||||
tracef("using MarkdownDocTemplate starting %[1]q", string([]byte(MarkdownDocTemplate)[0:8]))
|
||||
|
||||
const name = "cli"
|
||||
t, err := template.New(name).Parse(MarkdownDocTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return t.ExecuteTemplate(w, name, &cliCommandTemplate{
|
||||
Command: cmd,
|
||||
SectionNum: sectionNum,
|
||||
Commands: prepareCommands(cmd.Commands, 0),
|
||||
GlobalArgs: prepareArgsWithValues(cmd.VisibleFlags()),
|
||||
SynopsisArgs: prepareArgsSynopsis(cmd.VisibleFlags()),
|
||||
})
|
||||
}
|
||||
|
||||
func prepareCommands(commands []*cli.Command, level int) []string {
|
||||
var coms []string
|
||||
for _, command := range commands {
|
||||
if command.Hidden {
|
||||
continue
|
||||
}
|
||||
|
||||
usageText := prepareUsageText(command)
|
||||
|
||||
usage := prepareUsage(command, usageText)
|
||||
|
||||
prepared := fmt.Sprintf("%s %s\n\n%s%s",
|
||||
strings.Repeat("#", level+2),
|
||||
strings.Join(command.Names(), ", "),
|
||||
usage,
|
||||
usageText,
|
||||
)
|
||||
|
||||
flags := prepareArgsWithValues(command.VisibleFlags())
|
||||
if len(flags) > 0 {
|
||||
prepared += fmt.Sprintf("\n%s", strings.Join(flags, "\n"))
|
||||
}
|
||||
|
||||
coms = append(coms, prepared)
|
||||
|
||||
// recursively iterate subcommands
|
||||
if len(command.Commands) > 0 {
|
||||
coms = append(
|
||||
coms,
|
||||
prepareCommands(command.Commands, level+1)...,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return coms
|
||||
}
|
||||
|
||||
func prepareArgsWithValues(flags []cli.Flag) []string {
|
||||
return prepareFlags(flags, ", ", "**", "**", `""`, true)
|
||||
}
|
||||
|
||||
func prepareArgsSynopsis(flags []cli.Flag) []string {
|
||||
return prepareFlags(flags, "|", "[", "]", "[value]", false)
|
||||
}
|
||||
|
||||
func prepareFlags(
|
||||
flags []cli.Flag,
|
||||
sep, opener, closer, value string,
|
||||
addDetails bool,
|
||||
) []string {
|
||||
args := []string{}
|
||||
for _, f := range flags {
|
||||
flag, ok := f.(cli.DocGenerationFlag)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
modifiedArg := opener
|
||||
|
||||
for _, s := range f.Names() {
|
||||
trimmed := strings.TrimSpace(s)
|
||||
if len(modifiedArg) > len(opener) {
|
||||
modifiedArg += sep
|
||||
}
|
||||
if len(trimmed) > 1 {
|
||||
modifiedArg += fmt.Sprintf("--%s", trimmed)
|
||||
} else {
|
||||
modifiedArg += fmt.Sprintf("-%s", trimmed)
|
||||
}
|
||||
}
|
||||
modifiedArg += closer
|
||||
if flag.TakesValue() {
|
||||
modifiedArg += fmt.Sprintf("=%s", value)
|
||||
}
|
||||
|
||||
if addDetails {
|
||||
modifiedArg += flagDetails(flag)
|
||||
}
|
||||
|
||||
args = append(args, modifiedArg+"\n")
|
||||
|
||||
}
|
||||
sort.Strings(args)
|
||||
return args
|
||||
}
|
||||
|
||||
// flagDetails returns a string containing the flags metadata
|
||||
func flagDetails(flag cli.DocGenerationFlag) string {
|
||||
description := flag.GetUsage()
|
||||
value := getFlagDefaultValue(flag)
|
||||
if value != "" {
|
||||
description += " (default: " + value + ")"
|
||||
}
|
||||
return ": " + description
|
||||
}
|
||||
|
||||
func prepareUsageText(command *cli.Command) string {
|
||||
if command.UsageText == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Remove leading and trailing newlines
|
||||
preparedUsageText := strings.Trim(command.UsageText, "\n")
|
||||
|
||||
var usageText string
|
||||
if strings.Contains(preparedUsageText, "\n") {
|
||||
// Format multi-line string as a code block using the 4 space schema to allow for embedded markdown such
|
||||
// that it will not break the continuous code block.
|
||||
for _, ln := range strings.Split(preparedUsageText, "\n") {
|
||||
usageText += fmt.Sprintf(" %s\n", ln)
|
||||
}
|
||||
} else {
|
||||
// Style a single line as a note
|
||||
usageText = fmt.Sprintf(">%s\n", preparedUsageText)
|
||||
}
|
||||
|
||||
return usageText
|
||||
}
|
||||
|
||||
func prepareUsage(command *cli.Command, usageText string) string {
|
||||
if command.Usage == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
usage := command.Usage + "\n"
|
||||
// Add a newline to the Usage IFF there is a UsageText
|
||||
if usageText != "" {
|
||||
usage += "\n"
|
||||
}
|
||||
|
||||
return usage
|
||||
}
|
||||
|
||||
type (
|
||||
cliTabularAppTemplate struct {
|
||||
AppPath string
|
||||
Name string
|
||||
Usage string
|
||||
ArgsUsage string
|
||||
UsageText []string
|
||||
Description string
|
||||
GlobalFlags []cliTabularFlagTemplate
|
||||
Commands []cliTabularCommandTemplate
|
||||
}
|
||||
|
||||
cliTabularCommandTemplate struct {
|
||||
AppPath string
|
||||
Name string
|
||||
Aliases []string
|
||||
Usage string
|
||||
ArgsUsage string
|
||||
UsageText []string
|
||||
Description string
|
||||
Category string
|
||||
Flags []cliTabularFlagTemplate
|
||||
SubCommands []cliTabularCommandTemplate
|
||||
Level uint
|
||||
}
|
||||
|
||||
cliTabularFlagTemplate struct {
|
||||
Name string
|
||||
Aliases []string
|
||||
Usage string
|
||||
TakesValue bool
|
||||
Default string
|
||||
EnvVars []string
|
||||
Type string
|
||||
}
|
||||
)
|
||||
|
||||
// tabularTemplate is a struct for the tabular template preparation.
|
||||
type tabularTemplate struct{}
|
||||
|
||||
// PrepareCommands converts CLI commands into a structs for the rendering.
|
||||
func (tt tabularTemplate) PrepareCommands(commands []*cli.Command, appPath, parentCommandName string, level uint) []cliTabularCommandTemplate {
|
||||
var result = make([]cliTabularCommandTemplate, 0, len(commands))
|
||||
|
||||
for _, cmd := range commands {
|
||||
var command = cliTabularCommandTemplate{
|
||||
AppPath: appPath,
|
||||
Name: strings.TrimSpace(strings.Join([]string{parentCommandName, cmd.Name}, " ")),
|
||||
Aliases: cmd.Aliases,
|
||||
Usage: tt.PrepareMultilineString(cmd.Usage),
|
||||
UsageText: strings.FieldsFunc(cmd.UsageText, func(r rune) bool { return r == '\n' }),
|
||||
ArgsUsage: tt.PrepareMultilineString(cmd.ArgsUsage),
|
||||
Description: tt.PrepareMultilineString(cmd.Description),
|
||||
Category: cmd.Category,
|
||||
Flags: tt.PrepareFlags(cmd.VisibleFlags()),
|
||||
SubCommands: tt.PrepareCommands( // note: recursive call
|
||||
cmd.Commands,
|
||||
appPath,
|
||||
strings.Join([]string{parentCommandName, cmd.Name}, " "),
|
||||
level+1,
|
||||
),
|
||||
Level: level,
|
||||
}
|
||||
|
||||
result = append(result, command)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// PrepareFlags converts CLI flags into a structs for the rendering.
|
||||
func (tt tabularTemplate) PrepareFlags(flags []cli.Flag) []cliTabularFlagTemplate {
|
||||
var result = make([]cliTabularFlagTemplate, 0, len(flags))
|
||||
|
||||
for _, appFlag := range flags {
|
||||
flag, ok := appFlag.(cli.DocGenerationFlag)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
var f = cliTabularFlagTemplate{
|
||||
Usage: tt.PrepareMultilineString(flag.GetUsage()),
|
||||
EnvVars: flag.GetEnvVars(),
|
||||
TakesValue: flag.TakesValue(),
|
||||
Default: getFlagDefaultValue(flag),
|
||||
Type: flag.TypeName(),
|
||||
}
|
||||
|
||||
if boolFlag, isBool := appFlag.(*cli.BoolFlag); isBool {
|
||||
f.Default = strconv.FormatBool(boolFlag.Value)
|
||||
}
|
||||
|
||||
for i, name := range appFlag.Names() {
|
||||
name = strings.TrimSpace(name)
|
||||
|
||||
if i == 0 {
|
||||
f.Name = "--" + name
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if len(name) > 1 {
|
||||
name = "--" + name
|
||||
} else {
|
||||
name = "-" + name
|
||||
}
|
||||
|
||||
f.Aliases = append(f.Aliases, name)
|
||||
}
|
||||
|
||||
result = append(result, f)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// PrepareMultilineString prepares a string (removes line breaks).
|
||||
func (tabularTemplate) PrepareMultilineString(s string) string {
|
||||
return strings.TrimRight(
|
||||
strings.TrimSpace(
|
||||
strings.ReplaceAll(s, "\n", " "),
|
||||
),
|
||||
".\r\n\t",
|
||||
)
|
||||
}
|
||||
|
||||
func (tabularTemplate) Prettify(s string) string {
|
||||
var max = func(x, y int) int {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
var b strings.Builder
|
||||
|
||||
// search for tables
|
||||
for _, rawTable := range regexp.MustCompile(`(?m)^(\|[^\n]+\|\r?\n)((?:\|:?-+:?)+\|)(\n(?:\|[^\n]+\|\r?\n?)*)?$`).FindAllString(s, -1) {
|
||||
var lines = strings.FieldsFunc(rawTable, func(r rune) bool { return r == '\n' })
|
||||
|
||||
if len(lines) < 3 { // header, separator, body
|
||||
continue
|
||||
}
|
||||
|
||||
// parse table into the matrix
|
||||
var matrix = make([][]string, 0, len(lines))
|
||||
for _, line := range lines {
|
||||
items := strings.FieldsFunc(strings.Trim(line, "| "), func(r rune) bool { return r == '|' })
|
||||
|
||||
for i := range items {
|
||||
items[i] = strings.TrimSpace(items[i]) // trim spaces in cells
|
||||
}
|
||||
|
||||
matrix = append(matrix, items)
|
||||
}
|
||||
|
||||
// determine centered columns
|
||||
var centered = make([]bool, 0, len(matrix[1]))
|
||||
for _, cell := range matrix[1] {
|
||||
centered = append(centered, strings.HasPrefix(cell, ":") && strings.HasSuffix(cell, ":"))
|
||||
}
|
||||
|
||||
// calculate max lengths
|
||||
var lengths = make([]int, len(matrix[0]))
|
||||
for n, row := range matrix {
|
||||
for i, cell := range row {
|
||||
if n == 1 {
|
||||
continue // skip separator
|
||||
}
|
||||
|
||||
if l := utf8.RuneCountInString(cell); l > lengths[i] {
|
||||
lengths[i] = l
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// format cells
|
||||
for i, row := range matrix {
|
||||
for j, cell := range row {
|
||||
if i == 1 { // is separator
|
||||
if centered[j] {
|
||||
b.Reset()
|
||||
b.WriteRune(':')
|
||||
b.WriteString(strings.Repeat("-", max(0, lengths[j])))
|
||||
b.WriteRune(':')
|
||||
|
||||
row[j] = b.String()
|
||||
} else {
|
||||
row[j] = strings.Repeat("-", max(0, lengths[j]+2))
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
var (
|
||||
cellWidth = utf8.RuneCountInString(cell)
|
||||
padLeft, padRight = 1, max(1, lengths[j]-cellWidth+1) // align to the left
|
||||
)
|
||||
|
||||
if centered[j] { // is centered
|
||||
padLeft = max(1, (lengths[j]-cellWidth)/2)
|
||||
padRight = max(1, lengths[j]-cellWidth-(padLeft-1))
|
||||
}
|
||||
|
||||
b.Reset()
|
||||
b.WriteString(strings.Repeat(" ", padLeft))
|
||||
|
||||
if padLeft+cellWidth+padRight <= lengths[j]+1 {
|
||||
b.WriteRune(' ') // add an extra space if the cell is not full
|
||||
}
|
||||
|
||||
b.WriteString(cell)
|
||||
b.WriteString(strings.Repeat(" ", padRight))
|
||||
|
||||
row[j] = b.String()
|
||||
}
|
||||
}
|
||||
|
||||
b.Reset()
|
||||
|
||||
for _, row := range matrix { // build new table
|
||||
b.WriteRune('|')
|
||||
b.WriteString(strings.Join(row, "|"))
|
||||
b.WriteRune('|')
|
||||
b.WriteRune('\n')
|
||||
}
|
||||
|
||||
s = strings.Replace(s, rawTable, b.String(), 1)
|
||||
}
|
||||
|
||||
s = regexp.MustCompile(`\n{2,}`).ReplaceAllString(s, "\n\n") // normalize newlines
|
||||
s = strings.Trim(s, " \n") // trim spaces and newlines
|
||||
|
||||
return s + "\n" // add an extra newline
|
||||
}
|
||||
|
||||
// getFlagDefaultValue returns the default value of a flag. Previously, the [cli.DocGenerationFlag] interface included
|
||||
// a GetValue string method, but it was removed in https://github.com/urfave/cli/pull/1988.
|
||||
// This function serves as a workaround, attempting to retrieve the value using the removed method; if that fails, it
|
||||
// tries to obtain it via reflection (the [cli.FlagBase] still has a Value field).
|
||||
func getFlagDefaultValue(f cli.DocGenerationFlag) string {
|
||||
if !f.TakesValue() {
|
||||
return ""
|
||||
}
|
||||
|
||||
if v, ok := f.(interface{ GetValue() string }); ok {
|
||||
return v.GetValue()
|
||||
}
|
||||
|
||||
var ref = reflect.ValueOf(f)
|
||||
if ref.Kind() != reflect.Ptr {
|
||||
return ""
|
||||
} else {
|
||||
ref = ref.Elem()
|
||||
}
|
||||
|
||||
if ref.Kind() != reflect.Struct {
|
||||
return ""
|
||||
}
|
||||
|
||||
if val := ref.FieldByName("Value"); val.IsValid() && val.Type().Kind() != reflect.Bool {
|
||||
return fmt.Sprintf("%v", val.Interface())
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{{if gt .SectionNum 0}}% {{ .Command.Name }} {{ .SectionNum }}
|
||||
|
||||
{{end}}# NAME
|
||||
|
||||
{{ .Command.Name }}{{ if .Command.Usage }} - {{ .Command.Usage }}{{ end }}
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
{{ .Command.Name }}
|
||||
{{ if .SynopsisArgs }}
|
||||
```
|
||||
{{ range $v := .SynopsisArgs }}{{ $v }}{{ end }}```
|
||||
{{ end }}{{ if .Command.Description }}
|
||||
# DESCRIPTION
|
||||
|
||||
{{ .Command.Description }}
|
||||
{{ end }}
|
||||
**Usage**:
|
||||
|
||||
```{{ if .Command.UsageText }}
|
||||
{{ .Command.UsageText }}
|
||||
{{ else }}
|
||||
{{ .Command.Name }} [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...]
|
||||
{{ end }}```
|
||||
{{ if .GlobalArgs }}
|
||||
# GLOBAL OPTIONS
|
||||
{{ range $v := .GlobalArgs }}
|
||||
{{ $v }}{{ end }}
|
||||
{{ end }}{{ if .Commands }}
|
||||
# COMMANDS
|
||||
{{ range $v := .Commands }}
|
||||
{{ $v }}{{ end }}{{ end -}}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
{{ define "flags" }}
|
||||
| Name | Description | Type | Default value | Environment variables |
|
||||
|------|-------------|------|:-------------:|:---------------------:|
|
||||
{{ range $flag := . -}}
|
||||
{{- /**/ -}} | `{{ $flag.Name }}{{ if $flag.TakesValue }}="…"{{ end }}` {{ if $flag.Aliases }}(`{{ join $flag.Aliases "`, `" }}`) {{ end }}
|
||||
{{- /**/ -}} | {{ $flag.Usage }}
|
||||
{{- /**/ -}} | {{ $flag.Type }}
|
||||
{{- /**/ -}} | {{ if $flag.Default }}`{{ $flag.Default }}`{{ end }}
|
||||
{{- /**/ -}} | {{ if $flag.EnvVars }}`{{ join $flag.EnvVars "`, `" }}`{{ else }}*none*{{ end }}
|
||||
{{- /**/ -}} |
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ define "command" }}
|
||||
### `{{ .Name }}` {{ if gt .Level 0 }}sub{{ end }}command{{ if .Aliases }} (aliases: `{{ join .Aliases "`, `" }}`){{ end }}
|
||||
{{ if .Usage }}
|
||||
{{ .Usage }}.
|
||||
{{ end }}
|
||||
{{ if .UsageText }}
|
||||
{{ range $line := .UsageText -}}
|
||||
> {{ $line }}
|
||||
{{ end -}}
|
||||
{{ end }}
|
||||
{{ if .Description }}
|
||||
{{ .Description }}.
|
||||
{{ end }}
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
$ {{ .AppPath }} [GLOBAL FLAGS] {{ .Name }}{{ if .Flags }} [COMMAND FLAGS]{{ end }} {{ if .ArgsUsage }}{{ .ArgsUsage }}{{ else }}[ARGUMENTS...]{{ end }}
|
||||
```
|
||||
|
||||
{{ if .Flags -}}
|
||||
The following flags are supported:
|
||||
{{ template "flags" .Flags }}
|
||||
{{ end -}}
|
||||
|
||||
{{ if .SubCommands -}}
|
||||
{{ range $subCmd := .SubCommands -}}
|
||||
{{ template "command" $subCmd }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ end }}
|
||||
|
||||
## CLI interface{{ if .Name }} - {{ .Name }}{{ end }}
|
||||
|
||||
{{ if .Description }}{{ .Description }}.
|
||||
{{ end }}
|
||||
{{ if .Usage }}{{ .Usage }}.
|
||||
{{ end }}
|
||||
{{ if .UsageText }}
|
||||
{{ range $line := .UsageText -}}
|
||||
> {{ $line }}
|
||||
{{ end -}}
|
||||
{{ end }}
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
$ {{ .AppPath }}{{ if .GlobalFlags }} [GLOBAL FLAGS]{{ end }} [COMMAND] [COMMAND FLAGS] {{ if .ArgsUsage }}{{ .ArgsUsage }}{{ else }}[ARGUMENTS...]{{ end }}
|
||||
```
|
||||
|
||||
{{ if .GlobalFlags }}
|
||||
Global flags:
|
||||
|
||||
{{ template "flags" .GlobalFlags }}
|
||||
|
||||
{{ end -}}
|
||||
{{ if .Commands -}}
|
||||
{{ range $cmd := .Commands -}}
|
||||
{{ template "command" $cmd }}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
[flake8]
|
||||
max-line-length = 120
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
# cli
|
||||
|
||||
[](https://github.com/urfave/cli/actions/workflows/cli.yml)
|
||||
[](https://pkg.go.dev/github.com/urfave/cli/v2)
|
||||
[](https://goreportcard.com/report/github.com/urfave/cli/v2)
|
||||
[](https://app.codecov.io/gh/urfave/cli/tree/v2-maint)
|
||||
|
||||
cli is a simple, fast, and fun package for building command line apps in Go. The
|
||||
goal is to enable developers to write fast and distributable command line
|
||||
applications in an expressive way.
|
||||
|
||||
## Documentation
|
||||
|
||||
More documentation is available in [`./docs`](./docs) or the hosted
|
||||
documentation site at <https://cli.urfave.org>.
|
||||
|
||||
## License
|
||||
|
||||
See [`LICENSE`](./LICENSE)
|
||||
-536
@@ -1,536 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const suggestDidYouMeanTemplate = "Did you mean %q?"
|
||||
|
||||
var (
|
||||
changeLogURL = "https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md"
|
||||
appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL)
|
||||
contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you."
|
||||
errInvalidActionType = NewExitError("ERROR invalid Action type. "+
|
||||
fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+
|
||||
fmt.Sprintf("See %s", appActionDeprecationURL), 2)
|
||||
ignoreFlagPrefix = "test." // this is to ignore test flags when adding flags from other packages
|
||||
|
||||
SuggestFlag SuggestFlagFunc = nil // initialized in suggestions.go unless built with urfave_cli_no_suggest
|
||||
SuggestCommand SuggestCommandFunc = nil // initialized in suggestions.go unless built with urfave_cli_no_suggest
|
||||
SuggestDidYouMeanTemplate string = suggestDidYouMeanTemplate
|
||||
)
|
||||
|
||||
// App is the main structure of a cli application. It is recommended that
|
||||
// an app be created with the cli.NewApp() function
|
||||
type App struct {
|
||||
// The name of the program. Defaults to path.Base(os.Args[0])
|
||||
Name string
|
||||
// Full name of command for help, defaults to Name
|
||||
HelpName string
|
||||
// Description of the program.
|
||||
Usage string
|
||||
// Text to override the USAGE section of help
|
||||
UsageText string
|
||||
// Whether this command supports arguments
|
||||
Args bool
|
||||
// Description of the program argument format.
|
||||
ArgsUsage string
|
||||
// Version of the program
|
||||
Version string
|
||||
// Description of the program
|
||||
Description string
|
||||
// DefaultCommand is the (optional) name of a command
|
||||
// to run if no command names are passed as CLI arguments.
|
||||
DefaultCommand string
|
||||
// List of commands to execute
|
||||
Commands []*Command
|
||||
// List of flags to parse
|
||||
Flags []Flag
|
||||
// Boolean to enable bash completion commands
|
||||
EnableBashCompletion bool
|
||||
// Boolean to hide built-in help command and help flag
|
||||
HideHelp bool
|
||||
// Boolean to hide built-in help command but keep help flag.
|
||||
// Ignored if HideHelp is true.
|
||||
HideHelpCommand bool
|
||||
// Boolean to hide built-in version flag and the VERSION section of help
|
||||
HideVersion bool
|
||||
// categories contains the categorized commands and is populated on app startup
|
||||
categories CommandCategories
|
||||
// flagCategories contains the categorized flags and is populated on app startup
|
||||
flagCategories FlagCategories
|
||||
// An action to execute when the shell completion flag is set
|
||||
BashComplete BashCompleteFunc
|
||||
// An action to execute before any subcommands are run, but after the context is ready
|
||||
// If a non-nil error is returned, no subcommands are run
|
||||
Before BeforeFunc
|
||||
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||
// It is run even if Action() panics
|
||||
After AfterFunc
|
||||
// The action to execute when no subcommands are specified
|
||||
Action ActionFunc
|
||||
// Execute this function if the proper command cannot be found
|
||||
CommandNotFound CommandNotFoundFunc
|
||||
// Execute this function if a usage error occurs
|
||||
OnUsageError OnUsageErrorFunc
|
||||
// Execute this function when an invalid flag is accessed from the context
|
||||
InvalidFlagAccessHandler InvalidFlagAccessFunc
|
||||
// Compilation date
|
||||
Compiled time.Time
|
||||
// List of all authors who contributed
|
||||
Authors []*Author
|
||||
// Copyright of the binary if any
|
||||
Copyright string
|
||||
// Reader reader to write input to (useful for tests)
|
||||
Reader io.Reader
|
||||
// Writer writer to write output to
|
||||
Writer io.Writer
|
||||
// ErrWriter writes error output
|
||||
ErrWriter io.Writer
|
||||
// ExitErrHandler processes any error encountered while running an App before
|
||||
// it is returned to the caller. If no function is provided, HandleExitCoder
|
||||
// is used as the default behavior.
|
||||
ExitErrHandler ExitErrHandlerFunc
|
||||
// Other custom info
|
||||
Metadata map[string]interface{}
|
||||
// Carries a function which returns app specific info.
|
||||
ExtraInfo func() map[string]string
|
||||
// CustomAppHelpTemplate the text template for app help topic.
|
||||
// cli.go uses text/template to render templates. You can
|
||||
// render custom help text by setting this variable.
|
||||
CustomAppHelpTemplate string
|
||||
// SliceFlagSeparator is used to customize the separator for SliceFlag, the default is ","
|
||||
SliceFlagSeparator string
|
||||
// DisableSliceFlagSeparator is used to disable SliceFlagSeparator, the default is false
|
||||
DisableSliceFlagSeparator bool
|
||||
// Boolean to enable short-option handling so user can combine several
|
||||
// single-character bool arguments into one
|
||||
// i.e. foobar -o -v -> foobar -ov
|
||||
UseShortOptionHandling bool
|
||||
// Enable suggestions for commands and flags
|
||||
Suggest bool
|
||||
// Allows global flags set by libraries which use flag.XXXVar(...) directly
|
||||
// to be parsed through this library
|
||||
AllowExtFlags bool
|
||||
// Treat all flags as normal arguments if true
|
||||
SkipFlagParsing bool
|
||||
|
||||
didSetup bool
|
||||
separator separatorSpec
|
||||
|
||||
rootCommand *Command
|
||||
}
|
||||
|
||||
type SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string
|
||||
|
||||
type SuggestCommandFunc func(commands []*Command, provided string) string
|
||||
|
||||
// Tries to find out when this binary was compiled.
|
||||
// Returns the current time if it fails to find it.
|
||||
func compileTime() time.Time {
|
||||
info, err := os.Stat(os.Args[0])
|
||||
if err != nil {
|
||||
return time.Now()
|
||||
}
|
||||
return info.ModTime()
|
||||
}
|
||||
|
||||
// NewApp creates a new cli Application with some reasonable defaults for Name,
|
||||
// Usage, Version and Action.
|
||||
func NewApp() *App {
|
||||
return &App{
|
||||
Name: filepath.Base(os.Args[0]),
|
||||
Usage: "A new cli application",
|
||||
UsageText: "",
|
||||
BashComplete: DefaultAppComplete,
|
||||
Action: helpCommand.Action,
|
||||
Compiled: compileTime(),
|
||||
Reader: os.Stdin,
|
||||
Writer: os.Stdout,
|
||||
ErrWriter: os.Stderr,
|
||||
}
|
||||
}
|
||||
|
||||
// Setup runs initialization code to ensure all data structures are ready for
|
||||
// `Run` or inspection prior to `Run`. It is internally called by `Run`, but
|
||||
// will return early if setup has already happened.
|
||||
func (a *App) Setup() {
|
||||
if a.didSetup {
|
||||
return
|
||||
}
|
||||
|
||||
a.didSetup = true
|
||||
|
||||
if a.Name == "" {
|
||||
a.Name = filepath.Base(os.Args[0])
|
||||
}
|
||||
|
||||
if a.HelpName == "" {
|
||||
a.HelpName = a.Name
|
||||
}
|
||||
|
||||
if a.Usage == "" {
|
||||
a.Usage = "A new cli application"
|
||||
}
|
||||
|
||||
if a.Version == "" {
|
||||
a.HideVersion = true
|
||||
}
|
||||
|
||||
if a.BashComplete == nil {
|
||||
a.BashComplete = DefaultAppComplete
|
||||
}
|
||||
|
||||
if a.Action == nil {
|
||||
a.Action = helpCommand.Action
|
||||
}
|
||||
|
||||
if a.Compiled == (time.Time{}) {
|
||||
a.Compiled = compileTime()
|
||||
}
|
||||
|
||||
if a.Reader == nil {
|
||||
a.Reader = os.Stdin
|
||||
}
|
||||
|
||||
if a.Writer == nil {
|
||||
a.Writer = os.Stdout
|
||||
}
|
||||
|
||||
if a.ErrWriter == nil {
|
||||
a.ErrWriter = os.Stderr
|
||||
}
|
||||
|
||||
if a.AllowExtFlags {
|
||||
// add global flags added by other packages
|
||||
flag.VisitAll(func(f *flag.Flag) {
|
||||
// skip test flags
|
||||
if !strings.HasPrefix(f.Name, ignoreFlagPrefix) {
|
||||
a.Flags = append(a.Flags, &extFlag{f})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if len(a.SliceFlagSeparator) != 0 {
|
||||
a.separator.customized = true
|
||||
a.separator.sep = a.SliceFlagSeparator
|
||||
}
|
||||
|
||||
if a.DisableSliceFlagSeparator {
|
||||
a.separator.customized = true
|
||||
a.separator.disabled = true
|
||||
}
|
||||
|
||||
for _, c := range a.Commands {
|
||||
cname := c.Name
|
||||
if c.HelpName != "" {
|
||||
cname = c.HelpName
|
||||
}
|
||||
c.separator = a.separator
|
||||
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, cname)
|
||||
c.flagCategories = newFlagCategoriesFromFlags(c.Flags)
|
||||
}
|
||||
|
||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||
if !a.HideHelpCommand {
|
||||
a.appendCommand(helpCommand)
|
||||
}
|
||||
|
||||
if HelpFlag != nil {
|
||||
a.appendFlag(HelpFlag)
|
||||
}
|
||||
}
|
||||
|
||||
if !a.HideVersion {
|
||||
a.appendFlag(VersionFlag)
|
||||
}
|
||||
|
||||
a.categories = newCommandCategories()
|
||||
for _, command := range a.Commands {
|
||||
a.categories.AddCommand(command.Category, command)
|
||||
}
|
||||
sort.Sort(a.categories.(*commandCategories))
|
||||
|
||||
a.flagCategories = newFlagCategoriesFromFlags(a.Flags)
|
||||
|
||||
if a.Metadata == nil {
|
||||
a.Metadata = make(map[string]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) newRootCommand() *Command {
|
||||
return &Command{
|
||||
Name: a.Name,
|
||||
Usage: a.Usage,
|
||||
UsageText: a.UsageText,
|
||||
Description: a.Description,
|
||||
ArgsUsage: a.ArgsUsage,
|
||||
BashComplete: a.BashComplete,
|
||||
Before: a.Before,
|
||||
After: a.After,
|
||||
Action: a.Action,
|
||||
OnUsageError: a.OnUsageError,
|
||||
Subcommands: a.Commands,
|
||||
Flags: a.Flags,
|
||||
flagCategories: a.flagCategories,
|
||||
HideHelp: a.HideHelp,
|
||||
HideHelpCommand: a.HideHelpCommand,
|
||||
UseShortOptionHandling: a.UseShortOptionHandling,
|
||||
HelpName: a.HelpName,
|
||||
CustomHelpTemplate: a.CustomAppHelpTemplate,
|
||||
categories: a.categories,
|
||||
SkipFlagParsing: a.SkipFlagParsing,
|
||||
isRoot: true,
|
||||
separator: a.separator,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) newFlagSet() (*flag.FlagSet, error) {
|
||||
return flagSet(a.Name, a.Flags, a.separator)
|
||||
}
|
||||
|
||||
func (a *App) useShortOptionHandling() bool {
|
||||
return a.UseShortOptionHandling
|
||||
}
|
||||
|
||||
// Run is the entry point to the cli app. Parses the arguments slice and routes
|
||||
// to the proper flag/args combination
|
||||
func (a *App) Run(arguments []string) (err error) {
|
||||
return a.RunContext(context.Background(), arguments)
|
||||
}
|
||||
|
||||
// RunContext is like Run except it takes a Context that will be
|
||||
// passed to its commands and sub-commands. Through this, you can
|
||||
// propagate timeouts and cancellation requests
|
||||
func (a *App) RunContext(ctx context.Context, arguments []string) (err error) {
|
||||
a.Setup()
|
||||
|
||||
// handle the completion flag separately from the flagset since
|
||||
// completion could be attempted after a flag, but before its value was put
|
||||
// on the command line. this causes the flagset to interpret the completion
|
||||
// flag name as the value of the flag before it which is undesirable
|
||||
// note that we can only do this because the shell autocomplete function
|
||||
// always appends the completion flag at the end of the command
|
||||
shellComplete, arguments := checkShellCompleteFlag(a, arguments)
|
||||
|
||||
cCtx := NewContext(a, nil, &Context{Context: ctx})
|
||||
cCtx.shellComplete = shellComplete
|
||||
|
||||
a.rootCommand = a.newRootCommand()
|
||||
cCtx.Command = a.rootCommand
|
||||
|
||||
if err := checkDuplicatedCmds(a.rootCommand); err != nil {
|
||||
return err
|
||||
}
|
||||
return a.rootCommand.Run(cCtx, arguments...)
|
||||
}
|
||||
|
||||
// RunAsSubcommand is for legacy/compatibility purposes only. New code should only
|
||||
// use App.RunContext. This function is slated to be removed in v3.
|
||||
func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
||||
a.Setup()
|
||||
|
||||
cCtx := NewContext(a, nil, ctx)
|
||||
cCtx.shellComplete = ctx.shellComplete
|
||||
|
||||
a.rootCommand = a.newRootCommand()
|
||||
cCtx.Command = a.rootCommand
|
||||
|
||||
return a.rootCommand.Run(cCtx, ctx.Args().Slice()...)
|
||||
}
|
||||
|
||||
func (a *App) suggestFlagFromError(err error, command string) (string, error) {
|
||||
flag, parseErr := flagFromError(err)
|
||||
if parseErr != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
flags := a.Flags
|
||||
hideHelp := a.HideHelp
|
||||
if command != "" {
|
||||
cmd := a.Command(command)
|
||||
if cmd == nil {
|
||||
return "", err
|
||||
}
|
||||
flags = cmd.Flags
|
||||
hideHelp = hideHelp || cmd.HideHelp
|
||||
}
|
||||
|
||||
if SuggestFlag == nil {
|
||||
return "", err
|
||||
}
|
||||
suggestion := SuggestFlag(flags, flag, hideHelp)
|
||||
if len(suggestion) == 0 {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf(SuggestDidYouMeanTemplate+"\n\n", suggestion), nil
|
||||
}
|
||||
|
||||
// RunAndExitOnError calls .Run() and exits non-zero if an error was returned
|
||||
//
|
||||
// Deprecated: instead you should return an error that fulfills cli.ExitCoder
|
||||
// to cli.App.Run. This will cause the application to exit with the given error
|
||||
// code in the cli.ExitCoder
|
||||
func (a *App) RunAndExitOnError() {
|
||||
if err := a.Run(os.Args); err != nil {
|
||||
_, _ = fmt.Fprintln(a.ErrWriter, err)
|
||||
OsExiter(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Command returns the named command on App. Returns nil if the command does not exist
|
||||
func (a *App) Command(name string) *Command {
|
||||
for _, c := range a.Commands {
|
||||
if c.HasName(name) {
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// VisibleCategories returns a slice of categories and commands that are
|
||||
// Hidden=false
|
||||
func (a *App) VisibleCategories() []CommandCategory {
|
||||
ret := []CommandCategory{}
|
||||
for _, category := range a.categories.Categories() {
|
||||
if visible := func() CommandCategory {
|
||||
if len(category.VisibleCommands()) > 0 {
|
||||
return category
|
||||
}
|
||||
return nil
|
||||
}(); visible != nil {
|
||||
ret = append(ret, visible)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// VisibleCommands returns a slice of the Commands with Hidden=false
|
||||
func (a *App) VisibleCommands() []*Command {
|
||||
var ret []*Command
|
||||
for _, command := range a.Commands {
|
||||
if !command.Hidden {
|
||||
ret = append(ret, command)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// VisibleFlagCategories returns a slice containing all the categories with the flags they contain
|
||||
func (a *App) VisibleFlagCategories() []VisibleFlagCategory {
|
||||
if a.flagCategories == nil {
|
||||
return []VisibleFlagCategory{}
|
||||
}
|
||||
return a.flagCategories.VisibleCategories()
|
||||
}
|
||||
|
||||
// VisibleFlags returns a slice of the Flags with Hidden=false
|
||||
func (a *App) VisibleFlags() []Flag {
|
||||
return visibleFlags(a.Flags)
|
||||
}
|
||||
|
||||
func (a *App) appendFlag(fl Flag) {
|
||||
if !hasFlag(a.Flags, fl) {
|
||||
a.Flags = append(a.Flags, fl)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) appendCommand(c *Command) {
|
||||
if !hasCommand(a.Commands, c) {
|
||||
a.Commands = append(a.Commands, c)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) handleExitCoder(cCtx *Context, err error) {
|
||||
if a.ExitErrHandler != nil {
|
||||
a.ExitErrHandler(cCtx, err)
|
||||
} else {
|
||||
HandleExitCoder(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) argsWithDefaultCommand(oldArgs Args) Args {
|
||||
if a.DefaultCommand != "" {
|
||||
rawArgs := append([]string{a.DefaultCommand}, oldArgs.Slice()...)
|
||||
newArgs := args(rawArgs)
|
||||
|
||||
return &newArgs
|
||||
}
|
||||
|
||||
return oldArgs
|
||||
}
|
||||
|
||||
func runFlagActions(c *Context, fs []Flag) error {
|
||||
for _, f := range fs {
|
||||
isSet := false
|
||||
for _, name := range f.Names() {
|
||||
if c.IsSet(name) {
|
||||
isSet = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if isSet {
|
||||
if af, ok := f.(ActionableFlag); ok {
|
||||
if err := af.RunAction(c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Author represents someone who has contributed to a cli project.
|
||||
type Author struct {
|
||||
Name string // The Authors name
|
||||
Email string // The Authors email
|
||||
}
|
||||
|
||||
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
|
||||
func (a *Author) String() string {
|
||||
e := ""
|
||||
if a.Email != "" {
|
||||
e = " <" + a.Email + ">"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v%v", a.Name, e)
|
||||
}
|
||||
|
||||
// HandleAction attempts to figure out which Action signature was used. If
|
||||
// it's an ActionFunc or a func with the legacy signature for Action, the func
|
||||
// is run!
|
||||
func HandleAction(action interface{}, cCtx *Context) (err error) {
|
||||
switch a := action.(type) {
|
||||
case ActionFunc:
|
||||
return a(cCtx)
|
||||
case func(*Context) error:
|
||||
return a(cCtx)
|
||||
case func(*Context): // deprecated function signature
|
||||
a(cCtx)
|
||||
return nil
|
||||
}
|
||||
|
||||
return errInvalidActionType
|
||||
}
|
||||
|
||||
func checkStringSliceIncludes(want string, sSlice []string) bool {
|
||||
found := false
|
||||
for _, s := range sSlice {
|
||||
if want == s {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return found
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
package cli
|
||||
|
||||
type Args interface {
|
||||
// Get returns the nth argument, or else a blank string
|
||||
Get(n int) string
|
||||
// First returns the first argument, or else a blank string
|
||||
First() string
|
||||
// Tail returns the rest of the arguments (not the first one)
|
||||
// or else an empty string slice
|
||||
Tail() []string
|
||||
// Len returns the length of the wrapped slice
|
||||
Len() int
|
||||
// Present checks if there are any arguments present
|
||||
Present() bool
|
||||
// Slice returns a copy of the internal slice
|
||||
Slice() []string
|
||||
}
|
||||
|
||||
type args []string
|
||||
|
||||
func (a *args) Get(n int) string {
|
||||
if len(*a) > n {
|
||||
return (*a)[n]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (a *args) First() string {
|
||||
return a.Get(0)
|
||||
}
|
||||
|
||||
func (a *args) Tail() []string {
|
||||
if a.Len() >= 2 {
|
||||
tail := []string((*a)[1:])
|
||||
ret := make([]string, len(tail))
|
||||
copy(ret, tail)
|
||||
return ret
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (a *args) Len() int {
|
||||
return len(*a)
|
||||
}
|
||||
|
||||
func (a *args) Present() bool {
|
||||
return a.Len() != 0
|
||||
}
|
||||
|
||||
func (a *args) Slice() []string {
|
||||
ret := make([]string, len(*a))
|
||||
copy(ret, *a)
|
||||
return ret
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
// Package cli provides a minimal framework for creating and organizing command line
|
||||
// Go applications. cli is designed to be easy to understand and write, the most simple
|
||||
// cli application can be written as follows:
|
||||
//
|
||||
// func main() {
|
||||
// (&cli.App{}).Run(os.Args)
|
||||
// }
|
||||
//
|
||||
// Of course this application does not do much, so let's make this an actual application:
|
||||
//
|
||||
// func main() {
|
||||
// app := &cli.App{
|
||||
// Name: "greet",
|
||||
// Usage: "say a greeting",
|
||||
// Action: func(c *cli.Context) error {
|
||||
// fmt.Println("Greetings")
|
||||
// return nil
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// app.Run(os.Args)
|
||||
// }
|
||||
package cli
|
||||
|
||||
//go:generate make -C cmd/urfave-cli-genflags run
|
||||
-421
@@ -1,421 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Command is a subcommand for a cli.App.
|
||||
type Command struct {
|
||||
// The name of the command
|
||||
Name string
|
||||
// A list of aliases for the command
|
||||
Aliases []string
|
||||
// A short description of the usage of this command
|
||||
Usage string
|
||||
// Custom text to show on USAGE section of help
|
||||
UsageText string
|
||||
// A longer explanation of how the command works
|
||||
Description string
|
||||
// Whether this command supports arguments
|
||||
Args bool
|
||||
// A short description of the arguments of this command
|
||||
ArgsUsage string
|
||||
// The category the command is part of
|
||||
Category string
|
||||
// The function to call when checking for bash command completions
|
||||
BashComplete BashCompleteFunc
|
||||
// An action to execute before any sub-subcommands are run, but after the context is ready
|
||||
// If a non-nil error is returned, no sub-subcommands are run
|
||||
Before BeforeFunc
|
||||
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||
// It is run even if Action() panics
|
||||
After AfterFunc
|
||||
// The function to call when this command is invoked
|
||||
Action ActionFunc
|
||||
// Execute this function if a usage error occurs.
|
||||
OnUsageError OnUsageErrorFunc
|
||||
// List of child commands
|
||||
Subcommands []*Command
|
||||
// List of flags to parse
|
||||
Flags []Flag
|
||||
flagCategories FlagCategories
|
||||
// Treat all flags as normal arguments if true
|
||||
SkipFlagParsing bool
|
||||
// Boolean to hide built-in help command and help flag
|
||||
HideHelp bool
|
||||
// Boolean to hide built-in help command but keep help flag
|
||||
// Ignored if HideHelp is true.
|
||||
HideHelpCommand bool
|
||||
// Boolean to hide this command from help or completion
|
||||
Hidden bool
|
||||
// Boolean to enable short-option handling so user can combine several
|
||||
// single-character bool arguments into one
|
||||
// i.e. foobar -o -v -> foobar -ov
|
||||
UseShortOptionHandling bool
|
||||
|
||||
// Full name of command for help, defaults to full command name, including parent commands.
|
||||
HelpName string
|
||||
commandNamePath []string
|
||||
|
||||
// CustomHelpTemplate the text template for the command help topic.
|
||||
// cli.go uses text/template to render templates. You can
|
||||
// render custom help text by setting this variable.
|
||||
CustomHelpTemplate string
|
||||
|
||||
// categories contains the categorized commands and is populated on app startup
|
||||
categories CommandCategories
|
||||
|
||||
// if this is a root "special" command
|
||||
isRoot bool
|
||||
|
||||
separator separatorSpec
|
||||
}
|
||||
|
||||
type Commands []*Command
|
||||
|
||||
type CommandsByName []*Command
|
||||
|
||||
func (c CommandsByName) Len() int {
|
||||
return len(c)
|
||||
}
|
||||
|
||||
func (c CommandsByName) Less(i, j int) bool {
|
||||
return lexicographicLess(c[i].Name, c[j].Name)
|
||||
}
|
||||
|
||||
func (c CommandsByName) Swap(i, j int) {
|
||||
c[i], c[j] = c[j], c[i]
|
||||
}
|
||||
|
||||
// FullName returns the full name of the command.
|
||||
// For subcommands this ensures that parent commands are part of the command path
|
||||
func (c *Command) FullName() string {
|
||||
if c.commandNamePath == nil {
|
||||
return c.Name
|
||||
}
|
||||
return strings.Join(c.commandNamePath, " ")
|
||||
}
|
||||
|
||||
func (cmd *Command) Command(name string) *Command {
|
||||
for _, c := range cmd.Subcommands {
|
||||
if c.HasName(name) {
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Command) setup(ctx *Context) {
|
||||
if c.Command(helpCommand.Name) == nil && !c.HideHelp {
|
||||
if !c.HideHelpCommand {
|
||||
c.Subcommands = append(c.Subcommands, helpCommand)
|
||||
}
|
||||
}
|
||||
|
||||
if !c.HideHelp && HelpFlag != nil {
|
||||
// append help to flags
|
||||
c.appendFlag(HelpFlag)
|
||||
}
|
||||
|
||||
if ctx.App.UseShortOptionHandling {
|
||||
c.UseShortOptionHandling = true
|
||||
}
|
||||
|
||||
c.categories = newCommandCategories()
|
||||
for _, command := range c.Subcommands {
|
||||
c.categories.AddCommand(command.Category, command)
|
||||
}
|
||||
sort.Sort(c.categories.(*commandCategories))
|
||||
|
||||
for _, scmd := range c.Subcommands {
|
||||
if scmd.HelpName == "" {
|
||||
scmd.HelpName = fmt.Sprintf("%s %s", c.HelpName, scmd.Name)
|
||||
}
|
||||
scmd.separator = c.separator
|
||||
}
|
||||
|
||||
if c.BashComplete == nil {
|
||||
c.BashComplete = DefaultCompleteWithFlags(c)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Command) Run(cCtx *Context, arguments ...string) (err error) {
|
||||
|
||||
if !c.isRoot {
|
||||
c.setup(cCtx)
|
||||
if err := checkDuplicatedCmds(c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
a := args(arguments)
|
||||
set, err := c.parseFlags(&a, cCtx.shellComplete)
|
||||
cCtx.flagSet = set
|
||||
|
||||
if checkCompletions(cCtx) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if c.OnUsageError != nil {
|
||||
err = c.OnUsageError(cCtx, err, !c.isRoot)
|
||||
cCtx.App.handleExitCoder(cCtx, err)
|
||||
return err
|
||||
}
|
||||
_, _ = fmt.Fprintf(cCtx.App.Writer, "%s %s\n\n", "Incorrect Usage:", err.Error())
|
||||
if cCtx.App.Suggest {
|
||||
if suggestion, err := c.suggestFlagFromError(err, ""); err == nil {
|
||||
fmt.Fprintf(cCtx.App.Writer, "%s", suggestion)
|
||||
}
|
||||
}
|
||||
if !c.HideHelp {
|
||||
if c.isRoot {
|
||||
_ = ShowAppHelp(cCtx)
|
||||
} else {
|
||||
_ = ShowCommandHelp(cCtx.parentContext, c.Name)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if checkHelp(cCtx) {
|
||||
return helpCommand.Action(cCtx)
|
||||
}
|
||||
|
||||
if c.isRoot && !cCtx.App.HideVersion && checkVersion(cCtx) {
|
||||
ShowVersion(cCtx)
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.After != nil && !cCtx.shellComplete {
|
||||
defer func() {
|
||||
afterErr := c.After(cCtx)
|
||||
if afterErr != nil {
|
||||
cCtx.App.handleExitCoder(cCtx, err)
|
||||
if err != nil {
|
||||
err = newMultiError(err, afterErr)
|
||||
} else {
|
||||
err = afterErr
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
cerr := cCtx.checkRequiredFlags(c.Flags)
|
||||
if cerr != nil {
|
||||
_ = helpCommand.Action(cCtx)
|
||||
return cerr
|
||||
}
|
||||
|
||||
if c.Before != nil && !cCtx.shellComplete {
|
||||
beforeErr := c.Before(cCtx)
|
||||
if beforeErr != nil {
|
||||
cCtx.App.handleExitCoder(cCtx, beforeErr)
|
||||
err = beforeErr
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = runFlagActions(cCtx, c.Flags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var cmd *Command
|
||||
args := cCtx.Args()
|
||||
if args.Present() {
|
||||
name := args.First()
|
||||
cmd = c.Command(name)
|
||||
if cmd == nil {
|
||||
hasDefault := cCtx.App.DefaultCommand != ""
|
||||
isFlagName := checkStringSliceIncludes(name, cCtx.FlagNames())
|
||||
|
||||
var (
|
||||
isDefaultSubcommand = false
|
||||
defaultHasSubcommands = false
|
||||
)
|
||||
|
||||
if hasDefault {
|
||||
dc := cCtx.App.Command(cCtx.App.DefaultCommand)
|
||||
defaultHasSubcommands = len(dc.Subcommands) > 0
|
||||
for _, dcSub := range dc.Subcommands {
|
||||
if checkStringSliceIncludes(name, dcSub.Names()) {
|
||||
isDefaultSubcommand = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isFlagName || (hasDefault && (defaultHasSubcommands && isDefaultSubcommand)) {
|
||||
argsWithDefault := cCtx.App.argsWithDefaultCommand(args)
|
||||
if !reflect.DeepEqual(args, argsWithDefault) {
|
||||
cmd = cCtx.App.rootCommand.Command(argsWithDefault.First())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if c.isRoot && cCtx.App.DefaultCommand != "" {
|
||||
if dc := cCtx.App.Command(cCtx.App.DefaultCommand); dc != c {
|
||||
cmd = dc
|
||||
}
|
||||
}
|
||||
|
||||
if cmd != nil {
|
||||
newcCtx := NewContext(cCtx.App, nil, cCtx)
|
||||
newcCtx.Command = cmd
|
||||
return cmd.Run(newcCtx, cCtx.Args().Slice()...)
|
||||
}
|
||||
|
||||
if c.Action == nil {
|
||||
c.Action = helpCommand.Action
|
||||
}
|
||||
|
||||
err = c.Action(cCtx)
|
||||
|
||||
cCtx.App.handleExitCoder(cCtx, err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Command) newFlagSet() (*flag.FlagSet, error) {
|
||||
return flagSet(c.Name, c.Flags, c.separator)
|
||||
}
|
||||
|
||||
func (c *Command) useShortOptionHandling() bool {
|
||||
return c.UseShortOptionHandling
|
||||
}
|
||||
|
||||
func (c *Command) suggestFlagFromError(err error, command string) (string, error) {
|
||||
flag, parseErr := flagFromError(err)
|
||||
if parseErr != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
flags := c.Flags
|
||||
hideHelp := c.HideHelp
|
||||
if command != "" {
|
||||
cmd := c.Command(command)
|
||||
if cmd == nil {
|
||||
return "", err
|
||||
}
|
||||
flags = cmd.Flags
|
||||
hideHelp = hideHelp || cmd.HideHelp
|
||||
}
|
||||
|
||||
suggestion := SuggestFlag(flags, flag, hideHelp)
|
||||
if len(suggestion) == 0 {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf(SuggestDidYouMeanTemplate, suggestion) + "\n\n", nil
|
||||
}
|
||||
|
||||
func (c *Command) parseFlags(args Args, shellComplete bool) (*flag.FlagSet, error) {
|
||||
set, err := c.newFlagSet()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.SkipFlagParsing {
|
||||
return set, set.Parse(append([]string{"--"}, args.Tail()...))
|
||||
}
|
||||
|
||||
err = parseIter(set, c, args.Tail(), shellComplete)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = normalizeFlags(c.Flags, set)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return set, nil
|
||||
}
|
||||
|
||||
// Names returns the names including short names and aliases.
|
||||
func (c *Command) Names() []string {
|
||||
return append([]string{c.Name}, c.Aliases...)
|
||||
}
|
||||
|
||||
// HasName returns true if Command.Name matches given name
|
||||
func (c *Command) HasName(name string) bool {
|
||||
for _, n := range c.Names() {
|
||||
if n == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// VisibleCategories returns a slice of categories and commands that are
|
||||
// Hidden=false
|
||||
func (c *Command) VisibleCategories() []CommandCategory {
|
||||
ret := []CommandCategory{}
|
||||
for _, category := range c.categories.Categories() {
|
||||
if visible := func() CommandCategory {
|
||||
if len(category.VisibleCommands()) > 0 {
|
||||
return category
|
||||
}
|
||||
return nil
|
||||
}(); visible != nil {
|
||||
ret = append(ret, visible)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// VisibleCommands returns a slice of the Commands with Hidden=false
|
||||
func (c *Command) VisibleCommands() []*Command {
|
||||
var ret []*Command
|
||||
for _, command := range c.Subcommands {
|
||||
if !command.Hidden {
|
||||
ret = append(ret, command)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// VisibleFlagCategories returns a slice containing all the visible flag categories with the flags they contain
|
||||
func (c *Command) VisibleFlagCategories() []VisibleFlagCategory {
|
||||
if c.flagCategories == nil {
|
||||
c.flagCategories = newFlagCategoriesFromFlags(c.Flags)
|
||||
}
|
||||
return c.flagCategories.VisibleCategories()
|
||||
}
|
||||
|
||||
// VisibleFlags returns a slice of the Flags with Hidden=false
|
||||
func (c *Command) VisibleFlags() []Flag {
|
||||
return visibleFlags(c.Flags)
|
||||
}
|
||||
|
||||
func (c *Command) appendFlag(fl Flag) {
|
||||
if !hasFlag(c.Flags, fl) {
|
||||
c.Flags = append(c.Flags, fl)
|
||||
}
|
||||
}
|
||||
|
||||
func hasCommand(commands []*Command, command *Command) bool {
|
||||
for _, existing := range commands {
|
||||
if command == existing {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkDuplicatedCmds(parent *Command) error {
|
||||
seen := make(map[string]struct{})
|
||||
for _, c := range parent.Subcommands {
|
||||
for _, name := range c.Names() {
|
||||
if _, exists := seen[name]; exists {
|
||||
return fmt.Errorf("parent command [%s] has duplicated subcommand name or alias: %s", parent.Name, name)
|
||||
}
|
||||
seen[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
-272
@@ -1,272 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Context is a type that is passed through to
|
||||
// each Handler action in a cli application. Context
|
||||
// can be used to retrieve context-specific args and
|
||||
// parsed command-line options.
|
||||
type Context struct {
|
||||
context.Context
|
||||
App *App
|
||||
Command *Command
|
||||
shellComplete bool
|
||||
flagSet *flag.FlagSet
|
||||
parentContext *Context
|
||||
}
|
||||
|
||||
// NewContext creates a new context. For use in when invoking an App or Command action.
|
||||
func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
|
||||
c := &Context{App: app, flagSet: set, parentContext: parentCtx}
|
||||
if parentCtx != nil {
|
||||
c.Context = parentCtx.Context
|
||||
c.shellComplete = parentCtx.shellComplete
|
||||
if parentCtx.flagSet == nil {
|
||||
parentCtx.flagSet = &flag.FlagSet{}
|
||||
}
|
||||
}
|
||||
|
||||
c.Command = &Command{}
|
||||
|
||||
if c.Context == nil {
|
||||
c.Context = context.Background()
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// NumFlags returns the number of flags set
|
||||
func (cCtx *Context) NumFlags() int {
|
||||
return cCtx.flagSet.NFlag()
|
||||
}
|
||||
|
||||
// Set sets a context flag to a value.
|
||||
func (cCtx *Context) Set(name, value string) error {
|
||||
if fs := cCtx.lookupFlagSet(name); fs != nil {
|
||||
return fs.Set(name, value)
|
||||
}
|
||||
|
||||
return fmt.Errorf("no such flag -%s", name)
|
||||
}
|
||||
|
||||
// IsSet determines if the flag was actually set
|
||||
func (cCtx *Context) IsSet(name string) bool {
|
||||
|
||||
if fs := cCtx.lookupFlagSet(name); fs != nil {
|
||||
isSet := false
|
||||
fs.Visit(func(f *flag.Flag) {
|
||||
if f.Name == name {
|
||||
isSet = true
|
||||
}
|
||||
})
|
||||
if isSet {
|
||||
return true
|
||||
}
|
||||
|
||||
f := cCtx.lookupFlag(name)
|
||||
if f == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if f.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
// now redo flagset search on aliases
|
||||
aliases := f.Names()
|
||||
fs.Visit(func(f *flag.Flag) {
|
||||
for _, alias := range aliases {
|
||||
if f.Name == alias {
|
||||
isSet = true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if isSet {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// LocalFlagNames returns a slice of flag names used in this context.
|
||||
func (cCtx *Context) LocalFlagNames() []string {
|
||||
var names []string
|
||||
cCtx.flagSet.Visit(makeFlagNameVisitor(&names))
|
||||
// Check the flags which have been set via env or file
|
||||
if cCtx.Command != nil && cCtx.Command.Flags != nil {
|
||||
for _, f := range cCtx.Command.Flags {
|
||||
if f.IsSet() {
|
||||
names = append(names, f.Names()...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort out the duplicates since flag could be set via multiple
|
||||
// paths
|
||||
m := map[string]struct{}{}
|
||||
var unames []string
|
||||
for _, name := range names {
|
||||
if _, ok := m[name]; !ok {
|
||||
m[name] = struct{}{}
|
||||
unames = append(unames, name)
|
||||
}
|
||||
}
|
||||
|
||||
return unames
|
||||
}
|
||||
|
||||
// FlagNames returns a slice of flag names used by the this context and all of
|
||||
// its parent contexts.
|
||||
func (cCtx *Context) FlagNames() []string {
|
||||
var names []string
|
||||
for _, pCtx := range cCtx.Lineage() {
|
||||
names = append(names, pCtx.LocalFlagNames()...)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// Lineage returns *this* context and all of its ancestor contexts in order from
|
||||
// child to parent
|
||||
func (cCtx *Context) Lineage() []*Context {
|
||||
var lineage []*Context
|
||||
|
||||
for cur := cCtx; cur != nil; cur = cur.parentContext {
|
||||
lineage = append(lineage, cur)
|
||||
}
|
||||
|
||||
return lineage
|
||||
}
|
||||
|
||||
// Count returns the num of occurrences of this flag
|
||||
func (cCtx *Context) Count(name string) int {
|
||||
if fs := cCtx.lookupFlagSet(name); fs != nil {
|
||||
if cf, ok := fs.Lookup(name).Value.(Countable); ok {
|
||||
return cf.Count()
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Value returns the value of the flag corresponding to `name`
|
||||
func (cCtx *Context) Value(name string) interface{} {
|
||||
if fs := cCtx.lookupFlagSet(name); fs != nil {
|
||||
return fs.Lookup(name).Value.(flag.Getter).Get()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Args returns the command line arguments associated with the context.
|
||||
func (cCtx *Context) Args() Args {
|
||||
ret := args(cCtx.flagSet.Args())
|
||||
return &ret
|
||||
}
|
||||
|
||||
// NArg returns the number of the command line arguments.
|
||||
func (cCtx *Context) NArg() int {
|
||||
return cCtx.Args().Len()
|
||||
}
|
||||
|
||||
func (cCtx *Context) lookupFlag(name string) Flag {
|
||||
for _, c := range cCtx.Lineage() {
|
||||
if c.Command == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, f := range c.Command.Flags {
|
||||
for _, n := range f.Names() {
|
||||
if n == name {
|
||||
return f
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cCtx.App != nil {
|
||||
for _, f := range cCtx.App.Flags {
|
||||
for _, n := range f.Names() {
|
||||
if n == name {
|
||||
return f
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cCtx *Context) lookupFlagSet(name string) *flag.FlagSet {
|
||||
for _, c := range cCtx.Lineage() {
|
||||
if c.flagSet == nil {
|
||||
continue
|
||||
}
|
||||
if f := c.flagSet.Lookup(name); f != nil {
|
||||
return c.flagSet
|
||||
}
|
||||
}
|
||||
cCtx.onInvalidFlag(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cCtx *Context) checkRequiredFlags(flags []Flag) requiredFlagsErr {
|
||||
var missingFlags []string
|
||||
for _, f := range flags {
|
||||
if rf, ok := f.(RequiredFlag); ok && rf.IsRequired() {
|
||||
var flagPresent bool
|
||||
var flagName string
|
||||
|
||||
flagNames := f.Names()
|
||||
flagName = flagNames[0]
|
||||
|
||||
for _, key := range flagNames {
|
||||
if cCtx.IsSet(strings.TrimSpace(key)) {
|
||||
flagPresent = true
|
||||
}
|
||||
}
|
||||
|
||||
if !flagPresent && flagName != "" {
|
||||
missingFlags = append(missingFlags, flagName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(missingFlags) != 0 {
|
||||
return &errRequiredFlags{missingFlags: missingFlags}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cCtx *Context) onInvalidFlag(name string) {
|
||||
for cCtx != nil {
|
||||
if cCtx.App != nil && cCtx.App.InvalidFlagAccessHandler != nil {
|
||||
cCtx.App.InvalidFlagAccessHandler(cCtx, name)
|
||||
break
|
||||
}
|
||||
cCtx = cCtx.parentContext
|
||||
}
|
||||
}
|
||||
|
||||
func makeFlagNameVisitor(names *[]string) func(*flag.Flag) {
|
||||
return func(f *flag.Flag) {
|
||||
nameParts := strings.Split(f.Name, ",")
|
||||
name := strings.TrimSpace(nameParts[0])
|
||||
|
||||
for _, part := range nameParts {
|
||||
part = strings.TrimSpace(part)
|
||||
if len(part) > len(name) {
|
||||
name = part
|
||||
}
|
||||
}
|
||||
|
||||
if name != "" {
|
||||
*names = append(*names, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
-203
@@ -1,203 +0,0 @@
|
||||
//go:build !urfave_cli_no_docs
|
||||
// +build !urfave_cli_no_docs
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/cpuguy83/go-md2man/v2/md2man"
|
||||
)
|
||||
|
||||
// ToMarkdown creates a markdown string for the `*App`
|
||||
// The function errors if either parsing or writing of the string fails.
|
||||
func (a *App) ToMarkdown() (string, error) {
|
||||
var w bytes.Buffer
|
||||
if err := a.writeDocTemplate(&w, 0); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return w.String(), nil
|
||||
}
|
||||
|
||||
// ToMan creates a man page string with section number for the `*App`
|
||||
// The function errors if either parsing or writing of the string fails.
|
||||
func (a *App) ToManWithSection(sectionNumber int) (string, error) {
|
||||
var w bytes.Buffer
|
||||
if err := a.writeDocTemplate(&w, sectionNumber); err != nil {
|
||||
return "", err
|
||||
}
|
||||
man := md2man.Render(w.Bytes())
|
||||
return string(man), nil
|
||||
}
|
||||
|
||||
// ToMan creates a man page string for the `*App`
|
||||
// The function errors if either parsing or writing of the string fails.
|
||||
func (a *App) ToMan() (string, error) {
|
||||
man, err := a.ToManWithSection(8)
|
||||
return man, err
|
||||
}
|
||||
|
||||
type cliTemplate struct {
|
||||
App *App
|
||||
SectionNum int
|
||||
Commands []string
|
||||
GlobalArgs []string
|
||||
SynopsisArgs []string
|
||||
}
|
||||
|
||||
func (a *App) writeDocTemplate(w io.Writer, sectionNum int) error {
|
||||
const name = "cli"
|
||||
t, err := template.New(name).Parse(MarkdownDocTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.ExecuteTemplate(w, name, &cliTemplate{
|
||||
App: a,
|
||||
SectionNum: sectionNum,
|
||||
Commands: prepareCommands(a.Commands, 0),
|
||||
GlobalArgs: prepareArgsWithValues(a.VisibleFlags()),
|
||||
SynopsisArgs: prepareArgsSynopsis(a.VisibleFlags()),
|
||||
})
|
||||
}
|
||||
|
||||
func prepareCommands(commands []*Command, level int) []string {
|
||||
var coms []string
|
||||
for _, command := range commands {
|
||||
if command.Hidden {
|
||||
continue
|
||||
}
|
||||
|
||||
usageText := prepareUsageText(command)
|
||||
|
||||
usage := prepareUsage(command, usageText)
|
||||
|
||||
prepared := fmt.Sprintf("%s %s\n\n%s%s",
|
||||
strings.Repeat("#", level+2),
|
||||
strings.Join(command.Names(), ", "),
|
||||
usage,
|
||||
usageText,
|
||||
)
|
||||
|
||||
flags := prepareArgsWithValues(command.VisibleFlags())
|
||||
if len(flags) > 0 {
|
||||
prepared += fmt.Sprintf("\n%s", strings.Join(flags, "\n"))
|
||||
}
|
||||
|
||||
coms = append(coms, prepared)
|
||||
|
||||
// recursively iterate subcommands
|
||||
if len(command.Subcommands) > 0 {
|
||||
coms = append(
|
||||
coms,
|
||||
prepareCommands(command.Subcommands, level+1)...,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return coms
|
||||
}
|
||||
|
||||
func prepareArgsWithValues(flags []Flag) []string {
|
||||
return prepareFlags(flags, ", ", "**", "**", `""`, true)
|
||||
}
|
||||
|
||||
func prepareArgsSynopsis(flags []Flag) []string {
|
||||
return prepareFlags(flags, "|", "[", "]", "[value]", false)
|
||||
}
|
||||
|
||||
func prepareFlags(
|
||||
flags []Flag,
|
||||
sep, opener, closer, value string,
|
||||
addDetails bool,
|
||||
) []string {
|
||||
args := []string{}
|
||||
for _, f := range flags {
|
||||
flag, ok := f.(DocGenerationFlag)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
modifiedArg := opener
|
||||
|
||||
for _, s := range flag.Names() {
|
||||
trimmed := strings.TrimSpace(s)
|
||||
if len(modifiedArg) > len(opener) {
|
||||
modifiedArg += sep
|
||||
}
|
||||
if len(trimmed) > 1 {
|
||||
modifiedArg += fmt.Sprintf("--%s", trimmed)
|
||||
} else {
|
||||
modifiedArg += fmt.Sprintf("-%s", trimmed)
|
||||
}
|
||||
}
|
||||
modifiedArg += closer
|
||||
if flag.TakesValue() {
|
||||
modifiedArg += fmt.Sprintf("=%s", value)
|
||||
}
|
||||
|
||||
if addDetails {
|
||||
modifiedArg += flagDetails(flag)
|
||||
}
|
||||
|
||||
args = append(args, modifiedArg+"\n")
|
||||
|
||||
}
|
||||
sort.Strings(args)
|
||||
return args
|
||||
}
|
||||
|
||||
// flagDetails returns a string containing the flags metadata
|
||||
func flagDetails(flag DocGenerationFlag) string {
|
||||
description := flag.GetUsage()
|
||||
if flag.TakesValue() {
|
||||
defaultText := flag.GetDefaultText()
|
||||
if defaultText == "" {
|
||||
defaultText = flag.GetValue()
|
||||
}
|
||||
if defaultText != "" {
|
||||
description += " (default: " + defaultText + ")"
|
||||
}
|
||||
}
|
||||
return ": " + description
|
||||
}
|
||||
|
||||
func prepareUsageText(command *Command) string {
|
||||
if command.UsageText == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Remove leading and trailing newlines
|
||||
preparedUsageText := strings.Trim(command.UsageText, "\n")
|
||||
|
||||
var usageText string
|
||||
if strings.Contains(preparedUsageText, "\n") {
|
||||
// Format multi-line string as a code block using the 4 space schema to allow for embedded markdown such
|
||||
// that it will not break the continuous code block.
|
||||
for _, ln := range strings.Split(preparedUsageText, "\n") {
|
||||
usageText += fmt.Sprintf(" %s\n", ln)
|
||||
}
|
||||
} else {
|
||||
// Style a single line as a note
|
||||
usageText = fmt.Sprintf(">%s\n", preparedUsageText)
|
||||
}
|
||||
|
||||
return usageText
|
||||
}
|
||||
|
||||
func prepareUsage(command *Command, usageText string) string {
|
||||
if command.Usage == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
usage := command.Usage + "\n"
|
||||
// Add a newline to the Usage IFF there is a UsageText
|
||||
if usageText != "" {
|
||||
usage += "\n"
|
||||
}
|
||||
|
||||
return usage
|
||||
}
|
||||
-196
@@ -1,196 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// ToFishCompletion creates a fish completion string for the `*App`
|
||||
// The function errors if either parsing or writing of the string fails.
|
||||
func (a *App) ToFishCompletion() (string, error) {
|
||||
var w bytes.Buffer
|
||||
if err := a.writeFishCompletionTemplate(&w); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return w.String(), nil
|
||||
}
|
||||
|
||||
type fishCompletionTemplate struct {
|
||||
App *App
|
||||
Completions []string
|
||||
AllCommands []string
|
||||
}
|
||||
|
||||
func (a *App) writeFishCompletionTemplate(w io.Writer) error {
|
||||
const name = "cli"
|
||||
t, err := template.New(name).Parse(FishCompletionTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
allCommands := []string{}
|
||||
|
||||
// Add global flags
|
||||
completions := a.prepareFishFlags(a.VisibleFlags(), allCommands)
|
||||
|
||||
// Add help flag
|
||||
if !a.HideHelp {
|
||||
completions = append(
|
||||
completions,
|
||||
a.prepareFishFlags([]Flag{HelpFlag}, allCommands)...,
|
||||
)
|
||||
}
|
||||
|
||||
// Add version flag
|
||||
if !a.HideVersion {
|
||||
completions = append(
|
||||
completions,
|
||||
a.prepareFishFlags([]Flag{VersionFlag}, allCommands)...,
|
||||
)
|
||||
}
|
||||
|
||||
// Add commands and their flags
|
||||
completions = append(
|
||||
completions,
|
||||
a.prepareFishCommands(a.VisibleCommands(), &allCommands, []string{})...,
|
||||
)
|
||||
|
||||
return t.ExecuteTemplate(w, name, &fishCompletionTemplate{
|
||||
App: a,
|
||||
Completions: completions,
|
||||
AllCommands: allCommands,
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) prepareFishCommands(commands []*Command, allCommands *[]string, previousCommands []string) []string {
|
||||
completions := []string{}
|
||||
for _, command := range commands {
|
||||
if command.Hidden {
|
||||
continue
|
||||
}
|
||||
|
||||
var completion strings.Builder
|
||||
completion.WriteString(fmt.Sprintf(
|
||||
"complete -r -c %s -n '%s' -a '%s'",
|
||||
a.Name,
|
||||
a.fishSubcommandHelper(previousCommands),
|
||||
strings.Join(command.Names(), " "),
|
||||
))
|
||||
|
||||
if command.Usage != "" {
|
||||
completion.WriteString(fmt.Sprintf(" -d '%s'",
|
||||
escapeSingleQuotes(command.Usage)))
|
||||
}
|
||||
|
||||
if !command.HideHelp {
|
||||
completions = append(
|
||||
completions,
|
||||
a.prepareFishFlags([]Flag{HelpFlag}, command.Names())...,
|
||||
)
|
||||
}
|
||||
|
||||
*allCommands = append(*allCommands, command.Names()...)
|
||||
completions = append(completions, completion.String())
|
||||
completions = append(
|
||||
completions,
|
||||
a.prepareFishFlags(command.VisibleFlags(), command.Names())...,
|
||||
)
|
||||
|
||||
// recursively iterate subcommands
|
||||
if len(command.Subcommands) > 0 {
|
||||
completions = append(
|
||||
completions,
|
||||
a.prepareFishCommands(
|
||||
command.Subcommands, allCommands, command.Names(),
|
||||
)...,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return completions
|
||||
}
|
||||
|
||||
func (a *App) prepareFishFlags(flags []Flag, previousCommands []string) []string {
|
||||
completions := []string{}
|
||||
for _, f := range flags {
|
||||
flag, ok := f.(DocGenerationFlag)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
completion := &strings.Builder{}
|
||||
completion.WriteString(fmt.Sprintf(
|
||||
"complete -c %s -n '%s'",
|
||||
a.Name,
|
||||
a.fishSubcommandHelper(previousCommands),
|
||||
))
|
||||
|
||||
fishAddFileFlag(f, completion)
|
||||
|
||||
for idx, opt := range flag.Names() {
|
||||
if idx == 0 {
|
||||
completion.WriteString(fmt.Sprintf(
|
||||
" -l %s", strings.TrimSpace(opt),
|
||||
))
|
||||
} else {
|
||||
completion.WriteString(fmt.Sprintf(
|
||||
" -s %s", strings.TrimSpace(opt),
|
||||
))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if flag.TakesValue() {
|
||||
completion.WriteString(" -r")
|
||||
}
|
||||
|
||||
if flag.GetUsage() != "" {
|
||||
completion.WriteString(fmt.Sprintf(" -d '%s'",
|
||||
escapeSingleQuotes(flag.GetUsage())))
|
||||
}
|
||||
|
||||
completions = append(completions, completion.String())
|
||||
}
|
||||
|
||||
return completions
|
||||
}
|
||||
|
||||
func fishAddFileFlag(flag Flag, completion *strings.Builder) {
|
||||
switch f := flag.(type) {
|
||||
case *GenericFlag:
|
||||
if f.TakesFile {
|
||||
return
|
||||
}
|
||||
case *StringFlag:
|
||||
if f.TakesFile {
|
||||
return
|
||||
}
|
||||
case *StringSliceFlag:
|
||||
if f.TakesFile {
|
||||
return
|
||||
}
|
||||
case *PathFlag:
|
||||
if f.TakesFile {
|
||||
return
|
||||
}
|
||||
}
|
||||
completion.WriteString(" -f")
|
||||
}
|
||||
|
||||
func (a *App) fishSubcommandHelper(allCommands []string) string {
|
||||
fishHelper := fmt.Sprintf("__fish_%s_no_subcommand", a.Name)
|
||||
if len(allCommands) > 0 {
|
||||
fishHelper = fmt.Sprintf(
|
||||
"__fish_seen_subcommand_from %s",
|
||||
strings.Join(allCommands, " "),
|
||||
)
|
||||
}
|
||||
return fishHelper
|
||||
|
||||
}
|
||||
|
||||
func escapeSingleQuotes(input string) string {
|
||||
return strings.Replace(input, `'`, `\'`, -1)
|
||||
}
|
||||
-131
@@ -1,131 +0,0 @@
|
||||
# NOTE: this file is used by the tool defined in
|
||||
# ./cmd/urfave-cli-genflags/main.go which uses the
|
||||
# `Spec` type that maps to this file structure.
|
||||
flag_types:
|
||||
bool:
|
||||
struct_fields:
|
||||
- name: Count
|
||||
type: int
|
||||
pointer: true
|
||||
- name: DisableDefaultText
|
||||
type: bool
|
||||
- name: Action
|
||||
type: "func(*Context, bool) error"
|
||||
float64:
|
||||
struct_fields:
|
||||
- name: Action
|
||||
type: "func(*Context, float64) error"
|
||||
Float64Slice:
|
||||
value_pointer: true
|
||||
skip_interfaces:
|
||||
- fmt.Stringer
|
||||
struct_fields:
|
||||
- name: separator
|
||||
type: separatorSpec
|
||||
- name: Action
|
||||
type: "func(*Context, []float64) error"
|
||||
int:
|
||||
struct_fields:
|
||||
- name: Base
|
||||
type: int
|
||||
- name: Action
|
||||
type: "func(*Context, int) error"
|
||||
IntSlice:
|
||||
value_pointer: true
|
||||
skip_interfaces:
|
||||
- fmt.Stringer
|
||||
struct_fields:
|
||||
- name: separator
|
||||
type: separatorSpec
|
||||
- name: Action
|
||||
type: "func(*Context, []int) error"
|
||||
int64:
|
||||
struct_fields:
|
||||
- name: Base
|
||||
type: int
|
||||
- name: Action
|
||||
type: "func(*Context, int64) error"
|
||||
Int64Slice:
|
||||
value_pointer: true
|
||||
skip_interfaces:
|
||||
- fmt.Stringer
|
||||
struct_fields:
|
||||
- name: separator
|
||||
type: separatorSpec
|
||||
- name: Action
|
||||
type: "func(*Context, []int64) error"
|
||||
uint:
|
||||
struct_fields:
|
||||
- name: Base
|
||||
type: int
|
||||
- name: Action
|
||||
type: "func(*Context, uint) error"
|
||||
UintSlice:
|
||||
value_pointer: true
|
||||
skip_interfaces:
|
||||
- fmt.Stringer
|
||||
struct_fields:
|
||||
- name: separator
|
||||
type: separatorSpec
|
||||
- name: Action
|
||||
type: "func(*Context, []uint) error"
|
||||
uint64:
|
||||
struct_fields:
|
||||
- name: Base
|
||||
type: int
|
||||
- name: Action
|
||||
type: "func(*Context, uint64) error"
|
||||
Uint64Slice:
|
||||
value_pointer: true
|
||||
skip_interfaces:
|
||||
- fmt.Stringer
|
||||
struct_fields:
|
||||
- name: separator
|
||||
type: separatorSpec
|
||||
- name: Action
|
||||
type: "func(*Context, []uint64) error"
|
||||
string:
|
||||
struct_fields:
|
||||
- name: TakesFile
|
||||
type: bool
|
||||
- name: Action
|
||||
type: "func(*Context, string) error"
|
||||
StringSlice:
|
||||
value_pointer: true
|
||||
skip_interfaces:
|
||||
- fmt.Stringer
|
||||
struct_fields:
|
||||
- name: separator
|
||||
type: separatorSpec
|
||||
- name: TakesFile
|
||||
type: bool
|
||||
- name: Action
|
||||
type: "func(*Context, []string) error"
|
||||
- name: KeepSpace
|
||||
type: bool
|
||||
time.Duration:
|
||||
struct_fields:
|
||||
- name: Action
|
||||
type: "func(*Context, time.Duration) error"
|
||||
Timestamp:
|
||||
value_pointer: true
|
||||
struct_fields:
|
||||
- name: Layout
|
||||
type: string
|
||||
- name: Timezone
|
||||
type: "*time.Location"
|
||||
- name: Action
|
||||
type: "func(*Context, *time.Time) error"
|
||||
Generic:
|
||||
no_destination_pointer: true
|
||||
struct_fields:
|
||||
- name: TakesFile
|
||||
type: bool
|
||||
- name: Action
|
||||
type: "func(*Context, interface{}) error"
|
||||
Path:
|
||||
struct_fields:
|
||||
- name: TakesFile
|
||||
type: bool
|
||||
- name: Action
|
||||
type: "func(*Context, Path) error"
|
||||
-419
@@ -1,419 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
const defaultPlaceholder = "value"
|
||||
|
||||
const (
|
||||
defaultSliceFlagSeparator = ","
|
||||
disableSliceFlagSeparator = false
|
||||
)
|
||||
|
||||
var (
|
||||
slPfx = fmt.Sprintf("sl:::%d:::", time.Now().UTC().UnixNano())
|
||||
|
||||
commaWhitespace = regexp.MustCompile("[, ]+.*")
|
||||
)
|
||||
|
||||
// BashCompletionFlag enables bash-completion for all commands and subcommands
|
||||
var BashCompletionFlag Flag = &BoolFlag{
|
||||
Name: "generate-bash-completion",
|
||||
Hidden: true,
|
||||
}
|
||||
|
||||
// VersionFlag prints the version for the application
|
||||
var VersionFlag Flag = &BoolFlag{
|
||||
Name: "version",
|
||||
Aliases: []string{"v"},
|
||||
Usage: "print the version",
|
||||
DisableDefaultText: true,
|
||||
}
|
||||
|
||||
// HelpFlag prints the help for all commands and subcommands.
|
||||
// Set to nil to disable the flag. The subcommand
|
||||
// will still be added unless HideHelp or HideHelpCommand is set to true.
|
||||
var HelpFlag Flag = &BoolFlag{
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "show help",
|
||||
DisableDefaultText: true,
|
||||
}
|
||||
|
||||
// FlagStringer converts a flag definition to a string. This is used by help
|
||||
// to display a flag.
|
||||
var FlagStringer FlagStringFunc = stringifyFlag
|
||||
|
||||
// Serializer is used to circumvent the limitations of flag.FlagSet.Set
|
||||
type Serializer interface {
|
||||
Serialize() string
|
||||
}
|
||||
|
||||
// FlagNamePrefixer converts a full flag name and its placeholder into the help
|
||||
// message flag prefix. This is used by the default FlagStringer.
|
||||
var FlagNamePrefixer FlagNamePrefixFunc = prefixedNames
|
||||
|
||||
// FlagEnvHinter annotates flag help message with the environment variable
|
||||
// details. This is used by the default FlagStringer.
|
||||
var FlagEnvHinter FlagEnvHintFunc = withEnvHint
|
||||
|
||||
// FlagFileHinter annotates flag help message with the environment variable
|
||||
// details. This is used by the default FlagStringer.
|
||||
var FlagFileHinter FlagFileHintFunc = withFileHint
|
||||
|
||||
// FlagsByName is a slice of Flag.
|
||||
type FlagsByName []Flag
|
||||
|
||||
func (f FlagsByName) Len() int {
|
||||
return len(f)
|
||||
}
|
||||
|
||||
func (f FlagsByName) Less(i, j int) bool {
|
||||
if len(f[j].Names()) == 0 {
|
||||
return false
|
||||
} else if len(f[i].Names()) == 0 {
|
||||
return true
|
||||
}
|
||||
return lexicographicLess(f[i].Names()[0], f[j].Names()[0])
|
||||
}
|
||||
|
||||
func (f FlagsByName) Swap(i, j int) {
|
||||
f[i], f[j] = f[j], f[i]
|
||||
}
|
||||
|
||||
// ActionableFlag is an interface that wraps Flag interface and RunAction operation.
|
||||
type ActionableFlag interface {
|
||||
Flag
|
||||
RunAction(*Context) error
|
||||
}
|
||||
|
||||
// Flag is a common interface related to parsing flags in cli.
|
||||
// For more advanced flag parsing techniques, it is recommended that
|
||||
// this interface be implemented.
|
||||
type Flag interface {
|
||||
fmt.Stringer
|
||||
// Apply Flag settings to the given flag set
|
||||
Apply(*flag.FlagSet) error
|
||||
Names() []string
|
||||
IsSet() bool
|
||||
}
|
||||
|
||||
// RequiredFlag is an interface that allows us to mark flags as required
|
||||
// it allows flags required flags to be backwards compatible with the Flag interface
|
||||
type RequiredFlag interface {
|
||||
Flag
|
||||
|
||||
IsRequired() bool
|
||||
}
|
||||
|
||||
// DocGenerationFlag is an interface that allows documentation generation for the flag
|
||||
type DocGenerationFlag interface {
|
||||
Flag
|
||||
|
||||
// TakesValue returns true if the flag takes a value, otherwise false
|
||||
TakesValue() bool
|
||||
|
||||
// GetUsage returns the usage string for the flag
|
||||
GetUsage() string
|
||||
|
||||
// GetValue returns the flags value as string representation and an empty
|
||||
// string if the flag takes no value at all.
|
||||
GetValue() string
|
||||
|
||||
// GetDefaultText returns the default text for this flag
|
||||
GetDefaultText() string
|
||||
|
||||
// GetEnvVars returns the env vars for this flag
|
||||
GetEnvVars() []string
|
||||
}
|
||||
|
||||
// DocGenerationSliceFlag extends DocGenerationFlag for slice-based flags.
|
||||
type DocGenerationSliceFlag interface {
|
||||
DocGenerationFlag
|
||||
|
||||
// IsSliceFlag returns true for flags that can be given multiple times.
|
||||
IsSliceFlag() bool
|
||||
}
|
||||
|
||||
// VisibleFlag is an interface that allows to check if a flag is visible
|
||||
type VisibleFlag interface {
|
||||
Flag
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
IsVisible() bool
|
||||
}
|
||||
|
||||
// CategorizableFlag is an interface that allows us to potentially
|
||||
// use a flag in a categorized representation.
|
||||
type CategorizableFlag interface {
|
||||
VisibleFlag
|
||||
|
||||
GetCategory() string
|
||||
}
|
||||
|
||||
// Countable is an interface to enable detection of flag values which support
|
||||
// repetitive flags
|
||||
type Countable interface {
|
||||
Count() int
|
||||
}
|
||||
|
||||
func flagSet(name string, flags []Flag, spec separatorSpec) (*flag.FlagSet, error) {
|
||||
set := flag.NewFlagSet(name, flag.ContinueOnError)
|
||||
|
||||
for _, f := range flags {
|
||||
if c, ok := f.(customizedSeparator); ok {
|
||||
c.WithSeparatorSpec(spec)
|
||||
}
|
||||
if err := f.Apply(set); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
set.SetOutput(io.Discard)
|
||||
return set, nil
|
||||
}
|
||||
|
||||
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
|
||||
switch ff.Value.(type) {
|
||||
case Serializer:
|
||||
_ = set.Set(name, ff.Value.(Serializer).Serialize())
|
||||
default:
|
||||
_ = set.Set(name, ff.Value.String())
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
|
||||
visited := make(map[string]bool)
|
||||
set.Visit(func(f *flag.Flag) {
|
||||
visited[f.Name] = true
|
||||
})
|
||||
for _, f := range flags {
|
||||
parts := f.Names()
|
||||
if len(parts) == 1 {
|
||||
continue
|
||||
}
|
||||
var ff *flag.Flag
|
||||
for _, name := range parts {
|
||||
name = strings.Trim(name, " ")
|
||||
if visited[name] {
|
||||
if ff != nil {
|
||||
return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
|
||||
}
|
||||
ff = set.Lookup(name)
|
||||
}
|
||||
}
|
||||
if ff == nil {
|
||||
continue
|
||||
}
|
||||
for _, name := range parts {
|
||||
name = strings.Trim(name, " ")
|
||||
if !visited[name] {
|
||||
copyFlag(name, ff, set)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func visibleFlags(fl []Flag) []Flag {
|
||||
var visible []Flag
|
||||
for _, f := range fl {
|
||||
if vf, ok := f.(VisibleFlag); ok && vf.IsVisible() {
|
||||
visible = append(visible, f)
|
||||
}
|
||||
}
|
||||
return visible
|
||||
}
|
||||
|
||||
func prefixFor(name string) (prefix string) {
|
||||
if len(name) == 1 {
|
||||
prefix = "-"
|
||||
} else {
|
||||
prefix = "--"
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Returns the placeholder, if any, and the unquoted usage string.
|
||||
func unquoteUsage(usage string) (string, string) {
|
||||
for i := 0; i < len(usage); i++ {
|
||||
if usage[i] == '`' {
|
||||
for j := i + 1; j < len(usage); j++ {
|
||||
if usage[j] == '`' {
|
||||
name := usage[i+1 : j]
|
||||
usage = usage[:i] + name + usage[j+1:]
|
||||
return name, usage
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return "", usage
|
||||
}
|
||||
|
||||
func prefixedNames(names []string, placeholder string) string {
|
||||
var prefixed string
|
||||
for i, name := range names {
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
prefixed += prefixFor(name) + name
|
||||
if placeholder != "" {
|
||||
prefixed += " " + placeholder
|
||||
}
|
||||
if i < len(names)-1 {
|
||||
prefixed += ", "
|
||||
}
|
||||
}
|
||||
return prefixed
|
||||
}
|
||||
|
||||
func envFormat(envVars []string, prefix, sep, suffix string) string {
|
||||
if len(envVars) > 0 {
|
||||
return fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(envVars, sep), suffix)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func defaultEnvFormat(envVars []string) string {
|
||||
return envFormat(envVars, "$", ", $", "")
|
||||
}
|
||||
|
||||
func withEnvHint(envVars []string, str string) string {
|
||||
envText := ""
|
||||
if runtime.GOOS != "windows" || os.Getenv("PSHOME") != "" {
|
||||
envText = defaultEnvFormat(envVars)
|
||||
} else {
|
||||
envText = envFormat(envVars, "%", "%, %", "%")
|
||||
}
|
||||
return str + envText
|
||||
}
|
||||
|
||||
func FlagNames(name string, aliases []string) []string {
|
||||
var ret []string
|
||||
|
||||
for _, part := range append([]string{name}, aliases...) {
|
||||
// v1 -> v2 migration warning zone:
|
||||
// Strip off anything after the first found comma or space, which
|
||||
// *hopefully* makes it a tiny bit more obvious that unexpected behavior is
|
||||
// caused by using the v1 form of stringly typed "Name".
|
||||
ret = append(ret, commaWhitespace.ReplaceAllString(part, ""))
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func withFileHint(filePath, str string) string {
|
||||
fileText := ""
|
||||
if filePath != "" {
|
||||
fileText = fmt.Sprintf(" [%s]", filePath)
|
||||
}
|
||||
return str + fileText
|
||||
}
|
||||
|
||||
func formatDefault(format string) string {
|
||||
return " (default: " + format + ")"
|
||||
}
|
||||
|
||||
func stringifyFlag(f Flag) string {
|
||||
// enforce DocGeneration interface on flags to avoid reflection
|
||||
df, ok := f.(DocGenerationFlag)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
placeholder, usage := unquoteUsage(df.GetUsage())
|
||||
needsPlaceholder := df.TakesValue()
|
||||
|
||||
if needsPlaceholder && placeholder == "" {
|
||||
placeholder = defaultPlaceholder
|
||||
}
|
||||
|
||||
defaultValueString := ""
|
||||
|
||||
// set default text for all flags except bool flags
|
||||
// for bool flags display default text if DisableDefaultText is not
|
||||
// set
|
||||
if bf, ok := f.(*BoolFlag); !ok || !bf.DisableDefaultText {
|
||||
if s := df.GetDefaultText(); s != "" {
|
||||
defaultValueString = fmt.Sprintf(formatDefault("%s"), s)
|
||||
}
|
||||
}
|
||||
|
||||
usageWithDefault := strings.TrimSpace(usage + defaultValueString)
|
||||
|
||||
pn := prefixedNames(df.Names(), placeholder)
|
||||
sliceFlag, ok := f.(DocGenerationSliceFlag)
|
||||
if ok && sliceFlag.IsSliceFlag() {
|
||||
pn = pn + " [ " + pn + " ]"
|
||||
}
|
||||
|
||||
return withEnvHint(df.GetEnvVars(), fmt.Sprintf("%s\t%s", pn, usageWithDefault))
|
||||
}
|
||||
|
||||
func hasFlag(flags []Flag, fl Flag) bool {
|
||||
for _, existing := range flags {
|
||||
if fl == existing {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Return the first value from a list of environment variables and files
|
||||
// (which may or may not exist), a description of where the value was found,
|
||||
// and a boolean which is true if a value was found.
|
||||
func flagFromEnvOrFile(envVars []string, filePath string) (value string, fromWhere string, found bool) {
|
||||
for _, envVar := range envVars {
|
||||
envVar = strings.TrimSpace(envVar)
|
||||
if value, found := syscall.Getenv(envVar); found {
|
||||
return value, fmt.Sprintf("environment variable %q", envVar), true
|
||||
}
|
||||
}
|
||||
for _, fileVar := range strings.Split(filePath, ",") {
|
||||
if fileVar != "" {
|
||||
if data, err := os.ReadFile(fileVar); err == nil {
|
||||
return string(data), fmt.Sprintf("file %q", filePath), true
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
type customizedSeparator interface {
|
||||
WithSeparatorSpec(separatorSpec)
|
||||
}
|
||||
|
||||
type separatorSpec struct {
|
||||
sep string
|
||||
disabled bool
|
||||
customized bool
|
||||
}
|
||||
|
||||
func (s separatorSpec) flagSplitMultiValues(val string) []string {
|
||||
var (
|
||||
disabled bool = s.disabled
|
||||
sep string = s.sep
|
||||
)
|
||||
if !s.customized {
|
||||
disabled = disableSliceFlagSeparator
|
||||
sep = defaultSliceFlagSeparator
|
||||
}
|
||||
if disabled {
|
||||
return []string{val}
|
||||
}
|
||||
|
||||
return strings.Split(val, sep)
|
||||
}
|
||||
-178
@@ -1,178 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// boolValue needs to implement the boolFlag internal interface in flag
|
||||
// to be able to capture bool fields and values
|
||||
//
|
||||
// type boolFlag interface {
|
||||
// Value
|
||||
// IsBoolFlag() bool
|
||||
// }
|
||||
type boolValue struct {
|
||||
destination *bool
|
||||
count *int
|
||||
}
|
||||
|
||||
func newBoolValue(val bool, p *bool, count *int) *boolValue {
|
||||
*p = val
|
||||
return &boolValue{
|
||||
destination: p,
|
||||
count: count,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *boolValue) Set(s string) error {
|
||||
v, err := strconv.ParseBool(s)
|
||||
if err != nil {
|
||||
err = errors.New("parse error")
|
||||
return err
|
||||
}
|
||||
*b.destination = v
|
||||
if b.count != nil {
|
||||
*b.count = *b.count + 1
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *boolValue) Get() interface{} { return *b.destination }
|
||||
|
||||
func (b *boolValue) String() string {
|
||||
if b.destination != nil {
|
||||
return strconv.FormatBool(*b.destination)
|
||||
}
|
||||
return strconv.FormatBool(false)
|
||||
}
|
||||
|
||||
func (b *boolValue) IsBoolFlag() bool { return true }
|
||||
|
||||
func (b *boolValue) Count() int {
|
||||
if b.count != nil && *b.count > 0 {
|
||||
return *b.count
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// TakesValue returns true of the flag takes a value, otherwise false
|
||||
func (f *BoolFlag) TakesValue() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// GetUsage returns the usage string for the flag
|
||||
func (f *BoolFlag) GetUsage() string {
|
||||
return f.Usage
|
||||
}
|
||||
|
||||
// GetCategory returns the category for the flag
|
||||
func (f *BoolFlag) GetCategory() string {
|
||||
return f.Category
|
||||
}
|
||||
|
||||
// GetValue returns the flags value as string representation and an empty
|
||||
// string if the flag takes no value at all.
|
||||
func (f *BoolFlag) GetValue() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetDefaultText returns the default text for this flag
|
||||
func (f *BoolFlag) GetDefaultText() string {
|
||||
if f.DefaultText != "" {
|
||||
return f.DefaultText
|
||||
}
|
||||
if f.defaultValueSet {
|
||||
return fmt.Sprintf("%v", f.defaultValue)
|
||||
}
|
||||
return fmt.Sprintf("%v", f.Value)
|
||||
}
|
||||
|
||||
// GetEnvVars returns the env vars for this flag
|
||||
func (f *BoolFlag) GetEnvVars() []string {
|
||||
return f.EnvVars
|
||||
}
|
||||
|
||||
// RunAction executes flag action if set
|
||||
func (f *BoolFlag) RunAction(c *Context) error {
|
||||
if f.Action != nil {
|
||||
return f.Action(c, c.Bool(f.Name))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
func (f *BoolFlag) Apply(set *flag.FlagSet) error {
|
||||
// set default value so that environment wont be able to overwrite it
|
||||
f.defaultValue = f.Value
|
||||
f.defaultValueSet = true
|
||||
|
||||
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
|
||||
if val != "" {
|
||||
valBool, err := strconv.ParseBool(val)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %q as bool value from %s for flag %s: %s", val, source, f.Name, err)
|
||||
}
|
||||
|
||||
f.Value = valBool
|
||||
} else {
|
||||
// empty value implies that the env is defined but set to empty string, we have to assume that this is
|
||||
// what the user wants. If user doesnt want this then the env needs to be deleted or the flag removed from
|
||||
// file
|
||||
f.Value = false
|
||||
}
|
||||
f.HasBeenSet = true
|
||||
}
|
||||
|
||||
count := f.Count
|
||||
dest := f.Destination
|
||||
|
||||
if count == nil {
|
||||
count = new(int)
|
||||
}
|
||||
|
||||
// since count will be incremented for each alias as well
|
||||
// subtract number of aliases from overall count
|
||||
*count -= len(f.Aliases)
|
||||
|
||||
if dest == nil {
|
||||
dest = new(bool)
|
||||
}
|
||||
|
||||
for _, name := range f.Names() {
|
||||
value := newBoolValue(f.Value, dest, count)
|
||||
set.Var(value, name, f.Usage)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the flag’s value in the given Context.
|
||||
func (f *BoolFlag) Get(ctx *Context) bool {
|
||||
return ctx.Bool(f.Name)
|
||||
}
|
||||
|
||||
// Bool looks up the value of a local BoolFlag, returns
|
||||
// false if not found
|
||||
func (cCtx *Context) Bool(name string) bool {
|
||||
if fs := cCtx.lookupFlagSet(name); fs != nil {
|
||||
return lookupBool(name, fs)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func lookupBool(name string, set *flag.FlagSet) bool {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := strconv.ParseBool(f.Value.String())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return false
|
||||
}
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TakesValue returns true of the flag takes a value, otherwise false
|
||||
func (f *DurationFlag) TakesValue() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetUsage returns the usage string for the flag
|
||||
func (f *DurationFlag) GetUsage() string {
|
||||
return f.Usage
|
||||
}
|
||||
|
||||
// GetCategory returns the category for the flag
|
||||
func (f *DurationFlag) GetCategory() string {
|
||||
return f.Category
|
||||
}
|
||||
|
||||
// GetValue returns the flags value as string representation and an empty
|
||||
// string if the flag takes no value at all.
|
||||
func (f *DurationFlag) GetValue() string {
|
||||
return f.Value.String()
|
||||
}
|
||||
|
||||
// GetDefaultText returns the default text for this flag
|
||||
func (f *DurationFlag) GetDefaultText() string {
|
||||
if f.DefaultText != "" {
|
||||
return f.DefaultText
|
||||
}
|
||||
if f.defaultValueSet {
|
||||
return f.defaultValue.String()
|
||||
}
|
||||
return f.Value.String()
|
||||
}
|
||||
|
||||
// GetEnvVars returns the env vars for this flag
|
||||
func (f *DurationFlag) GetEnvVars() []string {
|
||||
return f.EnvVars
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
func (f *DurationFlag) Apply(set *flag.FlagSet) error {
|
||||
// set default value so that environment wont be able to overwrite it
|
||||
f.defaultValue = f.Value
|
||||
f.defaultValueSet = true
|
||||
|
||||
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
|
||||
if val != "" {
|
||||
valDuration, err := time.ParseDuration(val)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %q as duration value from %s for flag %s: %s", val, source, f.Name, err)
|
||||
}
|
||||
|
||||
f.Value = valDuration
|
||||
f.HasBeenSet = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range f.Names() {
|
||||
if f.Destination != nil {
|
||||
set.DurationVar(f.Destination, name, f.Value, f.Usage)
|
||||
continue
|
||||
}
|
||||
set.Duration(name, f.Value, f.Usage)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the flag’s value in the given Context.
|
||||
func (f *DurationFlag) Get(ctx *Context) time.Duration {
|
||||
return ctx.Duration(f.Name)
|
||||
}
|
||||
|
||||
// RunAction executes flag action if set
|
||||
func (f *DurationFlag) RunAction(c *Context) error {
|
||||
if f.Action != nil {
|
||||
return f.Action(c, c.Duration(f.Name))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Duration looks up the value of a local DurationFlag, returns
|
||||
// 0 if not found
|
||||
func (cCtx *Context) Duration(name string) time.Duration {
|
||||
if fs := cCtx.lookupFlagSet(name); fs != nil {
|
||||
return lookupDuration(name, fs)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupDuration(name string, set *flag.FlagSet) time.Duration {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := time.ParseDuration(f.Value.String())
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return 0
|
||||
}
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
package cli
|
||||
|
||||
import "flag"
|
||||
|
||||
type extFlag struct {
|
||||
f *flag.Flag
|
||||
}
|
||||
|
||||
func (e *extFlag) Apply(fs *flag.FlagSet) error {
|
||||
fs.Var(e.f.Value, e.f.Name, e.f.Usage)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *extFlag) Names() []string {
|
||||
return []string{e.f.Name}
|
||||
}
|
||||
|
||||
func (e *extFlag) IsSet() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *extFlag) String() string {
|
||||
return FlagStringer(e)
|
||||
}
|
||||
|
||||
func (e *extFlag) IsVisible() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *extFlag) TakesValue() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *extFlag) GetUsage() string {
|
||||
return e.f.Usage
|
||||
}
|
||||
|
||||
func (e *extFlag) GetValue() string {
|
||||
return e.f.Value.String()
|
||||
}
|
||||
|
||||
func (e *extFlag) GetDefaultText() string {
|
||||
return e.f.DefValue
|
||||
}
|
||||
|
||||
func (e *extFlag) GetEnvVars() []string {
|
||||
return nil
|
||||
}
|
||||
-107
@@ -1,107 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// TakesValue returns true of the flag takes a value, otherwise false
|
||||
func (f *Float64Flag) TakesValue() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetUsage returns the usage string for the flag
|
||||
func (f *Float64Flag) GetUsage() string {
|
||||
return f.Usage
|
||||
}
|
||||
|
||||
// GetCategory returns the category for the flag
|
||||
func (f *Float64Flag) GetCategory() string {
|
||||
return f.Category
|
||||
}
|
||||
|
||||
// GetValue returns the flags value as string representation and an empty
|
||||
// string if the flag takes no value at all.
|
||||
func (f *Float64Flag) GetValue() string {
|
||||
return fmt.Sprintf("%v", f.Value)
|
||||
}
|
||||
|
||||
// GetDefaultText returns the default text for this flag
|
||||
func (f *Float64Flag) GetDefaultText() string {
|
||||
if f.DefaultText != "" {
|
||||
return f.DefaultText
|
||||
}
|
||||
if f.defaultValueSet {
|
||||
return fmt.Sprintf("%v", f.defaultValue)
|
||||
}
|
||||
return fmt.Sprintf("%v", f.Value)
|
||||
}
|
||||
|
||||
// GetEnvVars returns the env vars for this flag
|
||||
func (f *Float64Flag) GetEnvVars() []string {
|
||||
return f.EnvVars
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
func (f *Float64Flag) Apply(set *flag.FlagSet) error {
|
||||
f.defaultValue = f.Value
|
||||
f.defaultValueSet = true
|
||||
|
||||
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
|
||||
if val != "" {
|
||||
valFloat, err := strconv.ParseFloat(val, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %q as float64 value from %s for flag %s: %s", val, source, f.Name, err)
|
||||
}
|
||||
|
||||
f.Value = valFloat
|
||||
f.HasBeenSet = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range f.Names() {
|
||||
if f.Destination != nil {
|
||||
set.Float64Var(f.Destination, name, f.Value, f.Usage)
|
||||
continue
|
||||
}
|
||||
set.Float64(name, f.Value, f.Usage)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the flag’s value in the given Context.
|
||||
func (f *Float64Flag) Get(ctx *Context) float64 {
|
||||
return ctx.Float64(f.Name)
|
||||
}
|
||||
|
||||
// RunAction executes flag action if set
|
||||
func (f *Float64Flag) RunAction(c *Context) error {
|
||||
if f.Action != nil {
|
||||
return f.Action(c, c.Float64(f.Name))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Float64 looks up the value of a local Float64Flag, returns
|
||||
// 0 if not found
|
||||
func (cCtx *Context) Float64(name string) float64 {
|
||||
if fs := cCtx.lookupFlagSet(name); fs != nil {
|
||||
return lookupFloat64(name, fs)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupFloat64(name string, set *flag.FlagSet) float64 {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := strconv.ParseFloat(f.Value.String(), 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return 0
|
||||
}
|
||||
-216
@@ -1,216 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Float64Slice wraps []float64 to satisfy flag.Value
|
||||
type Float64Slice struct {
|
||||
slice []float64
|
||||
separator separatorSpec
|
||||
hasBeenSet bool
|
||||
}
|
||||
|
||||
// NewFloat64Slice makes a *Float64Slice with default values
|
||||
func NewFloat64Slice(defaults ...float64) *Float64Slice {
|
||||
return &Float64Slice{slice: append([]float64{}, defaults...)}
|
||||
}
|
||||
|
||||
// clone allocate a copy of self object
|
||||
func (f *Float64Slice) clone() *Float64Slice {
|
||||
n := &Float64Slice{
|
||||
slice: make([]float64, len(f.slice)),
|
||||
hasBeenSet: f.hasBeenSet,
|
||||
}
|
||||
copy(n.slice, f.slice)
|
||||
return n
|
||||
}
|
||||
|
||||
func (f *Float64Slice) WithSeparatorSpec(spec separatorSpec) {
|
||||
f.separator = spec
|
||||
}
|
||||
|
||||
// Set parses the value into a float64 and appends it to the list of values
|
||||
func (f *Float64Slice) Set(value string) error {
|
||||
if !f.hasBeenSet {
|
||||
f.slice = []float64{}
|
||||
f.hasBeenSet = true
|
||||
}
|
||||
|
||||
if strings.HasPrefix(value, slPfx) {
|
||||
// Deserializing assumes overwrite
|
||||
_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &f.slice)
|
||||
f.hasBeenSet = true
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, s := range f.separator.flagSplitMultiValues(value) {
|
||||
tmp, err := strconv.ParseFloat(strings.TrimSpace(s), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.slice = append(f.slice, tmp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *Float64Slice) String() string {
|
||||
v := f.slice
|
||||
if v == nil {
|
||||
// treat nil the same as zero length non-nil
|
||||
v = make([]float64, 0)
|
||||
}
|
||||
return fmt.Sprintf("%#v", v)
|
||||
}
|
||||
|
||||
// Serialize allows Float64Slice to fulfill Serializer
|
||||
func (f *Float64Slice) Serialize() string {
|
||||
jsonBytes, _ := json.Marshal(f.slice)
|
||||
return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
|
||||
}
|
||||
|
||||
// Value returns the slice of float64s set by this flag
|
||||
func (f *Float64Slice) Value() []float64 {
|
||||
return f.slice
|
||||
}
|
||||
|
||||
// Get returns the slice of float64s set by this flag
|
||||
func (f *Float64Slice) Get() interface{} {
|
||||
return *f
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f *Float64SliceFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// TakesValue returns true if the flag takes a value, otherwise false
|
||||
func (f *Float64SliceFlag) TakesValue() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetUsage returns the usage string for the flag
|
||||
func (f *Float64SliceFlag) GetUsage() string {
|
||||
return f.Usage
|
||||
}
|
||||
|
||||
// GetCategory returns the category for the flag
|
||||
func (f *Float64SliceFlag) GetCategory() string {
|
||||
return f.Category
|
||||
}
|
||||
|
||||
// GetValue returns the flags value as string representation and an empty
|
||||
// string if the flag takes no value at all.
|
||||
func (f *Float64SliceFlag) GetValue() string {
|
||||
var defaultVals []string
|
||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||
for _, i := range f.Value.Value() {
|
||||
defaultVals = append(defaultVals, strings.TrimRight(strings.TrimRight(fmt.Sprintf("%f", i), "0"), "."))
|
||||
}
|
||||
}
|
||||
return strings.Join(defaultVals, ", ")
|
||||
}
|
||||
|
||||
// GetDefaultText returns the default text for this flag
|
||||
func (f *Float64SliceFlag) GetDefaultText() string {
|
||||
if f.DefaultText != "" {
|
||||
return f.DefaultText
|
||||
}
|
||||
return f.GetValue()
|
||||
}
|
||||
|
||||
// GetEnvVars returns the env vars for this flag
|
||||
func (f *Float64SliceFlag) GetEnvVars() []string {
|
||||
return f.EnvVars
|
||||
}
|
||||
|
||||
// IsSliceFlag implements DocGenerationSliceFlag.
|
||||
func (f *Float64SliceFlag) IsSliceFlag() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error {
|
||||
// apply any default
|
||||
if f.Destination != nil && f.Value != nil {
|
||||
f.Destination.slice = make([]float64, len(f.Value.slice))
|
||||
copy(f.Destination.slice, f.Value.slice)
|
||||
}
|
||||
|
||||
// resolve setValue (what we will assign to the set)
|
||||
var setValue *Float64Slice
|
||||
switch {
|
||||
case f.Destination != nil:
|
||||
setValue = f.Destination
|
||||
case f.Value != nil:
|
||||
setValue = f.Value.clone()
|
||||
default:
|
||||
setValue = new(Float64Slice)
|
||||
setValue.WithSeparatorSpec(f.separator)
|
||||
}
|
||||
|
||||
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
|
||||
if val != "" {
|
||||
for _, s := range f.separator.flagSplitMultiValues(val) {
|
||||
if err := setValue.Set(strings.TrimSpace(s)); err != nil {
|
||||
return fmt.Errorf("could not parse %q as float64 slice value from %s for flag %s: %s", val, source, f.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Set this to false so that we reset the slice if we then set values from
|
||||
// flags that have already been set by the environment.
|
||||
setValue.hasBeenSet = false
|
||||
f.HasBeenSet = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range f.Names() {
|
||||
set.Var(setValue, name, f.Usage)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Float64SliceFlag) WithSeparatorSpec(spec separatorSpec) {
|
||||
f.separator = spec
|
||||
}
|
||||
|
||||
// Get returns the flag’s value in the given Context.
|
||||
func (f *Float64SliceFlag) Get(ctx *Context) []float64 {
|
||||
return ctx.Float64Slice(f.Name)
|
||||
}
|
||||
|
||||
// RunAction executes flag action if set
|
||||
func (f *Float64SliceFlag) RunAction(c *Context) error {
|
||||
if f.Action != nil {
|
||||
return f.Action(c, c.Float64Slice(f.Name))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Float64Slice looks up the value of a local Float64SliceFlag, returns
|
||||
// nil if not found
|
||||
func (cCtx *Context) Float64Slice(name string) []float64 {
|
||||
if fs := cCtx.lookupFlagSet(name); fs != nil {
|
||||
return lookupFloat64Slice(name, fs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupFloat64Slice(name string, set *flag.FlagSet) []float64 {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
if slice, ok := unwrapFlagValue(f.Value).(*Float64Slice); ok {
|
||||
return slice.Value()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
-131
@@ -1,131 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Generic is a generic parseable type identified by a specific flag
|
||||
type Generic interface {
|
||||
Set(value string) error
|
||||
String() string
|
||||
}
|
||||
|
||||
type stringGeneric struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func (s *stringGeneric) Set(value string) error {
|
||||
s.value = value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stringGeneric) String() string {
|
||||
return s.value
|
||||
}
|
||||
|
||||
// TakesValue returns true of the flag takes a value, otherwise false
|
||||
func (f *GenericFlag) TakesValue() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetUsage returns the usage string for the flag
|
||||
func (f *GenericFlag) GetUsage() string {
|
||||
return f.Usage
|
||||
}
|
||||
|
||||
// GetCategory returns the category for the flag
|
||||
func (f *GenericFlag) GetCategory() string {
|
||||
return f.Category
|
||||
}
|
||||
|
||||
// GetValue returns the flags value as string representation and an empty
|
||||
// string if the flag takes no value at all.
|
||||
func (f *GenericFlag) GetValue() string {
|
||||
if f.Value != nil {
|
||||
return f.Value.String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetDefaultText returns the default text for this flag
|
||||
func (f *GenericFlag) GetDefaultText() string {
|
||||
if f.DefaultText != "" {
|
||||
return f.DefaultText
|
||||
}
|
||||
val := f.Value
|
||||
if f.defaultValueSet {
|
||||
val = f.defaultValue
|
||||
}
|
||||
|
||||
if val != nil {
|
||||
return val.String()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetEnvVars returns the env vars for this flag
|
||||
func (f *GenericFlag) GetEnvVars() []string {
|
||||
return f.EnvVars
|
||||
}
|
||||
|
||||
// Apply takes the flagset and calls Set on the generic flag with the value
|
||||
// provided by the user for parsing by the flag
|
||||
func (f *GenericFlag) Apply(set *flag.FlagSet) error {
|
||||
// set default value so that environment wont be able to overwrite it
|
||||
if f.Value != nil {
|
||||
f.defaultValue = &stringGeneric{value: f.Value.String()}
|
||||
f.defaultValueSet = true
|
||||
}
|
||||
|
||||
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
|
||||
if val != "" {
|
||||
if err := f.Value.Set(val); err != nil {
|
||||
return fmt.Errorf("could not parse %q from %s as value for flag %s: %s", val, source, f.Name, err)
|
||||
}
|
||||
|
||||
f.HasBeenSet = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range f.Names() {
|
||||
if f.Destination != nil {
|
||||
set.Var(f.Destination, name, f.Usage)
|
||||
continue
|
||||
}
|
||||
set.Var(f.Value, name, f.Usage)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the flag’s value in the given Context.
|
||||
func (f *GenericFlag) Get(ctx *Context) interface{} {
|
||||
return ctx.Generic(f.Name)
|
||||
}
|
||||
|
||||
// RunAction executes flag action if set
|
||||
func (f *GenericFlag) RunAction(c *Context) error {
|
||||
if f.Action != nil {
|
||||
return f.Action(c, c.Generic(f.Name))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generic looks up the value of a local GenericFlag, returns
|
||||
// nil if not found
|
||||
func (cCtx *Context) Generic(name string) interface{} {
|
||||
if fs := cCtx.lookupFlagSet(name); fs != nil {
|
||||
return lookupGeneric(name, fs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupGeneric(name string, set *flag.FlagSet) interface{} {
|
||||
if f := set.Lookup(name); f != nil {
|
||||
return f.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// TakesValue returns true of the flag takes a value, otherwise false
|
||||
func (f *IntFlag) TakesValue() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetUsage returns the usage string for the flag
|
||||
func (f *IntFlag) GetUsage() string {
|
||||
return f.Usage
|
||||
}
|
||||
|
||||
// GetCategory returns the category for the flag
|
||||
func (f *IntFlag) GetCategory() string {
|
||||
return f.Category
|
||||
}
|
||||
|
||||
// GetValue returns the flags value as string representation and an empty
|
||||
// string if the flag takes no value at all.
|
||||
func (f *IntFlag) GetValue() string {
|
||||
return fmt.Sprintf("%d", f.Value)
|
||||
}
|
||||
|
||||
// GetDefaultText returns the default text for this flag
|
||||
func (f *IntFlag) GetDefaultText() string {
|
||||
if f.DefaultText != "" {
|
||||
return f.DefaultText
|
||||
}
|
||||
if f.defaultValueSet {
|
||||
return fmt.Sprintf("%d", f.defaultValue)
|
||||
}
|
||||
return fmt.Sprintf("%d", f.Value)
|
||||
}
|
||||
|
||||
// GetEnvVars returns the env vars for this flag
|
||||
func (f *IntFlag) GetEnvVars() []string {
|
||||
return f.EnvVars
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
func (f *IntFlag) Apply(set *flag.FlagSet) error {
|
||||
// set default value so that environment wont be able to overwrite it
|
||||
f.defaultValue = f.Value
|
||||
f.defaultValueSet = true
|
||||
|
||||
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
|
||||
if val != "" {
|
||||
valInt, err := strconv.ParseInt(val, f.Base, 64)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %q as int value from %s for flag %s: %s", val, source, f.Name, err)
|
||||
}
|
||||
|
||||
f.Value = int(valInt)
|
||||
f.HasBeenSet = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range f.Names() {
|
||||
if f.Destination != nil {
|
||||
set.IntVar(f.Destination, name, f.Value, f.Usage)
|
||||
continue
|
||||
}
|
||||
set.Int(name, f.Value, f.Usage)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the flag’s value in the given Context.
|
||||
func (f *IntFlag) Get(ctx *Context) int {
|
||||
return ctx.Int(f.Name)
|
||||
}
|
||||
|
||||
// RunAction executes flag action if set
|
||||
func (f *IntFlag) RunAction(c *Context) error {
|
||||
if f.Action != nil {
|
||||
return f.Action(c, c.Int(f.Name))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Int looks up the value of a local IntFlag, returns
|
||||
// 0 if not found
|
||||
func (cCtx *Context) Int(name string) int {
|
||||
if fs := cCtx.lookupFlagSet(name); fs != nil {
|
||||
return lookupInt(name, fs)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupInt(name string, set *flag.FlagSet) int {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := strconv.ParseInt(f.Value.String(), 0, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return int(parsed)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// TakesValue returns true of the flag takes a value, otherwise false
|
||||
func (f *Int64Flag) TakesValue() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetUsage returns the usage string for the flag
|
||||
func (f *Int64Flag) GetUsage() string {
|
||||
return f.Usage
|
||||
}
|
||||
|
||||
// GetCategory returns the category for the flag
|
||||
func (f *Int64Flag) GetCategory() string {
|
||||
return f.Category
|
||||
}
|
||||
|
||||
// GetValue returns the flags value as string representation and an empty
|
||||
// string if the flag takes no value at all.
|
||||
func (f *Int64Flag) GetValue() string {
|
||||
return fmt.Sprintf("%d", f.Value)
|
||||
}
|
||||
|
||||
// GetDefaultText returns the default text for this flag
|
||||
func (f *Int64Flag) GetDefaultText() string {
|
||||
if f.DefaultText != "" {
|
||||
return f.DefaultText
|
||||
}
|
||||
if f.defaultValueSet {
|
||||
return fmt.Sprintf("%d", f.defaultValue)
|
||||
}
|
||||
return fmt.Sprintf("%d", f.Value)
|
||||
}
|
||||
|
||||
// GetEnvVars returns the env vars for this flag
|
||||
func (f *Int64Flag) GetEnvVars() []string {
|
||||
return f.EnvVars
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
func (f *Int64Flag) Apply(set *flag.FlagSet) error {
|
||||
// set default value so that environment wont be able to overwrite it
|
||||
f.defaultValue = f.Value
|
||||
f.defaultValueSet = true
|
||||
|
||||
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
|
||||
if val != "" {
|
||||
valInt, err := strconv.ParseInt(val, f.Base, 64)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %q as int value from %s for flag %s: %s", val, source, f.Name, err)
|
||||
}
|
||||
|
||||
f.Value = valInt
|
||||
f.HasBeenSet = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range f.Names() {
|
||||
if f.Destination != nil {
|
||||
set.Int64Var(f.Destination, name, f.Value, f.Usage)
|
||||
continue
|
||||
}
|
||||
set.Int64(name, f.Value, f.Usage)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the flag’s value in the given Context.
|
||||
func (f *Int64Flag) Get(ctx *Context) int64 {
|
||||
return ctx.Int64(f.Name)
|
||||
}
|
||||
|
||||
// RunAction executes flag action if set
|
||||
func (f *Int64Flag) RunAction(c *Context) error {
|
||||
if f.Action != nil {
|
||||
return f.Action(c, c.Int64(f.Name))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Int64 looks up the value of a local Int64Flag, returns
|
||||
// 0 if not found
|
||||
func (cCtx *Context) Int64(name string) int64 {
|
||||
if fs := cCtx.lookupFlagSet(name); fs != nil {
|
||||
return lookupInt64(name, fs)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupInt64(name string, set *flag.FlagSet) int64 {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := strconv.ParseInt(f.Value.String(), 0, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return 0
|
||||
}
|
||||
-215
@@ -1,215 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Int64Slice wraps []int64 to satisfy flag.Value
|
||||
type Int64Slice struct {
|
||||
slice []int64
|
||||
separator separatorSpec
|
||||
hasBeenSet bool
|
||||
}
|
||||
|
||||
// NewInt64Slice makes an *Int64Slice with default values
|
||||
func NewInt64Slice(defaults ...int64) *Int64Slice {
|
||||
return &Int64Slice{slice: append([]int64{}, defaults...)}
|
||||
}
|
||||
|
||||
// clone allocate a copy of self object
|
||||
func (i *Int64Slice) clone() *Int64Slice {
|
||||
n := &Int64Slice{
|
||||
slice: make([]int64, len(i.slice)),
|
||||
hasBeenSet: i.hasBeenSet,
|
||||
}
|
||||
copy(n.slice, i.slice)
|
||||
return n
|
||||
}
|
||||
|
||||
func (i *Int64Slice) WithSeparatorSpec(spec separatorSpec) {
|
||||
i.separator = spec
|
||||
}
|
||||
|
||||
// Set parses the value into an integer and appends it to the list of values
|
||||
func (i *Int64Slice) Set(value string) error {
|
||||
if !i.hasBeenSet {
|
||||
i.slice = []int64{}
|
||||
i.hasBeenSet = true
|
||||
}
|
||||
|
||||
if strings.HasPrefix(value, slPfx) {
|
||||
// Deserializing assumes overwrite
|
||||
_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &i.slice)
|
||||
i.hasBeenSet = true
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, s := range i.separator.flagSplitMultiValues(value) {
|
||||
tmp, err := strconv.ParseInt(strings.TrimSpace(s), 0, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.slice = append(i.slice, tmp)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (i *Int64Slice) String() string {
|
||||
v := i.slice
|
||||
if v == nil {
|
||||
// treat nil the same as zero length non-nil
|
||||
v = make([]int64, 0)
|
||||
}
|
||||
return fmt.Sprintf("%#v", v)
|
||||
}
|
||||
|
||||
// Serialize allows Int64Slice to fulfill Serializer
|
||||
func (i *Int64Slice) Serialize() string {
|
||||
jsonBytes, _ := json.Marshal(i.slice)
|
||||
return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
|
||||
}
|
||||
|
||||
// Value returns the slice of ints set by this flag
|
||||
func (i *Int64Slice) Value() []int64 {
|
||||
return i.slice
|
||||
}
|
||||
|
||||
// Get returns the slice of ints set by this flag
|
||||
func (i *Int64Slice) Get() interface{} {
|
||||
return *i
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f *Int64SliceFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// TakesValue returns true of the flag takes a value, otherwise false
|
||||
func (f *Int64SliceFlag) TakesValue() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetUsage returns the usage string for the flag
|
||||
func (f *Int64SliceFlag) GetUsage() string {
|
||||
return f.Usage
|
||||
}
|
||||
|
||||
// GetCategory returns the category for the flag
|
||||
func (f *Int64SliceFlag) GetCategory() string {
|
||||
return f.Category
|
||||
}
|
||||
|
||||
// GetValue returns the flags value as string representation and an empty
|
||||
// string if the flag takes no value at all.
|
||||
func (f *Int64SliceFlag) GetValue() string {
|
||||
var defaultVals []string
|
||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||
for _, i := range f.Value.Value() {
|
||||
defaultVals = append(defaultVals, strconv.FormatInt(i, 10))
|
||||
}
|
||||
}
|
||||
return strings.Join(defaultVals, ", ")
|
||||
}
|
||||
|
||||
// GetDefaultText returns the default text for this flag
|
||||
func (f *Int64SliceFlag) GetDefaultText() string {
|
||||
if f.DefaultText != "" {
|
||||
return f.DefaultText
|
||||
}
|
||||
return f.GetValue()
|
||||
}
|
||||
|
||||
// GetEnvVars returns the env vars for this flag
|
||||
func (f *Int64SliceFlag) GetEnvVars() []string {
|
||||
return f.EnvVars
|
||||
}
|
||||
|
||||
// IsSliceFlag implements DocGenerationSliceFlag.
|
||||
func (f *Int64SliceFlag) IsSliceFlag() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error {
|
||||
// apply any default
|
||||
if f.Destination != nil && f.Value != nil {
|
||||
f.Destination.slice = make([]int64, len(f.Value.slice))
|
||||
copy(f.Destination.slice, f.Value.slice)
|
||||
}
|
||||
|
||||
// resolve setValue (what we will assign to the set)
|
||||
var setValue *Int64Slice
|
||||
switch {
|
||||
case f.Destination != nil:
|
||||
setValue = f.Destination
|
||||
case f.Value != nil:
|
||||
setValue = f.Value.clone()
|
||||
default:
|
||||
setValue = new(Int64Slice)
|
||||
setValue.WithSeparatorSpec(f.separator)
|
||||
}
|
||||
|
||||
if val, source, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok && val != "" {
|
||||
for _, s := range f.separator.flagSplitMultiValues(val) {
|
||||
if err := setValue.Set(strings.TrimSpace(s)); err != nil {
|
||||
return fmt.Errorf("could not parse %q as int64 slice value from %s for flag %s: %s", val, source, f.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Set this to false so that we reset the slice if we then set values from
|
||||
// flags that have already been set by the environment.
|
||||
setValue.hasBeenSet = false
|
||||
f.HasBeenSet = true
|
||||
}
|
||||
|
||||
for _, name := range f.Names() {
|
||||
set.Var(setValue, name, f.Usage)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Int64SliceFlag) WithSeparatorSpec(spec separatorSpec) {
|
||||
f.separator = spec
|
||||
}
|
||||
|
||||
// Get returns the flag’s value in the given Context.
|
||||
func (f *Int64SliceFlag) Get(ctx *Context) []int64 {
|
||||
return ctx.Int64Slice(f.Name)
|
||||
}
|
||||
|
||||
// RunAction executes flag action if set
|
||||
func (f *Int64SliceFlag) RunAction(c *Context) error {
|
||||
if f.Action != nil {
|
||||
return f.Action(c, c.Int64Slice(f.Name))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Int64Slice looks up the value of a local Int64SliceFlag, returns
|
||||
// nil if not found
|
||||
func (cCtx *Context) Int64Slice(name string) []int64 {
|
||||
if fs := cCtx.lookupFlagSet(name); fs != nil {
|
||||
return lookupInt64Slice(name, fs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupInt64Slice(name string, set *flag.FlagSet) []int64 {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
if slice, ok := unwrapFlagValue(f.Value).(*Int64Slice); ok {
|
||||
return slice.Value()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Loaded 100 of 179 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user