From 325fb75a1d5244907bf4c0fa515795ba64f5754e Mon Sep 17 00:00:00 2001 From: lifubang Date: Wed, 18 Mar 2026 03:00:21 +0000 Subject: [PATCH 1/2] chore(deps): upgrade urfave/cli from v1 to v3 Migrate from urfave/cli v1 (maintenance mode) to v3 to benefit from active development, improved features, and long-term support. Signed-off-by: lifubang --- checkpoint.go | 93 +- create.go | 34 +- delete.go | 26 +- events.go | 23 +- exec.go | 137 +- features.go | 13 +- go.mod | 4 +- go.sum | 21 +- kill.go | 30 +- list.go | 39 +- main.go | 51 +- notify_socket.go | 10 +- pause.go | 24 +- ps.go | 36 +- restore.go | 63 +- rootless_linux.go | 12 +- run.go | 45 +- spec.go | 26 +- start.go | 15 +- state.go | 13 +- tests/cmd/pidfd-kill/pidfd-kill.go | 23 +- tests/cmd/recvtty/recvtty.go | 27 +- tests/cmd/remap-rootfs/remap-rootfs.go | 11 +- update.go | 78 +- utils.go | 38 +- utils_linux.go | 46 +- .../cpuguy83/go-md2man/v2/LICENSE.md | 21 - .../cpuguy83/go-md2man/v2/md2man/debug.go | 62 - .../cpuguy83/go-md2man/v2/md2man/md2man.go | 24 - .../cpuguy83/go-md2man/v2/md2man/roff.go | 416 --- .../russross/blackfriday/v2/.gitignore | 8 - .../russross/blackfriday/v2/.travis.yml | 17 - .../russross/blackfriday/v2/LICENSE.txt | 29 - .../russross/blackfriday/v2/README.md | 335 --- .../russross/blackfriday/v2/block.go | 1612 ------------ .../github.com/russross/blackfriday/v2/doc.go | 46 - .../russross/blackfriday/v2/entities.go | 2236 ----------------- .../github.com/russross/blackfriday/v2/esc.go | 70 - .../russross/blackfriday/v2/html.go | 952 ------- .../russross/blackfriday/v2/inline.go | 1228 --------- .../russross/blackfriday/v2/markdown.go | 950 ------- .../russross/blackfriday/v2/node.go | 360 --- .../russross/blackfriday/v2/smartypants.go | 457 ---- vendor/github.com/urfave/cli/.flake8 | 2 - vendor/github.com/urfave/cli/README.md | 51 - vendor/github.com/urfave/cli/app.go | 531 ---- vendor/github.com/urfave/cli/category.go | 44 - vendor/github.com/urfave/cli/cli.go | 22 - vendor/github.com/urfave/cli/command.go | 386 --- vendor/github.com/urfave/cli/context.go | 348 --- vendor/github.com/urfave/cli/docs.go | 151 -- vendor/github.com/urfave/cli/errors.go | 115 - vendor/github.com/urfave/cli/fish.go | 194 -- vendor/github.com/urfave/cli/flag.go | 348 --- vendor/github.com/urfave/cli/flag_bool.go | 109 - vendor/github.com/urfave/cli/flag_bool_t.go | 110 - vendor/github.com/urfave/cli/flag_duration.go | 106 - vendor/github.com/urfave/cli/flag_float64.go | 106 - vendor/github.com/urfave/cli/flag_generic.go | 110 - vendor/github.com/urfave/cli/flag_int.go | 105 - vendor/github.com/urfave/cli/flag_int64.go | 106 - .../github.com/urfave/cli/flag_int64_slice.go | 199 -- .../github.com/urfave/cli/flag_int_slice.go | 198 -- vendor/github.com/urfave/cli/flag_string.go | 98 - .../urfave/cli/flag_string_slice.go | 184 -- vendor/github.com/urfave/cli/flag_uint.go | 106 - vendor/github.com/urfave/cli/flag_uint64.go | 106 - vendor/github.com/urfave/cli/funcs.go | 44 - vendor/github.com/urfave/cli/help.go | 363 --- vendor/github.com/urfave/cli/parse.go | 94 - vendor/github.com/urfave/cli/template.go | 121 - .../github.com/urfave/cli/{ => v3}/.gitignore | 13 +- .../github.com/urfave/cli/v3/.golangci.yaml | 13 + .../urfave/cli/{ => v3}/CODE_OF_CONDUCT.md | 11 +- vendor/github.com/urfave/cli/{ => v3}/LICENSE | 2 +- vendor/github.com/urfave/cli/v3/Makefile | 26 + vendor/github.com/urfave/cli/v3/README.md | 56 + vendor/github.com/urfave/cli/v3/args.go | 400 +++ .../cli/v3/autocomplete/bash_autocomplete | 34 + .../cli/v3/autocomplete/fish_autocomplete | 35 + .../autocomplete/powershell_autocomplete.ps1 | 9 + .../cli/v3/autocomplete/zsh_autocomplete | 29 + vendor/github.com/urfave/cli/v3/category.go | 195 ++ vendor/github.com/urfave/cli/v3/cli.go | 60 + vendor/github.com/urfave/cli/v3/command.go | 598 +++++ .../github.com/urfave/cli/v3/command_parse.go | 224 ++ .../github.com/urfave/cli/v3/command_run.go | 371 +++ .../github.com/urfave/cli/v3/command_setup.go | 223 ++ vendor/github.com/urfave/cli/v3/completion.go | 102 + vendor/github.com/urfave/cli/v3/docs.go | 128 + vendor/github.com/urfave/cli/v3/errors.go | 182 ++ vendor/github.com/urfave/cli/v3/fish.go | 221 ++ vendor/github.com/urfave/cli/v3/flag.go | 223 ++ vendor/github.com/urfave/cli/v3/flag_bool.go | 78 + .../urfave/cli/v3/flag_bool_with_inverse.go | 240 ++ .../github.com/urfave/cli/v3/flag_duration.go | 50 + vendor/github.com/urfave/cli/v3/flag_ext.go | 63 + vendor/github.com/urfave/cli/v3/flag_float.go | 76 + .../urfave/cli/v3/flag_float_slice.go | 34 + .../github.com/urfave/cli/v3/flag_generic.go | 65 + vendor/github.com/urfave/cli/v3/flag_impl.go | 313 +++ vendor/github.com/urfave/cli/v3/flag_int.go | 104 + .../urfave/cli/v3/flag_int_slice.go | 52 + .../github.com/urfave/cli/v3/flag_map_impl.go | 138 + vendor/github.com/urfave/cli/v3/flag_mutex.go | 54 + .../urfave/cli/v3/flag_number_slice.go | 15 + .../urfave/cli/v3/flag_slice_base.go | 115 + .../github.com/urfave/cli/v3/flag_string.go | 64 + .../urfave/cli/v3/flag_string_map.go | 20 + .../urfave/cli/v3/flag_string_slice.go | 20 + .../urfave/cli/v3/flag_timestamp.go | 143 ++ vendor/github.com/urfave/cli/v3/flag_uint.go | 99 + .../urfave/cli/v3/flag_uint_slice.go | 63 + vendor/github.com/urfave/cli/v3/funcs.go | 53 + .../urfave/cli/v3/godoc-current.txt | 1500 +++++++++++ vendor/github.com/urfave/cli/v3/help.go | 624 +++++ .../urfave/cli/v3/mkdocs-requirements.txt | 5 + vendor/github.com/urfave/cli/v3/mkdocs.yml | 139 + vendor/github.com/urfave/cli/{ => v3}/sort.go | 0 .../github.com/urfave/cli/v3/staticcheck.conf | 1 + .../github.com/urfave/cli/v3/suggestions.go | 147 ++ vendor/github.com/urfave/cli/v3/template.go | 125 + .../github.com/urfave/cli/v3/value_source.go | 257 ++ vendor/modules.txt | 12 +- 124 files changed, 8307 insertions(+), 13735 deletions(-) delete mode 100644 vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md delete mode 100644 vendor/github.com/cpuguy83/go-md2man/v2/md2man/debug.go delete mode 100644 vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go delete mode 100644 vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go delete mode 100644 vendor/github.com/russross/blackfriday/v2/.gitignore delete mode 100644 vendor/github.com/russross/blackfriday/v2/.travis.yml delete mode 100644 vendor/github.com/russross/blackfriday/v2/LICENSE.txt delete mode 100644 vendor/github.com/russross/blackfriday/v2/README.md delete mode 100644 vendor/github.com/russross/blackfriday/v2/block.go delete mode 100644 vendor/github.com/russross/blackfriday/v2/doc.go delete mode 100644 vendor/github.com/russross/blackfriday/v2/entities.go delete mode 100644 vendor/github.com/russross/blackfriday/v2/esc.go delete mode 100644 vendor/github.com/russross/blackfriday/v2/html.go delete mode 100644 vendor/github.com/russross/blackfriday/v2/inline.go delete mode 100644 vendor/github.com/russross/blackfriday/v2/markdown.go delete mode 100644 vendor/github.com/russross/blackfriday/v2/node.go delete mode 100644 vendor/github.com/russross/blackfriday/v2/smartypants.go delete mode 100644 vendor/github.com/urfave/cli/.flake8 delete mode 100644 vendor/github.com/urfave/cli/README.md delete mode 100644 vendor/github.com/urfave/cli/app.go delete mode 100644 vendor/github.com/urfave/cli/category.go delete mode 100644 vendor/github.com/urfave/cli/cli.go delete mode 100644 vendor/github.com/urfave/cli/command.go delete mode 100644 vendor/github.com/urfave/cli/context.go delete mode 100644 vendor/github.com/urfave/cli/docs.go delete mode 100644 vendor/github.com/urfave/cli/errors.go delete mode 100644 vendor/github.com/urfave/cli/fish.go delete mode 100644 vendor/github.com/urfave/cli/flag.go delete mode 100644 vendor/github.com/urfave/cli/flag_bool.go delete mode 100644 vendor/github.com/urfave/cli/flag_bool_t.go delete mode 100644 vendor/github.com/urfave/cli/flag_duration.go delete mode 100644 vendor/github.com/urfave/cli/flag_float64.go delete mode 100644 vendor/github.com/urfave/cli/flag_generic.go delete mode 100644 vendor/github.com/urfave/cli/flag_int.go delete mode 100644 vendor/github.com/urfave/cli/flag_int64.go delete mode 100644 vendor/github.com/urfave/cli/flag_int64_slice.go delete mode 100644 vendor/github.com/urfave/cli/flag_int_slice.go delete mode 100644 vendor/github.com/urfave/cli/flag_string.go delete mode 100644 vendor/github.com/urfave/cli/flag_string_slice.go delete mode 100644 vendor/github.com/urfave/cli/flag_uint.go delete mode 100644 vendor/github.com/urfave/cli/flag_uint64.go delete mode 100644 vendor/github.com/urfave/cli/funcs.go delete mode 100644 vendor/github.com/urfave/cli/help.go delete mode 100644 vendor/github.com/urfave/cli/parse.go delete mode 100644 vendor/github.com/urfave/cli/template.go rename vendor/github.com/urfave/cli/{ => v3}/.gitignore (50%) create mode 100644 vendor/github.com/urfave/cli/v3/.golangci.yaml rename vendor/github.com/urfave/cli/{ => v3}/CODE_OF_CONDUCT.md (87%) rename vendor/github.com/urfave/cli/{ => v3}/LICENSE (95%) create mode 100644 vendor/github.com/urfave/cli/v3/Makefile create mode 100644 vendor/github.com/urfave/cli/v3/README.md create mode 100644 vendor/github.com/urfave/cli/v3/args.go create mode 100644 vendor/github.com/urfave/cli/v3/autocomplete/bash_autocomplete create mode 100644 vendor/github.com/urfave/cli/v3/autocomplete/fish_autocomplete create mode 100644 vendor/github.com/urfave/cli/v3/autocomplete/powershell_autocomplete.ps1 create mode 100644 vendor/github.com/urfave/cli/v3/autocomplete/zsh_autocomplete create mode 100644 vendor/github.com/urfave/cli/v3/category.go create mode 100644 vendor/github.com/urfave/cli/v3/cli.go create mode 100644 vendor/github.com/urfave/cli/v3/command.go create mode 100644 vendor/github.com/urfave/cli/v3/command_parse.go create mode 100644 vendor/github.com/urfave/cli/v3/command_run.go create mode 100644 vendor/github.com/urfave/cli/v3/command_setup.go create mode 100644 vendor/github.com/urfave/cli/v3/completion.go create mode 100644 vendor/github.com/urfave/cli/v3/docs.go create mode 100644 vendor/github.com/urfave/cli/v3/errors.go create mode 100644 vendor/github.com/urfave/cli/v3/fish.go create mode 100644 vendor/github.com/urfave/cli/v3/flag.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_bool.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_bool_with_inverse.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_duration.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_ext.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_float.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_float_slice.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_generic.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_impl.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_int.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_int_slice.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_map_impl.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_mutex.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_number_slice.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_slice_base.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_string.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_string_map.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_string_slice.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_timestamp.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_uint.go create mode 100644 vendor/github.com/urfave/cli/v3/flag_uint_slice.go create mode 100644 vendor/github.com/urfave/cli/v3/funcs.go create mode 100644 vendor/github.com/urfave/cli/v3/godoc-current.txt create mode 100644 vendor/github.com/urfave/cli/v3/help.go create mode 100644 vendor/github.com/urfave/cli/v3/mkdocs-requirements.txt create mode 100644 vendor/github.com/urfave/cli/v3/mkdocs.yml rename vendor/github.com/urfave/cli/{ => v3}/sort.go (100%) create mode 100644 vendor/github.com/urfave/cli/v3/staticcheck.conf create mode 100644 vendor/github.com/urfave/cli/v3/suggestions.go create mode 100644 vendor/github.com/urfave/cli/v3/template.go create mode 100644 vendor/github.com/urfave/cli/v3/value_source.go diff --git a/checkpoint.go b/checkpoint.go index 50046fb9357..74e11386c04 100644 --- a/checkpoint.go +++ b/checkpoint.go @@ -1,6 +1,7 @@ package main import ( + "context" "errors" "fmt" "net" @@ -11,13 +12,13 @@ import ( "github.com/moby/sys/userns" "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" "golang.org/x/sys/unix" "github.com/opencontainers/runc/libcontainer" ) -var checkpointCommand = cli.Command{ +var checkpointCommand = &cli.Command{ Name: "checkpoint", Usage: "checkpoint a running container", ArgsUsage: ` @@ -26,26 +27,26 @@ Where "" is the name for the instance of the container to be checkpointed.`, Description: `The checkpoint command saves the state of the container instance.`, Flags: []cli.Flag{ - cli.StringFlag{Name: "image-path", Value: "", Usage: "path for saving criu image files"}, - cli.StringFlag{Name: "work-path", Value: "", Usage: "path for saving work files and logs"}, - cli.StringFlag{Name: "parent-path", Value: "", Usage: "path for previous criu image files in pre-dump"}, - cli.BoolFlag{Name: "leave-running", Usage: "leave the process running after checkpointing"}, - cli.BoolFlag{Name: "tcp-established", Usage: "allow open tcp connections"}, - cli.BoolFlag{Name: "tcp-skip-in-flight", Usage: "skip in-flight tcp connections"}, - cli.BoolFlag{Name: "link-remap", Usage: "allow one to link unlinked files back when possible"}, - cli.BoolFlag{Name: "ext-unix-sk", Usage: "allow external unix sockets"}, - cli.BoolFlag{Name: "shell-job", Usage: "allow shell jobs"}, - cli.BoolFlag{Name: "lazy-pages", Usage: "use userfaultfd to lazily restore memory pages"}, - cli.IntFlag{Name: "status-fd", Value: -1, Usage: "criu writes \\0 to this FD once lazy-pages is ready"}, - cli.StringFlag{Name: "page-server", Value: "", Usage: "ADDRESS:PORT of the page server"}, - cli.BoolFlag{Name: "file-locks", Usage: "handle file locks, for safety"}, - cli.BoolFlag{Name: "pre-dump", Usage: "dump container's memory information only, leave the container running after this"}, - cli.StringFlag{Name: "manage-cgroups-mode", Value: "", Usage: "cgroups mode: soft|full|strict|ignore (default: soft)"}, - cli.StringSliceFlag{Name: "empty-ns", Usage: "create a namespace, but don't restore its properties"}, - cli.BoolFlag{Name: "auto-dedup", Usage: "enable auto deduplication of memory images"}, + &cli.StringFlag{Name: "image-path", Value: "", Usage: "path for saving criu image files"}, + &cli.StringFlag{Name: "work-path", Value: "", Usage: "path for saving work files and logs"}, + &cli.StringFlag{Name: "parent-path", Value: "", Usage: "path for previous criu image files in pre-dump"}, + &cli.BoolFlag{Name: "leave-running", Usage: "leave the process running after checkpointing"}, + &cli.BoolFlag{Name: "tcp-established", Usage: "allow open tcp connections"}, + &cli.BoolFlag{Name: "tcp-skip-in-flight", Usage: "skip in-flight tcp connections"}, + &cli.BoolFlag{Name: "link-remap", Usage: "allow one to link unlinked files back when possible"}, + &cli.BoolFlag{Name: "ext-unix-sk", Usage: "allow external unix sockets"}, + &cli.BoolFlag{Name: "shell-job", Usage: "allow shell jobs"}, + &cli.BoolFlag{Name: "lazy-pages", Usage: "use userfaultfd to lazily restore memory pages"}, + &cli.IntFlag{Name: "status-fd", Value: -1, Usage: "criu writes \\0 to this FD once lazy-pages is ready"}, + &cli.StringFlag{Name: "page-server", Value: "", Usage: "ADDRESS:PORT of the page server"}, + &cli.BoolFlag{Name: "file-locks", Usage: "handle file locks, for safety"}, + &cli.BoolFlag{Name: "pre-dump", Usage: "dump container's memory information only, leave the container running after this"}, + &cli.StringFlag{Name: "manage-cgroups-mode", Value: "", Usage: "cgroups mode: soft|full|strict|ignore (default: soft)"}, + &cli.StringSliceFlag{Name: "empty-ns", Usage: "create a namespace, but don't restore its properties"}, + &cli.BoolFlag{Name: "auto-dedup", Usage: "enable auto deduplication of memory images"}, }, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, exactArgs); err != nil { + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, exactArgs); err != nil { return err } // XXX: Currently this is untested with rootless containers. @@ -53,7 +54,7 @@ checkpointed.`, logrus.Warn("runc checkpoint is untested with rootless containers") } - container, err := getContainer(context) + container, err := getContainer(cmd) if err != nil { return err } @@ -64,7 +65,7 @@ checkpointed.`, if status == libcontainer.Created || status == libcontainer.Stopped { return fmt.Errorf("Container cannot be checkpointed in %s state", status.String()) } - options, err := criuOptions(context) + options, err := criuOptions(cmd) if err != nil { return err } @@ -80,8 +81,8 @@ checkpointed.`, }, } -func prepareImagePaths(context *cli.Context) (string, string, error) { - imagePath := context.String("image-path") +func prepareImagePaths(cmd *cli.Command) (string, string, error) { + imagePath := cmd.String("image-path") if imagePath == "" { imagePath = getDefaultImagePath() } @@ -90,7 +91,7 @@ func prepareImagePaths(context *cli.Context) (string, string, error) { return "", "", err } - parentPath := context.String("parent-path") + parentPath := cmd.String("parent-path") if parentPath == "" { return imagePath, parentPath, nil } @@ -112,35 +113,35 @@ func prepareImagePaths(context *cli.Context) (string, string, error) { return imagePath, parentPath, nil } -func criuOptions(context *cli.Context) (*libcontainer.CriuOpts, error) { - imagePath, parentPath, err := prepareImagePaths(context) +func criuOptions(cmd *cli.Command) (*libcontainer.CriuOpts, error) { + imagePath, parentPath, err := prepareImagePaths(cmd) if err != nil { return nil, err } opts := &libcontainer.CriuOpts{ ImagesDirectory: imagePath, - WorkDirectory: context.String("work-path"), + WorkDirectory: cmd.String("work-path"), ParentImage: parentPath, - LeaveRunning: context.Bool("leave-running"), - TcpEstablished: context.Bool("tcp-established"), - TcpSkipInFlight: context.Bool("tcp-skip-in-flight"), - LinkRemap: context.Bool("link-remap"), - ExternalUnixConnections: context.Bool("ext-unix-sk"), - ShellJob: context.Bool("shell-job"), - FileLocks: context.Bool("file-locks"), - PreDump: context.Bool("pre-dump"), - AutoDedup: context.Bool("auto-dedup"), - LazyPages: context.Bool("lazy-pages"), - StatusFd: context.Int("status-fd"), - LsmProfile: context.String("lsm-profile"), - LsmMountContext: context.String("lsm-mount-context"), - ManageCgroupsMode: context.String("manage-cgroups-mode"), + LeaveRunning: cmd.Bool("leave-running"), + TcpEstablished: cmd.Bool("tcp-established"), + TcpSkipInFlight: cmd.Bool("tcp-skip-in-flight"), + LinkRemap: cmd.Bool("link-remap"), + ExternalUnixConnections: cmd.Bool("ext-unix-sk"), + ShellJob: cmd.Bool("shell-job"), + FileLocks: cmd.Bool("file-locks"), + PreDump: cmd.Bool("pre-dump"), + AutoDedup: cmd.Bool("auto-dedup"), + LazyPages: cmd.Bool("lazy-pages"), + StatusFd: cmd.Int("status-fd"), + LsmProfile: cmd.String("lsm-profile"), + LsmMountContext: cmd.String("lsm-mount-context"), + ManageCgroupsMode: cmd.String("manage-cgroups-mode"), } // CRIU options below may or may not be set. - if psOpt := context.String("page-server"); psOpt != "" { + if psOpt := cmd.String("page-server"); psOpt != "" { address, port, err := net.SplitHostPort(psOpt) if err != nil || address == "" || port == "" { @@ -159,12 +160,12 @@ func criuOptions(context *cli.Context) (*libcontainer.CriuOpts, error) { // runc doesn't manage network devices and their configuration. nsmask := unix.CLONE_NEWNET - if context.IsSet("empty-ns") { + if cmd.IsSet("empty-ns") { namespaceMapping := map[specs.LinuxNamespaceType]int{ specs.NetworkNamespace: unix.CLONE_NEWNET, } - for _, ns := range context.StringSlice("empty-ns") { + for _, ns := range cmd.StringSlice("empty-ns") { f, exists := namespaceMapping[specs.LinuxNamespaceType(ns)] if !exists { return nil, fmt.Errorf("namespace %q is not supported", ns) diff --git a/create.go b/create.go index 8ed59b2e75c..a443adf2ba8 100644 --- a/create.go +++ b/create.go @@ -1,13 +1,14 @@ package main import ( + "context" "fmt" "os" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var createCommand = cli.Command{ +var createCommand = &cli.Command{ Name: "create", Usage: "create a container", ArgsUsage: ` @@ -23,44 +24,47 @@ The specification file includes an args parameter. The args parameter is used to specify command(s) that get run when the container is started. To change the command(s) that get executed on start, edit the args parameter of the spec. See "runc spec --help" for more explanation.`, + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "bundle, b", - Value: "", - Usage: `path to the root of the bundle directory, defaults to the current directory`, + &cli.StringFlag{ + Name: "bundle", + Aliases: []string{"b"}, + Value: "", + Usage: `path to the root of the bundle directory, defaults to the current directory`, }, - cli.StringFlag{ + &cli.StringFlag{ Name: "console-socket", Value: "", Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "pidfd-socket", Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the init process", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "pid-file", Value: "", Usage: "specify the file to write the process id to", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-pivot", Usage: "do not use pivot root to jail process inside rootfs. This should be used whenever the rootfs is on top of a ramdisk", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-new-keyring", Usage: "do not create a new session keyring for the container. This will cause the container to inherit the calling processes session key", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "preserve-fds", Usage: "Pass N additional file descriptors to the container (stdio + $LISTEN_FDS + N in total)", }, }, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, exactArgs); err != nil { + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, exactArgs); err != nil { return err } - status, err := startContainer(context, CT_ACT_CREATE, nil) + status, err := startContainer(cmd, CT_ACT_CREATE, nil) if err == nil { // exit with the container's exit status so any external supervisor // is notified of the exit with the correct exit status. diff --git a/delete.go b/delete.go index dcb19be1b94..6bc85411a0e 100644 --- a/delete.go +++ b/delete.go @@ -1,6 +1,7 @@ package main import ( + "context" "errors" "fmt" "os" @@ -8,7 +9,7 @@ import ( "time" "github.com/opencontainers/runc/libcontainer" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" "golang.org/x/sys/unix" ) @@ -24,7 +25,7 @@ func killContainer(container *libcontainer.Container) error { return errors.New("container init still running") } -var deleteCommand = cli.Command{ +var deleteCommand = &cli.Command{ Name: "delete", Usage: "delete any resources held by the container often used with detached container", ArgsUsage: ` @@ -37,25 +38,28 @@ status of "ubuntu01" as "stopped" the following will delete resources held for "ubuntu01" removing "ubuntu01" from the runc list of containers: # runc delete ubuntu01`, + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "force, f", - Usage: "Forcibly deletes the container if it is still running (uses SIGKILL)", + &cli.BoolFlag{ + Name: "force", + Aliases: []string{"f"}, + Usage: "Forcibly deletes the container if it is still running (uses SIGKILL)", }, }, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, exactArgs); err != nil { + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, exactArgs); err != nil { return err } - id := context.Args().First() - force := context.Bool("force") - container, err := getContainer(context) + id := cmd.Args().First() + force := cmd.Bool("force") + container, err := getContainer(cmd) if err != nil { if errors.Is(err, libcontainer.ErrNotExist) { // if there was an aborted start or something of the sort then the container's directory could exist but // libcontainer does not see it because the state.json file inside that directory was never created. - path := filepath.Join(context.GlobalString("root"), id) + path := filepath.Join(cmd.String("root"), id) if e := os.RemoveAll(path); e != nil { fmt.Fprintf(os.Stderr, "remove %s: %v\n", path, e) } diff --git a/events.go b/events.go index f024448491f..5aa992891cb 100644 --- a/events.go +++ b/events.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "errors" "fmt" @@ -14,10 +15,10 @@ import ( "github.com/opencontainers/runc/types" "github.com/sirupsen/logrus" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var eventsCommand = cli.Command{ +var eventsCommand = &cli.Command{ Name: "events", Usage: "display container events such as OOM notifications, cpu, memory, and IO usage statistics", ArgsUsage: ` @@ -25,19 +26,21 @@ var eventsCommand = cli.Command{ Where "" is the name for the instance of the container.`, Description: `The events command displays information about the container. By default the information is displayed once every 5 seconds.`, + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, Flags: []cli.Flag{ - cli.DurationFlag{Name: "interval", Value: 5 * time.Second, Usage: "set the stats collection interval"}, - cli.BoolFlag{Name: "stats", Usage: "display the container's stats then exit"}, + &cli.DurationFlag{Name: "interval", Value: 5 * time.Second, Usage: "set the stats collection interval"}, + &cli.BoolFlag{Name: "stats", Usage: "display the container's stats then exit"}, }, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, exactArgs); err != nil { + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, exactArgs); err != nil { return err } - container, err := getContainer(context) + container, err := getContainer(cmd) if err != nil { return err } - duration := context.Duration("interval") + duration := cmd.Duration("interval") if duration <= 0 { return errors.New("duration interval must be greater than 0") } @@ -61,7 +64,7 @@ information is displayed once every 5 seconds.`, } } }) - if context.Bool("stats") { + if cmd.Bool("stats") { s, err := container.Stats() if err != nil { return err @@ -72,7 +75,7 @@ information is displayed once every 5 seconds.`, return nil } go func() { - for range time.Tick(context.Duration("interval")) { + for range time.Tick(cmd.Duration("interval")) { s, err := container.Stats() if err != nil { logrus.Error(err) diff --git a/exec.go b/exec.go index cd5a9d17154..c809f36c839 100644 --- a/exec.go +++ b/exec.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "errors" "fmt" @@ -11,10 +12,10 @@ import ( "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/utils" "github.com/opencontainers/runtime-spec/specs-go" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var execCommand = cli.Command{ +var execCommand = &cli.Command{ Name: "exec", Usage: "execute new process inside the container", ArgsUsage: ` [command options] || -p process.json @@ -28,93 +29,105 @@ For example, if the container is configured to run the linux ps command the following will output a list of processes running in the container: # runc exec ps`, + // Stop parsing flags after the first positional argument (command) + // This allows passing flags like -c to the command being executed + StopOnNthArg: intPtr(1), + // Disable comma as separator for slice flags + // This allows cgroup controller lists like "cpu,cpuacct:subcpu". + DisableSliceFlagSeparator: true, Flags: []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "console-socket", Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "pidfd-socket", Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the exec process", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cwd", Usage: "current working directory in the container", }, - cli.StringSliceFlag{ - Name: "env, e", - Usage: "set environment variables", + &cli.StringSliceFlag{ + Name: "env", + Aliases: []string{"e"}, + Usage: "set environment variables", }, - cli.BoolFlag{ - Name: "tty, t", - Usage: "allocate a pseudo-TTY", + &cli.BoolFlag{ + Name: "tty", + Aliases: []string{"t"}, + Usage: "allocate a pseudo-TTY", }, - cli.StringFlag{ - Name: "user, u", - Usage: "UID (format: [:])", + &cli.StringFlag{ + Name: "user", + Aliases: []string{"u"}, + Usage: "UID (format: [:])", }, - cli.Int64SliceFlag{ - Name: "additional-gids, g", - Usage: "additional gids", + &cli.Int64SliceFlag{ + Name: "additional-gids", + Aliases: []string{"g"}, + Usage: "additional gids", }, - cli.StringFlag{ - Name: "process, p", - Usage: "path to the process.json", + &cli.StringFlag{ + Name: "process", + Aliases: []string{"p"}, + Usage: "path to the process.json", }, - cli.BoolFlag{ - Name: "detach,d", - Usage: "detach from the container's process", + &cli.BoolFlag{ + Name: "detach", + Aliases: []string{"d"}, + Usage: "detach from the container's process", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "pid-file", Value: "", Usage: "specify the file to write the process id to", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "process-label", Usage: "set the asm process label for the process commonly used with selinux", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "apparmor", Usage: "set the apparmor profile for the process", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-new-privs", Usage: "set the no new privileges value for the process", }, - cli.StringSliceFlag{ - Name: "cap, c", - Value: &cli.StringSlice{}, - Usage: "add a capability to the bounding set for the process", + &cli.StringSliceFlag{ + Name: "cap", + Aliases: []string{"c"}, + Value: []string{}, + Usage: "add a capability to the bounding set for the process", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "preserve-fds", Usage: "Pass N additional file descriptors to the container (stdio + $LISTEN_FDS + N in total)", }, - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "cgroup", Usage: "run the process in an (existing) sub-cgroup(s). Format is [:].", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "ignore-paused", Usage: "allow exec in a paused container", }, }, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, minArgs); err != nil { + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, minArgs); err != nil { return err } - if err := revisePidFile(context); err != nil { + if err := revisePidFile(cmd); err != nil { return err } - status, err := execProcess(context) + status, err := execProcess(cmd) if err == nil { os.Exit(status) } fatalWithCode(fmt.Errorf("exec failed: %w", err), 255) return nil // to satisfy the linter }, - SkipArgReorder: true, } // getSubCgroupPaths parses --cgroup arguments, which can either be @@ -152,8 +165,8 @@ func getSubCgroupPaths(args []string) (map[string]string, error) { return paths, nil } -func execProcess(context *cli.Context) (int, error) { - container, err := getContainer(context) +func execProcess(cmd *cli.Command) (int, error) { + container, err := getContainer(cmd) if err != nil { return -1, err } @@ -164,15 +177,15 @@ func execProcess(context *cli.Context) (int, error) { if status == libcontainer.Stopped { return -1, errors.New("cannot exec in a stopped container") } - if status == libcontainer.Paused && !context.Bool("ignore-paused") { + if status == libcontainer.Paused && !cmd.Bool("ignore-paused") { return -1, errors.New("cannot exec in a paused container (use --ignore-paused to override)") } - p, err := getProcess(context, container) + p, err := getProcess(cmd, container) if err != nil { return -1, err } - cgPaths, err := getSubCgroupPaths(context.StringSlice("cgroup")) + cgPaths, err := getSubCgroupPaths(cmd.StringSlice("cgroup")) if err != nil { return -1, err } @@ -181,20 +194,20 @@ func execProcess(context *cli.Context) (int, error) { enableSubreaper: false, shouldDestroy: false, container: container, - consoleSocket: context.String("console-socket"), - pidfdSocket: context.String("pidfd-socket"), - detach: context.Bool("detach"), - pidFile: context.String("pid-file"), + consoleSocket: cmd.String("console-socket"), + pidfdSocket: cmd.String("pidfd-socket"), + detach: cmd.Bool("detach"), + pidFile: cmd.String("pid-file"), action: CT_ACT_RUN, init: false, - preserveFDs: context.Int("preserve-fds"), + preserveFDs: cmd.Int("preserve-fds"), subCgroupPaths: cgPaths, } return r.run(p) } -func getProcess(context *cli.Context, c *libcontainer.Container) (*specs.Process, error) { - if path := context.String("process"); path != "" { +func getProcess(cmd *cli.Command, c *libcontainer.Container) (*specs.Process, error) { + if path := cmd.String("process"); path != "" { f, err := os.Open(path) if err != nil { return nil, err @@ -219,22 +232,22 @@ func getProcess(context *cli.Context, c *libcontainer.Container) (*specs.Process return nil, err } p := spec.Process - args := context.Args() + args := cmd.Args().Slice() if len(args) < 2 { return nil, errors.New("exec args cannot be empty") } p.Args = args[1:] // Override the cwd, if passed. - if cwd := context.String("cwd"); cwd != "" { + if cwd := cmd.String("cwd"); cwd != "" { p.Cwd = cwd } - if ap := context.String("apparmor"); ap != "" { + if ap := cmd.String("apparmor"); ap != "" { p.ApparmorProfile = ap } - if l := context.String("process-label"); l != "" { + if l := cmd.String("process-label"); l != "" { p.SelinuxLabel = l } - if caps := context.StringSlice("cap"); len(caps) > 0 { + if caps := cmd.StringSlice("cap"); len(caps) > 0 { for _, c := range caps { p.Capabilities.Bounding = append(p.Capabilities.Bounding, c) p.Capabilities.Effective = append(p.Capabilities.Effective, c) @@ -248,15 +261,15 @@ func getProcess(context *cli.Context, c *libcontainer.Container) (*specs.Process } } // append the passed env variables - p.Env = append(p.Env, context.StringSlice("env")...) + p.Env = append(p.Env, cmd.StringSlice("env")...) // Always set tty to false, unless explicitly enabled from CLI. - p.Terminal = context.Bool("tty") - if context.IsSet("no-new-privs") { - p.NoNewPrivileges = context.Bool("no-new-privs") + p.Terminal = cmd.Bool("tty") + if cmd.IsSet("no-new-privs") { + p.NoNewPrivileges = cmd.Bool("no-new-privs") } // Override the user, if passed. - if user := context.String("user"); user != "" { + if user := cmd.String("user"); user != "" { uids, gids, ok := strings.Cut(user, ":") if ok { gid, err := strconv.Atoi(gids) @@ -271,7 +284,7 @@ func getProcess(context *cli.Context, c *libcontainer.Container) (*specs.Process } p.User.UID = uint32(uid) } - for _, gid := range context.Int64Slice("additional-gids") { + for _, gid := range cmd.Int64Slice("additional-gids") { if gid < 0 { return nil, fmt.Errorf("additional-gids must be a positive number %d", gid) } diff --git a/features.go b/features.go index 0cb7049f636..46c0f202f0d 100644 --- a/features.go +++ b/features.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "fmt" @@ -11,10 +12,10 @@ import ( runcfeatures "github.com/opencontainers/runc/types/features" "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go/features" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var featuresCommand = cli.Command{ +var featuresCommand = &cli.Command{ Name: "features", Usage: "show the enabled features", ArgsUsage: "", @@ -22,8 +23,10 @@ var featuresCommand = cli.Command{ The result is parsable as a JSON. See https://github.com/opencontainers/runtime-spec/blob/main/features.md for the type definition. `, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 0, exactArgs); err != nil { + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 0, exactArgs); err != nil { return err } @@ -93,7 +96,7 @@ var featuresCommand = cli.Command{ feat.Annotations[runcfeatures.AnnotationLibseccompVersion] = fmt.Sprintf("%d.%d.%d", major, minor, patch) } - enc := json.NewEncoder(context.App.Writer) + enc := json.NewEncoder(cmd.Writer) enc.SetIndent("", " ") return enc.Encode(feat) }, diff --git a/go.mod b/go.mod index f5d3898e188..a7efe948aaa 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/opencontainers/selinux v1.13.1 github.com/seccomp/libseccomp-golang v0.11.1 github.com/sirupsen/logrus v1.9.4 - github.com/urfave/cli v1.22.17 + github.com/urfave/cli/v3 v3.8.0 github.com/vishvananda/netlink v1.3.1 github.com/vishvananda/netns v0.0.5 golang.org/x/net v0.53.0 @@ -31,6 +31,4 @@ require ( require ( cyphar.com/go-pathrs v0.2.4 // indirect github.com/cilium/ebpf v0.17.3 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect ) diff --git a/go.sum b/go.sum index 1223a1b3f0c..93e50f7d5e7 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,5 @@ cyphar.com/go-pathrs v0.2.4 h1:iD/mge36swa1UFKdINkr1Frkpp6wZsy3YYEildj9cLY= cyphar.com/go-pathrs v0.2.4/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc= -github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/checkpoint-restore/go-criu/v7 v7.2.0 h1:qGiWA4App1gGlEfIJ68WR9jbezV9J7yZdjzglezcqKo= github.com/checkpoint-restore/go-criu/v7 v7.2.0/go.mod h1:u0LCWLg0w4yqqu14aXhiB4YD3a1qd8EcCEg7vda5dwo= github.com/cilium/ebpf v0.17.3 h1:FnP4r16PWYSE4ux6zN+//jMcW4nMVRvuTLVTvCjyyjg= @@ -9,11 +8,8 @@ github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/q github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA= github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w= -github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= -github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE= github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -58,24 +54,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/seccomp/libseccomp-golang v0.11.1 h1:wuk4ZjSx6kyQII4rj6G6fvVzRHQaSiPvccJazDagu4g= github.com/seccomp/libseccomp-golang v0.11.1/go.mod h1:5m1Lk8E9OwgZTTVz4bBOer7JuazaBa+xTkM895tDiWc= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/urfave/cli v1.22.17 h1:SYzXoiPfQjHBbkYxbew5prZHS1TOLT3ierW8SYLqtVQ= -github.com/urfave/cli v1.22.17/go.mod h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo= +github.com/urfave/cli/v3 v3.8.0 h1:XqKPrm0q4P0q5JpoclYoCAv0/MIvH/jZ2umzuf8pNTI= +github.com/urfave/cli/v3 v3.8.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= @@ -91,8 +77,5 @@ golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/kill.go b/kill.go index ac1e47a5b19..b4e6a347142 100644 --- a/kill.go +++ b/kill.go @@ -1,17 +1,18 @@ package main import ( + "context" "errors" "fmt" "strconv" "strings" "github.com/opencontainers/runc/libcontainer" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" "golang.org/x/sys/unix" ) -var killCommand = cli.Command{ +var killCommand = &cli.Command{ Name: "kill", Usage: "kill sends the specified signal (default: SIGTERM) to the container's init process", ArgsUsage: ` [signal] @@ -24,26 +25,31 @@ For example, if the container id is "ubuntu01" the following will send a "KILL" signal to the init process of the "ubuntu01" container: # runc kill ubuntu01 KILL`, + // Stop parsing flags after the first positional argument (container ID). + StopOnNthArg: intPtr(1), + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "all, a", - Usage: "(obsoleted, do not use)", - Hidden: true, + &cli.BoolFlag{ + Name: "all", + Aliases: []string{"a"}, + Usage: "(obsoleted, do not use)", + Hidden: true, }, }, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, minArgs); err != nil { + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, minArgs); err != nil { return err } - if err := checkArgs(context, 2, maxArgs); err != nil { + if err := checkArgs(cmd, 2, maxArgs); err != nil { return err } - container, err := getContainer(context) + container, err := getContainer(cmd) if err != nil { return err } - sigstr := context.Args().Get(1) + sigstr := cmd.Args().Get(1) if sigstr == "" { sigstr = "SIGTERM" } @@ -53,7 +59,7 @@ signal to the init process of the "ubuntu01" container: return err } err = container.Signal(signal) - if errors.Is(err, libcontainer.ErrNotRunning) && context.Bool("all") { + if errors.Is(err, libcontainer.ErrNotRunning) && cmd.Bool("all") { err = nil } return err diff --git a/list.go b/list.go index 997cd88173b..11910a62097 100644 --- a/list.go +++ b/list.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "errors" "fmt" @@ -13,7 +14,7 @@ import ( "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/utils" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) const formatOptions = `table or json` @@ -41,7 +42,7 @@ type containerState struct { Owner string `json:"owner"` } -var listCommand = cli.Command{ +var listCommand = &cli.Command{ Name: "list", Usage: "lists containers started by runc with the given root", ArgsUsage: ` @@ -56,34 +57,38 @@ To list containers created via the default "--root": EXAMPLE 2: To list containers created using a non-default value for "--root": # runc --root value list`, + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "format, f", - Value: "table", - Usage: `select one of: ` + formatOptions, + &cli.StringFlag{ + Name: "format", + Aliases: []string{"f"}, + Value: "table", + Usage: `select one of: ` + formatOptions, }, - cli.BoolFlag{ - Name: "quiet, q", - Usage: "display only container IDs", + &cli.BoolFlag{ + Name: "quiet", + Aliases: []string{"q"}, + Usage: "display only container IDs", }, }, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 0, exactArgs); err != nil { + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 0, exactArgs); err != nil { return err } - s, err := getContainers(context) + s, err := getContainers(cmd) if err != nil { return err } - if context.Bool("quiet") { + if cmd.Bool("quiet") { for _, item := range s { fmt.Println(item.ID) } return nil } - switch context.String("format") { + switch cmd.String("format") { case "table": w := tabwriter.NewWriter(os.Stdout, 12, 1, 3, ' ', 0) fmt.Fprint(w, "ID\tPID\tSTATUS\tBUNDLE\tCREATED\tOWNER\n") @@ -110,11 +115,11 @@ To list containers created using a non-default value for "--root": }, } -func getContainers(context *cli.Context) ([]containerState, error) { - root := context.GlobalString("root") +func getContainers(cmd *cli.Command) ([]containerState, error) { + root := cmd.String("root") list, err := os.ReadDir(root) if err != nil { - if errors.Is(err, os.ErrNotExist) && context.IsSet("root") { + if errors.Is(err, os.ErrNotExist) && cmd.IsSet("root") { // Ignore non-existing default root directory // (no containers created yet). return nil, nil diff --git a/main.go b/main.go index e9ed5a47ded..3ee1009aed6 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ package main import ( + "context" _ "embed" "errors" "fmt" @@ -20,7 +21,7 @@ import ( "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) // version is set from the contents of VERSION file. @@ -37,10 +38,10 @@ var extraVersion = "" // and will be populated by the Makefile. var gitCommit = "" -func printVersion(c *cli.Context) { - w := c.App.Writer +func printVersion(c *cli.Command) { + w := c.Writer - fmt.Fprintln(w, "runc version", c.App.Version) + fmt.Fprintln(w, "runc version", c.Version) if gitCommit != "" { fmt.Fprintln(w, "commit:", gitCommit) } @@ -81,10 +82,12 @@ value for "bundle" is the current directory.` ) func main() { - app := cli.NewApp() + app := &cli.Command{} app.Name = "runc" app.Version = strings.TrimSpace(version) + extraVersion app.Usage = usage + // Disable comma as separator for slice flags. + app.DisableSliceFlagSeparator = true cli.VersionPrinter = printVersion @@ -97,36 +100,36 @@ func main() { } app.Flags = []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", Usage: "enable debug logging", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "log", Value: "", Usage: "set the log file to write runc logs to (default is '/dev/stderr')", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "log-format", Value: "text", Usage: "set the log format ('text' (default), or 'json')", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "root", Value: root, Usage: "root directory for storage of container state (this should be located in tmpfs)", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "systemd-cgroup", Usage: "enable systemd cgroup support, expects cgroupsPath to be of form \"slice:prefix:name\" for e.g. \"system.slice:runc:434234\"", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "rootless", Value: "auto", Usage: "ignore cgroup permission errors ('true', 'false', or 'auto')", }, } - app.Commands = []cli.Command{ + app.Commands = []*cli.Command{ checkpointCommand, createCommand, deleteCommand, @@ -145,8 +148,8 @@ func main() { updateCommand, featuresCommand, } - app.Before = func(context *cli.Context) error { - if !context.IsSet("root") && xdgDirUsed { + app.Before = func(ctx context.Context, cmd *cli.Command) (context.Context, error) { + if !cmd.IsSet("root") && xdgDirUsed { // According to the XDG specification, we need to set anything in // XDG_RUNTIME_DIR to have a sticky bit if we don't want it to get // auto-pruned. @@ -159,18 +162,22 @@ func main() { fatal(err) } } - if err := reviseRootDir(context); err != nil { - return err + if err := reviseRootDir(cmd); err != nil { + return ctx, err + } + + if err := configLogrus(cmd); err != nil { + return ctx, err } - return configLogrus(context) + return ctx, nil } // If the command returns an error, cli takes upon itself to print // the error on cli.ErrWriter and exit. // Use our own writer here to ensure the log gets sent to the right location. cli.ErrWriter = &FatalWriter{cli.ErrWriter} - if err := app.Run(os.Args); err != nil { + if err := app.Run(context.Background(), os.Args); err != nil { fatal(err) } } @@ -187,8 +194,8 @@ func (f *FatalWriter) Write(p []byte) (n int, err error) { return len(p), nil } -func configLogrus(context *cli.Context) error { - if context.GlobalBool("debug") { +func configLogrus(cmd *cli.Command) error { + if cmd.Bool("debug") { logrus.SetLevel(logrus.DebugLevel) logrus.SetReportCaller(true) // Shorten function and file names reported by the logger, by @@ -205,7 +212,7 @@ func configLogrus(context *cli.Context) error { }) } - switch f := context.GlobalString("log-format"); f { + switch f := cmd.String("log-format"); f { case "": // do nothing case "text": @@ -216,7 +223,7 @@ func configLogrus(context *cli.Context) error { return errors.New("invalid log-format: " + f) } - if file := context.GlobalString("log"); file != "" { + if file := cmd.String("log"); file != "" { f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0o644) if err != nil { return err diff --git a/notify_socket.go b/notify_socket.go index e57e73a002e..0e73098bc61 100644 --- a/notify_socket.go +++ b/notify_socket.go @@ -15,7 +15,7 @@ import ( "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" "golang.org/x/sys/unix" ) @@ -25,12 +25,12 @@ type notifySocket struct { socketPath string } -func newNotifySocket(context *cli.Context, notifySocketHost, id string) *notifySocket { +func newNotifySocket(cmd *cli.Command, notifySocketHost, id string) *notifySocket { if notifySocketHost == "" { return nil } - root := filepath.Join(context.GlobalString("root"), id) + root := filepath.Join(cmd.String("root"), id) socketPath := filepath.Join(root, "notify", "notify.sock") notifySocket := ¬ifySocket{ @@ -84,8 +84,8 @@ func (s *notifySocket) setupSocketDirectory() error { return os.Mkdir(path.Dir(s.socketPath), 0o755) } -func notifySocketStart(context *cli.Context, notifySocketHost, id string) (*notifySocket, error) { - notifySocket := newNotifySocket(context, notifySocketHost, id) +func notifySocketStart(cmd *cli.Command, notifySocketHost, id string) (*notifySocket, error) { + notifySocket := newNotifySocket(cmd, notifySocketHost, id) if notifySocket == nil { return nil, nil } diff --git a/pause.go b/pause.go index b5d354db6c9..9be0773762f 100644 --- a/pause.go +++ b/pause.go @@ -1,10 +1,12 @@ package main import ( - "github.com/urfave/cli" + "context" + + "github.com/urfave/cli/v3" ) -var pauseCommand = cli.Command{ +var pauseCommand = &cli.Command{ Name: "pause", Usage: "pause suspends all processes inside the container", ArgsUsage: ` @@ -14,11 +16,13 @@ paused. `, Description: `The pause command suspends all processes in the instance of the container. Use runc list to identify instances of containers and their current status.`, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, exactArgs); err != nil { + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, exactArgs); err != nil { return err } - container, err := getContainer(context) + container, err := getContainer(cmd) if err != nil { return err } @@ -31,7 +35,7 @@ Use runc list to identify instances of containers and their current status.`, }, } -var resumeCommand = cli.Command{ +var resumeCommand = &cli.Command{ Name: "resume", Usage: "resumes all processes that have been previously paused", ArgsUsage: ` @@ -41,11 +45,13 @@ resumed.`, Description: `The resume command resumes all processes in the instance of the container. Use runc list to identify instances of containers and their current status.`, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, exactArgs); err != nil { + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, exactArgs); err != nil { return err } - container, err := getContainer(context) + container, err := getContainer(cmd) if err != nil { return err } diff --git a/ps.go b/ps.go index 4e79a9a0601..8517c35cd7e 100644 --- a/ps.go +++ b/ps.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "errors" "fmt" @@ -10,26 +11,32 @@ import ( "strconv" "strings" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var psCommand = cli.Command{ +var psCommand = &cli.Command{ Name: "ps", Usage: "ps displays the processes running inside a container", ArgsUsage: ` [ps options]`, + // Stop parsing flags after the first positional argument (the container ID). + // This allows passing flags like -aux to the underlying ps command. + StopOnNthArg: intPtr(1), + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "format, f", - Value: "table", - Usage: `select one of: ` + formatOptions, + &cli.StringFlag{ + Name: "format", + Aliases: []string{"f"}, + Value: "table", + Usage: `select one of: ` + formatOptions, }, }, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, minArgs); err != nil { + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, minArgs); err != nil { return err } - container, err := getContainer(context) + container, err := getContainer(cmd) if err != nil { return err } @@ -40,7 +47,7 @@ var psCommand = cli.Command{ return err } - switch context.String("format") { + switch cmd.String("format") { case "table": case "json": return json.NewEncoder(os.Stdout).Encode(pids) @@ -49,16 +56,16 @@ var psCommand = cli.Command{ } // [1:] is to remove command name, ex: - // context.Args(): [container_id ps_arg1 ps_arg2 ...] + // cmd.Args(): [container_id ps_arg1 ps_arg2 ...] // psArgs: [ps_arg1 ps_arg2 ...] // - psArgs := context.Args()[1:] + psArgs := cmd.Args().Slice()[1:] if len(psArgs) == 0 { psArgs = []string{"-ef"} } - cmd := exec.Command("ps", psArgs...) - output, err := cmd.CombinedOutput() + cmdExec := exec.Command("ps", psArgs...) + output, err := cmdExec.CombinedOutput() if err != nil { return fmt.Errorf("%w: %s", err, output) } @@ -86,7 +93,6 @@ var psCommand = cli.Command{ } return nil }, - SkipArgReorder: true, } func getPidIndex(title string) (int, error) { diff --git a/restore.go b/restore.go index f1648eaea57..410cde66245 100644 --- a/restore.go +++ b/restore.go @@ -1,14 +1,15 @@ package main import ( + "context" "os" "github.com/moby/sys/userns" "github.com/sirupsen/logrus" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var restoreCommand = cli.Command{ +var restoreCommand = &cli.Command{ Name: "restore", Usage: "restore a container from a previous checkpoint", ArgsUsage: ` @@ -17,90 +18,94 @@ Where "" is the name for the instance of the container to be restored.`, Description: `Restores the saved state of the container instance that was previously saved using the runc checkpoint command.`, + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, Flags: []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "console-socket", Value: "", Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "image-path", Value: "", Usage: "path to criu image files for restoring", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "work-path", Value: "", Usage: "path for saving work files and logs", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "tcp-established", Usage: "allow open tcp connections", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "ext-unix-sk", Usage: "allow external unix sockets", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "shell-job", Usage: "allow shell jobs", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "file-locks", Usage: "handle file locks, for safety", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "manage-cgroups-mode", Value: "", Usage: "cgroups mode: soft|full|strict|ignore (default: soft)", }, - cli.StringFlag{ - Name: "bundle, b", - Value: "", - Usage: "path to the root of the bundle directory", + &cli.StringFlag{ + Name: "bundle", + Aliases: []string{"b"}, + Value: "", + Usage: "path to the root of the bundle directory", }, - cli.BoolFlag{ - Name: "detach,d", - Usage: "detach from the container's process", + &cli.BoolFlag{ + Name: "detach", + Aliases: []string{"d"}, + Usage: "detach from the container's process", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "pid-file", Value: "", Usage: "specify the file to write the process id to", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-subreaper", Usage: "disable the use of the subreaper used to reap reparented processes", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-pivot", Usage: "do not use pivot root to jail process inside rootfs. This should be used whenever the rootfs is on top of a ramdisk", }, - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "empty-ns", Usage: "create a namespace, but don't restore its properties", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "auto-dedup", Usage: "enable auto deduplication of memory images", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "lazy-pages", Usage: "use userfaultfd to lazily restore memory pages", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "lsm-profile", Value: "", Usage: "Specify an LSM profile to be used during restore in the form of TYPE:NAME.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "lsm-mount-context", Value: "", Usage: "Specify an LSM mount context to be used during restore.", }, }, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, exactArgs); err != nil { + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, exactArgs); err != nil { return err } // XXX: Currently this is untested with rootless containers. @@ -108,11 +113,11 @@ using the runc checkpoint command.`, logrus.Warn("runc checkpoint is untested with rootless containers") } - options, err := criuOptions(context) + options, err := criuOptions(cmd) if err != nil { return err } - status, err := startContainer(context, CT_ACT_RESTORE, options) + status, err := startContainer(cmd, CT_ACT_RESTORE, options) if err != nil { return err } diff --git a/rootless_linux.go b/rootless_linux.go index f9d9a42ba0a..f7f3708a149 100644 --- a/rootless_linux.go +++ b/rootless_linux.go @@ -5,14 +5,14 @@ import ( "github.com/moby/sys/userns" "github.com/sirupsen/logrus" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" "github.com/opencontainers/cgroups/systemd" ) -func shouldUseRootlessCgroupManager(context *cli.Context) (bool, error) { - if context != nil { - b, err := parseBoolOrAuto(context.GlobalString("rootless")) +func shouldUseRootlessCgroupManager(cmd *cli.Command) (bool, error) { + if cmd != nil { + b, err := parseBoolOrAuto(cmd.String("rootless")) if err != nil { return false, err } @@ -37,7 +37,7 @@ func shouldUseRootlessCgroupManager(context *cli.Context) (bool, error) { // // On error, we assume we are root. An error may happen during shelling out to `busctl` CLI, // mostly when $DBUS_SESSION_BUS_ADDRESS is unset. - if context.GlobalBool("systemd-cgroup") { + if cmd.Bool("systemd-cgroup") { ownerUID, err := systemd.DetectUID() if err != nil { logrus.WithError(err).Debug("failed to get the OwnerUID value, assuming the value to be 0") @@ -46,7 +46,7 @@ func shouldUseRootlessCgroupManager(context *cli.Context) (bool, error) { return ownerUID != 0, nil } // [cgroupfs driver] - // As we are unaware of cgroups path, we can't determine whether we have the full + // As we are unaware of cgroups path, we can't determine whether we have to full // access to the cgroups path. // Either way, we can safely decide to use the rootless cgroups manager. return true, nil diff --git a/run.go b/run.go index b03b8129bd9..25a6f4f82e3 100644 --- a/run.go +++ b/run.go @@ -1,14 +1,15 @@ package main import ( + "context" "fmt" "os" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) // default action is to start a container -var runCommand = cli.Command{ +var runCommand = &cli.Command{ Name: "run", Usage: "create and run a container", ArgsUsage: ` @@ -24,56 +25,60 @@ The specification file includes an args parameter. The args parameter is used to specify command(s) that get run when the container is started. To change the command(s) that get executed on start, edit the args parameter of the spec. See "runc spec --help" for more explanation.`, + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "bundle, b", - Value: "", - Usage: `path to the root of the bundle directory, defaults to the current directory`, + &cli.StringFlag{ + Name: "bundle", + Aliases: []string{"b"}, + Value: "", + Usage: `path to the root of the bundle directory, defaults to the current directory`, }, - cli.StringFlag{ + &cli.StringFlag{ Name: "console-socket", Value: "", Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "pidfd-socket", Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the init process", }, - cli.BoolFlag{ - Name: "detach, d", - Usage: "detach from the container's process", + &cli.BoolFlag{ + Name: "detach", + Aliases: []string{"d"}, + Usage: "detach from the container's process", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "keep", Usage: "do not delete the container after it exits", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "pid-file", Value: "", Usage: "specify the file to write the process id to", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-subreaper", Usage: "disable the use of the subreaper used to reap reparented processes", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-pivot", Usage: "do not use pivot root to jail process inside rootfs. This should be used whenever the rootfs is on top of a ramdisk", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-new-keyring", Usage: "do not create a new session keyring for the container. This will cause the container to inherit the calling processes session key", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "preserve-fds", Usage: "Pass N additional file descriptors to the container (stdio + $LISTEN_FDS + N in total)", }, }, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, exactArgs); err != nil { + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, exactArgs); err != nil { return err } - status, err := startContainer(context, CT_ACT_RUN, nil) + status, err := startContainer(cmd, CT_ACT_RUN, nil) if err == nil { // exit with the container's exit status so any external supervisor is // notified of the exit with the correct exit status. diff --git a/spec.go b/spec.go index 15e933eb0b9..1edf915f855 100644 --- a/spec.go +++ b/spec.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "errors" "fmt" @@ -9,10 +10,10 @@ import ( "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/specconv" "github.com/opencontainers/runtime-spec/specs-go" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var specCommand = cli.Command{ +var specCommand = &cli.Command{ Name: "spec", Usage: "create a new specification file", ArgsUsage: "", @@ -64,24 +65,27 @@ generate a proper rootless spec file. Note that --rootless is not needed when you execute runc as the root in a user namespace created by an unprivileged user. `, + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "bundle, b", - Value: "", - Usage: "path to the root of the bundle directory", + &cli.StringFlag{ + Name: "bundle", + Aliases: []string{"b"}, + Value: "", + Usage: "path to the root of the bundle directory", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "rootless", Usage: "generate a configuration for a rootless container", }, }, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 0, exactArgs); err != nil { + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 0, exactArgs); err != nil { return err } spec := specconv.Example() - rootless := context.Bool("rootless") + rootless := cmd.Bool("rootless") if rootless { specconv.ToRootless(spec) } @@ -96,7 +100,7 @@ created by an unprivileged user. } return nil } - bundle := context.String("bundle") + bundle := cmd.String("bundle") if bundle != "" { if err := os.Chdir(bundle); err != nil { return err diff --git a/start.go b/start.go index 338737c0a32..f983325ba05 100644 --- a/start.go +++ b/start.go @@ -1,15 +1,16 @@ package main import ( + "context" "errors" "fmt" "os" "github.com/opencontainers/runc/libcontainer" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var startCommand = cli.Command{ +var startCommand = &cli.Command{ Name: "start", Usage: "executes the user defined process in a created container", ArgsUsage: ` @@ -18,11 +19,13 @@ Where "" is your name for the instance of the container that you are starting. The name you provide for the container instance must be unique on your host.`, Description: `The start command executes the user defined process in a created container.`, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, exactArgs); err != nil { + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, exactArgs); err != nil { return err } - container, err := getContainer(context) + container, err := getContainer(cmd) if err != nil { return err } @@ -32,7 +35,7 @@ your host.`, } switch status { case libcontainer.Created: - notifySocket, err := notifySocketStart(context, os.Getenv("NOTIFY_SOCKET"), container.ID()) + notifySocket, err := notifySocketStart(cmd, os.Getenv("NOTIFY_SOCKET"), container.ID()) if err != nil { return err } diff --git a/state.go b/state.go index b645e5ab62b..2e58733b346 100644 --- a/state.go +++ b/state.go @@ -1,15 +1,16 @@ package main import ( + "context" "encoding/json" "os" "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/utils" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var stateCommand = cli.Command{ +var stateCommand = &cli.Command{ Name: "state", Usage: "output the state of a container", ArgsUsage: ` @@ -17,11 +18,13 @@ var stateCommand = cli.Command{ Where "" is your name for the instance of the container.`, Description: `The state command outputs current state information for the instance of a container.`, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, exactArgs); err != nil { + // Disable comma as separator for slice flags. + DisableSliceFlagSeparator: true, + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, exactArgs); err != nil { return err } - container, err := getContainer(context) + container, err := getContainer(cmd) if err != nil { return err } diff --git a/tests/cmd/pidfd-kill/pidfd-kill.go b/tests/cmd/pidfd-kill/pidfd-kill.go index c3ae74c92c6..299fb74abc8 100644 --- a/tests/cmd/pidfd-kill/pidfd-kill.go +++ b/tests/cmd/pidfd-kill/pidfd-kill.go @@ -5,13 +5,14 @@ package main import ( + "context" "errors" "fmt" "net" "os" "os/signal" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" "golang.org/x/sys/unix" "github.com/opencontainers/runc/internal/cmsg" @@ -32,32 +33,32 @@ pidfd: ) func main() { - app := cli.NewApp() + app := &cli.Command{} app.Name = "pidfd-kill" app.Usage = usage app.Flags = []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "signal", Value: "SIGKILL", Usage: "Signal to send to the init process", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "pid-file", Value: "", - Usage: "Path to write the pidfd-kill process ID to", + Usage: "Path to write to pidfd-kill process ID to", }, } - app.Action = func(ctx *cli.Context) error { - args := ctx.Args() + app.Action = func(_ context.Context, cmd *cli.Command) error { + args := cmd.Args().Slice() if len(args) != 1 { return errors.New("required a single socket path") } - socketFile := ctx.Args()[0] + socketFile := args[0] - pidFile := ctx.String("pid-file") + pidFile := cmd.String("pid-file") if pidFile != "" { pid := fmt.Sprintf("%d\n", os.Getpid()) if err := os.WriteFile(pidFile, []byte(pid), 0o644); err != nil { @@ -66,7 +67,7 @@ func main() { defer os.Remove(pidFile) } - sigStr := ctx.String("signal") + sigStr := cmd.String("signal") if sigStr == "" { sigStr = "SIGKILL" } @@ -84,7 +85,7 @@ func main() { return unix.PidfdSendSignal(int(pidfdFile.Fd()), sig, nil, 0) } - if err := app.Run(os.Args); err != nil { + if err := app.Run(context.Background(), os.Args); err != nil { fmt.Fprintln(os.Stderr, "fatal error:", err) os.Exit(1) } diff --git a/tests/cmd/recvtty/recvtty.go b/tests/cmd/recvtty/recvtty.go index 83abbc1dacc..a89b60e11e7 100644 --- a/tests/cmd/recvtty/recvtty.go +++ b/tests/cmd/recvtty/recvtty.go @@ -25,6 +25,7 @@ package main import ( + "context" "errors" "fmt" "io" @@ -34,7 +35,7 @@ import ( "sync" "github.com/containerd/console" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" "github.com/opencontainers/runc/internal/cmsg" ) @@ -175,7 +176,7 @@ func handleNull(path string) error { } func main() { - app := cli.NewApp() + app := &cli.Command{} app.Name = "recvtty" app.Usage = usage @@ -191,30 +192,30 @@ func main() { // Set the flags. app.Flags = []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "mode, m", Value: "single", Usage: "Mode of operation (single or null)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "pid-file", Value: "", Usage: "Path to write daemon process ID to", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-stdin", Usage: "Disable stdin handling (no-op for null mode)", }, } - app.Action = func(ctx *cli.Context) error { - args := ctx.Args() + app.Action = func(_ context.Context, cmd *cli.Command) error { + args := cmd.Args().Slice() if len(args) != 1 { return errors.New("need to specify a single socket path") } - path := ctx.Args()[0] + path := args[0] - pidPath := ctx.String("pid-file") + pidPath := cmd.String("pid-file") if pidPath != "" { pid := fmt.Sprintf("%d\n", os.Getpid()) if err := os.WriteFile(pidPath, []byte(pid), 0o644); err != nil { @@ -222,8 +223,8 @@ func main() { } } - noStdin := ctx.Bool("no-stdin") - switch ctx.String("mode") { + noStdin := cmd.Bool("no-stdin") + switch cmd.String("mode") { case "single": if err := handleSingle(path, noStdin); err != nil { return err @@ -233,11 +234,11 @@ func main() { return err } default: - return fmt.Errorf("need to select a valid mode: %s", ctx.String("mode")) + return fmt.Errorf("need to select a valid mode: %s", cmd.String("mode")) } return nil } - if err := app.Run(os.Args); err != nil { + if err := app.Run(context.Background(), os.Args); err != nil { bail(err) } } diff --git a/tests/cmd/remap-rootfs/remap-rootfs.go b/tests/cmd/remap-rootfs/remap-rootfs.go index a9439b70cbc..9f4ceab36a0 100644 --- a/tests/cmd/remap-rootfs/remap-rootfs.go +++ b/tests/cmd/remap-rootfs/remap-rootfs.go @@ -6,6 +6,7 @@ package main import ( + "context" "encoding/json" "errors" "fmt" @@ -13,7 +14,7 @@ import ( "path/filepath" "syscall" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" "github.com/opencontainers/runtime-spec/specs-go" ) @@ -102,12 +103,12 @@ func remapRootfs(root string, uidMap, gidMap []specs.LinuxIDMapping) error { } func main() { - app := cli.NewApp() + app := &cli.Command{} app.Name = "remap-rootfs" app.Usage = usage - app.Action = func(ctx *cli.Context) error { - args := ctx.Args() + app.Action = func(_ context.Context, cmd *cli.Command) error { + args := cmd.Args().Slice() if len(args) != 1 { return errors.New("exactly one bundle argument must be provided") } @@ -141,7 +142,7 @@ func main() { return remapRootfs(rootfs, uidMap, gidMap) } - if err := app.Run(os.Args); err != nil { + if err := app.Run(context.Background(), os.Args); err != nil { fmt.Fprintln(os.Stderr, "error:", err) os.Exit(1) } diff --git a/update.go b/update.go index 11a157184d7..432b28ac34a 100644 --- a/update.go +++ b/update.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "errors" "fmt" @@ -14,19 +15,20 @@ import ( "github.com/docker/go-units" "github.com/opencontainers/runc/libcontainer/intelrdt" "github.com/opencontainers/runtime-spec/specs-go" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) func mkPtr[T any](v T) *T { return &v } -var updateCommand = cli.Command{ +var updateCommand = &cli.Command{ Name: "update", Usage: "update container resource constraints", ArgsUsage: ``, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "resources, r", - Value: "", + &cli.StringFlag{ + Name: "resources", + Aliases: []string{"r"}, + Value: "", Usage: `path to the file containing the resources to update or '-' to read from the standard input The accepted format is as follow (unchanged values can be omitted): @@ -59,86 +61,86 @@ other options are ignored. `, }, - cli.IntFlag{ + &cli.IntFlag{ Name: "blkio-weight", Usage: "Specifies per cgroup weight, range is from 10 to 1000", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cpu-period", Usage: "CPU CFS period to be used for hardcapping (in usecs). 0 to use system default", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cpu-quota", Usage: "CPU CFS hardcap limit (in usecs). Allowed cpu time in a given period", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cpu-burst", Usage: "CPU CFS hardcap burst limit (in usecs). Allowed accumulated cpu time additionally for burst a given period", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cpu-share", Usage: "CPU shares (relative weight vs. other containers)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cpu-rt-period", Usage: "CPU realtime period to be used for hardcapping (in usecs). 0 to use system default", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cpu-rt-runtime", Usage: "CPU realtime hardcap limit (in usecs). Allowed cpu time in a given period", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cpuset-cpus", Usage: "CPU(s) to use", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cpuset-mems", Usage: "Memory node(s) to use", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "kernel-memory", Usage: "(obsoleted; do not use)", Hidden: true, }, - cli.StringFlag{ + &cli.StringFlag{ Name: "kernel-memory-tcp", Usage: "(obsoleted; do not use)", Hidden: true, }, - cli.StringFlag{ + &cli.StringFlag{ Name: "memory", Usage: "Memory limit (in bytes)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cpu-idle", Usage: "set cgroup SCHED_IDLE or not, 0: default behavior, 1: SCHED_IDLE", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "memory-reservation", Usage: "Memory reservation or soft_limit (in bytes)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "memory-swap", Usage: "Total memory usage (memory + swap); set '-1' to enable unlimited swap", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "pids-limit", Usage: "Maximum number of pids allowed in the container", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "l3-cache-schema", Usage: "The string of Intel RDT/CAT L3 cache schema", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "mem-bw-schema", Usage: "The string of Intel RDT/MBA memory bandwidth schema", }, }, - Action: func(context *cli.Context) error { - if err := checkArgs(context, 1, exactArgs); err != nil { + Action: func(_ context.Context, cmd *cli.Command) error { + if err := checkArgs(cmd, 1, exactArgs); err != nil { return err } - container, err := getContainer(context) + container, err := getContainer(cmd) if err != nil { return err } @@ -155,7 +157,7 @@ other options are ignored. config := container.Config() - if in := context.String("resources"); in != "" { + if in := cmd.String("resources"); in != "" { var ( f *os.File err error @@ -175,16 +177,16 @@ other options are ignored. return err } } else { - if val := context.Int("blkio-weight"); val != 0 { + if val := cmd.Int("blkio-weight"); val != 0 { r.BlockIO.Weight = mkPtr(uint16(val)) } - if val := context.String("cpuset-cpus"); val != "" { + if val := cmd.String("cpuset-cpus"); val != "" { r.CPU.Cpus = val } - if val := context.String("cpuset-mems"); val != "" { + if val := cmd.String("cpuset-mems"); val != "" { r.CPU.Mems = val } - if val := context.String("cpu-idle"); val != "" { + if val := cmd.String("cpu-idle"); val != "" { idle, err := strconv.ParseInt(val, 10, 64) if err != nil { return fmt.Errorf("invalid value for cpu-idle: %w", err) @@ -201,7 +203,7 @@ other options are ignored. {"cpu-rt-period", &r.CPU.RealtimePeriod}, {"cpu-share", &r.CPU.Shares}, } { - if val := context.String(pair.opt); val != "" { + if val := cmd.String(pair.opt); val != "" { v, err := strconv.ParseUint(val, 10, 64) if err != nil { return fmt.Errorf("invalid value for %s: %w", pair.opt, err) @@ -216,7 +218,7 @@ other options are ignored. {"cpu-quota", &r.CPU.Quota}, {"cpu-rt-runtime", &r.CPU.RealtimeRuntime}, } { - if val := context.String(pair.opt); val != "" { + if val := cmd.String(pair.opt); val != "" { v, err := strconv.ParseInt(val, 10, 64) if err != nil { return fmt.Errorf("invalid value for %s: %w", pair.opt, err) @@ -234,7 +236,7 @@ other options are ignored. {"kernel-memory-tcp", &r.Memory.KernelTCP}, {"memory-reservation", &r.Memory.Reservation}, } { - if val := context.String(pair.opt); val != "" { + if val := cmd.String(pair.opt); val != "" { var v int64 if val != "-1" { @@ -249,8 +251,8 @@ other options are ignored. } } - if context.IsSet("pids-limit") { - r.Pids.Limit = mkPtr(int64(context.Int("pids-limit"))) + if cmd.IsSet("pids-limit") { + r.Pids.Limit = mkPtr(int64(cmd.Int("pids-limit"))) } } @@ -359,8 +361,8 @@ other options are ignored. config.Cgroups.Resources.Unified = r.Unified // Update Intel RDT - l3CacheSchema := context.String("l3-cache-schema") - memBwSchema := context.String("mem-bw-schema") + l3CacheSchema := cmd.String("l3-cache-schema") + memBwSchema := cmd.String("mem-bw-schema") if l3CacheSchema != "" && !intelrdt.IsCATEnabled() { return errors.New("Intel RDT/CAT: l3 cache schema is not enabled") } diff --git a/utils.go b/utils.go index 75752f18374..e22037a3618 100644 --- a/utils.go +++ b/utils.go @@ -1,6 +1,7 @@ package main import ( + "context" "errors" "fmt" "os" @@ -11,7 +12,7 @@ import ( "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) const ( @@ -20,27 +21,27 @@ const ( maxArgs ) -func checkArgs(context *cli.Context, expected, checkType int) error { +func checkArgs(cmd *cli.Command, expected, checkType int) error { var err error - cmdName := context.Command.Name + cmdName := cmd.Name switch checkType { case exactArgs: - if context.NArg() != expected { + if cmd.NArg() != expected { err = fmt.Errorf("%s: %q requires exactly %d argument(s)", os.Args[0], cmdName, expected) } case minArgs: - if context.NArg() < expected { + if cmd.NArg() < expected { err = fmt.Errorf("%s: %q requires a minimum of %d argument(s)", os.Args[0], cmdName, expected) } case maxArgs: - if context.NArg() > expected { + if cmd.NArg() > expected { err = fmt.Errorf("%s: %q requires a maximum of %d argument(s)", os.Args[0], cmdName, expected) } } if err != nil { fmt.Printf("Incorrect Usage.\n\n") - _ = cli.ShowCommandHelp(context, cmdName) + _ = cli.ShowCommandHelp(context.Background(), cmd, cmdName) return err } return nil @@ -68,8 +69,8 @@ func fatalWithCode(err error, ret int) { } // setupSpec performs initial setup based on the cli.Context for the container -func setupSpec(context *cli.Context) (*specs.Spec, error) { - bundle := context.String("bundle") +func setupSpec(cmd *cli.Command) (*specs.Spec, error) { + bundle := cmd.String("bundle") if bundle != "" { if err := os.Chdir(bundle); err != nil { return nil, err @@ -82,8 +83,8 @@ func setupSpec(context *cli.Context) (*specs.Spec, error) { return spec, nil } -func revisePidFile(context *cli.Context) error { - pidFile := context.String("pid-file") +func revisePidFile(cmd *cli.Command) error { + pidFile := cmd.String("pid-file") if pidFile == "" { return nil } @@ -94,17 +95,17 @@ func revisePidFile(context *cli.Context) error { if err != nil { return err } - return context.Set("pid-file", pidFile) + return cmd.Set("pid-file", pidFile) } // reviseRootDir ensures that the --root option argument, // if specified, is converted to an absolute and cleaned path, // and that this path is sane. -func reviseRootDir(context *cli.Context) error { - if !context.IsSet("root") { +func reviseRootDir(cmd *cli.Command) error { + if !cmd.IsSet("root") { return nil } - root, err := filepath.Abs(context.GlobalString("root")) + root, err := filepath.Abs(cmd.String("root")) if err != nil { return err } @@ -117,7 +118,7 @@ func reviseRootDir(context *cli.Context) error { return errors.New("Option --root argument should not be set to /") } - return context.GlobalSet("root", root) + return cmd.Set("root", root) } // parseBoolOrAuto returns (nil, nil) if s is empty or "auto" @@ -128,3 +129,8 @@ func parseBoolOrAuto(s string) (*bool, error) { b, err := strconv.ParseBool(s) return &b, err } + +// intPtr is a helper function to create int pointer. +func intPtr(i int) *int { + return &i +} diff --git a/utils_linux.go b/utils_linux.go index 6858a7a4822..1da1c872d88 100644 --- a/utils_linux.go +++ b/utils_linux.go @@ -12,7 +12,7 @@ import ( "github.com/opencontainers/runtime-spec/specs-go" selinux "github.com/opencontainers/selinux/go-selinux" "github.com/sirupsen/logrus" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" "golang.org/x/sys/unix" "github.com/opencontainers/runc/internal/pathrs" @@ -29,12 +29,12 @@ var errEmptyID = errors.New("container id cannot be empty") // getContainer returns the specified container instance by loading it from // a state directory (root). -func getContainer(context *cli.Context) (*libcontainer.Container, error) { - id := context.Args().First() +func getContainer(cmd *cli.Command) (*libcontainer.Container, error) { + id := cmd.Args().First() if id == "" { return nil, errEmptyID } - root := context.GlobalString("root") + root := cmd.String("root") return libcontainer.Load(root, id) } @@ -181,16 +181,16 @@ func createPidFile(path string, process *libcontainer.Process) error { return os.Rename(tmpName, path) } -func createContainer(context *cli.Context, id string, spec *specs.Spec) (*libcontainer.Container, error) { - rootlessCg, err := shouldUseRootlessCgroupManager(context) +func createContainer(cmd *cli.Command, id string, spec *specs.Spec) (*libcontainer.Container, error) { + rootlessCg, err := shouldUseRootlessCgroupManager(cmd) if err != nil { return nil, err } config, err := specconv.CreateLibcontainerConfig(&specconv.CreateOpts{ CgroupName: id, - UseSystemdCgroup: context.GlobalBool("systemd-cgroup"), - NoPivotRoot: context.Bool("no-pivot"), - NoNewKeyring: context.Bool("no-new-keyring"), + UseSystemdCgroup: cmd.Bool("systemd-cgroup"), + NoPivotRoot: cmd.Bool("no-pivot"), + NoNewKeyring: cmd.Bool("no-new-keyring"), Spec: spec, RootlessEUID: os.Geteuid() != 0, RootlessCgroups: rootlessCg, @@ -199,7 +199,7 @@ func createContainer(context *cli.Context, id string, spec *specs.Spec) (*libcon return nil, err } - root := context.GlobalString("root") + root := cmd.String("root") return libcontainer.Create(root, id, config) } @@ -378,26 +378,26 @@ const ( CT_ACT_RESTORE ) -func startContainer(context *cli.Context, action CtAct, criuOpts *libcontainer.CriuOpts) (int, error) { - if err := revisePidFile(context); err != nil { +func startContainer(cmd *cli.Command, action CtAct, criuOpts *libcontainer.CriuOpts) (int, error) { + if err := revisePidFile(cmd); err != nil { return -1, err } - spec, err := setupSpec(context) + spec, err := setupSpec(cmd) if err != nil { return -1, err } - id := context.Args().First() + id := cmd.Args().First() if id == "" { return -1, errEmptyID } - notifySocket := newNotifySocket(context, os.Getenv("NOTIFY_SOCKET"), id) + notifySocket := newNotifySocket(cmd, os.Getenv("NOTIFY_SOCKET"), id) if notifySocket != nil { notifySocket.setupSpec(spec) } - container, err := createContainer(context, id, spec) + container, err := createContainer(cmd, id, spec) if err != nil { return -1, err } @@ -414,16 +414,16 @@ func startContainer(context *cli.Context, action CtAct, criuOpts *libcontainer.C } r := &runner{ - enableSubreaper: !context.Bool("no-subreaper"), - shouldDestroy: !context.Bool("keep"), + enableSubreaper: !cmd.Bool("no-subreaper"), + shouldDestroy: !cmd.Bool("keep"), container: container, listenFDs: activation.Files(), // On-demand socket activation. notifySocket: notifySocket, - consoleSocket: context.String("console-socket"), - pidfdSocket: context.String("pidfd-socket"), - detach: context.Bool("detach"), - pidFile: context.String("pid-file"), - preserveFDs: context.Int("preserve-fds"), + consoleSocket: cmd.String("console-socket"), + pidfdSocket: cmd.String("pidfd-socket"), + detach: cmd.Bool("detach"), + pidFile: cmd.String("pid-file"), + preserveFDs: cmd.Int("preserve-fds"), action: action, criuOpts: criuOpts, init: true, diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md b/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md deleted file mode 100644 index 1cade6cef6a..00000000000 --- a/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Brian Goff - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/debug.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/debug.go deleted file mode 100644 index 0ec4b12c75d..00000000000 --- a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/debug.go +++ /dev/null @@ -1,62 +0,0 @@ -package md2man - -import ( - "fmt" - "io" - "os" - "strings" - - "github.com/russross/blackfriday/v2" -) - -func fmtListFlags(flags blackfriday.ListType) string { - knownFlags := []struct { - name string - flag blackfriday.ListType - }{ - {"ListTypeOrdered", blackfriday.ListTypeOrdered}, - {"ListTypeDefinition", blackfriday.ListTypeDefinition}, - {"ListTypeTerm", blackfriday.ListTypeTerm}, - {"ListItemContainsBlock", blackfriday.ListItemContainsBlock}, - {"ListItemBeginningOfList", blackfriday.ListItemBeginningOfList}, - {"ListItemEndOfList", blackfriday.ListItemEndOfList}, - } - - var f []string - for _, kf := range knownFlags { - if flags&kf.flag != 0 { - f = append(f, kf.name) - flags &^= kf.flag - } - } - if flags != 0 { - f = append(f, fmt.Sprintf("Unknown(%#x)", flags)) - } - return strings.Join(f, "|") -} - -type debugDecorator struct { - blackfriday.Renderer -} - -func depth(node *blackfriday.Node) int { - d := 0 - for n := node.Parent; n != nil; n = n.Parent { - d++ - } - return d -} - -func (d *debugDecorator) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus { - fmt.Fprintf(os.Stderr, "%s%s %v %v\n", - strings.Repeat(" ", depth(node)), - map[bool]string{true: "+", false: "-"}[entering], - node, - fmtListFlags(node.ListFlags)) - var b strings.Builder - status := d.Renderer.RenderNode(io.MultiWriter(&b, w), node, entering) - if b.Len() > 0 { - fmt.Fprintf(os.Stderr, ">> %q\n", b.String()) - } - return status -} diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go deleted file mode 100644 index 5673f5c0bc6..00000000000 --- a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go +++ /dev/null @@ -1,24 +0,0 @@ -// Package md2man aims in converting markdown into roff (man pages). -package md2man - -import ( - "os" - "strconv" - - "github.com/russross/blackfriday/v2" -) - -// Render converts a markdown document into a roff formatted document. -func Render(doc []byte) []byte { - renderer := NewRoffRenderer() - var r blackfriday.Renderer = renderer - if v, _ := strconv.ParseBool(os.Getenv("MD2MAN_DEBUG")); v { - r = &debugDecorator{Renderer: r} - } - - return blackfriday.Run(doc, - []blackfriday.Option{ - blackfriday.WithRenderer(r), - blackfriday.WithExtensions(renderer.GetExtensions()), - }...) -} diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go deleted file mode 100644 index 4f1070fc5b7..00000000000 --- a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go +++ /dev/null @@ -1,416 +0,0 @@ -package md2man - -import ( - "bufio" - "bytes" - "fmt" - "io" - "os" - "strings" - - "github.com/russross/blackfriday/v2" -) - -// roffRenderer implements the blackfriday.Renderer interface for creating -// roff format (manpages) from markdown text -type roffRenderer struct { - listCounters []int - firstHeader bool - listDepth int -} - -const ( - titleHeader = ".TH " - topLevelHeader = "\n\n.SH " - secondLevelHdr = "\n.SH " - otherHeader = "\n.SS " - crTag = "\n" - emphTag = "\\fI" - emphCloseTag = "\\fP" - strongTag = "\\fB" - strongCloseTag = "\\fP" - breakTag = "\n.br\n" - paraTag = "\n.PP\n" - hruleTag = "\n.ti 0\n\\l'\\n(.lu'\n" - linkTag = "\n\\[la]" - linkCloseTag = "\\[ra]" - codespanTag = "\\fB" - codespanCloseTag = "\\fR" - codeTag = "\n.EX\n" - codeCloseTag = ".EE\n" // Do not prepend a newline character since code blocks, by definition, include a newline already (or at least as how blackfriday gives us on). - quoteTag = "\n.PP\n.RS\n" - quoteCloseTag = "\n.RE\n" - listTag = "\n.RS\n" - listCloseTag = ".RE\n" - dtTag = "\n.TP\n" - dd2Tag = "\n" - tableStart = "\n.TS\nallbox;\n" - tableEnd = ".TE\n" - tableCellStart = "T{\n" - tableCellEnd = "\nT}" - tablePreprocessor = `'\" t` -) - -// NewRoffRenderer creates a new blackfriday Renderer for generating roff documents -// from markdown -func NewRoffRenderer() *roffRenderer { - return &roffRenderer{} -} - -// GetExtensions returns the list of extensions used by this renderer implementation -func (*roffRenderer) GetExtensions() blackfriday.Extensions { - return blackfriday.NoIntraEmphasis | - blackfriday.Tables | - blackfriday.FencedCode | - blackfriday.SpaceHeadings | - blackfriday.Footnotes | - blackfriday.Titleblock | - blackfriday.DefinitionLists -} - -// RenderHeader handles outputting the header at document start -func (r *roffRenderer) RenderHeader(w io.Writer, ast *blackfriday.Node) { - // We need to walk the tree to check if there are any tables. - // If there are, we need to enable the roff table preprocessor. - ast.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus { - if node.Type == blackfriday.Table { - out(w, tablePreprocessor+"\n") - return blackfriday.Terminate - } - return blackfriday.GoToNext - }) - - // disable hyphenation - out(w, ".nh\n") -} - -// RenderFooter handles outputting the footer at the document end; the roff -// renderer has no footer information -func (r *roffRenderer) RenderFooter(w io.Writer, ast *blackfriday.Node) { -} - -// RenderNode is called for each node in a markdown document; based on the node -// type the equivalent roff output is sent to the writer -func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus { - walkAction := blackfriday.GoToNext - - switch node.Type { - case blackfriday.Text: - // Special case: format the NAME section as required for proper whatis parsing. - // Refer to the lexgrog(1) and groff_man(7) manual pages for details. - if node.Parent != nil && - node.Parent.Type == blackfriday.Paragraph && - node.Parent.Prev != nil && - node.Parent.Prev.Type == blackfriday.Heading && - node.Parent.Prev.FirstChild != nil && - bytes.EqualFold(node.Parent.Prev.FirstChild.Literal, []byte("NAME")) { - before, after, found := bytesCut(node.Literal, []byte(" - ")) - escapeSpecialChars(w, before) - if found { - out(w, ` \- `) - escapeSpecialChars(w, after) - } - } else { - escapeSpecialChars(w, node.Literal) - } - case blackfriday.Softbreak: - out(w, crTag) - case blackfriday.Hardbreak: - out(w, breakTag) - case blackfriday.Emph: - if entering { - out(w, emphTag) - } else { - out(w, emphCloseTag) - } - case blackfriday.Strong: - if entering { - out(w, strongTag) - } else { - out(w, strongCloseTag) - } - case blackfriday.Link: - // Don't render the link text for automatic links, because this - // will only duplicate the URL in the roff output. - // See https://daringfireball.net/projects/markdown/syntax#autolink - if !bytes.Equal(node.LinkData.Destination, node.FirstChild.Literal) { - out(w, string(node.FirstChild.Literal)) - } - // Hyphens in a link must be escaped to avoid word-wrap in the rendered man page. - escapedLink := strings.ReplaceAll(string(node.LinkData.Destination), "-", "\\-") - out(w, linkTag+escapedLink+linkCloseTag) - walkAction = blackfriday.SkipChildren - case blackfriday.Image: - // ignore images - walkAction = blackfriday.SkipChildren - case blackfriday.Code: - out(w, codespanTag) - escapeSpecialChars(w, node.Literal) - out(w, codespanCloseTag) - case blackfriday.Document: - break - case blackfriday.Paragraph: - if entering { - if r.listDepth > 0 { - // roff .PP markers break lists - if node.Prev != nil { // continued paragraph - if node.Prev.Type == blackfriday.List && node.Prev.ListFlags&blackfriday.ListTypeDefinition == 0 { - out(w, ".IP\n") - } else { - out(w, crTag) - } - } - } else if node.Prev != nil && node.Prev.Type == blackfriday.Heading { - out(w, crTag) - } else { - out(w, paraTag) - } - } else { - if node.Next == nil || node.Next.Type != blackfriday.List { - out(w, crTag) - } - } - case blackfriday.BlockQuote: - if entering { - out(w, quoteTag) - } else { - out(w, quoteCloseTag) - } - case blackfriday.Heading: - r.handleHeading(w, node, entering) - case blackfriday.HorizontalRule: - out(w, hruleTag) - case blackfriday.List: - r.handleList(w, node, entering) - case blackfriday.Item: - r.handleItem(w, node, entering) - case blackfriday.CodeBlock: - out(w, codeTag) - escapeSpecialChars(w, node.Literal) - out(w, codeCloseTag) - case blackfriday.Table: - r.handleTable(w, node, entering) - case blackfriday.TableHead: - case blackfriday.TableBody: - case blackfriday.TableRow: - // no action as cell entries do all the nroff formatting - return blackfriday.GoToNext - case blackfriday.TableCell: - r.handleTableCell(w, node, entering) - case blackfriday.HTMLSpan: - // ignore other HTML tags - case blackfriday.HTMLBlock: - if bytes.HasPrefix(node.Literal, []byte("|" - processingInstruction = "[<][?].*?[?][>]" - singleQuotedValue = "'[^']*'" - tagName = "[A-Za-z][A-Za-z0-9-]*" - unquotedValue = "[^\"'=<>`\\x00-\\x20]+" -) - -// HTMLRendererParameters is a collection of supplementary parameters tweaking -// the behavior of various parts of HTML renderer. -type HTMLRendererParameters struct { - // Prepend this text to each relative URL. - AbsolutePrefix string - // Add this text to each footnote anchor, to ensure uniqueness. - FootnoteAnchorPrefix string - // Show this text inside the tag for a footnote return link, if the - // HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string - // [return] is used. - FootnoteReturnLinkContents string - // If set, add this text to the front of each Heading ID, to ensure - // uniqueness. - HeadingIDPrefix string - // If set, add this text to the back of each Heading ID, to ensure uniqueness. - HeadingIDSuffix string - // Increase heading levels: if the offset is 1,

becomes

etc. - // Negative offset is also valid. - // Resulting levels are clipped between 1 and 6. - HeadingLevelOffset int - - Title string // Document title (used if CompletePage is set) - CSS string // Optional CSS file URL (used if CompletePage is set) - Icon string // Optional icon file URL (used if CompletePage is set) - - Flags HTMLFlags // Flags allow customizing this renderer's behavior -} - -// HTMLRenderer is a type that implements the Renderer interface for HTML output. -// -// Do not create this directly, instead use the NewHTMLRenderer function. -type HTMLRenderer struct { - HTMLRendererParameters - - closeTag string // how to end singleton tags: either " />" or ">" - - // Track heading IDs to prevent ID collision in a single generation. - headingIDs map[string]int - - lastOutputLen int - disableTags int - - sr *SPRenderer -} - -const ( - xhtmlClose = " />" - htmlClose = ">" -) - -// NewHTMLRenderer creates and configures an HTMLRenderer object, which -// satisfies the Renderer interface. -func NewHTMLRenderer(params HTMLRendererParameters) *HTMLRenderer { - // configure the rendering engine - closeTag := htmlClose - if params.Flags&UseXHTML != 0 { - closeTag = xhtmlClose - } - - if params.FootnoteReturnLinkContents == "" { - // U+FE0E is VARIATION SELECTOR-15. - // It suppresses automatic emoji presentation of the preceding - // U+21A9 LEFTWARDS ARROW WITH HOOK on iOS and iPadOS. - params.FootnoteReturnLinkContents = "↩\ufe0e" - } - - return &HTMLRenderer{ - HTMLRendererParameters: params, - - closeTag: closeTag, - headingIDs: make(map[string]int), - - sr: NewSmartypantsRenderer(params.Flags), - } -} - -func isHTMLTag(tag []byte, tagname string) bool { - found, _ := findHTMLTagPos(tag, tagname) - return found -} - -// Look for a character, but ignore it when it's in any kind of quotes, it -// might be JavaScript -func skipUntilCharIgnoreQuotes(html []byte, start int, char byte) int { - inSingleQuote := false - inDoubleQuote := false - inGraveQuote := false - i := start - for i < len(html) { - switch { - case html[i] == char && !inSingleQuote && !inDoubleQuote && !inGraveQuote: - return i - case html[i] == '\'': - inSingleQuote = !inSingleQuote - case html[i] == '"': - inDoubleQuote = !inDoubleQuote - case html[i] == '`': - inGraveQuote = !inGraveQuote - } - i++ - } - return start -} - -func findHTMLTagPos(tag []byte, tagname string) (bool, int) { - i := 0 - if i < len(tag) && tag[0] != '<' { - return false, -1 - } - i++ - i = skipSpace(tag, i) - - if i < len(tag) && tag[i] == '/' { - i++ - } - - i = skipSpace(tag, i) - j := 0 - for ; i < len(tag); i, j = i+1, j+1 { - if j >= len(tagname) { - break - } - - if strings.ToLower(string(tag[i]))[0] != tagname[j] { - return false, -1 - } - } - - if i == len(tag) { - return false, -1 - } - - rightAngle := skipUntilCharIgnoreQuotes(tag, i, '>') - if rightAngle >= i { - return true, rightAngle - } - - return false, -1 -} - -func skipSpace(tag []byte, i int) int { - for i < len(tag) && isspace(tag[i]) { - i++ - } - return i -} - -func isRelativeLink(link []byte) (yes bool) { - // a tag begin with '#' - if link[0] == '#' { - return true - } - - // link begin with '/' but not '//', the second maybe a protocol relative link - if len(link) >= 2 && link[0] == '/' && link[1] != '/' { - return true - } - - // only the root '/' - if len(link) == 1 && link[0] == '/' { - return true - } - - // current directory : begin with "./" - if bytes.HasPrefix(link, []byte("./")) { - return true - } - - // parent directory : begin with "../" - if bytes.HasPrefix(link, []byte("../")) { - return true - } - - return false -} - -func (r *HTMLRenderer) ensureUniqueHeadingID(id string) string { - for count, found := r.headingIDs[id]; found; count, found = r.headingIDs[id] { - tmp := fmt.Sprintf("%s-%d", id, count+1) - - if _, tmpFound := r.headingIDs[tmp]; !tmpFound { - r.headingIDs[id] = count + 1 - id = tmp - } else { - id = id + "-1" - } - } - - if _, found := r.headingIDs[id]; !found { - r.headingIDs[id] = 0 - } - - return id -} - -func (r *HTMLRenderer) addAbsPrefix(link []byte) []byte { - if r.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' { - newDest := r.AbsolutePrefix - if link[0] != '/' { - newDest += "/" - } - newDest += string(link) - return []byte(newDest) - } - return link -} - -func appendLinkAttrs(attrs []string, flags HTMLFlags, link []byte) []string { - if isRelativeLink(link) { - return attrs - } - val := []string{} - if flags&NofollowLinks != 0 { - val = append(val, "nofollow") - } - if flags&NoreferrerLinks != 0 { - val = append(val, "noreferrer") - } - if flags&NoopenerLinks != 0 { - val = append(val, "noopener") - } - if flags&HrefTargetBlank != 0 { - attrs = append(attrs, "target=\"_blank\"") - } - if len(val) == 0 { - return attrs - } - attr := fmt.Sprintf("rel=%q", strings.Join(val, " ")) - return append(attrs, attr) -} - -func isMailto(link []byte) bool { - return bytes.HasPrefix(link, []byte("mailto:")) -} - -func needSkipLink(flags HTMLFlags, dest []byte) bool { - if flags&SkipLinks != 0 { - return true - } - return flags&Safelink != 0 && !isSafeLink(dest) && !isMailto(dest) -} - -func isSmartypantable(node *Node) bool { - pt := node.Parent.Type - return pt != Link && pt != CodeBlock && pt != Code -} - -func appendLanguageAttr(attrs []string, info []byte) []string { - if len(info) == 0 { - return attrs - } - endOfLang := bytes.IndexAny(info, "\t ") - if endOfLang < 0 { - endOfLang = len(info) - } - return append(attrs, fmt.Sprintf("class=\"language-%s\"", info[:endOfLang])) -} - -func (r *HTMLRenderer) tag(w io.Writer, name []byte, attrs []string) { - w.Write(name) - if len(attrs) > 0 { - w.Write(spaceBytes) - w.Write([]byte(strings.Join(attrs, " "))) - } - w.Write(gtBytes) - r.lastOutputLen = 1 -} - -func footnoteRef(prefix string, node *Node) []byte { - urlFrag := prefix + string(slugify(node.Destination)) - anchor := fmt.Sprintf(`%d`, urlFrag, node.NoteID) - return []byte(fmt.Sprintf(`%s`, urlFrag, anchor)) -} - -func footnoteItem(prefix string, slug []byte) []byte { - return []byte(fmt.Sprintf(`
  • `, prefix, slug)) -} - -func footnoteReturnLink(prefix, returnLink string, slug []byte) []byte { - const format = ` %s` - return []byte(fmt.Sprintf(format, prefix, slug, returnLink)) -} - -func itemOpenCR(node *Node) bool { - if node.Prev == nil { - return false - } - ld := node.Parent.ListData - return !ld.Tight && ld.ListFlags&ListTypeDefinition == 0 -} - -func skipParagraphTags(node *Node) bool { - grandparent := node.Parent.Parent - if grandparent == nil || grandparent.Type != List { - return false - } - tightOrTerm := grandparent.Tight || node.Parent.ListFlags&ListTypeTerm != 0 - return grandparent.Type == List && tightOrTerm -} - -func cellAlignment(align CellAlignFlags) string { - switch align { - case TableAlignmentLeft: - return "left" - case TableAlignmentRight: - return "right" - case TableAlignmentCenter: - return "center" - default: - return "" - } -} - -func (r *HTMLRenderer) out(w io.Writer, text []byte) { - if r.disableTags > 0 { - w.Write(htmlTagRe.ReplaceAll(text, []byte{})) - } else { - w.Write(text) - } - r.lastOutputLen = len(text) -} - -func (r *HTMLRenderer) cr(w io.Writer) { - if r.lastOutputLen > 0 { - r.out(w, nlBytes) - } -} - -var ( - nlBytes = []byte{'\n'} - gtBytes = []byte{'>'} - spaceBytes = []byte{' '} -) - -var ( - brTag = []byte("
    ") - brXHTMLTag = []byte("
    ") - emTag = []byte("") - emCloseTag = []byte("") - strongTag = []byte("") - strongCloseTag = []byte("") - delTag = []byte("") - delCloseTag = []byte("") - ttTag = []byte("") - ttCloseTag = []byte("") - aTag = []byte("") - preTag = []byte("
    ")
    -	preCloseTag        = []byte("
    ") - codeTag = []byte("") - codeCloseTag = []byte("") - pTag = []byte("

    ") - pCloseTag = []byte("

    ") - blockquoteTag = []byte("
    ") - blockquoteCloseTag = []byte("
    ") - hrTag = []byte("
    ") - hrXHTMLTag = []byte("
    ") - ulTag = []byte("
      ") - ulCloseTag = []byte("
    ") - olTag = []byte("
      ") - olCloseTag = []byte("
    ") - dlTag = []byte("
    ") - dlCloseTag = []byte("
    ") - liTag = []byte("
  • ") - liCloseTag = []byte("
  • ") - ddTag = []byte("
    ") - ddCloseTag = []byte("
    ") - dtTag = []byte("
    ") - dtCloseTag = []byte("
    ") - tableTag = []byte("") - tableCloseTag = []byte("
    ") - tdTag = []byte("") - thTag = []byte("") - theadTag = []byte("") - theadCloseTag = []byte("") - tbodyTag = []byte("") - tbodyCloseTag = []byte("") - trTag = []byte("") - trCloseTag = []byte("") - h1Tag = []byte("") - h2Tag = []byte("") - h3Tag = []byte("") - h4Tag = []byte("") - h5Tag = []byte("") - h6Tag = []byte("") - - footnotesDivBytes = []byte("\n
    \n\n") - footnotesCloseDivBytes = []byte("\n
    \n") -) - -func headingTagsFromLevel(level int) ([]byte, []byte) { - if level <= 1 { - return h1Tag, h1CloseTag - } - switch level { - case 2: - return h2Tag, h2CloseTag - case 3: - return h3Tag, h3CloseTag - case 4: - return h4Tag, h4CloseTag - case 5: - return h5Tag, h5CloseTag - } - return h6Tag, h6CloseTag -} - -func (r *HTMLRenderer) outHRTag(w io.Writer) { - if r.Flags&UseXHTML == 0 { - r.out(w, hrTag) - } else { - r.out(w, hrXHTMLTag) - } -} - -// RenderNode is a default renderer of a single node of a syntax tree. For -// block nodes it will be called twice: first time with entering=true, second -// time with entering=false, so that it could know when it's working on an open -// tag and when on close. It writes the result to w. -// -// The return value is a way to tell the calling walker to adjust its walk -// pattern: e.g. it can terminate the traversal by returning Terminate. Or it -// can ask the walker to skip a subtree of this node by returning SkipChildren. -// The typical behavior is to return GoToNext, which asks for the usual -// traversal to the next node. -func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkStatus { - attrs := []string{} - switch node.Type { - case Text: - if r.Flags&Smartypants != 0 { - var tmp bytes.Buffer - escapeHTML(&tmp, node.Literal) - r.sr.Process(w, tmp.Bytes()) - } else { - if node.Parent.Type == Link { - escLink(w, node.Literal) - } else { - escapeHTML(w, node.Literal) - } - } - case Softbreak: - r.cr(w) - // TODO: make it configurable via out(renderer.softbreak) - case Hardbreak: - if r.Flags&UseXHTML == 0 { - r.out(w, brTag) - } else { - r.out(w, brXHTMLTag) - } - r.cr(w) - case Emph: - if entering { - r.out(w, emTag) - } else { - r.out(w, emCloseTag) - } - case Strong: - if entering { - r.out(w, strongTag) - } else { - r.out(w, strongCloseTag) - } - case Del: - if entering { - r.out(w, delTag) - } else { - r.out(w, delCloseTag) - } - case HTMLSpan: - if r.Flags&SkipHTML != 0 { - break - } - r.out(w, node.Literal) - case Link: - // mark it but don't link it if it is not a safe link: no smartypants - dest := node.LinkData.Destination - if needSkipLink(r.Flags, dest) { - if entering { - r.out(w, ttTag) - } else { - r.out(w, ttCloseTag) - } - } else { - if entering { - dest = r.addAbsPrefix(dest) - var hrefBuf bytes.Buffer - hrefBuf.WriteString("href=\"") - escLink(&hrefBuf, dest) - hrefBuf.WriteByte('"') - attrs = append(attrs, hrefBuf.String()) - if node.NoteID != 0 { - r.out(w, footnoteRef(r.FootnoteAnchorPrefix, node)) - break - } - attrs = appendLinkAttrs(attrs, r.Flags, dest) - if len(node.LinkData.Title) > 0 { - var titleBuff bytes.Buffer - titleBuff.WriteString("title=\"") - escapeHTML(&titleBuff, node.LinkData.Title) - titleBuff.WriteByte('"') - attrs = append(attrs, titleBuff.String()) - } - r.tag(w, aTag, attrs) - } else { - if node.NoteID != 0 { - break - } - r.out(w, aCloseTag) - } - } - case Image: - if r.Flags&SkipImages != 0 { - return SkipChildren - } - if entering { - dest := node.LinkData.Destination - dest = r.addAbsPrefix(dest) - if r.disableTags == 0 { - //if options.safe && potentiallyUnsafe(dest) { - //out(w, ``)
-				//} else {
-				r.out(w, []byte(`<img src=`)) - } - } - case Code: - r.out(w, codeTag) - escapeAllHTML(w, node.Literal) - r.out(w, codeCloseTag) - case Document: - break - case Paragraph: - if skipParagraphTags(node) { - break - } - if entering { - // TODO: untangle this clusterfuck about when the newlines need - // to be added and when not. - if node.Prev != nil { - switch node.Prev.Type { - case HTMLBlock, List, Paragraph, Heading, CodeBlock, BlockQuote, HorizontalRule: - r.cr(w) - } - } - if node.Parent.Type == BlockQuote && node.Prev == nil { - r.cr(w) - } - r.out(w, pTag) - } else { - r.out(w, pCloseTag) - if !(node.Parent.Type == Item && node.Next == nil) { - r.cr(w) - } - } - case BlockQuote: - if entering { - r.cr(w) - r.out(w, blockquoteTag) - } else { - r.out(w, blockquoteCloseTag) - r.cr(w) - } - case HTMLBlock: - if r.Flags&SkipHTML != 0 { - break - } - r.cr(w) - r.out(w, node.Literal) - r.cr(w) - case Heading: - headingLevel := r.HTMLRendererParameters.HeadingLevelOffset + node.Level - openTag, closeTag := headingTagsFromLevel(headingLevel) - if entering { - if node.IsTitleblock { - attrs = append(attrs, `class="title"`) - } - if node.HeadingID != "" { - id := r.ensureUniqueHeadingID(node.HeadingID) - if r.HeadingIDPrefix != "" { - id = r.HeadingIDPrefix + id - } - if r.HeadingIDSuffix != "" { - id = id + r.HeadingIDSuffix - } - attrs = append(attrs, fmt.Sprintf(`id="%s"`, id)) - } - r.cr(w) - r.tag(w, openTag, attrs) - } else { - r.out(w, closeTag) - if !(node.Parent.Type == Item && node.Next == nil) { - r.cr(w) - } - } - case HorizontalRule: - r.cr(w) - r.outHRTag(w) - r.cr(w) - case List: - openTag := ulTag - closeTag := ulCloseTag - if node.ListFlags&ListTypeOrdered != 0 { - openTag = olTag - closeTag = olCloseTag - } - if node.ListFlags&ListTypeDefinition != 0 { - openTag = dlTag - closeTag = dlCloseTag - } - if entering { - if node.IsFootnotesList { - r.out(w, footnotesDivBytes) - r.outHRTag(w) - r.cr(w) - } - r.cr(w) - if node.Parent.Type == Item && node.Parent.Parent.Tight { - r.cr(w) - } - r.tag(w, openTag[:len(openTag)-1], attrs) - r.cr(w) - } else { - r.out(w, closeTag) - //cr(w) - //if node.parent.Type != Item { - // cr(w) - //} - if node.Parent.Type == Item && node.Next != nil { - r.cr(w) - } - if node.Parent.Type == Document || node.Parent.Type == BlockQuote { - r.cr(w) - } - if node.IsFootnotesList { - r.out(w, footnotesCloseDivBytes) - } - } - case Item: - openTag := liTag - closeTag := liCloseTag - if node.ListFlags&ListTypeDefinition != 0 { - openTag = ddTag - closeTag = ddCloseTag - } - if node.ListFlags&ListTypeTerm != 0 { - openTag = dtTag - closeTag = dtCloseTag - } - if entering { - if itemOpenCR(node) { - r.cr(w) - } - if node.ListData.RefLink != nil { - slug := slugify(node.ListData.RefLink) - r.out(w, footnoteItem(r.FootnoteAnchorPrefix, slug)) - break - } - r.out(w, openTag) - } else { - if node.ListData.RefLink != nil { - slug := slugify(node.ListData.RefLink) - if r.Flags&FootnoteReturnLinks != 0 { - r.out(w, footnoteReturnLink(r.FootnoteAnchorPrefix, r.FootnoteReturnLinkContents, slug)) - } - } - r.out(w, closeTag) - r.cr(w) - } - case CodeBlock: - attrs = appendLanguageAttr(attrs, node.Info) - r.cr(w) - r.out(w, preTag) - r.tag(w, codeTag[:len(codeTag)-1], attrs) - escapeAllHTML(w, node.Literal) - r.out(w, codeCloseTag) - r.out(w, preCloseTag) - if node.Parent.Type != Item { - r.cr(w) - } - case Table: - if entering { - r.cr(w) - r.out(w, tableTag) - } else { - r.out(w, tableCloseTag) - r.cr(w) - } - case TableCell: - openTag := tdTag - closeTag := tdCloseTag - if node.IsHeader { - openTag = thTag - closeTag = thCloseTag - } - if entering { - align := cellAlignment(node.Align) - if align != "" { - attrs = append(attrs, fmt.Sprintf(`align="%s"`, align)) - } - if node.Prev == nil { - r.cr(w) - } - r.tag(w, openTag, attrs) - } else { - r.out(w, closeTag) - r.cr(w) - } - case TableHead: - if entering { - r.cr(w) - r.out(w, theadTag) - } else { - r.out(w, theadCloseTag) - r.cr(w) - } - case TableBody: - if entering { - r.cr(w) - r.out(w, tbodyTag) - // XXX: this is to adhere to a rather silly test. Should fix test. - if node.FirstChild == nil { - r.cr(w) - } - } else { - r.out(w, tbodyCloseTag) - r.cr(w) - } - case TableRow: - if entering { - r.cr(w) - r.out(w, trTag) - } else { - r.out(w, trCloseTag) - r.cr(w) - } - default: - panic("Unknown node type " + node.Type.String()) - } - return GoToNext -} - -// RenderHeader writes HTML document preamble and TOC if requested. -func (r *HTMLRenderer) RenderHeader(w io.Writer, ast *Node) { - r.writeDocumentHeader(w) - if r.Flags&TOC != 0 { - r.writeTOC(w, ast) - } -} - -// RenderFooter writes HTML document footer. -func (r *HTMLRenderer) RenderFooter(w io.Writer, ast *Node) { - if r.Flags&CompletePage == 0 { - return - } - io.WriteString(w, "\n\n\n") -} - -func (r *HTMLRenderer) writeDocumentHeader(w io.Writer) { - if r.Flags&CompletePage == 0 { - return - } - ending := "" - if r.Flags&UseXHTML != 0 { - io.WriteString(w, "\n") - io.WriteString(w, "\n") - ending = " /" - } else { - io.WriteString(w, "\n") - io.WriteString(w, "\n") - } - io.WriteString(w, "\n") - io.WriteString(w, " ") - if r.Flags&Smartypants != 0 { - r.sr.Process(w, []byte(r.Title)) - } else { - escapeHTML(w, []byte(r.Title)) - } - io.WriteString(w, "\n") - io.WriteString(w, " \n") - io.WriteString(w, " \n") - if r.CSS != "" { - io.WriteString(w, " \n") - } - if r.Icon != "" { - io.WriteString(w, " \n") - } - io.WriteString(w, "\n") - io.WriteString(w, "\n\n") -} - -func (r *HTMLRenderer) writeTOC(w io.Writer, ast *Node) { - buf := bytes.Buffer{} - - inHeading := false - tocLevel := 0 - headingCount := 0 - - ast.Walk(func(node *Node, entering bool) WalkStatus { - if node.Type == Heading && !node.HeadingData.IsTitleblock { - inHeading = entering - if entering { - node.HeadingID = fmt.Sprintf("toc_%d", headingCount) - if node.Level == tocLevel { - buf.WriteString("\n\n
  • ") - } else if node.Level < tocLevel { - for node.Level < tocLevel { - tocLevel-- - buf.WriteString("
  • \n") - } - buf.WriteString("\n\n
  • ") - } else { - for node.Level > tocLevel { - tocLevel++ - buf.WriteString("\n") - } - - if buf.Len() > 0 { - io.WriteString(w, "\n") - } - r.lastOutputLen = buf.Len() -} diff --git a/vendor/github.com/russross/blackfriday/v2/inline.go b/vendor/github.com/russross/blackfriday/v2/inline.go deleted file mode 100644 index d45bd941726..00000000000 --- a/vendor/github.com/russross/blackfriday/v2/inline.go +++ /dev/null @@ -1,1228 +0,0 @@ -// -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross . -// Distributed under the Simplified BSD License. -// See README.md for details. -// - -// -// Functions to parse inline elements. -// - -package blackfriday - -import ( - "bytes" - "regexp" - "strconv" -) - -var ( - urlRe = `((https?|ftp):\/\/|\/)[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+` - anchorRe = regexp.MustCompile(`^(]+")?\s?>` + urlRe + `<\/a>)`) - - // https://www.w3.org/TR/html5/syntax.html#character-references - // highest unicode code point in 17 planes (2^20): 1,114,112d = - // 7 dec digits or 6 hex digits - // named entity references can be 2-31 characters with stuff like < - // at one end and ∳ at the other. There - // are also sometimes numbers at the end, although this isn't inherent - // in the specification; there are never numbers anywhere else in - // current character references, though; see ¾ and ▒, etc. - // https://www.w3.org/TR/html5/syntax.html#named-character-references - // - // entity := "&" (named group | number ref) ";" - // named group := [a-zA-Z]{2,31}[0-9]{0,2} - // number ref := "#" (dec ref | hex ref) - // dec ref := [0-9]{1,7} - // hex ref := ("x" | "X") [0-9a-fA-F]{1,6} - htmlEntityRe = regexp.MustCompile(`&([a-zA-Z]{2,31}[0-9]{0,2}|#([0-9]{1,7}|[xX][0-9a-fA-F]{1,6}));`) -) - -// Functions to parse text within a block -// Each function returns the number of chars taken care of -// data is the complete block being rendered -// offset is the number of valid chars before the current cursor - -func (p *Markdown) inline(currBlock *Node, data []byte) { - // handlers might call us recursively: enforce a maximum depth - if p.nesting >= p.maxNesting || len(data) == 0 { - return - } - p.nesting++ - beg, end := 0, 0 - for end < len(data) { - handler := p.inlineCallback[data[end]] - if handler != nil { - if consumed, node := handler(p, data, end); consumed == 0 { - // No action from the callback. - end++ - } else { - // Copy inactive chars into the output. - currBlock.AppendChild(text(data[beg:end])) - if node != nil { - currBlock.AppendChild(node) - } - // Skip past whatever the callback used. - beg = end + consumed - end = beg - } - } else { - end++ - } - } - if beg < len(data) { - if data[end-1] == '\n' { - end-- - } - currBlock.AppendChild(text(data[beg:end])) - } - p.nesting-- -} - -// single and double emphasis parsing -func emphasis(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - c := data[0] - - if len(data) > 2 && data[1] != c { - // whitespace cannot follow an opening emphasis; - // strikethrough only takes two characters '~~' - if c == '~' || isspace(data[1]) { - return 0, nil - } - ret, node := helperEmphasis(p, data[1:], c) - if ret == 0 { - return 0, nil - } - - return ret + 1, node - } - - if len(data) > 3 && data[1] == c && data[2] != c { - if isspace(data[2]) { - return 0, nil - } - ret, node := helperDoubleEmphasis(p, data[2:], c) - if ret == 0 { - return 0, nil - } - - return ret + 2, node - } - - if len(data) > 4 && data[1] == c && data[2] == c && data[3] != c { - if c == '~' || isspace(data[3]) { - return 0, nil - } - ret, node := helperTripleEmphasis(p, data, 3, c) - if ret == 0 { - return 0, nil - } - - return ret + 3, node - } - - return 0, nil -} - -func codeSpan(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - - nb := 0 - - // count the number of backticks in the delimiter - for nb < len(data) && data[nb] == '`' { - nb++ - } - - // find the next delimiter - i, end := 0, 0 - for end = nb; end < len(data) && i < nb; end++ { - if data[end] == '`' { - i++ - } else { - i = 0 - } - } - - // no matching delimiter? - if i < nb && end >= len(data) { - return 0, nil - } - - // trim outside whitespace - fBegin := nb - for fBegin < end && data[fBegin] == ' ' { - fBegin++ - } - - fEnd := end - nb - for fEnd > fBegin && data[fEnd-1] == ' ' { - fEnd-- - } - - // render the code span - if fBegin != fEnd { - code := NewNode(Code) - code.Literal = data[fBegin:fEnd] - return end, code - } - - return end, nil -} - -// newline preceded by two spaces becomes
    -func maybeLineBreak(p *Markdown, data []byte, offset int) (int, *Node) { - origOffset := offset - for offset < len(data) && data[offset] == ' ' { - offset++ - } - - if offset < len(data) && data[offset] == '\n' { - if offset-origOffset >= 2 { - return offset - origOffset + 1, NewNode(Hardbreak) - } - return offset - origOffset, nil - } - return 0, nil -} - -// newline without two spaces works when HardLineBreak is enabled -func lineBreak(p *Markdown, data []byte, offset int) (int, *Node) { - if p.extensions&HardLineBreak != 0 { - return 1, NewNode(Hardbreak) - } - return 0, nil -} - -type linkType int - -const ( - linkNormal linkType = iota - linkImg - linkDeferredFootnote - linkInlineFootnote -) - -func isReferenceStyleLink(data []byte, pos int, t linkType) bool { - if t == linkDeferredFootnote { - return false - } - return pos < len(data)-1 && data[pos] == '[' && data[pos+1] != '^' -} - -func maybeImage(p *Markdown, data []byte, offset int) (int, *Node) { - if offset < len(data)-1 && data[offset+1] == '[' { - return link(p, data, offset) - } - return 0, nil -} - -func maybeInlineFootnote(p *Markdown, data []byte, offset int) (int, *Node) { - if offset < len(data)-1 && data[offset+1] == '[' { - return link(p, data, offset) - } - return 0, nil -} - -// '[': parse a link or an image or a footnote -func link(p *Markdown, data []byte, offset int) (int, *Node) { - // no links allowed inside regular links, footnote, and deferred footnotes - if p.insideLink && (offset > 0 && data[offset-1] == '[' || len(data)-1 > offset && data[offset+1] == '^') { - return 0, nil - } - - var t linkType - switch { - // special case: ![^text] == deferred footnote (that follows something with - // an exclamation point) - case p.extensions&Footnotes != 0 && len(data)-1 > offset && data[offset+1] == '^': - t = linkDeferredFootnote - // ![alt] == image - case offset >= 0 && data[offset] == '!': - t = linkImg - offset++ - // ^[text] == inline footnote - // [^refId] == deferred footnote - case p.extensions&Footnotes != 0: - if offset >= 0 && data[offset] == '^' { - t = linkInlineFootnote - offset++ - } else if len(data)-1 > offset && data[offset+1] == '^' { - t = linkDeferredFootnote - } - // [text] == regular link - default: - t = linkNormal - } - - data = data[offset:] - - var ( - i = 1 - noteID int - title, link, altContent []byte - textHasNl = false - ) - - if t == linkDeferredFootnote { - i++ - } - - // look for the matching closing bracket - for level := 1; level > 0 && i < len(data); i++ { - switch { - case data[i] == '\n': - textHasNl = true - - case isBackslashEscaped(data, i): - continue - - case data[i] == '[': - level++ - - case data[i] == ']': - level-- - if level <= 0 { - i-- // compensate for extra i++ in for loop - } - } - } - - if i >= len(data) { - return 0, nil - } - - txtE := i - i++ - var footnoteNode *Node - - // skip any amount of whitespace or newline - // (this is much more lax than original markdown syntax) - for i < len(data) && isspace(data[i]) { - i++ - } - - // inline style link - switch { - case i < len(data) && data[i] == '(': - // skip initial whitespace - i++ - - for i < len(data) && isspace(data[i]) { - i++ - } - - linkB := i - - // look for link end: ' " ) - findlinkend: - for i < len(data) { - switch { - case data[i] == '\\': - i += 2 - - case data[i] == ')' || data[i] == '\'' || data[i] == '"': - break findlinkend - - default: - i++ - } - } - - if i >= len(data) { - return 0, nil - } - linkE := i - - // look for title end if present - titleB, titleE := 0, 0 - if data[i] == '\'' || data[i] == '"' { - i++ - titleB = i - - findtitleend: - for i < len(data) { - switch { - case data[i] == '\\': - i += 2 - - case data[i] == ')': - break findtitleend - - default: - i++ - } - } - - if i >= len(data) { - return 0, nil - } - - // skip whitespace after title - titleE = i - 1 - for titleE > titleB && isspace(data[titleE]) { - titleE-- - } - - // check for closing quote presence - if data[titleE] != '\'' && data[titleE] != '"' { - titleB, titleE = 0, 0 - linkE = i - } - } - - // remove whitespace at the end of the link - for linkE > linkB && isspace(data[linkE-1]) { - linkE-- - } - - // remove optional angle brackets around the link - if data[linkB] == '<' { - linkB++ - } - if data[linkE-1] == '>' { - linkE-- - } - - // build escaped link and title - if linkE > linkB { - link = data[linkB:linkE] - } - - if titleE > titleB { - title = data[titleB:titleE] - } - - i++ - - // reference style link - case isReferenceStyleLink(data, i, t): - var id []byte - altContentConsidered := false - - // look for the id - i++ - linkB := i - for i < len(data) && data[i] != ']' { - i++ - } - if i >= len(data) { - return 0, nil - } - linkE := i - - // find the reference - if linkB == linkE { - if textHasNl { - var b bytes.Buffer - - for j := 1; j < txtE; j++ { - switch { - case data[j] != '\n': - b.WriteByte(data[j]) - case data[j-1] != ' ': - b.WriteByte(' ') - } - } - - id = b.Bytes() - } else { - id = data[1:txtE] - altContentConsidered = true - } - } else { - id = data[linkB:linkE] - } - - // find the reference with matching id - lr, ok := p.getRef(string(id)) - if !ok { - return 0, nil - } - - // keep link and title from reference - link = lr.link - title = lr.title - if altContentConsidered { - altContent = lr.text - } - i++ - - // shortcut reference style link or reference or inline footnote - default: - var id []byte - - // craft the id - if textHasNl { - var b bytes.Buffer - - for j := 1; j < txtE; j++ { - switch { - case data[j] != '\n': - b.WriteByte(data[j]) - case data[j-1] != ' ': - b.WriteByte(' ') - } - } - - id = b.Bytes() - } else { - if t == linkDeferredFootnote { - id = data[2:txtE] // get rid of the ^ - } else { - id = data[1:txtE] - } - } - - footnoteNode = NewNode(Item) - if t == linkInlineFootnote { - // create a new reference - noteID = len(p.notes) + 1 - - var fragment []byte - if len(id) > 0 { - if len(id) < 16 { - fragment = make([]byte, len(id)) - } else { - fragment = make([]byte, 16) - } - copy(fragment, slugify(id)) - } else { - fragment = append([]byte("footnote-"), []byte(strconv.Itoa(noteID))...) - } - - ref := &reference{ - noteID: noteID, - hasBlock: false, - link: fragment, - title: id, - footnote: footnoteNode, - } - - p.notes = append(p.notes, ref) - - link = ref.link - title = ref.title - } else { - // find the reference with matching id - lr, ok := p.getRef(string(id)) - if !ok { - return 0, nil - } - - if t == linkDeferredFootnote { - lr.noteID = len(p.notes) + 1 - lr.footnote = footnoteNode - p.notes = append(p.notes, lr) - } - - // keep link and title from reference - link = lr.link - // if inline footnote, title == footnote contents - title = lr.title - noteID = lr.noteID - } - - // rewind the whitespace - i = txtE + 1 - } - - var uLink []byte - if t == linkNormal || t == linkImg { - if len(link) > 0 { - var uLinkBuf bytes.Buffer - unescapeText(&uLinkBuf, link) - uLink = uLinkBuf.Bytes() - } - - // links need something to click on and somewhere to go - if len(uLink) == 0 || (t == linkNormal && txtE <= 1) { - return 0, nil - } - } - - // call the relevant rendering function - var linkNode *Node - switch t { - case linkNormal: - linkNode = NewNode(Link) - linkNode.Destination = normalizeURI(uLink) - linkNode.Title = title - if len(altContent) > 0 { - linkNode.AppendChild(text(altContent)) - } else { - // links cannot contain other links, so turn off link parsing - // temporarily and recurse - insideLink := p.insideLink - p.insideLink = true - p.inline(linkNode, data[1:txtE]) - p.insideLink = insideLink - } - - case linkImg: - linkNode = NewNode(Image) - linkNode.Destination = uLink - linkNode.Title = title - linkNode.AppendChild(text(data[1:txtE])) - i++ - - case linkInlineFootnote, linkDeferredFootnote: - linkNode = NewNode(Link) - linkNode.Destination = link - linkNode.Title = title - linkNode.NoteID = noteID - linkNode.Footnote = footnoteNode - if t == linkInlineFootnote { - i++ - } - - default: - return 0, nil - } - - return i, linkNode -} - -func (p *Markdown) inlineHTMLComment(data []byte) int { - if len(data) < 5 { - return 0 - } - if data[0] != '<' || data[1] != '!' || data[2] != '-' || data[3] != '-' { - return 0 - } - i := 5 - // scan for an end-of-comment marker, across lines if necessary - for i < len(data) && !(data[i-2] == '-' && data[i-1] == '-' && data[i] == '>') { - i++ - } - // no end-of-comment marker - if i >= len(data) { - return 0 - } - return i + 1 -} - -func stripMailto(link []byte) []byte { - if bytes.HasPrefix(link, []byte("mailto://")) { - return link[9:] - } else if bytes.HasPrefix(link, []byte("mailto:")) { - return link[7:] - } else { - return link - } -} - -// autolinkType specifies a kind of autolink that gets detected. -type autolinkType int - -// These are the possible flag values for the autolink renderer. -const ( - notAutolink autolinkType = iota - normalAutolink - emailAutolink -) - -// '<' when tags or autolinks are allowed -func leftAngle(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - altype, end := tagLength(data) - if size := p.inlineHTMLComment(data); size > 0 { - end = size - } - if end > 2 { - if altype != notAutolink { - var uLink bytes.Buffer - unescapeText(&uLink, data[1:end+1-2]) - if uLink.Len() > 0 { - link := uLink.Bytes() - node := NewNode(Link) - node.Destination = link - if altype == emailAutolink { - node.Destination = append([]byte("mailto:"), link...) - } - node.AppendChild(text(stripMailto(link))) - return end, node - } - } else { - htmlTag := NewNode(HTMLSpan) - htmlTag.Literal = data[:end] - return end, htmlTag - } - } - - return end, nil -} - -// '\\' backslash escape -var escapeChars = []byte("\\`*_{}[]()#+-.!:|&<>~") - -func escape(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - - if len(data) > 1 { - if p.extensions&BackslashLineBreak != 0 && data[1] == '\n' { - return 2, NewNode(Hardbreak) - } - if bytes.IndexByte(escapeChars, data[1]) < 0 { - return 0, nil - } - - return 2, text(data[1:2]) - } - - return 2, nil -} - -func unescapeText(ob *bytes.Buffer, src []byte) { - i := 0 - for i < len(src) { - org := i - for i < len(src) && src[i] != '\\' { - i++ - } - - if i > org { - ob.Write(src[org:i]) - } - - if i+1 >= len(src) { - break - } - - ob.WriteByte(src[i+1]) - i += 2 - } -} - -// '&' escaped when it doesn't belong to an entity -// valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; -func entity(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - - end := 1 - - if end < len(data) && data[end] == '#' { - end++ - } - - for end < len(data) && isalnum(data[end]) { - end++ - } - - if end < len(data) && data[end] == ';' { - end++ // real entity - } else { - return 0, nil // lone '&' - } - - ent := data[:end] - // undo & escaping or it will be converted to &amp; by another - // escaper in the renderer - if bytes.Equal(ent, []byte("&")) { - ent = []byte{'&'} - } - - return end, text(ent) -} - -func linkEndsWithEntity(data []byte, linkEnd int) bool { - entityRanges := htmlEntityRe.FindAllIndex(data[:linkEnd], -1) - return entityRanges != nil && entityRanges[len(entityRanges)-1][1] == linkEnd -} - -// hasPrefixCaseInsensitive is a custom implementation of -// strings.HasPrefix(strings.ToLower(s), prefix) -// we rolled our own because ToLower pulls in a huge machinery of lowercasing -// anything from Unicode and that's very slow. Since this func will only be -// used on ASCII protocol prefixes, we can take shortcuts. -func hasPrefixCaseInsensitive(s, prefix []byte) bool { - if len(s) < len(prefix) { - return false - } - delta := byte('a' - 'A') - for i, b := range prefix { - if b != s[i] && b != s[i]+delta { - return false - } - } - return true -} - -var protocolPrefixes = [][]byte{ - []byte("http://"), - []byte("https://"), - []byte("ftp://"), - []byte("file://"), - []byte("mailto:"), -} - -const shortestPrefix = 6 // len("ftp://"), the shortest of the above - -func maybeAutoLink(p *Markdown, data []byte, offset int) (int, *Node) { - // quick check to rule out most false hits - if p.insideLink || len(data) < offset+shortestPrefix { - return 0, nil - } - for _, prefix := range protocolPrefixes { - endOfHead := offset + 8 // 8 is the len() of the longest prefix - if endOfHead > len(data) { - endOfHead = len(data) - } - if hasPrefixCaseInsensitive(data[offset:endOfHead], prefix) { - return autoLink(p, data, offset) - } - } - return 0, nil -} - -func autoLink(p *Markdown, data []byte, offset int) (int, *Node) { - // Now a more expensive check to see if we're not inside an anchor element - anchorStart := offset - offsetFromAnchor := 0 - for anchorStart > 0 && data[anchorStart] != '<' { - anchorStart-- - offsetFromAnchor++ - } - - anchorStr := anchorRe.Find(data[anchorStart:]) - if anchorStr != nil { - anchorClose := NewNode(HTMLSpan) - anchorClose.Literal = anchorStr[offsetFromAnchor:] - return len(anchorStr) - offsetFromAnchor, anchorClose - } - - // scan backward for a word boundary - rewind := 0 - for offset-rewind > 0 && rewind <= 7 && isletter(data[offset-rewind-1]) { - rewind++ - } - if rewind > 6 { // longest supported protocol is "mailto" which has 6 letters - return 0, nil - } - - origData := data - data = data[offset-rewind:] - - if !isSafeLink(data) { - return 0, nil - } - - linkEnd := 0 - for linkEnd < len(data) && !isEndOfLink(data[linkEnd]) { - linkEnd++ - } - - // Skip punctuation at the end of the link - if (data[linkEnd-1] == '.' || data[linkEnd-1] == ',') && data[linkEnd-2] != '\\' { - linkEnd-- - } - - // But don't skip semicolon if it's a part of escaped entity: - if data[linkEnd-1] == ';' && data[linkEnd-2] != '\\' && !linkEndsWithEntity(data, linkEnd) { - linkEnd-- - } - - // See if the link finishes with a punctuation sign that can be closed. - var copen byte - switch data[linkEnd-1] { - case '"': - copen = '"' - case '\'': - copen = '\'' - case ')': - copen = '(' - case ']': - copen = '[' - case '}': - copen = '{' - default: - copen = 0 - } - - if copen != 0 { - bufEnd := offset - rewind + linkEnd - 2 - - openDelim := 1 - - /* Try to close the final punctuation sign in this same line; - * if we managed to close it outside of the URL, that means that it's - * not part of the URL. If it closes inside the URL, that means it - * is part of the URL. - * - * Examples: - * - * foo http://www.pokemon.com/Pikachu_(Electric) bar - * => http://www.pokemon.com/Pikachu_(Electric) - * - * foo (http://www.pokemon.com/Pikachu_(Electric)) bar - * => http://www.pokemon.com/Pikachu_(Electric) - * - * foo http://www.pokemon.com/Pikachu_(Electric)) bar - * => http://www.pokemon.com/Pikachu_(Electric)) - * - * (foo http://www.pokemon.com/Pikachu_(Electric)) bar - * => foo http://www.pokemon.com/Pikachu_(Electric) - */ - - for bufEnd >= 0 && origData[bufEnd] != '\n' && openDelim != 0 { - if origData[bufEnd] == data[linkEnd-1] { - openDelim++ - } - - if origData[bufEnd] == copen { - openDelim-- - } - - bufEnd-- - } - - if openDelim == 0 { - linkEnd-- - } - } - - var uLink bytes.Buffer - unescapeText(&uLink, data[:linkEnd]) - - if uLink.Len() > 0 { - node := NewNode(Link) - node.Destination = uLink.Bytes() - node.AppendChild(text(uLink.Bytes())) - return linkEnd, node - } - - return linkEnd, nil -} - -func isEndOfLink(char byte) bool { - return isspace(char) || char == '<' -} - -var validUris = [][]byte{[]byte("http://"), []byte("https://"), []byte("ftp://"), []byte("mailto://")} -var validPaths = [][]byte{[]byte("/"), []byte("./"), []byte("../")} - -func isSafeLink(link []byte) bool { - for _, path := range validPaths { - if len(link) >= len(path) && bytes.Equal(link[:len(path)], path) { - if len(link) == len(path) { - return true - } else if isalnum(link[len(path)]) { - return true - } - } - } - - for _, prefix := range validUris { - // TODO: handle unicode here - // case-insensitive prefix test - if len(link) > len(prefix) && bytes.Equal(bytes.ToLower(link[:len(prefix)]), prefix) && isalnum(link[len(prefix)]) { - return true - } - } - - return false -} - -// return the length of the given tag, or 0 is it's not valid -func tagLength(data []byte) (autolink autolinkType, end int) { - var i, j int - - // a valid tag can't be shorter than 3 chars - if len(data) < 3 { - return notAutolink, 0 - } - - // begins with a '<' optionally followed by '/', followed by letter or number - if data[0] != '<' { - return notAutolink, 0 - } - if data[1] == '/' { - i = 2 - } else { - i = 1 - } - - if !isalnum(data[i]) { - return notAutolink, 0 - } - - // scheme test - autolink = notAutolink - - // try to find the beginning of an URI - for i < len(data) && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-') { - i++ - } - - if i > 1 && i < len(data) && data[i] == '@' { - if j = isMailtoAutoLink(data[i:]); j != 0 { - return emailAutolink, i + j - } - } - - if i > 2 && i < len(data) && data[i] == ':' { - autolink = normalAutolink - i++ - } - - // complete autolink test: no whitespace or ' or " - switch { - case i >= len(data): - autolink = notAutolink - case autolink != notAutolink: - j = i - - for i < len(data) { - if data[i] == '\\' { - i += 2 - } else if data[i] == '>' || data[i] == '\'' || data[i] == '"' || isspace(data[i]) { - break - } else { - i++ - } - - } - - if i >= len(data) { - return autolink, 0 - } - if i > j && data[i] == '>' { - return autolink, i + 1 - } - - // one of the forbidden chars has been found - autolink = notAutolink - } - i += bytes.IndexByte(data[i:], '>') - if i < 0 { - return autolink, 0 - } - return autolink, i + 1 -} - -// look for the address part of a mail autolink and '>' -// this is less strict than the original markdown e-mail address matching -func isMailtoAutoLink(data []byte) int { - nb := 0 - - // address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' - for i := 0; i < len(data); i++ { - if isalnum(data[i]) { - continue - } - - switch data[i] { - case '@': - nb++ - - case '-', '.', '_': - break - - case '>': - if nb == 1 { - return i + 1 - } - return 0 - default: - return 0 - } - } - - return 0 -} - -// look for the next emph char, skipping other constructs -func helperFindEmphChar(data []byte, c byte) int { - i := 0 - - for i < len(data) { - for i < len(data) && data[i] != c && data[i] != '`' && data[i] != '[' { - i++ - } - if i >= len(data) { - return 0 - } - // do not count escaped chars - if i != 0 && data[i-1] == '\\' { - i++ - continue - } - if data[i] == c { - return i - } - - if data[i] == '`' { - // skip a code span - tmpI := 0 - i++ - for i < len(data) && data[i] != '`' { - if tmpI == 0 && data[i] == c { - tmpI = i - } - i++ - } - if i >= len(data) { - return tmpI - } - i++ - } else if data[i] == '[' { - // skip a link - tmpI := 0 - i++ - for i < len(data) && data[i] != ']' { - if tmpI == 0 && data[i] == c { - tmpI = i - } - i++ - } - i++ - for i < len(data) && (data[i] == ' ' || data[i] == '\n') { - i++ - } - if i >= len(data) { - return tmpI - } - if data[i] != '[' && data[i] != '(' { // not a link - if tmpI > 0 { - return tmpI - } - continue - } - cc := data[i] - i++ - for i < len(data) && data[i] != cc { - if tmpI == 0 && data[i] == c { - return i - } - i++ - } - if i >= len(data) { - return tmpI - } - i++ - } - } - return 0 -} - -func helperEmphasis(p *Markdown, data []byte, c byte) (int, *Node) { - i := 0 - - // skip one symbol if coming from emph3 - if len(data) > 1 && data[0] == c && data[1] == c { - i = 1 - } - - for i < len(data) { - length := helperFindEmphChar(data[i:], c) - if length == 0 { - return 0, nil - } - i += length - if i >= len(data) { - return 0, nil - } - - if i+1 < len(data) && data[i+1] == c { - i++ - continue - } - - if data[i] == c && !isspace(data[i-1]) { - - if p.extensions&NoIntraEmphasis != 0 { - if !(i+1 == len(data) || isspace(data[i+1]) || ispunct(data[i+1])) { - continue - } - } - - emph := NewNode(Emph) - p.inline(emph, data[:i]) - return i + 1, emph - } - } - - return 0, nil -} - -func helperDoubleEmphasis(p *Markdown, data []byte, c byte) (int, *Node) { - i := 0 - - for i < len(data) { - length := helperFindEmphChar(data[i:], c) - if length == 0 { - return 0, nil - } - i += length - - if i+1 < len(data) && data[i] == c && data[i+1] == c && i > 0 && !isspace(data[i-1]) { - nodeType := Strong - if c == '~' { - nodeType = Del - } - node := NewNode(nodeType) - p.inline(node, data[:i]) - return i + 2, node - } - i++ - } - return 0, nil -} - -func helperTripleEmphasis(p *Markdown, data []byte, offset int, c byte) (int, *Node) { - i := 0 - origData := data - data = data[offset:] - - for i < len(data) { - length := helperFindEmphChar(data[i:], c) - if length == 0 { - return 0, nil - } - i += length - - // skip whitespace preceded symbols - if data[i] != c || isspace(data[i-1]) { - continue - } - - switch { - case i+2 < len(data) && data[i+1] == c && data[i+2] == c: - // triple symbol found - strong := NewNode(Strong) - em := NewNode(Emph) - strong.AppendChild(em) - p.inline(em, data[:i]) - return i + 3, strong - case (i+1 < len(data) && data[i+1] == c): - // double symbol found, hand over to emph1 - length, node := helperEmphasis(p, origData[offset-2:], c) - if length == 0 { - return 0, nil - } - return length - 2, node - default: - // single symbol found, hand over to emph2 - length, node := helperDoubleEmphasis(p, origData[offset-1:], c) - if length == 0 { - return 0, nil - } - return length - 1, node - } - } - return 0, nil -} - -func text(s []byte) *Node { - node := NewNode(Text) - node.Literal = s - return node -} - -func normalizeURI(s []byte) []byte { - return s // TODO: implement -} diff --git a/vendor/github.com/russross/blackfriday/v2/markdown.go b/vendor/github.com/russross/blackfriday/v2/markdown.go deleted file mode 100644 index 58d2e4538c6..00000000000 --- a/vendor/github.com/russross/blackfriday/v2/markdown.go +++ /dev/null @@ -1,950 +0,0 @@ -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross . -// Distributed under the Simplified BSD License. -// See README.md for details. - -package blackfriday - -import ( - "bytes" - "fmt" - "io" - "strings" - "unicode/utf8" -) - -// -// Markdown parsing and processing -// - -// Version string of the package. Appears in the rendered document when -// CompletePage flag is on. -const Version = "2.0" - -// Extensions is a bitwise or'ed collection of enabled Blackfriday's -// extensions. -type Extensions int - -// These are the supported markdown parsing extensions. -// OR these values together to select multiple extensions. -const ( - NoExtensions Extensions = 0 - NoIntraEmphasis Extensions = 1 << iota // Ignore emphasis markers inside words - Tables // Render tables - FencedCode // Render fenced code blocks - Autolink // Detect embedded URLs that are not explicitly marked - Strikethrough // Strikethrough text using ~~test~~ - LaxHTMLBlocks // Loosen up HTML block parsing rules - SpaceHeadings // Be strict about prefix heading rules - HardLineBreak // Translate newlines into line breaks - TabSizeEight // Expand tabs to eight spaces instead of four - Footnotes // Pandoc-style footnotes - NoEmptyLineBeforeBlock // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block - HeadingIDs // specify heading IDs with {#id} - Titleblock // Titleblock ala pandoc - AutoHeadingIDs // Create the heading ID from the text - BackslashLineBreak // Translate trailing backslashes into line breaks - DefinitionLists // Render definition lists - - CommonHTMLFlags HTMLFlags = UseXHTML | Smartypants | - SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes - - CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode | - Autolink | Strikethrough | SpaceHeadings | HeadingIDs | - BackslashLineBreak | DefinitionLists -) - -// ListType contains bitwise or'ed flags for list and list item objects. -type ListType int - -// These are the possible flag values for the ListItem renderer. -// Multiple flag values may be ORed together. -// These are mostly of interest if you are writing a new output format. -const ( - ListTypeOrdered ListType = 1 << iota - ListTypeDefinition - ListTypeTerm - - ListItemContainsBlock - ListItemBeginningOfList // TODO: figure out if this is of any use now - ListItemEndOfList -) - -// CellAlignFlags holds a type of alignment in a table cell. -type CellAlignFlags int - -// These are the possible flag values for the table cell renderer. -// Only a single one of these values will be used; they are not ORed together. -// These are mostly of interest if you are writing a new output format. -const ( - TableAlignmentLeft CellAlignFlags = 1 << iota - TableAlignmentRight - TableAlignmentCenter = (TableAlignmentLeft | TableAlignmentRight) -) - -// The size of a tab stop. -const ( - TabSizeDefault = 4 - TabSizeDouble = 8 -) - -// blockTags is a set of tags that are recognized as HTML block tags. -// Any of these can be included in markdown text without special escaping. -var blockTags = map[string]struct{}{ - "blockquote": {}, - "del": {}, - "div": {}, - "dl": {}, - "fieldset": {}, - "form": {}, - "h1": {}, - "h2": {}, - "h3": {}, - "h4": {}, - "h5": {}, - "h6": {}, - "iframe": {}, - "ins": {}, - "math": {}, - "noscript": {}, - "ol": {}, - "pre": {}, - "p": {}, - "script": {}, - "style": {}, - "table": {}, - "ul": {}, - - // HTML5 - "address": {}, - "article": {}, - "aside": {}, - "canvas": {}, - "figcaption": {}, - "figure": {}, - "footer": {}, - "header": {}, - "hgroup": {}, - "main": {}, - "nav": {}, - "output": {}, - "progress": {}, - "section": {}, - "video": {}, -} - -// Renderer is the rendering interface. This is mostly of interest if you are -// implementing a new rendering format. -// -// Only an HTML implementation is provided in this repository, see the README -// for external implementations. -type Renderer interface { - // RenderNode is the main rendering method. It will be called once for - // every leaf node and twice for every non-leaf node (first with - // entering=true, then with entering=false). The method should write its - // rendition of the node to the supplied writer w. - RenderNode(w io.Writer, node *Node, entering bool) WalkStatus - - // RenderHeader is a method that allows the renderer to produce some - // content preceding the main body of the output document. The header is - // understood in the broad sense here. For example, the default HTML - // renderer will write not only the HTML document preamble, but also the - // table of contents if it was requested. - // - // The method will be passed an entire document tree, in case a particular - // implementation needs to inspect it to produce output. - // - // The output should be written to the supplied writer w. If your - // implementation has no header to write, supply an empty implementation. - RenderHeader(w io.Writer, ast *Node) - - // RenderFooter is a symmetric counterpart of RenderHeader. - RenderFooter(w io.Writer, ast *Node) -} - -// Callback functions for inline parsing. One such function is defined -// for each character that triggers a response when parsing inline data. -type inlineParser func(p *Markdown, data []byte, offset int) (int, *Node) - -// Markdown is a type that holds extensions and the runtime state used by -// Parse, and the renderer. You can not use it directly, construct it with New. -type Markdown struct { - renderer Renderer - referenceOverride ReferenceOverrideFunc - refs map[string]*reference - inlineCallback [256]inlineParser - extensions Extensions - nesting int - maxNesting int - insideLink bool - - // Footnotes need to be ordered as well as available to quickly check for - // presence. If a ref is also a footnote, it's stored both in refs and here - // in notes. Slice is nil if footnotes not enabled. - notes []*reference - - doc *Node - tip *Node // = doc - oldTip *Node - lastMatchedContainer *Node // = doc - allClosed bool -} - -func (p *Markdown) getRef(refid string) (ref *reference, found bool) { - if p.referenceOverride != nil { - r, overridden := p.referenceOverride(refid) - if overridden { - if r == nil { - return nil, false - } - return &reference{ - link: []byte(r.Link), - title: []byte(r.Title), - noteID: 0, - hasBlock: false, - text: []byte(r.Text)}, true - } - } - // refs are case insensitive - ref, found = p.refs[strings.ToLower(refid)] - return ref, found -} - -func (p *Markdown) finalize(block *Node) { - above := block.Parent - block.open = false - p.tip = above -} - -func (p *Markdown) addChild(node NodeType, offset uint32) *Node { - return p.addExistingChild(NewNode(node), offset) -} - -func (p *Markdown) addExistingChild(node *Node, offset uint32) *Node { - for !p.tip.canContain(node.Type) { - p.finalize(p.tip) - } - p.tip.AppendChild(node) - p.tip = node - return node -} - -func (p *Markdown) closeUnmatchedBlocks() { - if !p.allClosed { - for p.oldTip != p.lastMatchedContainer { - parent := p.oldTip.Parent - p.finalize(p.oldTip) - p.oldTip = parent - } - p.allClosed = true - } -} - -// -// -// Public interface -// -// - -// Reference represents the details of a link. -// See the documentation in Options for more details on use-case. -type Reference struct { - // Link is usually the URL the reference points to. - Link string - // Title is the alternate text describing the link in more detail. - Title string - // Text is the optional text to override the ref with if the syntax used was - // [refid][] - Text string -} - -// ReferenceOverrideFunc is expected to be called with a reference string and -// return either a valid Reference type that the reference string maps to or -// nil. If overridden is false, the default reference logic will be executed. -// See the documentation in Options for more details on use-case. -type ReferenceOverrideFunc func(reference string) (ref *Reference, overridden bool) - -// New constructs a Markdown processor. You can use the same With* functions as -// for Run() to customize parser's behavior and the renderer. -func New(opts ...Option) *Markdown { - var p Markdown - for _, opt := range opts { - opt(&p) - } - p.refs = make(map[string]*reference) - p.maxNesting = 16 - p.insideLink = false - docNode := NewNode(Document) - p.doc = docNode - p.tip = docNode - p.oldTip = docNode - p.lastMatchedContainer = docNode - p.allClosed = true - // register inline parsers - p.inlineCallback[' '] = maybeLineBreak - p.inlineCallback['*'] = emphasis - p.inlineCallback['_'] = emphasis - if p.extensions&Strikethrough != 0 { - p.inlineCallback['~'] = emphasis - } - p.inlineCallback['`'] = codeSpan - p.inlineCallback['\n'] = lineBreak - p.inlineCallback['['] = link - p.inlineCallback['<'] = leftAngle - p.inlineCallback['\\'] = escape - p.inlineCallback['&'] = entity - p.inlineCallback['!'] = maybeImage - p.inlineCallback['^'] = maybeInlineFootnote - if p.extensions&Autolink != 0 { - p.inlineCallback['h'] = maybeAutoLink - p.inlineCallback['m'] = maybeAutoLink - p.inlineCallback['f'] = maybeAutoLink - p.inlineCallback['H'] = maybeAutoLink - p.inlineCallback['M'] = maybeAutoLink - p.inlineCallback['F'] = maybeAutoLink - } - if p.extensions&Footnotes != 0 { - p.notes = make([]*reference, 0) - } - return &p -} - -// Option customizes the Markdown processor's default behavior. -type Option func(*Markdown) - -// WithRenderer allows you to override the default renderer. -func WithRenderer(r Renderer) Option { - return func(p *Markdown) { - p.renderer = r - } -} - -// WithExtensions allows you to pick some of the many extensions provided by -// Blackfriday. You can bitwise OR them. -func WithExtensions(e Extensions) Option { - return func(p *Markdown) { - p.extensions = e - } -} - -// WithNoExtensions turns off all extensions and custom behavior. -func WithNoExtensions() Option { - return func(p *Markdown) { - p.extensions = NoExtensions - p.renderer = NewHTMLRenderer(HTMLRendererParameters{ - Flags: HTMLFlagsNone, - }) - } -} - -// WithRefOverride sets an optional function callback that is called every -// time a reference is resolved. -// -// In Markdown, the link reference syntax can be made to resolve a link to -// a reference instead of an inline URL, in one of the following ways: -// -// * [link text][refid] -// * [refid][] -// -// Usually, the refid is defined at the bottom of the Markdown document. If -// this override function is provided, the refid is passed to the override -// function first, before consulting the defined refids at the bottom. If -// the override function indicates an override did not occur, the refids at -// the bottom will be used to fill in the link details. -func WithRefOverride(o ReferenceOverrideFunc) Option { - return func(p *Markdown) { - p.referenceOverride = o - } -} - -// Run is the main entry point to Blackfriday. It parses and renders a -// block of markdown-encoded text. -// -// The simplest invocation of Run takes one argument, input: -// output := Run(input) -// This will parse the input with CommonExtensions enabled and render it with -// the default HTMLRenderer (with CommonHTMLFlags). -// -// Variadic arguments opts can customize the default behavior. Since Markdown -// type does not contain exported fields, you can not use it directly. Instead, -// use the With* functions. For example, this will call the most basic -// functionality, with no extensions: -// output := Run(input, WithNoExtensions()) -// -// You can use any number of With* arguments, even contradicting ones. They -// will be applied in order of appearance and the latter will override the -// former: -// output := Run(input, WithNoExtensions(), WithExtensions(exts), -// WithRenderer(yourRenderer)) -func Run(input []byte, opts ...Option) []byte { - r := NewHTMLRenderer(HTMLRendererParameters{ - Flags: CommonHTMLFlags, - }) - optList := []Option{WithRenderer(r), WithExtensions(CommonExtensions)} - optList = append(optList, opts...) - parser := New(optList...) - ast := parser.Parse(input) - var buf bytes.Buffer - parser.renderer.RenderHeader(&buf, ast) - ast.Walk(func(node *Node, entering bool) WalkStatus { - return parser.renderer.RenderNode(&buf, node, entering) - }) - parser.renderer.RenderFooter(&buf, ast) - return buf.Bytes() -} - -// Parse is an entry point to the parsing part of Blackfriday. It takes an -// input markdown document and produces a syntax tree for its contents. This -// tree can then be rendered with a default or custom renderer, or -// analyzed/transformed by the caller to whatever non-standard needs they have. -// The return value is the root node of the syntax tree. -func (p *Markdown) Parse(input []byte) *Node { - p.block(input) - // Walk the tree and finish up some of unfinished blocks - for p.tip != nil { - p.finalize(p.tip) - } - // Walk the tree again and process inline markdown in each block - p.doc.Walk(func(node *Node, entering bool) WalkStatus { - if node.Type == Paragraph || node.Type == Heading || node.Type == TableCell { - p.inline(node, node.content) - node.content = nil - } - return GoToNext - }) - p.parseRefsToAST() - return p.doc -} - -func (p *Markdown) parseRefsToAST() { - if p.extensions&Footnotes == 0 || len(p.notes) == 0 { - return - } - p.tip = p.doc - block := p.addBlock(List, nil) - block.IsFootnotesList = true - block.ListFlags = ListTypeOrdered - flags := ListItemBeginningOfList - // Note: this loop is intentionally explicit, not range-form. This is - // because the body of the loop will append nested footnotes to p.notes and - // we need to process those late additions. Range form would only walk over - // the fixed initial set. - for i := 0; i < len(p.notes); i++ { - ref := p.notes[i] - p.addExistingChild(ref.footnote, 0) - block := ref.footnote - block.ListFlags = flags | ListTypeOrdered - block.RefLink = ref.link - if ref.hasBlock { - flags |= ListItemContainsBlock - p.block(ref.title) - } else { - p.inline(block, ref.title) - } - flags &^= ListItemBeginningOfList | ListItemContainsBlock - } - above := block.Parent - finalizeList(block) - p.tip = above - block.Walk(func(node *Node, entering bool) WalkStatus { - if node.Type == Paragraph || node.Type == Heading { - p.inline(node, node.content) - node.content = nil - } - return GoToNext - }) -} - -// -// Link references -// -// This section implements support for references that (usually) appear -// as footnotes in a document, and can be referenced anywhere in the document. -// The basic format is: -// -// [1]: http://www.google.com/ "Google" -// [2]: http://www.github.com/ "Github" -// -// Anywhere in the document, the reference can be linked by referring to its -// label, i.e., 1 and 2 in this example, as in: -// -// This library is hosted on [Github][2], a git hosting site. -// -// Actual footnotes as specified in Pandoc and supported by some other Markdown -// libraries such as php-markdown are also taken care of. They look like this: -// -// This sentence needs a bit of further explanation.[^note] -// -// [^note]: This is the explanation. -// -// Footnotes should be placed at the end of the document in an ordered list. -// Finally, there are inline footnotes such as: -// -// Inline footnotes^[Also supported.] provide a quick inline explanation, -// but are rendered at the bottom of the document. -// - -// reference holds all information necessary for a reference-style links or -// footnotes. -// -// Consider this markdown with reference-style links: -// -// [link][ref] -// -// [ref]: /url/ "tooltip title" -// -// It will be ultimately converted to this HTML: -// -//

    link

    -// -// And a reference structure will be populated as follows: -// -// p.refs["ref"] = &reference{ -// link: "/url/", -// title: "tooltip title", -// } -// -// Alternatively, reference can contain information about a footnote. Consider -// this markdown: -// -// Text needing a footnote.[^a] -// -// [^a]: This is the note -// -// A reference structure will be populated as follows: -// -// p.refs["a"] = &reference{ -// link: "a", -// title: "This is the note", -// noteID: , -// } -// -// TODO: As you can see, it begs for splitting into two dedicated structures -// for refs and for footnotes. -type reference struct { - link []byte - title []byte - noteID int // 0 if not a footnote ref - hasBlock bool - footnote *Node // a link to the Item node within a list of footnotes - - text []byte // only gets populated by refOverride feature with Reference.Text -} - -func (r *reference) String() string { - return fmt.Sprintf("{link: %q, title: %q, text: %q, noteID: %d, hasBlock: %v}", - r.link, r.title, r.text, r.noteID, r.hasBlock) -} - -// Check whether or not data starts with a reference link. -// If so, it is parsed and stored in the list of references -// (in the render struct). -// Returns the number of bytes to skip to move past it, -// or zero if the first line is not a reference. -func isReference(p *Markdown, data []byte, tabSize int) int { - // up to 3 optional leading spaces - if len(data) < 4 { - return 0 - } - i := 0 - for i < 3 && data[i] == ' ' { - i++ - } - - noteID := 0 - - // id part: anything but a newline between brackets - if data[i] != '[' { - return 0 - } - i++ - if p.extensions&Footnotes != 0 { - if i < len(data) && data[i] == '^' { - // we can set it to anything here because the proper noteIds will - // be assigned later during the second pass. It just has to be != 0 - noteID = 1 - i++ - } - } - idOffset := i - for i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != ']' { - i++ - } - if i >= len(data) || data[i] != ']' { - return 0 - } - idEnd := i - // footnotes can have empty ID, like this: [^], but a reference can not be - // empty like this: []. Break early if it's not a footnote and there's no ID - if noteID == 0 && idOffset == idEnd { - return 0 - } - // spacer: colon (space | tab)* newline? (space | tab)* - i++ - if i >= len(data) || data[i] != ':' { - return 0 - } - i++ - for i < len(data) && (data[i] == ' ' || data[i] == '\t') { - i++ - } - if i < len(data) && (data[i] == '\n' || data[i] == '\r') { - i++ - if i < len(data) && data[i] == '\n' && data[i-1] == '\r' { - i++ - } - } - for i < len(data) && (data[i] == ' ' || data[i] == '\t') { - i++ - } - if i >= len(data) { - return 0 - } - - var ( - linkOffset, linkEnd int - titleOffset, titleEnd int - lineEnd int - raw []byte - hasBlock bool - ) - - if p.extensions&Footnotes != 0 && noteID != 0 { - linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize) - lineEnd = linkEnd - } else { - linkOffset, linkEnd, titleOffset, titleEnd, lineEnd = scanLinkRef(p, data, i) - } - if lineEnd == 0 { - return 0 - } - - // a valid ref has been found - - ref := &reference{ - noteID: noteID, - hasBlock: hasBlock, - } - - if noteID > 0 { - // reusing the link field for the id since footnotes don't have links - ref.link = data[idOffset:idEnd] - // if footnote, it's not really a title, it's the contained text - ref.title = raw - } else { - ref.link = data[linkOffset:linkEnd] - ref.title = data[titleOffset:titleEnd] - } - - // id matches are case-insensitive - id := string(bytes.ToLower(data[idOffset:idEnd])) - - p.refs[id] = ref - - return lineEnd -} - -func scanLinkRef(p *Markdown, data []byte, i int) (linkOffset, linkEnd, titleOffset, titleEnd, lineEnd int) { - // link: whitespace-free sequence, optionally between angle brackets - if data[i] == '<' { - i++ - } - linkOffset = i - for i < len(data) && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' { - i++ - } - linkEnd = i - if data[linkOffset] == '<' && data[linkEnd-1] == '>' { - linkOffset++ - linkEnd-- - } - - // optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) - for i < len(data) && (data[i] == ' ' || data[i] == '\t') { - i++ - } - if i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != '\'' && data[i] != '"' && data[i] != '(' { - return - } - - // compute end-of-line - if i >= len(data) || data[i] == '\r' || data[i] == '\n' { - lineEnd = i - } - if i+1 < len(data) && data[i] == '\r' && data[i+1] == '\n' { - lineEnd++ - } - - // optional (space|tab)* spacer after a newline - if lineEnd > 0 { - i = lineEnd + 1 - for i < len(data) && (data[i] == ' ' || data[i] == '\t') { - i++ - } - } - - // optional title: any non-newline sequence enclosed in '"() alone on its line - if i+1 < len(data) && (data[i] == '\'' || data[i] == '"' || data[i] == '(') { - i++ - titleOffset = i - - // look for EOL - for i < len(data) && data[i] != '\n' && data[i] != '\r' { - i++ - } - if i+1 < len(data) && data[i] == '\n' && data[i+1] == '\r' { - titleEnd = i + 1 - } else { - titleEnd = i - } - - // step back - i-- - for i > titleOffset && (data[i] == ' ' || data[i] == '\t') { - i-- - } - if i > titleOffset && (data[i] == '\'' || data[i] == '"' || data[i] == ')') { - lineEnd = titleEnd - titleEnd = i - } - } - - return -} - -// The first bit of this logic is the same as Parser.listItem, but the rest -// is much simpler. This function simply finds the entire block and shifts it -// over by one tab if it is indeed a block (just returns the line if it's not). -// blockEnd is the end of the section in the input buffer, and contents is the -// extracted text that was shifted over one tab. It will need to be rendered at -// the end of the document. -func scanFootnote(p *Markdown, data []byte, i, indentSize int) (blockStart, blockEnd int, contents []byte, hasBlock bool) { - if i == 0 || len(data) == 0 { - return - } - - // skip leading whitespace on first line - for i < len(data) && data[i] == ' ' { - i++ - } - - blockStart = i - - // find the end of the line - blockEnd = i - for i < len(data) && data[i-1] != '\n' { - i++ - } - - // get working buffer - var raw bytes.Buffer - - // put the first line into the working buffer - raw.Write(data[blockEnd:i]) - blockEnd = i - - // process the following lines - containsBlankLine := false - -gatherLines: - for blockEnd < len(data) { - i++ - - // find the end of this line - for i < len(data) && data[i-1] != '\n' { - i++ - } - - // if it is an empty line, guess that it is part of this item - // and move on to the next line - if p.isEmpty(data[blockEnd:i]) > 0 { - containsBlankLine = true - blockEnd = i - continue - } - - n := 0 - if n = isIndented(data[blockEnd:i], indentSize); n == 0 { - // this is the end of the block. - // we don't want to include this last line in the index. - break gatherLines - } - - // if there were blank lines before this one, insert a new one now - if containsBlankLine { - raw.WriteByte('\n') - containsBlankLine = false - } - - // get rid of that first tab, write to buffer - raw.Write(data[blockEnd+n : i]) - hasBlock = true - - blockEnd = i - } - - if data[blockEnd-1] != '\n' { - raw.WriteByte('\n') - } - - contents = raw.Bytes() - - return -} - -// -// -// Miscellaneous helper functions -// -// - -// Test if a character is a punctuation symbol. -// Taken from a private function in regexp in the stdlib. -func ispunct(c byte) bool { - for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") { - if c == r { - return true - } - } - return false -} - -// Test if a character is a whitespace character. -func isspace(c byte) bool { - return ishorizontalspace(c) || isverticalspace(c) -} - -// Test if a character is a horizontal whitespace character. -func ishorizontalspace(c byte) bool { - return c == ' ' || c == '\t' -} - -// Test if a character is a vertical character. -func isverticalspace(c byte) bool { - return c == '\n' || c == '\r' || c == '\f' || c == '\v' -} - -// Test if a character is letter. -func isletter(c byte) bool { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') -} - -// Test if a character is a letter or a digit. -// TODO: check when this is looking for ASCII alnum and when it should use unicode -func isalnum(c byte) bool { - return (c >= '0' && c <= '9') || isletter(c) -} - -// Replace tab characters with spaces, aligning to the next TAB_SIZE column. -// always ends output with a newline -func expandTabs(out *bytes.Buffer, line []byte, tabSize int) { - // first, check for common cases: no tabs, or only tabs at beginning of line - i, prefix := 0, 0 - slowcase := false - for i = 0; i < len(line); i++ { - if line[i] == '\t' { - if prefix == i { - prefix++ - } else { - slowcase = true - break - } - } - } - - // no need to decode runes if all tabs are at the beginning of the line - if !slowcase { - for i = 0; i < prefix*tabSize; i++ { - out.WriteByte(' ') - } - out.Write(line[prefix:]) - return - } - - // the slow case: we need to count runes to figure out how - // many spaces to insert for each tab - column := 0 - i = 0 - for i < len(line) { - start := i - for i < len(line) && line[i] != '\t' { - _, size := utf8.DecodeRune(line[i:]) - i += size - column++ - } - - if i > start { - out.Write(line[start:i]) - } - - if i >= len(line) { - break - } - - for { - out.WriteByte(' ') - column++ - if column%tabSize == 0 { - break - } - } - - i++ - } -} - -// Find if a line counts as indented or not. -// Returns number of characters the indent is (0 = not indented). -func isIndented(data []byte, indentSize int) int { - if len(data) == 0 { - return 0 - } - if data[0] == '\t' { - return 1 - } - if len(data) < indentSize { - return 0 - } - for i := 0; i < indentSize; i++ { - if data[i] != ' ' { - return 0 - } - } - return indentSize -} - -// Create a url-safe slug for fragments -func slugify(in []byte) []byte { - if len(in) == 0 { - return in - } - out := make([]byte, 0, len(in)) - sym := false - - for _, ch := range in { - if isalnum(ch) { - sym = false - out = append(out, ch) - } else if sym { - continue - } else { - out = append(out, '-') - sym = true - } - } - var a, b int - var ch byte - for a, ch = range out { - if ch != '-' { - break - } - } - for b = len(out) - 1; b > 0; b-- { - if out[b] != '-' { - break - } - } - return out[a : b+1] -} diff --git a/vendor/github.com/russross/blackfriday/v2/node.go b/vendor/github.com/russross/blackfriday/v2/node.go deleted file mode 100644 index 04e6050ceea..00000000000 --- a/vendor/github.com/russross/blackfriday/v2/node.go +++ /dev/null @@ -1,360 +0,0 @@ -package blackfriday - -import ( - "bytes" - "fmt" -) - -// NodeType specifies a type of a single node of a syntax tree. Usually one -// node (and its type) corresponds to a single markdown feature, e.g. emphasis -// or code block. -type NodeType int - -// Constants for identifying different types of nodes. See NodeType. -const ( - Document NodeType = iota - BlockQuote - List - Item - Paragraph - Heading - HorizontalRule - Emph - Strong - Del - Link - Image - Text - HTMLBlock - CodeBlock - Softbreak - Hardbreak - Code - HTMLSpan - Table - TableCell - TableHead - TableBody - TableRow -) - -var nodeTypeNames = []string{ - Document: "Document", - BlockQuote: "BlockQuote", - List: "List", - Item: "Item", - Paragraph: "Paragraph", - Heading: "Heading", - HorizontalRule: "HorizontalRule", - Emph: "Emph", - Strong: "Strong", - Del: "Del", - Link: "Link", - Image: "Image", - Text: "Text", - HTMLBlock: "HTMLBlock", - CodeBlock: "CodeBlock", - Softbreak: "Softbreak", - Hardbreak: "Hardbreak", - Code: "Code", - HTMLSpan: "HTMLSpan", - Table: "Table", - TableCell: "TableCell", - TableHead: "TableHead", - TableBody: "TableBody", - TableRow: "TableRow", -} - -func (t NodeType) String() string { - return nodeTypeNames[t] -} - -// ListData contains fields relevant to a List and Item node type. -type ListData struct { - ListFlags ListType - Tight bool // Skip

    s around list item data if true - BulletChar byte // '*', '+' or '-' in bullet lists - Delimiter byte // '.' or ')' after the number in ordered lists - RefLink []byte // If not nil, turns this list item into a footnote item and triggers different rendering - IsFootnotesList bool // This is a list of footnotes -} - -// LinkData contains fields relevant to a Link node type. -type LinkData struct { - Destination []byte // Destination is what goes into a href - Title []byte // Title is the tooltip thing that goes in a title attribute - NoteID int // NoteID contains a serial number of a footnote, zero if it's not a footnote - Footnote *Node // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil. -} - -// CodeBlockData contains fields relevant to a CodeBlock node type. -type CodeBlockData struct { - IsFenced bool // Specifies whether it's a fenced code block or an indented one - Info []byte // This holds the info string - FenceChar byte - FenceLength int - FenceOffset int -} - -// TableCellData contains fields relevant to a TableCell node type. -type TableCellData struct { - IsHeader bool // This tells if it's under the header row - Align CellAlignFlags // This holds the value for align attribute -} - -// HeadingData contains fields relevant to a Heading node type. -type HeadingData struct { - Level int // This holds the heading level number - HeadingID string // This might hold heading ID, if present - IsTitleblock bool // Specifies whether it's a title block -} - -// Node is a single element in the abstract syntax tree of the parsed document. -// It holds connections to the structurally neighboring nodes and, for certain -// types of nodes, additional information that might be needed when rendering. -type Node struct { - Type NodeType // Determines the type of the node - Parent *Node // Points to the parent - FirstChild *Node // Points to the first child, if any - LastChild *Node // Points to the last child, if any - Prev *Node // Previous sibling; nil if it's the first child - Next *Node // Next sibling; nil if it's the last child - - Literal []byte // Text contents of the leaf nodes - - HeadingData // Populated if Type is Heading - ListData // Populated if Type is List - CodeBlockData // Populated if Type is CodeBlock - LinkData // Populated if Type is Link - TableCellData // Populated if Type is TableCell - - content []byte // Markdown content of the block nodes - open bool // Specifies an open block node that has not been finished to process yet -} - -// NewNode allocates a node of a specified type. -func NewNode(typ NodeType) *Node { - return &Node{ - Type: typ, - open: true, - } -} - -func (n *Node) String() string { - ellipsis := "" - snippet := n.Literal - if len(snippet) > 16 { - snippet = snippet[:16] - ellipsis = "..." - } - return fmt.Sprintf("%s: '%s%s'", n.Type, snippet, ellipsis) -} - -// Unlink removes node 'n' from the tree. -// It panics if the node is nil. -func (n *Node) Unlink() { - if n.Prev != nil { - n.Prev.Next = n.Next - } else if n.Parent != nil { - n.Parent.FirstChild = n.Next - } - if n.Next != nil { - n.Next.Prev = n.Prev - } else if n.Parent != nil { - n.Parent.LastChild = n.Prev - } - n.Parent = nil - n.Next = nil - n.Prev = nil -} - -// AppendChild adds a node 'child' as a child of 'n'. -// It panics if either node is nil. -func (n *Node) AppendChild(child *Node) { - child.Unlink() - child.Parent = n - if n.LastChild != nil { - n.LastChild.Next = child - child.Prev = n.LastChild - n.LastChild = child - } else { - n.FirstChild = child - n.LastChild = child - } -} - -// InsertBefore inserts 'sibling' immediately before 'n'. -// It panics if either node is nil. -func (n *Node) InsertBefore(sibling *Node) { - sibling.Unlink() - sibling.Prev = n.Prev - if sibling.Prev != nil { - sibling.Prev.Next = sibling - } - sibling.Next = n - n.Prev = sibling - sibling.Parent = n.Parent - if sibling.Prev == nil { - sibling.Parent.FirstChild = sibling - } -} - -// IsContainer returns true if 'n' can contain children. -func (n *Node) IsContainer() bool { - switch n.Type { - case Document: - fallthrough - case BlockQuote: - fallthrough - case List: - fallthrough - case Item: - fallthrough - case Paragraph: - fallthrough - case Heading: - fallthrough - case Emph: - fallthrough - case Strong: - fallthrough - case Del: - fallthrough - case Link: - fallthrough - case Image: - fallthrough - case Table: - fallthrough - case TableHead: - fallthrough - case TableBody: - fallthrough - case TableRow: - fallthrough - case TableCell: - return true - default: - return false - } -} - -// IsLeaf returns true if 'n' is a leaf node. -func (n *Node) IsLeaf() bool { - return !n.IsContainer() -} - -func (n *Node) canContain(t NodeType) bool { - if n.Type == List { - return t == Item - } - if n.Type == Document || n.Type == BlockQuote || n.Type == Item { - return t != Item - } - if n.Type == Table { - return t == TableHead || t == TableBody - } - if n.Type == TableHead || n.Type == TableBody { - return t == TableRow - } - if n.Type == TableRow { - return t == TableCell - } - return false -} - -// WalkStatus allows NodeVisitor to have some control over the tree traversal. -// It is returned from NodeVisitor and different values allow Node.Walk to -// decide which node to go to next. -type WalkStatus int - -const ( - // GoToNext is the default traversal of every node. - GoToNext WalkStatus = iota - // SkipChildren tells walker to skip all children of current node. - SkipChildren - // Terminate tells walker to terminate the traversal. - Terminate -) - -// NodeVisitor is a callback to be called when traversing the syntax tree. -// Called twice for every node: once with entering=true when the branch is -// first visited, then with entering=false after all the children are done. -type NodeVisitor func(node *Node, entering bool) WalkStatus - -// Walk is a convenience method that instantiates a walker and starts a -// traversal of subtree rooted at n. -func (n *Node) Walk(visitor NodeVisitor) { - w := newNodeWalker(n) - for w.current != nil { - status := visitor(w.current, w.entering) - switch status { - case GoToNext: - w.next() - case SkipChildren: - w.entering = false - w.next() - case Terminate: - return - } - } -} - -type nodeWalker struct { - current *Node - root *Node - entering bool -} - -func newNodeWalker(root *Node) *nodeWalker { - return &nodeWalker{ - current: root, - root: root, - entering: true, - } -} - -func (nw *nodeWalker) next() { - if (!nw.current.IsContainer() || !nw.entering) && nw.current == nw.root { - nw.current = nil - return - } - if nw.entering && nw.current.IsContainer() { - if nw.current.FirstChild != nil { - nw.current = nw.current.FirstChild - nw.entering = true - } else { - nw.entering = false - } - } else if nw.current.Next == nil { - nw.current = nw.current.Parent - nw.entering = false - } else { - nw.current = nw.current.Next - nw.entering = true - } -} - -func dump(ast *Node) { - fmt.Println(dumpString(ast)) -} - -func dumpR(ast *Node, depth int) string { - if ast == nil { - return "" - } - indent := bytes.Repeat([]byte("\t"), depth) - content := ast.Literal - if content == nil { - content = ast.content - } - result := fmt.Sprintf("%s%s(%q)\n", indent, ast.Type, content) - for n := ast.FirstChild; n != nil; n = n.Next { - result += dumpR(n, depth+1) - } - return result -} - -func dumpString(ast *Node) string { - return dumpR(ast, 0) -} diff --git a/vendor/github.com/russross/blackfriday/v2/smartypants.go b/vendor/github.com/russross/blackfriday/v2/smartypants.go deleted file mode 100644 index 3a220e94247..00000000000 --- a/vendor/github.com/russross/blackfriday/v2/smartypants.go +++ /dev/null @@ -1,457 +0,0 @@ -// -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross . -// Distributed under the Simplified BSD License. -// See README.md for details. -// - -// -// -// SmartyPants rendering -// -// - -package blackfriday - -import ( - "bytes" - "io" -) - -// SPRenderer is a struct containing state of a Smartypants renderer. -type SPRenderer struct { - inSingleQuote bool - inDoubleQuote bool - callbacks [256]smartCallback -} - -func wordBoundary(c byte) bool { - return c == 0 || isspace(c) || ispunct(c) -} - -func tolower(c byte) byte { - if c >= 'A' && c <= 'Z' { - return c - 'A' + 'a' - } - return c -} - -func isdigit(c byte) bool { - return c >= '0' && c <= '9' -} - -func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote byte, isOpen *bool, addNBSP bool) bool { - // edge of the buffer is likely to be a tag that we don't get to see, - // so we treat it like text sometimes - - // enumerate all sixteen possibilities for (previousChar, nextChar) - // each can be one of {0, space, punct, other} - switch { - case previousChar == 0 && nextChar == 0: - // context is not any help here, so toggle - *isOpen = !*isOpen - case isspace(previousChar) && nextChar == 0: - // [ "] might be [ "foo...] - *isOpen = true - case ispunct(previousChar) && nextChar == 0: - // [!"] hmm... could be [Run!"] or [("...] - *isOpen = false - case /* isnormal(previousChar) && */ nextChar == 0: - // [a"] is probably a close - *isOpen = false - case previousChar == 0 && isspace(nextChar): - // [" ] might be [...foo" ] - *isOpen = false - case isspace(previousChar) && isspace(nextChar): - // [ " ] context is not any help here, so toggle - *isOpen = !*isOpen - case ispunct(previousChar) && isspace(nextChar): - // [!" ] is probably a close - *isOpen = false - case /* isnormal(previousChar) && */ isspace(nextChar): - // [a" ] this is one of the easy cases - *isOpen = false - case previousChar == 0 && ispunct(nextChar): - // ["!] hmm... could be ["$1.95] or ["!...] - *isOpen = false - case isspace(previousChar) && ispunct(nextChar): - // [ "!] looks more like [ "$1.95] - *isOpen = true - case ispunct(previousChar) && ispunct(nextChar): - // [!"!] context is not any help here, so toggle - *isOpen = !*isOpen - case /* isnormal(previousChar) && */ ispunct(nextChar): - // [a"!] is probably a close - *isOpen = false - case previousChar == 0 /* && isnormal(nextChar) */ : - // ["a] is probably an open - *isOpen = true - case isspace(previousChar) /* && isnormal(nextChar) */ : - // [ "a] this is one of the easy cases - *isOpen = true - case ispunct(previousChar) /* && isnormal(nextChar) */ : - // [!"a] is probably an open - *isOpen = true - default: - // [a'b] maybe a contraction? - *isOpen = false - } - - // Note that with the limited lookahead, this non-breaking - // space will also be appended to single double quotes. - if addNBSP && !*isOpen { - out.WriteString(" ") - } - - out.WriteByte('&') - if *isOpen { - out.WriteByte('l') - } else { - out.WriteByte('r') - } - out.WriteByte(quote) - out.WriteString("quo;") - - if addNBSP && *isOpen { - out.WriteString(" ") - } - - return true -} - -func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 2 { - t1 := tolower(text[1]) - - if t1 == '\'' { - nextChar := byte(0) - if len(text) >= 3 { - nextChar = text[2] - } - if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) { - return 1 - } - } - - if (t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && (len(text) < 3 || wordBoundary(text[2])) { - out.WriteString("’") - return 0 - } - - if len(text) >= 3 { - t2 := tolower(text[2]) - - if ((t1 == 'r' && t2 == 'e') || (t1 == 'l' && t2 == 'l') || (t1 == 'v' && t2 == 'e')) && - (len(text) < 4 || wordBoundary(text[3])) { - out.WriteString("’") - return 0 - } - } - } - - nextChar := byte(0) - if len(text) > 1 { - nextChar = text[1] - } - if smartQuoteHelper(out, previousChar, nextChar, 's', &r.inSingleQuote, false) { - return 0 - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartParens(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 3 { - t1 := tolower(text[1]) - t2 := tolower(text[2]) - - if t1 == 'c' && t2 == ')' { - out.WriteString("©") - return 2 - } - - if t1 == 'r' && t2 == ')' { - out.WriteString("®") - return 2 - } - - if len(text) >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')' { - out.WriteString("™") - return 3 - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartDash(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 2 { - if text[1] == '-' { - out.WriteString("—") - return 1 - } - - if wordBoundary(previousChar) && wordBoundary(text[1]) { - out.WriteString("–") - return 0 - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartDashLatex(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 3 && text[1] == '-' && text[2] == '-' { - out.WriteString("—") - return 2 - } - if len(text) >= 2 && text[1] == '-' { - out.WriteString("–") - return 1 - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte, addNBSP bool) int { - if bytes.HasPrefix(text, []byte(""")) { - nextChar := byte(0) - if len(text) >= 7 { - nextChar = text[6] - } - if smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, addNBSP) { - return 5 - } - } - - if bytes.HasPrefix(text, []byte("�")) { - return 3 - } - - out.WriteByte('&') - return 0 -} - -func (r *SPRenderer) smartAmp(angledQuotes, addNBSP bool) func(*bytes.Buffer, byte, []byte) int { - var quote byte = 'd' - if angledQuotes { - quote = 'a' - } - - return func(out *bytes.Buffer, previousChar byte, text []byte) int { - return r.smartAmpVariant(out, previousChar, text, quote, addNBSP) - } -} - -func (r *SPRenderer) smartPeriod(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 3 && text[1] == '.' && text[2] == '.' { - out.WriteString("…") - return 2 - } - - if len(text) >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.' { - out.WriteString("…") - return 4 - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartBacktick(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 2 && text[1] == '`' { - nextChar := byte(0) - if len(text) >= 3 { - nextChar = text[2] - } - if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) { - return 1 - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartNumberGeneric(out *bytes.Buffer, previousChar byte, text []byte) int { - if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 { - // is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b - // note: check for regular slash (/) or fraction slash (⁄, 0x2044, or 0xe2 81 84 in utf-8) - // and avoid changing dates like 1/23/2005 into fractions. - numEnd := 0 - for len(text) > numEnd && isdigit(text[numEnd]) { - numEnd++ - } - if numEnd == 0 { - out.WriteByte(text[0]) - return 0 - } - denStart := numEnd + 1 - if len(text) > numEnd+3 && text[numEnd] == 0xe2 && text[numEnd+1] == 0x81 && text[numEnd+2] == 0x84 { - denStart = numEnd + 3 - } else if len(text) < numEnd+2 || text[numEnd] != '/' { - out.WriteByte(text[0]) - return 0 - } - denEnd := denStart - for len(text) > denEnd && isdigit(text[denEnd]) { - denEnd++ - } - if denEnd == denStart { - out.WriteByte(text[0]) - return 0 - } - if len(text) == denEnd || wordBoundary(text[denEnd]) && text[denEnd] != '/' { - out.WriteString("") - out.Write(text[:numEnd]) - out.WriteString("") - out.Write(text[denStart:denEnd]) - out.WriteString("") - return denEnd - 1 - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartNumber(out *bytes.Buffer, previousChar byte, text []byte) int { - if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 { - if text[0] == '1' && text[1] == '/' && text[2] == '2' { - if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' { - out.WriteString("½") - return 2 - } - } - - if text[0] == '1' && text[1] == '/' && text[2] == '4' { - if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h') { - out.WriteString("¼") - return 2 - } - } - - if text[0] == '3' && text[1] == '/' && text[2] == '4' { - if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's') { - out.WriteString("¾") - return 2 - } - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartDoubleQuoteVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte) int { - nextChar := byte(0) - if len(text) > 1 { - nextChar = text[1] - } - if !smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, false) { - out.WriteString(""") - } - - return 0 -} - -func (r *SPRenderer) smartDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int { - return r.smartDoubleQuoteVariant(out, previousChar, text, 'd') -} - -func (r *SPRenderer) smartAngledDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int { - return r.smartDoubleQuoteVariant(out, previousChar, text, 'a') -} - -func (r *SPRenderer) smartLeftAngle(out *bytes.Buffer, previousChar byte, text []byte) int { - i := 0 - - for i < len(text) && text[i] != '>' { - i++ - } - - out.Write(text[:i+1]) - return i -} - -type smartCallback func(out *bytes.Buffer, previousChar byte, text []byte) int - -// NewSmartypantsRenderer constructs a Smartypants renderer object. -func NewSmartypantsRenderer(flags HTMLFlags) *SPRenderer { - var ( - r SPRenderer - - smartAmpAngled = r.smartAmp(true, false) - smartAmpAngledNBSP = r.smartAmp(true, true) - smartAmpRegular = r.smartAmp(false, false) - smartAmpRegularNBSP = r.smartAmp(false, true) - - addNBSP = flags&SmartypantsQuotesNBSP != 0 - ) - - if flags&SmartypantsAngledQuotes == 0 { - r.callbacks['"'] = r.smartDoubleQuote - if !addNBSP { - r.callbacks['&'] = smartAmpRegular - } else { - r.callbacks['&'] = smartAmpRegularNBSP - } - } else { - r.callbacks['"'] = r.smartAngledDoubleQuote - if !addNBSP { - r.callbacks['&'] = smartAmpAngled - } else { - r.callbacks['&'] = smartAmpAngledNBSP - } - } - r.callbacks['\''] = r.smartSingleQuote - r.callbacks['('] = r.smartParens - if flags&SmartypantsDashes != 0 { - if flags&SmartypantsLatexDashes == 0 { - r.callbacks['-'] = r.smartDash - } else { - r.callbacks['-'] = r.smartDashLatex - } - } - r.callbacks['.'] = r.smartPeriod - if flags&SmartypantsFractions == 0 { - r.callbacks['1'] = r.smartNumber - r.callbacks['3'] = r.smartNumber - } else { - for ch := '1'; ch <= '9'; ch++ { - r.callbacks[ch] = r.smartNumberGeneric - } - } - r.callbacks['<'] = r.smartLeftAngle - r.callbacks['`'] = r.smartBacktick - return &r -} - -// Process is the entry point of the Smartypants renderer. -func (r *SPRenderer) Process(w io.Writer, text []byte) { - mark := 0 - for i := 0; i < len(text); i++ { - if action := r.callbacks[text[i]]; action != nil { - if i > mark { - w.Write(text[mark:i]) - } - previousChar := byte(0) - if i > 0 { - previousChar = text[i-1] - } - var tmp bytes.Buffer - i += action(&tmp, previousChar, text[i:]) - w.Write(tmp.Bytes()) - mark = i + 1 - } - } - if mark < len(text) { - w.Write(text[mark:]) - } -} diff --git a/vendor/github.com/urfave/cli/.flake8 b/vendor/github.com/urfave/cli/.flake8 deleted file mode 100644 index 6deafc26170..00000000000 --- a/vendor/github.com/urfave/cli/.flake8 +++ /dev/null @@ -1,2 +0,0 @@ -[flake8] -max-line-length = 120 diff --git a/vendor/github.com/urfave/cli/README.md b/vendor/github.com/urfave/cli/README.md deleted file mode 100644 index c7dd62bc674..00000000000 --- a/vendor/github.com/urfave/cli/README.md +++ /dev/null @@ -1,51 +0,0 @@ -cli -=== - -[![Run Tests](https://github.com/urfave/cli/actions/workflows/cli.yml/badge.svg?branch=v1-maint)](https://github.com/urfave/cli/actions/workflows/cli.yml) -[![Go Reference](https://pkg.go.dev/badge/github.com/urfave/cli/.svg)](https://pkg.go.dev/github.com/urfave/cli/) -[![Go Report Card](https://goreportcard.com/badge/urfave/cli)](https://goreportcard.com/report/urfave/cli) -[![codecov](https://codecov.io/gh/urfave/cli/branch/v1-maint/graph/badge.svg)](https://codecov.io/gh/urfave/cli) - -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. - -## Usage Documentation - -Usage documentation for `v1` is available [at the docs -site](https://cli.urfave.org/v1/getting-started/) or in-tree at -[./docs/v1/manual.md](./docs/v1/manual.md) - -## Installation - -Make sure you have a working Go environment. Go version 1.18+ is supported. - -### Supported platforms - -cli is tested against multiple versions of Go on Linux, and against the latest released -version of Go on OS X and Windows. For full details, see -[./.github/workflows/cli.yml](./.github/workflows/cli.yml). - -### Build tags - -You can use the following build tags: - -#### `urfave_cli_no_docs` - -When set, this removes `ToMarkdown` and `ToMan` methods, so your application -won't be able to call those. This reduces the resulting binary size by about -300-400 KB (measured using Go 1.18.1 on Linux/amd64), due to less dependencies. - -### Using `v1` releases - -``` -$ go get github.com/urfave/cli -``` - -```go -... -import ( - "github.com/urfave/cli" -) -... -``` diff --git a/vendor/github.com/urfave/cli/app.go b/vendor/github.com/urfave/cli/app.go deleted file mode 100644 index df5a9a91be3..00000000000 --- a/vendor/github.com/urfave/cli/app.go +++ /dev/null @@ -1,531 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "io" - "os" - "path/filepath" - "sort" - "time" -) - -var ( - changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md" - appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL) - // unused variable. commented for now. will remove in future if agreed upon by everyone - //runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", 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) -) - -// 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 - // Description of the program argument format. - ArgsUsage string - // Version of the program - Version string - // Description of the program - Description 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 - HideHelp bool - // Boolean to hide built-in version flag and the VERSION section of help - HideVersion bool - // Populate on app startup, only gettable through method Categories() - categories CommandCategories - // An action to execute when the bash-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 - // Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}` - // *Note*: support for the deprecated `Action` signature will be removed in a future version - Action interface{} - - // Execute this function if the proper command cannot be found - CommandNotFound CommandNotFoundFunc - // Execute this function if an usage error occurs - OnUsageError OnUsageErrorFunc - // Compilation date - Compiled time.Time - // List of all authors who contributed - Authors []Author - // Copyright of the binary if any - Copyright string - // Name of Author (Note: Use App.Authors, this is deprecated) - Author string - // Email of Author (Note: Use App.Authors, this is deprecated) - Email string - // Writer writer to write output to - Writer io.Writer - // ErrWriter writes error output - ErrWriter io.Writer - // Execute this function to handle ExitErrors. If not provided, HandleExitCoder is provided to - // function as a default, so this is optional. - 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 - // Boolean to enable short-option handling so user can combine several - // single-character bool arguements into one - // i.e. foobar -o -v -> foobar -ov - UseShortOptionHandling bool - - didSetup bool -} - -// 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]), - HelpName: filepath.Base(os.Args[0]), - Usage: "A new cli application", - UsageText: "", - BashComplete: DefaultAppComplete, - Action: helpCommand.Action, - Compiled: compileTime(), - Writer: os.Stdout, - } -} - -// 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.Author != "" || a.Email != "" { - a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email}) - } - - var newCmds []Command - for _, c := range a.Commands { - if c.HelpName == "" { - c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) - } - newCmds = append(newCmds, c) - } - a.Commands = newCmds - - if a.Command(helpCommand.Name) == nil && !a.HideHelp { - a.Commands = append(a.Commands, helpCommand) - if (HelpFlag != BoolFlag{}) { - a.appendFlag(HelpFlag) - } - } - - if a.Version == "" { - a.HideVersion = true - } - - if !a.HideVersion { - a.appendFlag(VersionFlag) - } - - a.categories = CommandCategories{} - for _, command := range a.Commands { - a.categories = a.categories.AddCommand(command.Category, command) - } - sort.Sort(a.categories) - - if a.Metadata == nil { - a.Metadata = make(map[string]interface{}) - } - - if a.Writer == nil { - a.Writer = os.Stdout - } -} - -func (a *App) newFlagSet() (*flag.FlagSet, error) { - return flagSet(a.Name, a.Flags) -} - -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) { - 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) - - set, err := a.newFlagSet() - if err != nil { - return err - } - - err = parseIter(set, a, arguments[1:], shellComplete) - nerr := normalizeFlags(a.Flags, set) - context := NewContext(a, set, nil) - if nerr != nil { - _, _ = fmt.Fprintln(a.Writer, nerr) - _ = ShowAppHelp(context) - return nerr - } - context.shellComplete = shellComplete - - if checkCompletions(context) { - return nil - } - - if err != nil { - if a.OnUsageError != nil { - err := a.OnUsageError(context, err, false) - a.handleExitCoder(context, err) - return err - } - _, _ = fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) - _ = ShowAppHelp(context) - return err - } - - if !a.HideHelp && checkHelp(context) { - _ = ShowAppHelp(context) - return nil - } - - if !a.HideVersion && checkVersion(context) { - ShowVersion(context) - return nil - } - - cerr := checkRequiredFlags(a.Flags, context) - if cerr != nil { - _ = ShowAppHelp(context) - return cerr - } - - if a.After != nil && !context.shellComplete { - defer func() { - if afterErr := a.After(context); afterErr != nil { - if err != nil { - err = NewMultiError(err, afterErr) - } else { - err = afterErr - } - } - }() - } - - if a.Before != nil && !context.shellComplete { - beforeErr := a.Before(context) - if beforeErr != nil { - a.handleExitCoder(context, beforeErr) - err = beforeErr - return err - } - } - - args := context.Args() - if args.Present() { - name := args.First() - c := a.Command(name) - if c != nil { - return c.Run(context) - } - } - - if a.Action == nil { - a.Action = helpCommand.Action - } - - // Run default Action - err = HandleAction(a.Action, context) - - a.handleExitCoder(context, err) - return err -} - -// 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 eror -// code in the cli.ExitCoder -func (a *App) RunAndExitOnError() { - if err := a.Run(os.Args); err != nil { - _, _ = fmt.Fprintln(a.errWriter(), err) - OsExiter(1) - } -} - -// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to -// generate command-specific flags -func (a *App) RunAsSubcommand(ctx *Context) (err error) { - // append help to commands - if len(a.Commands) > 0 { - if a.Command(helpCommand.Name) == nil && !a.HideHelp { - a.Commands = append(a.Commands, helpCommand) - if (HelpFlag != BoolFlag{}) { - a.appendFlag(HelpFlag) - } - } - } - - newCmds := []Command{} - for _, c := range a.Commands { - if c.HelpName == "" { - c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) - } - newCmds = append(newCmds, c) - } - a.Commands = newCmds - - set, err := a.newFlagSet() - if err != nil { - return err - } - - err = parseIter(set, a, ctx.Args().Tail(), ctx.shellComplete) - nerr := normalizeFlags(a.Flags, set) - context := NewContext(a, set, ctx) - - if nerr != nil { - _, _ = fmt.Fprintln(a.Writer, nerr) - _, _ = fmt.Fprintln(a.Writer) - if len(a.Commands) > 0 { - _ = ShowSubcommandHelp(context) - } else { - _ = ShowCommandHelp(ctx, context.Args().First()) - } - return nerr - } - - if checkCompletions(context) { - return nil - } - - if err != nil { - if a.OnUsageError != nil { - err = a.OnUsageError(context, err, true) - a.handleExitCoder(context, err) - return err - } - _, _ = fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) - _ = ShowSubcommandHelp(context) - return err - } - - if len(a.Commands) > 0 { - if checkSubcommandHelp(context) { - return nil - } - } else { - if checkCommandHelp(ctx, context.Args().First()) { - return nil - } - } - - cerr := checkRequiredFlags(a.Flags, context) - if cerr != nil { - _ = ShowSubcommandHelp(context) - return cerr - } - - if a.After != nil && !context.shellComplete { - defer func() { - afterErr := a.After(context) - if afterErr != nil { - a.handleExitCoder(context, err) - if err != nil { - err = NewMultiError(err, afterErr) - } else { - err = afterErr - } - } - }() - } - - if a.Before != nil && !context.shellComplete { - beforeErr := a.Before(context) - if beforeErr != nil { - a.handleExitCoder(context, beforeErr) - err = beforeErr - return err - } - } - - args := context.Args() - if args.Present() { - name := args.First() - c := a.Command(name) - if c != nil { - return c.Run(context) - } - } - - // Run default Action - err = HandleAction(a.Action, context) - - a.handleExitCoder(context, err) - return err -} - -// 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 -} - -// Categories returns a slice containing all the categories with the commands they contain -func (a *App) Categories() CommandCategories { - return a.categories -} - -// VisibleCategories returns a slice of categories and commands that are -// Hidden=false -func (a *App) VisibleCategories() []*CommandCategory { - ret := []*CommandCategory{} - for _, category := range a.categories { - if visible := func() *CommandCategory { - for _, command := range category.Commands { - if !command.Hidden { - 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 -} - -// VisibleFlags returns a slice of the Flags with Hidden=false -func (a *App) VisibleFlags() []Flag { - return visibleFlags(a.Flags) -} - -func (a *App) hasFlag(flag Flag) bool { - for _, f := range a.Flags { - if flag == f { - return true - } - } - - return false -} - -func (a *App) errWriter() io.Writer { - // When the app ErrWriter is nil use the package level one. - if a.ErrWriter == nil { - return ErrWriter - } - - return a.ErrWriter -} - -func (a *App) appendFlag(flag Flag) { - if !a.hasFlag(flag) { - a.Flags = append(a.Flags, flag) - } -} - -func (a *App) handleExitCoder(context *Context, err error) { - if a.ExitErrHandler != nil { - a.ExitErrHandler(context, err) - } else { - HandleExitCoder(err) - } -} - -// 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{}, context *Context) (err error) { - switch a := action.(type) { - case ActionFunc: - return a(context) - case func(*Context) error: - return a(context) - case func(*Context): // deprecated function signature - a(context) - return nil - } - - return errInvalidActionType -} diff --git a/vendor/github.com/urfave/cli/category.go b/vendor/github.com/urfave/cli/category.go deleted file mode 100644 index bf3c73c55ee..00000000000 --- a/vendor/github.com/urfave/cli/category.go +++ /dev/null @@ -1,44 +0,0 @@ -package cli - -// CommandCategories is a slice of *CommandCategory. -type CommandCategories []*CommandCategory - -// CommandCategory is a category containing commands. -type CommandCategory struct { - Name string - Commands Commands -} - -func (c CommandCategories) Less(i, j int) bool { - return lexicographicLess(c[i].Name, c[j].Name) -} - -func (c CommandCategories) Len() int { - return len(c) -} - -func (c CommandCategories) Swap(i, j int) { - c[i], c[j] = c[j], c[i] -} - -// AddCommand adds a command to a category. -func (c CommandCategories) AddCommand(category string, command Command) CommandCategories { - for _, commandCategory := range c { - if commandCategory.Name == category { - commandCategory.Commands = append(commandCategory.Commands, command) - return c - } - } - return append(c, &CommandCategory{Name: category, Commands: []Command{command}}) -} - -// VisibleCommands returns a slice of the Commands with Hidden=false -func (c *CommandCategory) VisibleCommands() []Command { - ret := []Command{} - for _, command := range c.Commands { - if !command.Hidden { - ret = append(ret, command) - } - } - return ret -} diff --git a/vendor/github.com/urfave/cli/cli.go b/vendor/github.com/urfave/cli/cli.go deleted file mode 100644 index 4bd25083924..00000000000 --- a/vendor/github.com/urfave/cli/cli.go +++ /dev/null @@ -1,22 +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.NewApp().Run(os.Args) -// } -// -// Of course this application does not do much, so let's make this an actual application: -// func main() { -// app := cli.NewApp() -// app.Name = "greet" -// app.Usage = "say a greeting" -// app.Action = func(c *cli.Context) error { -// println("Greetings") -// return nil -// } -// -// app.Run(os.Args) -// } -package cli - -//go:generate go run flag-gen/main.go flag-gen/assets_vfsdata.go diff --git a/vendor/github.com/urfave/cli/command.go b/vendor/github.com/urfave/cli/command.go deleted file mode 100644 index 6c2f9cad526..00000000000 --- a/vendor/github.com/urfave/cli/command.go +++ /dev/null @@ -1,386 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "sort" - "strings" -) - -// Command is a subcommand for a cli.App. -type Command struct { - // The name of the command - Name string - // short name of the command. Typically one character (deprecated, use `Aliases`) - ShortName 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 - // 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 interface{} - // TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind - // of deprecation period has passed, maybe? - - // Execute this function if a usage error occurs. - OnUsageError OnUsageErrorFunc - // List of child commands - Subcommands Commands - // List of flags to parse - Flags []Flag - // Treat all flags as normal arguments if true - SkipFlagParsing bool - // Skip argument reordering which attempts to move flags before arguments, - // but only works if all flags appear after all arguments. This behavior was - // removed n version 2 since it only works under specific conditions so we - // backport here by exposing it as an option for compatibility. - SkipArgReorder bool - // Boolean to hide built-in help command - HideHelp 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 -} - -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, " ") -} - -// Commands is a slice of Command -type Commands []Command - -// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags -func (c Command) Run(ctx *Context) (err error) { - if !c.SkipFlagParsing { - if len(c.Subcommands) > 0 { - return c.startApp(ctx) - } - } - - if !c.HideHelp && (HelpFlag != BoolFlag{}) { - // append help to flags - c.Flags = append( - c.Flags, - HelpFlag, - ) - } - - if ctx.App.UseShortOptionHandling { - c.UseShortOptionHandling = true - } - - set, err := c.parseFlags(ctx.Args().Tail(), ctx.shellComplete) - - context := NewContext(ctx.App, set, ctx) - context.Command = c - if checkCommandCompletions(context, c.Name) { - return nil - } - - if err != nil { - if c.OnUsageError != nil { - err := c.OnUsageError(context, err, false) - context.App.handleExitCoder(context, err) - return err - } - _, _ = fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error()) - _, _ = fmt.Fprintln(context.App.Writer) - _ = ShowCommandHelp(context, c.Name) - return err - } - - if checkCommandHelp(context, c.Name) { - return nil - } - - cerr := checkRequiredFlags(c.Flags, context) - if cerr != nil { - _ = ShowCommandHelp(context, c.Name) - return cerr - } - - if c.After != nil { - defer func() { - afterErr := c.After(context) - if afterErr != nil { - context.App.handleExitCoder(context, err) - if err != nil { - err = NewMultiError(err, afterErr) - } else { - err = afterErr - } - } - }() - } - - if c.Before != nil { - err = c.Before(context) - if err != nil { - context.App.handleExitCoder(context, err) - return err - } - } - - if c.Action == nil { - c.Action = helpSubcommand.Action - } - - err = HandleAction(c.Action, context) - - if err != nil { - context.App.handleExitCoder(context, err) - } - return err -} - -func (c *Command) parseFlags(args Args, shellComplete bool) (*flag.FlagSet, error) { - if c.SkipFlagParsing { - set, err := c.newFlagSet() - if err != nil { - return nil, err - } - - return set, set.Parse(append([]string{"--"}, args...)) - } - - if !c.SkipArgReorder { - args = reorderArgs(c.Flags, args) - } - - set, err := c.newFlagSet() - if err != nil { - return nil, err - } - - err = parseIter(set, c, args, shellComplete) - if err != nil { - return nil, err - } - - err = normalizeFlags(c.Flags, set) - if err != nil { - return nil, err - } - - return set, nil -} - -func (c *Command) newFlagSet() (*flag.FlagSet, error) { - return flagSet(c.Name, c.Flags) -} - -func (c *Command) useShortOptionHandling() bool { - return c.UseShortOptionHandling -} - -// reorderArgs moves all flags (via reorderedArgs) before the rest of -// the arguments (remainingArgs) as this is what flag expects. -func reorderArgs(commandFlags []Flag, args []string) []string { - var remainingArgs, reorderedArgs []string - - nextIndexMayContainValue := false - for i, arg := range args { - - // if we're expecting an option-value, check if this arg is a value, in - // which case it should be re-ordered next to its associated flag - if nextIndexMayContainValue && !argIsFlag(commandFlags, arg) { - nextIndexMayContainValue = false - reorderedArgs = append(reorderedArgs, arg) - } else if arg == "--" { - // don't reorder any args after the -- delimiter As described in the POSIX spec: - // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02 - // > Guideline 10: - // > The first -- argument that is not an option-argument should be accepted - // > as a delimiter indicating the end of options. Any following arguments - // > should be treated as operands, even if they begin with the '-' character. - - // make sure the "--" delimiter itself is at the start - remainingArgs = append([]string{"--"}, remainingArgs...) - remainingArgs = append(remainingArgs, args[i+1:]...) - break - // checks if this is an arg that should be re-ordered - } else if argIsFlag(commandFlags, arg) { - // we have determined that this is a flag that we should re-order - reorderedArgs = append(reorderedArgs, arg) - // if this arg does not contain a "=", then the next index may contain the value for this flag - nextIndexMayContainValue = !strings.Contains(arg, "=") - - // simply append any remaining args - } else { - remainingArgs = append(remainingArgs, arg) - } - } - - return append(reorderedArgs, remainingArgs...) -} - -// argIsFlag checks if an arg is one of our command flags -func argIsFlag(commandFlags []Flag, arg string) bool { - if arg == "-" || arg == "--" { - // `-` is never a flag - // `--` is an option-value when following a flag, and a delimiter indicating the end of options in other cases. - return false - } - // flags always start with a - - if !strings.HasPrefix(arg, "-") { - return false - } - // this line turns `--flag` into `flag` - if strings.HasPrefix(arg, "--") { - arg = strings.Replace(arg, "-", "", 2) - } - // this line turns `-flag` into `flag` - if strings.HasPrefix(arg, "-") { - arg = strings.Replace(arg, "-", "", 1) - } - // this line turns `flag=value` into `flag` - arg = strings.Split(arg, "=")[0] - // look through all the flags, to see if the `arg` is one of our flags - for _, flag := range commandFlags { - for _, key := range strings.Split(flag.GetName(), ",") { - key := strings.TrimSpace(key) - if key == arg { - return true - } - } - } - // return false if this arg was not one of our flags - return false -} - -// Names returns the names including short names and aliases. -func (c Command) Names() []string { - names := []string{c.Name} - - if c.ShortName != "" { - names = append(names, c.ShortName) - } - - return append(names, c.Aliases...) -} - -// HasName returns true if Command.Name or Command.ShortName matches given name -func (c Command) HasName(name string) bool { - for _, n := range c.Names() { - if n == name { - return true - } - } - return false -} - -func (c Command) startApp(ctx *Context) error { - app := NewApp() - app.Metadata = ctx.App.Metadata - app.ExitErrHandler = ctx.App.ExitErrHandler - // set the name and usage - app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) - if c.HelpName == "" { - app.HelpName = c.HelpName - } else { - app.HelpName = app.Name - } - - app.Usage = c.Usage - app.Description = c.Description - app.ArgsUsage = c.ArgsUsage - - // set CommandNotFound - app.CommandNotFound = ctx.App.CommandNotFound - app.CustomAppHelpTemplate = c.CustomHelpTemplate - - // set the flags and commands - app.Commands = c.Subcommands - app.Flags = c.Flags - app.HideHelp = c.HideHelp - - app.Version = ctx.App.Version - app.HideVersion = ctx.App.HideVersion - app.Compiled = ctx.App.Compiled - app.Author = ctx.App.Author - app.Email = ctx.App.Email - app.Writer = ctx.App.Writer - app.ErrWriter = ctx.App.ErrWriter - app.UseShortOptionHandling = ctx.App.UseShortOptionHandling - - app.categories = CommandCategories{} - for _, command := range c.Subcommands { - app.categories = app.categories.AddCommand(command.Category, command) - } - - sort.Sort(app.categories) - - // bash completion - app.EnableBashCompletion = ctx.App.EnableBashCompletion - if c.BashComplete != nil { - app.BashComplete = c.BashComplete - } - - // set the actions - app.Before = c.Before - app.After = c.After - if c.Action != nil { - app.Action = c.Action - } else { - app.Action = helpSubcommand.Action - } - app.OnUsageError = c.OnUsageError - - for index, cc := range app.Commands { - app.Commands[index].commandNamePath = []string{c.Name, cc.Name} - } - - return app.RunAsSubcommand(ctx) -} - -// VisibleFlags returns a slice of the Flags with Hidden=false -func (c Command) VisibleFlags() []Flag { - return visibleFlags(c.Flags) -} diff --git a/vendor/github.com/urfave/cli/context.go b/vendor/github.com/urfave/cli/context.go deleted file mode 100644 index 3adf37e7b29..00000000000 --- a/vendor/github.com/urfave/cli/context.go +++ /dev/null @@ -1,348 +0,0 @@ -package cli - -import ( - "errors" - "flag" - "fmt" - "os" - "reflect" - "strings" - "syscall" -) - -// 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 { - App *App - Command Command - shellComplete bool - flagSet *flag.FlagSet - setFlags map[string]bool - 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.shellComplete = parentCtx.shellComplete - } - - return c -} - -// NumFlags returns the number of flags set -func (c *Context) NumFlags() int { - return c.flagSet.NFlag() -} - -// Set sets a context flag to a value. -func (c *Context) Set(name, value string) error { - c.setFlags = nil - return c.flagSet.Set(name, value) -} - -// GlobalSet sets a context flag to a value on the global flagset -func (c *Context) GlobalSet(name, value string) error { - globalContext(c).setFlags = nil - return globalContext(c).flagSet.Set(name, value) -} - -// IsSet determines if the flag was actually set -func (c *Context) IsSet(name string) bool { - if c.setFlags == nil { - c.setFlags = make(map[string]bool) - - c.flagSet.Visit(func(f *flag.Flag) { - c.setFlags[f.Name] = true - }) - - c.flagSet.VisitAll(func(f *flag.Flag) { - if _, ok := c.setFlags[f.Name]; ok { - return - } - c.setFlags[f.Name] = false - }) - - // XXX hack to support IsSet for flags with EnvVar - // - // There isn't an easy way to do this with the current implementation since - // whether a flag was set via an environment variable is very difficult to - // determine here. Instead, we intend to introduce a backwards incompatible - // change in version 2 to add `IsSet` to the Flag interface to push the - // responsibility closer to where the information required to determine - // whether a flag is set by non-standard means such as environment - // variables is available. - // - // See https://github.com/urfave/cli/issues/294 for additional discussion - flags := c.Command.Flags - if c.Command.Name == "" { // cannot == Command{} since it contains slice types - if c.App != nil { - flags = c.App.Flags - } - } - for _, f := range flags { - eachName(f.GetName(), func(name string) { - if isSet, ok := c.setFlags[name]; isSet || !ok { - // Check if a flag is set - if isSet { - // If the flag is set, also set its other aliases - eachName(f.GetName(), func(name string) { - c.setFlags[name] = true - }) - } - - return - } - - val := reflect.ValueOf(f) - if val.Kind() == reflect.Ptr { - val = val.Elem() - } - - filePathValue := val.FieldByName("FilePath") - if filePathValue.IsValid() { - eachName(filePathValue.String(), func(filePath string) { - if _, err := os.Stat(filePath); err == nil { - c.setFlags[name] = true - return - } - }) - } - - envVarValue := val.FieldByName("EnvVar") - if envVarValue.IsValid() { - eachName(envVarValue.String(), func(envVar string) { - envVar = strings.TrimSpace(envVar) - if _, ok := syscall.Getenv(envVar); ok { - c.setFlags[name] = true - return - } - }) - } - }) - } - } - - return c.setFlags[name] -} - -// GlobalIsSet determines if the global flag was actually set -func (c *Context) GlobalIsSet(name string) bool { - ctx := c - if ctx.parentContext != nil { - ctx = ctx.parentContext - } - - for ; ctx != nil; ctx = ctx.parentContext { - if ctx.IsSet(name) { - return true - } - } - return false -} - -// FlagNames returns a slice of flag names used in this context. -func (c *Context) FlagNames() (names []string) { - for _, f := range c.Command.Flags { - name := strings.Split(f.GetName(), ",")[0] - if name == "help" { - continue - } - names = append(names, name) - } - return -} - -// GlobalFlagNames returns a slice of global flag names used by the app. -func (c *Context) GlobalFlagNames() (names []string) { - for _, f := range c.App.Flags { - name := strings.Split(f.GetName(), ",")[0] - if name == "help" || name == "version" { - continue - } - names = append(names, name) - } - return -} - -// Parent returns the parent context, if any -func (c *Context) Parent() *Context { - return c.parentContext -} - -// value returns the value of the flag coressponding to `name` -func (c *Context) value(name string) interface{} { - return c.flagSet.Lookup(name).Value.(flag.Getter).Get() -} - -// Args contains apps console arguments -type Args []string - -// Args returns the command line arguments associated with the context. -func (c *Context) Args() Args { - args := Args(c.flagSet.Args()) - return args -} - -// NArg returns the number of the command line arguments. -func (c *Context) NArg() int { - return len(c.Args()) -} - -// Get returns the nth argument, or else a blank string -func (a Args) Get(n int) string { - if len(a) > n { - return a[n] - } - return "" -} - -// First returns the first argument, or else a blank string -func (a Args) First() string { - return a.Get(0) -} - -// Tail returns the rest of the arguments (not the first one) -// or else an empty string slice -func (a Args) Tail() []string { - if len(a) >= 2 { - return []string(a)[1:] - } - return []string{} -} - -// Present checks if there are any arguments present -func (a Args) Present() bool { - return len(a) != 0 -} - -// Swap swaps arguments at the given indexes -func (a Args) Swap(from, to int) error { - if from >= len(a) || to >= len(a) { - return errors.New("index out of range") - } - a[from], a[to] = a[to], a[from] - return nil -} - -func globalContext(ctx *Context) *Context { - if ctx == nil { - return nil - } - - for { - if ctx.parentContext == nil { - return ctx - } - ctx = ctx.parentContext - } -} - -func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet { - if ctx.parentContext != nil { - ctx = ctx.parentContext - } - for ; ctx != nil; ctx = ctx.parentContext { - if f := ctx.flagSet.Lookup(name); f != nil { - return ctx.flagSet - } - } - return nil -} - -func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { - switch ff.Value.(type) { - case *StringSlice: - 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 := strings.Split(f.GetName(), ",") - 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 -} - -type requiredFlagsErr interface { - error - getMissingFlags() []string -} - -type errRequiredFlags struct { - missingFlags []string -} - -func (e *errRequiredFlags) Error() string { - numberOfMissingFlags := len(e.missingFlags) - if numberOfMissingFlags == 1 { - return fmt.Sprintf("Required flag %q not set", e.missingFlags[0]) - } - joinedMissingFlags := strings.Join(e.missingFlags, ", ") - return fmt.Sprintf("Required flags %q not set", joinedMissingFlags) -} - -func (e *errRequiredFlags) getMissingFlags() []string { - return e.missingFlags -} - -func checkRequiredFlags(flags []Flag, context *Context) requiredFlagsErr { - var missingFlags []string - for _, f := range flags { - if rf, ok := f.(RequiredFlag); ok && rf.IsRequired() { - var flagPresent bool - var flagName string - for _, key := range strings.Split(f.GetName(), ",") { - key = strings.TrimSpace(key) - if len(key) > 1 { - flagName = key - } - - if context.IsSet(key) { - flagPresent = true - } - } - - if !flagPresent && flagName != "" { - missingFlags = append(missingFlags, flagName) - } - } - } - - if len(missingFlags) != 0 { - return &errRequiredFlags{missingFlags: missingFlags} - } - - return nil -} diff --git a/vendor/github.com/urfave/cli/docs.go b/vendor/github.com/urfave/cli/docs.go deleted file mode 100644 index 725fa7ff2be..00000000000 --- a/vendor/github.com/urfave/cli/docs.go +++ /dev/null @@ -1,151 +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); err != nil { - return "", err - } - return w.String(), 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) { - var w bytes.Buffer - if err := a.writeDocTemplate(&w); err != nil { - return "", err - } - man := md2man.Render(w.Bytes()) - return string(man), nil -} - -type cliTemplate struct { - App *App - Commands []string - GlobalArgs []string - SynopsisArgs []string -} - -func (a *App) writeDocTemplate(w io.Writer) error { - const name = "cli" - t, err := template.New(name).Parse(MarkdownDocTemplate) - if err != nil { - return err - } - return t.ExecuteTemplate(w, name, &cliTemplate{ - App: a, - Commands: prepareCommands(a.Commands, 0), - GlobalArgs: prepareArgsWithValues(a.Flags), - SynopsisArgs: prepareArgsSynopsis(a.Flags), - }) -} - -func prepareCommands(commands []Command, level int) []string { - coms := []string{} - for i := range commands { - command := &commands[i] - if command.Hidden { - continue - } - usage := "" - if command.Usage != "" { - usage = command.Usage - } - - prepared := fmt.Sprintf("%s %s\n\n%s\n", - strings.Repeat("#", level+2), - strings.Join(command.Names(), ", "), - usage, - ) - - flags := prepareArgsWithValues(command.Flags) - if len(flags) > 0 { - prepared += fmt.Sprintf("\n%s", strings.Join(flags, "\n")) - } - - coms = append(coms, prepared) - - // recursevly 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 strings.Split(flag.GetName(), ",") { - 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() - value := flag.GetValue() - if value != "" { - description += " (default: " + value + ")" - } - return ": " + description -} diff --git a/vendor/github.com/urfave/cli/errors.go b/vendor/github.com/urfave/cli/errors.go deleted file mode 100644 index 562b2953cf2..00000000000 --- a/vendor/github.com/urfave/cli/errors.go +++ /dev/null @@ -1,115 +0,0 @@ -package cli - -import ( - "fmt" - "io" - "os" - "strings" -) - -// OsExiter is the function used when the app exits. If not set defaults to os.Exit. -var OsExiter = os.Exit - -// ErrWriter is used to write errors to the user. This can be anything -// implementing the io.Writer interface and defaults to os.Stderr. -var ErrWriter io.Writer = os.Stderr - -// MultiError is an error that wraps multiple errors. -type MultiError struct { - Errors []error -} - -// NewMultiError creates a new MultiError. Pass in one or more errors. -func NewMultiError(err ...error) MultiError { - return MultiError{Errors: err} -} - -// Error implements the error interface. -func (m MultiError) Error() string { - errs := make([]string, len(m.Errors)) - for i, err := range m.Errors { - errs[i] = err.Error() - } - - return strings.Join(errs, "\n") -} - -type ErrorFormatter interface { - Format(s fmt.State, verb rune) -} - -// ExitCoder is the interface checked by `App` and `Command` for a custom exit -// code -type ExitCoder interface { - error - ExitCode() int -} - -// ExitError fulfills both the builtin `error` interface and `ExitCoder` -type ExitError struct { - exitCode int - message interface{} -} - -// NewExitError makes a new *ExitError -func NewExitError(message interface{}, exitCode int) *ExitError { - return &ExitError{ - exitCode: exitCode, - message: message, - } -} - -// Error returns the string message, fulfilling the interface required by -// `error` -func (ee *ExitError) Error() string { - return fmt.Sprintf("%v", ee.message) -} - -// ExitCode returns the exit code, fulfilling the interface required by -// `ExitCoder` -func (ee *ExitError) ExitCode() int { - return ee.exitCode -} - -// HandleExitCoder checks if the error fulfills the ExitCoder interface, and if -// so prints the error to stderr (if it is non-empty) and calls OsExiter with the -// given exit code. If the given error is a MultiError, then this func is -// called on all members of the Errors slice and calls OsExiter with the last exit code. -func HandleExitCoder(err error) { - if err == nil { - return - } - - if exitErr, ok := err.(ExitCoder); ok { - if err.Error() != "" { - if _, ok := exitErr.(ErrorFormatter); ok { - fmt.Fprintf(ErrWriter, "%+v\n", err) - } else { - fmt.Fprintln(ErrWriter, err) - } - } - OsExiter(exitErr.ExitCode()) - return - } - - if multiErr, ok := err.(MultiError); ok { - code := handleMultiError(multiErr) - OsExiter(code) - return - } -} - -func handleMultiError(multiErr MultiError) int { - code := 1 - for _, merr := range multiErr.Errors { - if multiErr2, ok := merr.(MultiError); ok { - code = handleMultiError(multiErr2) - } else { - fmt.Fprintln(ErrWriter, merr) - if exitErr, ok := merr.(ExitCoder); ok { - code = exitErr.ExitCode() - } - } - } - return code -} diff --git a/vendor/github.com/urfave/cli/fish.go b/vendor/github.com/urfave/cli/fish.go deleted file mode 100644 index cf183af611f..00000000000 --- a/vendor/github.com/urfave/cli/fish.go +++ /dev/null @@ -1,194 +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 i := range commands { - command := &commands[i] - - 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.Flags, command.Names())..., - ) - - // recursevly 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 strings.Split(flag.GetName(), ",") { - 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 - } - } - 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) -} diff --git a/vendor/github.com/urfave/cli/flag.go b/vendor/github.com/urfave/cli/flag.go deleted file mode 100644 index 5b7ae6c3f0b..00000000000 --- a/vendor/github.com/urfave/cli/flag.go +++ /dev/null @@ -1,348 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "io/ioutil" - "reflect" - "runtime" - "strconv" - "strings" - "syscall" -) - -const defaultPlaceholder = "value" - -// 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, v", - Usage: "print the version", -} - -// HelpFlag prints the help for all commands and subcommands -// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand -// unless HideHelp is set to true) -var HelpFlag Flag = BoolFlag{ - Name: "help, h", - Usage: "show help", -} - -// FlagStringer converts a flag definition to a string. This is used by help -// to display a flag. -var FlagStringer FlagStringFunc = stringifyFlag - -// 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 { - return lexicographicLess(f[i].GetName(), f[j].GetName()) -} - -func (f FlagsByName) Swap(i, j int) { - f[i], f[j] = f[j], f[i] -} - -// 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) - GetName() string -} - -// 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 -} - -// errorableFlag is an interface that allows us to return errors during apply -// it allows flags defined in this library to return errors in a fashion backwards compatible -// TODO remove in v2 and modify the existing Flag interface to return errors -type errorableFlag interface { - Flag - - ApplyWithError(*flag.FlagSet) error -} - -func flagSet(name string, flags []Flag) (*flag.FlagSet, error) { - set := flag.NewFlagSet(name, flag.ContinueOnError) - - for _, f := range flags { - //TODO remove in v2 when errorableFlag is removed - if ef, ok := f.(errorableFlag); ok { - if err := ef.ApplyWithError(set); err != nil { - return nil, err - } - } else { - f.Apply(set) - } - } - set.SetOutput(ioutil.Discard) - return set, nil -} - -func eachName(longName string, fn func(string)) { - parts := strings.Split(longName, ",") - for _, name := range parts { - name = strings.Trim(name, " ") - fn(name) - } -} - -func visibleFlags(fl []Flag) []Flag { - var visible []Flag - for _, f := range fl { - field := flagValue(f).FieldByName("Hidden") - if !field.IsValid() || !field.Bool() { - 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(fullName, placeholder string) string { - var prefixed string - parts := strings.Split(fullName, ",") - for i, name := range parts { - name = strings.Trim(name, " ") - prefixed += prefixFor(name) + name - if placeholder != "" { - prefixed += " " + placeholder - } - if i < len(parts)-1 { - prefixed += ", " - } - } - return prefixed -} - -func withEnvHint(envVar, str string) string { - envText := "" - if envVar != "" { - prefix := "$" - suffix := "" - sep := ", $" - if runtime.GOOS == "windows" { - prefix = "%" - suffix = "%" - sep = "%, %" - } - envText = " [" + prefix + strings.Join(strings.Split(envVar, ","), sep) + suffix + "]" - } - return str + envText -} - -func withFileHint(filePath, str string) string { - fileText := "" - if filePath != "" { - fileText = fmt.Sprintf(" [%s]", filePath) - } - return str + fileText -} - -func flagValue(f Flag) reflect.Value { - fv := reflect.ValueOf(f) - for fv.Kind() == reflect.Ptr { - fv = reflect.Indirect(fv) - } - return fv -} - -func stringifyFlag(f Flag) string { - fv := flagValue(f) - - switch f.(type) { - case IntSliceFlag: - return FlagFileHinter( - fv.FieldByName("FilePath").String(), - FlagEnvHinter( - fv.FieldByName("EnvVar").String(), - stringifyIntSliceFlag(f.(IntSliceFlag)), - ), - ) - case Int64SliceFlag: - return FlagFileHinter( - fv.FieldByName("FilePath").String(), - FlagEnvHinter( - fv.FieldByName("EnvVar").String(), - stringifyInt64SliceFlag(f.(Int64SliceFlag)), - ), - ) - case StringSliceFlag: - return FlagFileHinter( - fv.FieldByName("FilePath").String(), - FlagEnvHinter( - fv.FieldByName("EnvVar").String(), - stringifyStringSliceFlag(f.(StringSliceFlag)), - ), - ) - } - - placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String()) - - needsPlaceholder := false - defaultValueString := "" - - if val := fv.FieldByName("Value"); val.IsValid() { - needsPlaceholder = true - defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface()) - - if val.Kind() == reflect.String && val.String() != "" { - defaultValueString = fmt.Sprintf(" (default: %q)", val.String()) - } - } - - if defaultValueString == " (default: )" { - defaultValueString = "" - } - - if needsPlaceholder && placeholder == "" { - placeholder = defaultPlaceholder - } - - usageWithDefault := strings.TrimSpace(usage + defaultValueString) - - return FlagFileHinter( - fv.FieldByName("FilePath").String(), - FlagEnvHinter( - fv.FieldByName("EnvVar").String(), - FlagNamePrefixer(fv.FieldByName("Name").String(), placeholder)+"\t"+usageWithDefault, - ), - ) -} - -func stringifyIntSliceFlag(f IntSliceFlag) string { - var defaultVals []string - if f.Value != nil && len(f.Value.Value()) > 0 { - for _, i := range f.Value.Value() { - defaultVals = append(defaultVals, strconv.Itoa(i)) - } - } - - return stringifySliceFlag(f.Usage, f.Name, defaultVals) -} - -func stringifyInt64SliceFlag(f Int64SliceFlag) 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 stringifySliceFlag(f.Usage, f.Name, defaultVals) -} - -func stringifyStringSliceFlag(f StringSliceFlag) string { - var defaultVals []string - if f.Value != nil && len(f.Value.Value()) > 0 { - for _, s := range f.Value.Value() { - if len(s) > 0 { - defaultVals = append(defaultVals, strconv.Quote(s)) - } - } - } - - return stringifySliceFlag(f.Usage, f.Name, defaultVals) -} - -func stringifySliceFlag(usage, name string, defaultVals []string) string { - placeholder, usage := unquoteUsage(usage) - if placeholder == "" { - placeholder = defaultPlaceholder - } - - defaultVal := "" - if len(defaultVals) > 0 { - defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", ")) - } - - usageWithDefault := strings.TrimSpace(usage + defaultVal) - return FlagNamePrefixer(name, placeholder) + "\t" + usageWithDefault -} - -func flagFromFileEnv(filePath, envName string) (val string, ok bool) { - for _, envVar := range strings.Split(envName, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - return envVal, true - } - } - for _, fileVar := range strings.Split(filePath, ",") { - if fileVar != "" { - if data, err := ioutil.ReadFile(fileVar); err == nil { - return string(data), true - } - } - } - return "", false -} diff --git a/vendor/github.com/urfave/cli/flag_bool.go b/vendor/github.com/urfave/cli/flag_bool.go deleted file mode 100644 index 2499b0b524a..00000000000 --- a/vendor/github.com/urfave/cli/flag_bool.go +++ /dev/null @@ -1,109 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "strconv" -) - -// BoolFlag is a flag with type bool -type BoolFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - Destination *bool -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f BoolFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f BoolFlag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f BoolFlag) IsRequired() bool { - return f.Required -} - -// 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 -} - -// 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 "" -} - -// Bool looks up the value of a local BoolFlag, returns -// false if not found -func (c *Context) Bool(name string) bool { - return lookupBool(name, c.flagSet) -} - -// GlobalBool looks up the value of a global BoolFlag, returns -// false if not found -func (c *Context) GlobalBool(name string) bool { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupBool(name, fs) - } - return false -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f BoolFlag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f BoolFlag) ApplyWithError(set *flag.FlagSet) error { - val := false - if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - if envVal == "" { - val = false - } else { - envValBool, err := strconv.ParseBool(envVal) - if err != nil { - return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) - } - val = envValBool - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.BoolVar(f.Destination, name, val, f.Usage) - return - } - set.Bool(name, val, f.Usage) - }) - - return nil -} - -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 -} diff --git a/vendor/github.com/urfave/cli/flag_bool_t.go b/vendor/github.com/urfave/cli/flag_bool_t.go deleted file mode 100644 index cd0888fa21e..00000000000 --- a/vendor/github.com/urfave/cli/flag_bool_t.go +++ /dev/null @@ -1,110 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "strconv" -) - -// BoolTFlag is a flag with type bool that is true by default -type BoolTFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - Destination *bool -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f BoolTFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f BoolTFlag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f BoolTFlag) IsRequired() bool { - return f.Required -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f BoolTFlag) TakesValue() bool { - return false -} - -// GetUsage returns the usage string for the flag -func (f BoolTFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f BoolTFlag) GetValue() string { - return "" -} - -// BoolT looks up the value of a local BoolTFlag, returns -// false if not found -func (c *Context) BoolT(name string) bool { - return lookupBoolT(name, c.flagSet) -} - -// GlobalBoolT looks up the value of a global BoolTFlag, returns -// false if not found -func (c *Context) GlobalBoolT(name string) bool { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupBoolT(name, fs) - } - return false -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f BoolTFlag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f BoolTFlag) ApplyWithError(set *flag.FlagSet) error { - val := true - - if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - if envVal == "" { - val = false - } else { - envValBool, err := strconv.ParseBool(envVal) - if err != nil { - return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) - } - val = envValBool - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.BoolVar(f.Destination, name, val, f.Usage) - return - } - set.Bool(name, val, f.Usage) - }) - - return nil -} - -func lookupBoolT(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 -} diff --git a/vendor/github.com/urfave/cli/flag_duration.go b/vendor/github.com/urfave/cli/flag_duration.go deleted file mode 100644 index df4ade589d0..00000000000 --- a/vendor/github.com/urfave/cli/flag_duration.go +++ /dev/null @@ -1,106 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "time" -) - -// DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) -type DurationFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - Value time.Duration - Destination *time.Duration -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f DurationFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f DurationFlag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f DurationFlag) IsRequired() bool { - return f.Required -} - -// 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 -} - -// 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() -} - -// Duration looks up the value of a local DurationFlag, returns -// 0 if not found -func (c *Context) Duration(name string) time.Duration { - return lookupDuration(name, c.flagSet) -} - -// GlobalDuration looks up the value of a global DurationFlag, returns -// 0 if not found -func (c *Context) GlobalDuration(name string) time.Duration { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupDuration(name, fs) - } - return 0 -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f DurationFlag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f DurationFlag) ApplyWithError(set *flag.FlagSet) error { - if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - envValDuration, err := time.ParseDuration(envVal) - if err != nil { - return fmt.Errorf("could not parse %s as duration for flag %s: %s", envVal, f.Name, err) - } - - f.Value = envValDuration - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.DurationVar(f.Destination, name, f.Value, f.Usage) - return - } - set.Duration(name, f.Value, f.Usage) - }) - - return nil -} - -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 -} diff --git a/vendor/github.com/urfave/cli/flag_float64.go b/vendor/github.com/urfave/cli/flag_float64.go deleted file mode 100644 index 65398d3b5c3..00000000000 --- a/vendor/github.com/urfave/cli/flag_float64.go +++ /dev/null @@ -1,106 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "strconv" -) - -// Float64Flag is a flag with type float64 -type Float64Flag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - Value float64 - Destination *float64 -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f Float64Flag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f Float64Flag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f Float64Flag) IsRequired() bool { - return f.Required -} - -// 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 -} - -// 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("%f", f.Value) -} - -// Float64 looks up the value of a local Float64Flag, returns -// 0 if not found -func (c *Context) Float64(name string) float64 { - return lookupFloat64(name, c.flagSet) -} - -// GlobalFloat64 looks up the value of a global Float64Flag, returns -// 0 if not found -func (c *Context) GlobalFloat64(name string) float64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupFloat64(name, fs) - } - return 0 -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f Float64Flag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f Float64Flag) ApplyWithError(set *flag.FlagSet) error { - if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - envValFloat, err := strconv.ParseFloat(envVal, 10) - if err != nil { - return fmt.Errorf("could not parse %s as float64 value for flag %s: %s", envVal, f.Name, err) - } - - f.Value = envValFloat - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.Float64Var(f.Destination, name, f.Value, f.Usage) - return - } - set.Float64(name, f.Value, f.Usage) - }) - - return nil -} - -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 -} diff --git a/vendor/github.com/urfave/cli/flag_generic.go b/vendor/github.com/urfave/cli/flag_generic.go deleted file mode 100644 index c43dae7d0b2..00000000000 --- a/vendor/github.com/urfave/cli/flag_generic.go +++ /dev/null @@ -1,110 +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 -} - -// GenericFlag is a flag with type Generic -type GenericFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value Generic -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f GenericFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f GenericFlag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f GenericFlag) IsRequired() bool { - return f.Required -} - -// 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 -} - -// 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 "" -} - -// Apply takes the flagset and calls Set on the generic flag with the value -// provided by the user for parsing by the flag -// Ignores parsing errors -func (f GenericFlag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError 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) ApplyWithError(set *flag.FlagSet) error { - val := f.Value - if fileEnvVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - if err := val.Set(fileEnvVal); err != nil { - return fmt.Errorf("could not parse %s as value for flag %s: %s", fileEnvVal, f.Name, err) - } - } - - eachName(f.Name, func(name string) { - set.Var(f.Value, name, f.Usage) - }) - - return nil -} - -// Generic looks up the value of a local GenericFlag, returns -// nil if not found -func (c *Context) Generic(name string) interface{} { - return lookupGeneric(name, c.flagSet) -} - -// GlobalGeneric looks up the value of a global GenericFlag, returns -// nil if not found -func (c *Context) GlobalGeneric(name string) interface{} { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupGeneric(name, fs) - } - return nil -} - -func lookupGeneric(name string, set *flag.FlagSet) interface{} { - f := set.Lookup(name) - if f != nil { - parsed, err := f.Value, error(nil) - if err != nil { - return nil - } - return parsed - } - return nil -} diff --git a/vendor/github.com/urfave/cli/flag_int.go b/vendor/github.com/urfave/cli/flag_int.go deleted file mode 100644 index bae32e2818e..00000000000 --- a/vendor/github.com/urfave/cli/flag_int.go +++ /dev/null @@ -1,105 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "strconv" -) - -// IntFlag is a flag with type int -type IntFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - Value int - Destination *int -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f IntFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f IntFlag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f IntFlag) IsRequired() bool { - return f.Required -} - -// 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 -} - -// 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) -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f IntFlag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f IntFlag) ApplyWithError(set *flag.FlagSet) error { - if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - envValInt, err := strconv.ParseInt(envVal, 0, 64) - if err != nil { - return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) - } - f.Value = int(envValInt) - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.IntVar(f.Destination, name, f.Value, f.Usage) - return - } - set.Int(name, f.Value, f.Usage) - }) - - return nil -} - -// Int looks up the value of a local IntFlag, returns -// 0 if not found -func (c *Context) Int(name string) int { - return lookupInt(name, c.flagSet) -} - -// GlobalInt looks up the value of a global IntFlag, returns -// 0 if not found -func (c *Context) GlobalInt(name string) int { - if fs := lookupGlobalFlagSet(name, c); 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 -} diff --git a/vendor/github.com/urfave/cli/flag_int64.go b/vendor/github.com/urfave/cli/flag_int64.go deleted file mode 100644 index aaafbe9d6d5..00000000000 --- a/vendor/github.com/urfave/cli/flag_int64.go +++ /dev/null @@ -1,106 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "strconv" -) - -// Int64Flag is a flag with type int64 -type Int64Flag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - Value int64 - Destination *int64 -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f Int64Flag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f Int64Flag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f Int64Flag) IsRequired() bool { - return f.Required -} - -// 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 -} - -// 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) -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f Int64Flag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f Int64Flag) ApplyWithError(set *flag.FlagSet) error { - if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - envValInt, err := strconv.ParseInt(envVal, 0, 64) - if err != nil { - return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) - } - - f.Value = envValInt - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.Int64Var(f.Destination, name, f.Value, f.Usage) - return - } - set.Int64(name, f.Value, f.Usage) - }) - - return nil -} - -// Int64 looks up the value of a local Int64Flag, returns -// 0 if not found -func (c *Context) Int64(name string) int64 { - return lookupInt64(name, c.flagSet) -} - -// GlobalInt64 looks up the value of a global Int64Flag, returns -// 0 if not found -func (c *Context) GlobalInt64(name string) int64 { - if fs := lookupGlobalFlagSet(name, c); 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 -} diff --git a/vendor/github.com/urfave/cli/flag_int64_slice.go b/vendor/github.com/urfave/cli/flag_int64_slice.go deleted file mode 100644 index 80772e7c2a8..00000000000 --- a/vendor/github.com/urfave/cli/flag_int64_slice.go +++ /dev/null @@ -1,199 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "strconv" - "strings" -) - -// Int64Slice is an opaque type for []int to satisfy flag.Value and flag.Getter -type Int64Slice []int64 - -// Set parses the value into an integer and appends it to the list of values -func (f *Int64Slice) Set(value string) error { - tmp, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return err - } - *f = append(*f, tmp) - return nil -} - -// String returns a readable representation of this value (for usage defaults) -func (f *Int64Slice) String() string { - slice := make([]string, len(*f)) - for i, v := range *f { - slice[i] = strconv.FormatInt(v, 10) - } - - return strings.Join(slice, ",") -} - -// Value returns the slice of ints set by this flag -func (f *Int64Slice) Value() []int64 { - return *f -} - -// Get returns the slice of ints set by this flag -func (f *Int64Slice) Get() interface{} { - return *f -} - -// Int64SliceFlag is a flag with type *Int64Slice -type Int64SliceFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - Value *Int64Slice -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f Int64SliceFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f Int64SliceFlag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f Int64SliceFlag) IsRequired() bool { - return f.Required -} - -// 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 -} - -// 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 { - if f.Value != nil { - return f.Value.String() - } - return "" -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f Int64SliceFlag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f Int64SliceFlag) ApplyWithError(set *flag.FlagSet) error { - if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - newVal := &Int64Slice{} - for _, s := range strings.Split(envVal, ",") { - s = strings.TrimSpace(s) - if err := newVal.Set(s); err != nil { - return fmt.Errorf("could not parse %s as int64 slice value for flag %s: %s", envVal, f.Name, err) - } - } - if f.Value == nil { - f.Value = newVal - } else { - *f.Value = *newVal - } - } - - eachName(f.Name, func(name string) { - if f.Value == nil { - f.Value = &Int64Slice{} - } - set.Var(f.Value, name, f.Usage) - }) - - return nil -} - -// Int64Slice looks up the value of a local Int64SliceFlag, returns -// nil if not found -func (c *Context) Int64Slice(name string) []int64 { - return lookupInt64Slice(name, c.flagSet) -} - -// GlobalInt64Slice looks up the value of a global Int64SliceFlag, returns -// nil if not found -func (c *Context) GlobalInt64Slice(name string) []int64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt64Slice(name, fs) - } - return nil -} - -func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { - f := set.Lookup(name) - if f != nil { - value, ok := f.Value.(*Int64Slice) - if !ok { - return nil - } - - // extract the slice from asserted value - parsed := value.Value() - - // extract default value from the flag - var defaultVal []int64 - for _, v := range strings.Split(f.DefValue, ",") { - if v != "" { - int64Value, err := strconv.ParseInt(v, 10, 64) - if err != nil { - panic(err) - } - defaultVal = append(defaultVal, int64Value) - } - } - // if the current value is not equal to the default value - // remove the default values from the flag - if !isInt64SliceEqual(parsed, defaultVal) { - for _, v := range defaultVal { - parsed = removeFromInt64Slice(parsed, v) - } - } - return parsed - } - return nil -} - -func removeFromInt64Slice(slice []int64, val int64) []int64 { - for i, v := range slice { - if v == val { - ret := append([]int64{}, slice[:i]...) - ret = append(ret, slice[i+1:]...) - return ret - } - } - return slice -} - -func isInt64SliceEqual(newValue, defaultValue []int64) bool { - // If one is nil, the other must also be nil. - if (newValue == nil) != (defaultValue == nil) { - return false - } - - if len(newValue) != len(defaultValue) { - return false - } - - for i, v := range newValue { - if v != defaultValue[i] { - return false - } - } - - return true -} diff --git a/vendor/github.com/urfave/cli/flag_int_slice.go b/vendor/github.com/urfave/cli/flag_int_slice.go deleted file mode 100644 index af6d582debc..00000000000 --- a/vendor/github.com/urfave/cli/flag_int_slice.go +++ /dev/null @@ -1,198 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "strconv" - "strings" -) - -// IntSlice is an opaque type for []int to satisfy flag.Value and flag.Getter -type IntSlice []int - -// Set parses the value into an integer and appends it to the list of values -func (f *IntSlice) Set(value string) error { - tmp, err := strconv.Atoi(value) - if err != nil { - return err - } - *f = append(*f, tmp) - return nil -} - -// String returns a readable representation of this value (for usage defaults) -func (f *IntSlice) String() string { - slice := make([]string, len(*f)) - for i, v := range *f { - slice[i] = strconv.Itoa(v) - } - - return strings.Join(slice, ",") -} - -// Value returns the slice of ints set by this flag -func (f *IntSlice) Value() []int { - return *f -} - -// Get returns the slice of ints set by this flag -func (f *IntSlice) Get() interface{} { - return *f -} - -// IntSliceFlag is a flag with type *IntSlice -type IntSliceFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - Value *IntSlice -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f IntSliceFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f IntSliceFlag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f IntSliceFlag) IsRequired() bool { - return f.Required -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f IntSliceFlag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f IntSliceFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f IntSliceFlag) GetValue() string { - if f.Value != nil { - return f.Value.String() - } - return "" -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f IntSliceFlag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f IntSliceFlag) ApplyWithError(set *flag.FlagSet) error { - if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - newVal := &IntSlice{} - for _, s := range strings.Split(envVal, ",") { - s = strings.TrimSpace(s) - if err := newVal.Set(s); err != nil { - return fmt.Errorf("could not parse %s as int slice value for flag %s: %s", envVal, f.Name, err) - } - } - if f.Value == nil { - f.Value = newVal - } else { - *f.Value = *newVal - } - } - - eachName(f.Name, func(name string) { - if f.Value == nil { - f.Value = &IntSlice{} - } - set.Var(f.Value, name, f.Usage) - }) - - return nil -} - -// IntSlice looks up the value of a local IntSliceFlag, returns -// nil if not found -func (c *Context) IntSlice(name string) []int { - return lookupIntSlice(name, c.flagSet) -} - -// GlobalIntSlice looks up the value of a global IntSliceFlag, returns -// nil if not found -func (c *Context) GlobalIntSlice(name string) []int { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupIntSlice(name, fs) - } - return nil -} - -func lookupIntSlice(name string, set *flag.FlagSet) []int { - f := set.Lookup(name) - if f != nil { - value, ok := f.Value.(*IntSlice) - if !ok { - return nil - } - // extract the slice from asserted value - slice := value.Value() - - // extract default value from the flag - var defaultVal []int - for _, v := range strings.Split(f.DefValue, ",") { - if v != "" { - intValue, err := strconv.Atoi(v) - if err != nil { - panic(err) - } - defaultVal = append(defaultVal, intValue) - } - } - // if the current value is not equal to the default value - // remove the default values from the flag - if !isIntSliceEqual(slice, defaultVal) { - for _, v := range defaultVal { - slice = removeFromIntSlice(slice, v) - } - } - return slice - } - return nil -} - -func removeFromIntSlice(slice []int, val int) []int { - for i, v := range slice { - if v == val { - ret := append([]int{}, slice[:i]...) - ret = append(ret, slice[i+1:]...) - return ret - } - } - return slice -} - -func isIntSliceEqual(newValue, defaultValue []int) bool { - // If one is nil, the other must also be nil. - if (newValue == nil) != (defaultValue == nil) { - return false - } - - if len(newValue) != len(defaultValue) { - return false - } - - for i, v := range newValue { - if v != defaultValue[i] { - return false - } - } - - return true -} diff --git a/vendor/github.com/urfave/cli/flag_string.go b/vendor/github.com/urfave/cli/flag_string.go deleted file mode 100644 index 9f29da40b93..00000000000 --- a/vendor/github.com/urfave/cli/flag_string.go +++ /dev/null @@ -1,98 +0,0 @@ -package cli - -import "flag" - -// StringFlag is a flag with type string -type StringFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value string - Destination *string -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f StringFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f StringFlag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f StringFlag) IsRequired() bool { - return f.Required -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f StringFlag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f StringFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f StringFlag) GetValue() string { - return f.Value -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f StringFlag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f StringFlag) ApplyWithError(set *flag.FlagSet) error { - if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - f.Value = envVal - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.StringVar(f.Destination, name, f.Value, f.Usage) - return - } - set.String(name, f.Value, f.Usage) - }) - - return nil -} - -// String looks up the value of a local StringFlag, returns -// "" if not found -func (c *Context) String(name string) string { - return lookupString(name, c.flagSet) -} - -// GlobalString looks up the value of a global StringFlag, returns -// "" if not found -func (c *Context) GlobalString(name string) string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupString(name, fs) - } - return "" -} - -func lookupString(name string, set *flag.FlagSet) string { - f := set.Lookup(name) - if f != nil { - parsed, err := f.Value.String(), error(nil) - if err != nil { - return "" - } - return parsed - } - return "" -} diff --git a/vendor/github.com/urfave/cli/flag_string_slice.go b/vendor/github.com/urfave/cli/flag_string_slice.go deleted file mode 100644 index a7c71e9dcc3..00000000000 --- a/vendor/github.com/urfave/cli/flag_string_slice.go +++ /dev/null @@ -1,184 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "strings" -) - -// StringSlice is an opaque type for []string to satisfy flag.Value and flag.Getter -type StringSlice []string - -// Set appends the string value to the list of values -func (f *StringSlice) Set(value string) error { - *f = append(*f, value) - return nil -} - -// String returns a readable representation of this value (for usage defaults) -func (f *StringSlice) String() string { - return strings.Join(*f, ",") -} - -// Value returns the slice of strings set by this flag -func (f *StringSlice) Value() []string { - return *f -} - -// Get returns the slice of strings set by this flag -func (f *StringSlice) Get() interface{} { - return *f -} - -// StringSliceFlag is a flag with type *StringSlice -type StringSliceFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value *StringSlice -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f StringSliceFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f StringSliceFlag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f StringSliceFlag) IsRequired() bool { - return f.Required -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f StringSliceFlag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f StringSliceFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f StringSliceFlag) GetValue() string { - if f.Value != nil { - return f.Value.String() - } - return "" -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f StringSliceFlag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f StringSliceFlag) ApplyWithError(set *flag.FlagSet) error { - if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - newVal := &StringSlice{} - for _, s := range strings.Split(envVal, ",") { - s = strings.TrimSpace(s) - if err := newVal.Set(s); err != nil { - return fmt.Errorf("could not parse %s as string value for flag %s: %s", envVal, f.Name, err) - } - } - if f.Value == nil { - f.Value = newVal - } else { - *f.Value = *newVal - } - } - - eachName(f.Name, func(name string) { - if f.Value == nil { - f.Value = &StringSlice{} - } - set.Var(f.Value, name, f.Usage) - }) - - return nil -} - -// StringSlice looks up the value of a local StringSliceFlag, returns -// nil if not found -func (c *Context) StringSlice(name string) []string { - return lookupStringSlice(name, c.flagSet) -} - -// GlobalStringSlice looks up the value of a global StringSliceFlag, returns -// nil if not found -func (c *Context) GlobalStringSlice(name string) []string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupStringSlice(name, fs) - } - return nil -} - -func lookupStringSlice(name string, set *flag.FlagSet) []string { - f := set.Lookup(name) - if f != nil { - value, ok := f.Value.(*StringSlice) - if !ok { - return nil - } - // extract the slice from asserted value - slice := value.Value() - - // extract default value from the flag - var defaultVal []string - for _, v := range strings.Split(f.DefValue, ",") { - defaultVal = append(defaultVal, v) - } - - // if the current value is not equal to the default value - // remove the default values from the flag - if !isStringSliceEqual(slice, defaultVal) { - for _, v := range defaultVal { - slice = removeFromStringSlice(slice, v) - } - } - return slice - } - return nil -} - -func removeFromStringSlice(slice []string, val string) []string { - for i, v := range slice { - if v == val { - ret := append([]string{}, slice[:i]...) - ret = append(ret, slice[i+1:]...) - return ret - } - } - return slice -} - -func isStringSliceEqual(newValue, defaultValue []string) bool { - // If one is nil, the other must also be nil. - if (newValue == nil) != (defaultValue == nil) { - return false - } - - if len(newValue) != len(defaultValue) { - return false - } - - for i, v := range newValue { - if v != defaultValue[i] { - return false - } - } - - return true -} diff --git a/vendor/github.com/urfave/cli/flag_uint.go b/vendor/github.com/urfave/cli/flag_uint.go deleted file mode 100644 index d6a04f40870..00000000000 --- a/vendor/github.com/urfave/cli/flag_uint.go +++ /dev/null @@ -1,106 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "strconv" -) - -// UintFlag is a flag with type uint -type UintFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - Value uint - Destination *uint -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f UintFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f UintFlag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f UintFlag) IsRequired() bool { - return f.Required -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f UintFlag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f UintFlag) GetUsage() string { - return f.Usage -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f UintFlag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f UintFlag) ApplyWithError(set *flag.FlagSet) error { - if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - envValInt, err := strconv.ParseUint(envVal, 0, 64) - if err != nil { - return fmt.Errorf("could not parse %s as uint value for flag %s: %s", envVal, f.Name, err) - } - - f.Value = uint(envValInt) - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.UintVar(f.Destination, name, f.Value, f.Usage) - return - } - set.Uint(name, f.Value, f.Usage) - }) - - return nil -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f UintFlag) GetValue() string { - return fmt.Sprintf("%d", f.Value) -} - -// Uint looks up the value of a local UintFlag, returns -// 0 if not found -func (c *Context) Uint(name string) uint { - return lookupUint(name, c.flagSet) -} - -// GlobalUint looks up the value of a global UintFlag, returns -// 0 if not found -func (c *Context) GlobalUint(name string) uint { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupUint(name, fs) - } - return 0 -} - -func lookupUint(name string, set *flag.FlagSet) uint { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return uint(parsed) - } - return 0 -} diff --git a/vendor/github.com/urfave/cli/flag_uint64.go b/vendor/github.com/urfave/cli/flag_uint64.go deleted file mode 100644 index ea6493a8be8..00000000000 --- a/vendor/github.com/urfave/cli/flag_uint64.go +++ /dev/null @@ -1,106 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "strconv" -) - -// Uint64Flag is a flag with type uint64 -type Uint64Flag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - Value uint64 - Destination *uint64 -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f Uint64Flag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f Uint64Flag) GetName() string { - return f.Name -} - -// IsRequired returns whether or not the flag is required -func (f Uint64Flag) IsRequired() bool { - return f.Required -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f Uint64Flag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f Uint64Flag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f Uint64Flag) GetValue() string { - return fmt.Sprintf("%d", f.Value) -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f Uint64Flag) Apply(set *flag.FlagSet) { - _ = f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f Uint64Flag) ApplyWithError(set *flag.FlagSet) error { - if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok { - envValInt, err := strconv.ParseUint(envVal, 0, 64) - if err != nil { - return fmt.Errorf("could not parse %s as uint64 value for flag %s: %s", envVal, f.Name, err) - } - - f.Value = envValInt - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.Uint64Var(f.Destination, name, f.Value, f.Usage) - return - } - set.Uint64(name, f.Value, f.Usage) - }) - - return nil -} - -// Uint64 looks up the value of a local Uint64Flag, returns -// 0 if not found -func (c *Context) Uint64(name string) uint64 { - return lookupUint64(name, c.flagSet) -} - -// GlobalUint64 looks up the value of a global Uint64Flag, returns -// 0 if not found -func (c *Context) GlobalUint64(name string) uint64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupUint64(name, fs) - } - return 0 -} - -func lookupUint64(name string, set *flag.FlagSet) uint64 { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return parsed - } - return 0 -} diff --git a/vendor/github.com/urfave/cli/funcs.go b/vendor/github.com/urfave/cli/funcs.go deleted file mode 100644 index 0036b1130aa..00000000000 --- a/vendor/github.com/urfave/cli/funcs.go +++ /dev/null @@ -1,44 +0,0 @@ -package cli - -// BashCompleteFunc is an action to execute when the bash-completion flag is set -type BashCompleteFunc func(*Context) - -// BeforeFunc is 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 -type BeforeFunc func(*Context) error - -// AfterFunc is an action to execute after any subcommands are run, but after the -// subcommand has finished it is run even if Action() panics -type AfterFunc func(*Context) error - -// ActionFunc is the action to execute when no subcommands are specified -type ActionFunc func(*Context) error - -// CommandNotFoundFunc is executed if the proper command cannot be found -type CommandNotFoundFunc func(*Context, string) - -// OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying -// customized usage error messages. This function is able to replace the -// original error messages. If this function is not set, the "Incorrect usage" -// is displayed and the execution is interrupted. -type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error - -// ExitErrHandlerFunc is executed if provided in order to handle ExitError values -// returned by Actions and Before/After functions. -type ExitErrHandlerFunc func(context *Context, err error) - -// FlagStringFunc is used by the help generation to display a flag, which is -// expected to be a single line. -type FlagStringFunc func(Flag) string - -// FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix -// text for a flag's full name. -type FlagNamePrefixFunc func(fullName, placeholder string) string - -// FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help -// with the environment variable details. -type FlagEnvHintFunc func(envVar, str string) string - -// FlagFileHintFunc is used by the default FlagStringFunc to annotate flag help -// with the file path details. -type FlagFileHintFunc func(filePath, str string) string diff --git a/vendor/github.com/urfave/cli/help.go b/vendor/github.com/urfave/cli/help.go deleted file mode 100644 index 2280e338ef0..00000000000 --- a/vendor/github.com/urfave/cli/help.go +++ /dev/null @@ -1,363 +0,0 @@ -package cli - -import ( - "fmt" - "io" - "os" - "strings" - "text/tabwriter" - "text/template" - "unicode/utf8" -) - -var helpCommand = Command{ - Name: "help", - Aliases: []string{"h"}, - Usage: "Shows a list of commands or help for one command", - ArgsUsage: "[command]", - Action: func(c *Context) error { - args := c.Args() - if args.Present() { - return ShowCommandHelp(c, args.First()) - } - - _ = ShowAppHelp(c) - return nil - }, -} - -var helpSubcommand = Command{ - Name: "help", - Aliases: []string{"h"}, - Usage: "Shows a list of commands or help for one command", - ArgsUsage: "[command]", - Action: func(c *Context) error { - args := c.Args() - if args.Present() { - return ShowCommandHelp(c, args.First()) - } - - return ShowSubcommandHelp(c) - }, -} - -// Prints help for the App or Command -type helpPrinter func(w io.Writer, templ string, data interface{}) - -// Prints help for the App or Command with custom template function. -type helpPrinterCustom func(w io.Writer, templ string, data interface{}, customFunc map[string]interface{}) - -// HelpPrinter is a function that writes the help output. If not set explicitly, -// this calls HelpPrinterCustom using only the default template functions. -// -// If custom logic for printing help is required, this function can be -// overridden. If the ExtraInfo field is defined on an App, this function -// should not be modified, as HelpPrinterCustom will be used directly in order -// to capture the extra information. -var HelpPrinter helpPrinter = printHelp - -// HelpPrinterCustom is a function that writes the help output. It is used as -// the default implementation of HelpPrinter, and may be called directly if -// the ExtraInfo field is set on an App. -var HelpPrinterCustom helpPrinterCustom = printHelpCustom - -// VersionPrinter prints the version for the App -var VersionPrinter = printVersion - -// ShowAppHelpAndExit - Prints the list of subcommands for the app and exits with exit code. -func ShowAppHelpAndExit(c *Context, exitCode int) { - _ = ShowAppHelp(c) - os.Exit(exitCode) -} - -// ShowAppHelp is an action that displays the help. -func ShowAppHelp(c *Context) error { - template := c.App.CustomAppHelpTemplate - if template == "" { - template = AppHelpTemplate - } - - if c.App.ExtraInfo == nil { - HelpPrinter(c.App.Writer, template, c.App) - return nil - } - - customAppData := func() map[string]interface{} { - return map[string]interface{}{ - "ExtraInfo": c.App.ExtraInfo, - } - } - HelpPrinterCustom(c.App.Writer, template, c.App, customAppData()) - - return nil -} - -// DefaultAppComplete prints the list of subcommands as the default app completion method -func DefaultAppComplete(c *Context) { - DefaultCompleteWithFlags(nil)(c) -} - -func printCommandSuggestions(commands []Command, writer io.Writer) { - for _, command := range commands { - if command.Hidden { - continue - } - if os.Getenv("_CLI_ZSH_AUTOCOMPLETE_HACK") == "1" { - for _, name := range command.Names() { - _, _ = fmt.Fprintf(writer, "%s:%s\n", name, command.Usage) - } - } else { - for _, name := range command.Names() { - _, _ = fmt.Fprintf(writer, "%s\n", name) - } - } - } -} - -func cliArgContains(flagName string) bool { - for _, name := range strings.Split(flagName, ",") { - name = strings.TrimSpace(name) - count := utf8.RuneCountInString(name) - if count > 2 { - count = 2 - } - flag := fmt.Sprintf("%s%s", strings.Repeat("-", count), name) - for _, a := range os.Args { - if a == flag { - return true - } - } - } - return false -} - -func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) { - cur := strings.TrimPrefix(lastArg, "-") - cur = strings.TrimPrefix(cur, "-") - for _, flag := range flags { - if bflag, ok := flag.(BoolFlag); ok && bflag.Hidden { - continue - } - for _, name := range strings.Split(flag.GetName(), ",") { - name = strings.TrimSpace(name) - // this will get total count utf8 letters in flag name - count := utf8.RuneCountInString(name) - if count > 2 { - count = 2 // resuse this count to generate single - or -- in flag completion - } - // if flag name has more than one utf8 letter and last argument in cli has -- prefix then - // skip flag completion for short flags example -v or -x - if strings.HasPrefix(lastArg, "--") && count == 1 { - continue - } - // match if last argument matches this flag and it is not repeated - if strings.HasPrefix(name, cur) && cur != name && !cliArgContains(flag.GetName()) { - flagCompletion := fmt.Sprintf("%s%s", strings.Repeat("-", count), name) - _, _ = fmt.Fprintln(writer, flagCompletion) - } - } - } -} - -func DefaultCompleteWithFlags(cmd *Command) func(c *Context) { - return func(c *Context) { - if len(os.Args) > 2 { - lastArg := os.Args[len(os.Args)-2] - if strings.HasPrefix(lastArg, "-") { - printFlagSuggestions(lastArg, c.App.Flags, c.App.Writer) - if cmd != nil { - printFlagSuggestions(lastArg, cmd.Flags, c.App.Writer) - } - return - } - } - if cmd != nil { - printCommandSuggestions(cmd.Subcommands, c.App.Writer) - } else { - printCommandSuggestions(c.App.Commands, c.App.Writer) - } - } -} - -// ShowCommandHelpAndExit - exits with code after showing help -func ShowCommandHelpAndExit(c *Context, command string, code int) { - _ = ShowCommandHelp(c, command) - os.Exit(code) -} - -// ShowCommandHelp prints help for the given command -func ShowCommandHelp(ctx *Context, command string) error { - // show the subcommand help for a command with subcommands - if command == "" { - HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App) - return nil - } - - for _, c := range ctx.App.Commands { - if c.HasName(command) { - templ := c.CustomHelpTemplate - if templ == "" { - templ = CommandHelpTemplate - } - - HelpPrinter(ctx.App.Writer, templ, c) - - return nil - } - } - - if ctx.App.CommandNotFound == nil { - return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3) - } - - ctx.App.CommandNotFound(ctx, command) - return nil -} - -// ShowSubcommandHelp prints help for the given subcommand -func ShowSubcommandHelp(c *Context) error { - return ShowCommandHelp(c, c.Command.Name) -} - -// ShowVersion prints the version number of the App -func ShowVersion(c *Context) { - VersionPrinter(c) -} - -func printVersion(c *Context) { - _, _ = fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) -} - -// ShowCompletions prints the lists of commands within a given context -func ShowCompletions(c *Context) { - a := c.App - if a != nil && a.BashComplete != nil { - a.BashComplete(c) - } -} - -// ShowCommandCompletions prints the custom completions for a given command -func ShowCommandCompletions(ctx *Context, command string) { - c := ctx.App.Command(command) - if c != nil { - if c.BashComplete != nil { - c.BashComplete(ctx) - } else { - DefaultCompleteWithFlags(c)(ctx) - } - } - -} - -// printHelpCustom is the default implementation of HelpPrinterCustom. -// -// The customFuncs map will be combined with a default template.FuncMap to -// allow using arbitrary functions in template rendering. -func printHelpCustom(out io.Writer, templ string, data interface{}, customFuncs map[string]interface{}) { - funcMap := template.FuncMap{ - "join": strings.Join, - } - for key, value := range customFuncs { - funcMap[key] = value - } - - w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) - t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) - err := t.Execute(w, data) - if err != nil { - // If the writer is closed, t.Execute will fail, and there's nothing - // we can do to recover. - if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" { - _, _ = fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err) - } - return - } - _ = w.Flush() -} - -func printHelp(out io.Writer, templ string, data interface{}) { - HelpPrinterCustom(out, templ, data, nil) -} - -func checkVersion(c *Context) bool { - found := false - if VersionFlag.GetName() != "" { - eachName(VersionFlag.GetName(), func(name string) { - if c.GlobalBool(name) || c.Bool(name) { - found = true - } - }) - } - return found -} - -func checkHelp(c *Context) bool { - found := false - if HelpFlag.GetName() != "" { - eachName(HelpFlag.GetName(), func(name string) { - if c.GlobalBool(name) || c.Bool(name) { - found = true - } - }) - } - return found -} - -func checkCommandHelp(c *Context, name string) bool { - if c.Bool("h") || c.Bool("help") { - _ = ShowCommandHelp(c, name) - return true - } - - return false -} - -func checkSubcommandHelp(c *Context) bool { - if c.Bool("h") || c.Bool("help") { - _ = ShowSubcommandHelp(c) - return true - } - - return false -} - -func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { - if !a.EnableBashCompletion { - return false, arguments - } - - pos := len(arguments) - 1 - lastArg := arguments[pos] - - if lastArg != "--"+BashCompletionFlag.GetName() { - return false, arguments - } - - return true, arguments[:pos] -} - -func checkCompletions(c *Context) bool { - if !c.shellComplete { - return false - } - - if args := c.Args(); args.Present() { - name := args.First() - if cmd := c.App.Command(name); cmd != nil { - // let the command handle the completion - return false - } - } - - ShowCompletions(c) - return true -} - -func checkCommandCompletions(c *Context, name string) bool { - if !c.shellComplete { - return false - } - - ShowCommandCompletions(c, name) - return true -} diff --git a/vendor/github.com/urfave/cli/parse.go b/vendor/github.com/urfave/cli/parse.go deleted file mode 100644 index 7df17296a42..00000000000 --- a/vendor/github.com/urfave/cli/parse.go +++ /dev/null @@ -1,94 +0,0 @@ -package cli - -import ( - "flag" - "strings" -) - -type iterativeParser interface { - newFlagSet() (*flag.FlagSet, error) - useShortOptionHandling() bool -} - -// To enable short-option handling (e.g., "-it" vs "-i -t") we have to -// iteratively catch parsing errors. This way we achieve LR parsing without -// transforming any arguments. Otherwise, there is no way we can discriminate -// combined short options from common arguments that should be left untouched. -// Pass `shellComplete` to continue parsing options on failure during shell -// completion when, the user-supplied options may be incomplete. -func parseIter(set *flag.FlagSet, ip iterativeParser, args []string, shellComplete bool) error { - for { - err := set.Parse(args) - if !ip.useShortOptionHandling() || err == nil { - if shellComplete { - return nil - } - return err - } - - errStr := err.Error() - trimmed := strings.TrimPrefix(errStr, "flag provided but not defined: -") - if errStr == trimmed { - return err - } - - // regenerate the initial args with the split short opts - argsWereSplit := false - for i, arg := range args { - // skip args that are not part of the error message - if name := strings.TrimLeft(arg, "-"); name != trimmed { - continue - } - - // if we can't split, the error was accurate - shortOpts := splitShortOptions(set, arg) - if len(shortOpts) == 1 { - return err - } - - // swap current argument with the split version - args = append(args[:i], append(shortOpts, args[i+1:]...)...) - argsWereSplit = true - break - } - - // This should be an impossible to reach code path, but in case the arg - // splitting failed to happen, this will prevent infinite loops - if !argsWereSplit { - return err - } - - // Since custom parsing failed, replace the flag set before retrying - newSet, err := ip.newFlagSet() - if err != nil { - return err - } - *set = *newSet - } -} - -func splitShortOptions(set *flag.FlagSet, arg string) []string { - shortFlagsExist := func(s string) bool { - for _, c := range s[1:] { - if f := set.Lookup(string(c)); f == nil { - return false - } - } - return true - } - - if !isSplittable(arg) || !shortFlagsExist(arg) { - return []string{arg} - } - - separated := make([]string, 0, len(arg)-1) - for _, flagChar := range arg[1:] { - separated = append(separated, "-"+string(flagChar)) - } - - return separated -} - -func isSplittable(flagArg string) bool { - return strings.HasPrefix(flagArg, "-") && !strings.HasPrefix(flagArg, "--") && len(flagArg) > 2 -} diff --git a/vendor/github.com/urfave/cli/template.go b/vendor/github.com/urfave/cli/template.go deleted file mode 100644 index c631fb97dd1..00000000000 --- a/vendor/github.com/urfave/cli/template.go +++ /dev/null @@ -1,121 +0,0 @@ -package cli - -// AppHelpTemplate is the text template for the Default help topic. -// cli.go uses text/template to render templates. You can -// render custom help text by setting this variable. -var AppHelpTemplate = `NAME: - {{.Name}}{{if .Usage}} - {{.Usage}}{{end}} - -USAGE: - {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} - -VERSION: - {{.Version}}{{end}}{{end}}{{if .Description}} - -DESCRIPTION: - {{.Description}}{{end}}{{if len .Authors}} - -AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: - {{range $index, $author := .Authors}}{{if $index}} - {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}} - -COMMANDS:{{range .VisibleCategories}}{{if .Name}} - - {{.Name}}:{{range .VisibleCommands}} - {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}} - {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} - -GLOBAL OPTIONS: - {{range $index, $option := .VisibleFlags}}{{if $index}} - {{end}}{{$option}}{{end}}{{end}}{{if .Copyright}} - -COPYRIGHT: - {{.Copyright}}{{end}} -` - -// CommandHelpTemplate is 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. -var CommandHelpTemplate = `NAME: - {{.HelpName}} - {{.Usage}} - -USAGE: - {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} - -CATEGORY: - {{.Category}}{{end}}{{if .Description}} - -DESCRIPTION: - {{.Description}}{{end}}{{if .VisibleFlags}} - -OPTIONS: - {{range .VisibleFlags}}{{.}} - {{end}}{{end}} -` - -// SubcommandHelpTemplate is the text template for the subcommand help topic. -// cli.go uses text/template to render templates. You can -// render custom help text by setting this variable. -var SubcommandHelpTemplate = `NAME: - {{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}} - -USAGE: - {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} - -COMMANDS:{{range .VisibleCategories}}{{if .Name}} - - {{.Name}}:{{range .VisibleCommands}} - {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}} - {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} - -OPTIONS: - {{range .VisibleFlags}}{{.}} - {{end}}{{end}} -` - -var MarkdownDocTemplate = `% {{ .App.Name }}(8) {{ .App.Description }} - -% {{ .App.Author }} - -# NAME - -{{ .App.Name }}{{ if .App.Usage }} - {{ .App.Usage }}{{ end }} - -# SYNOPSIS - -{{ .App.Name }} -{{ if .SynopsisArgs }} -` + "```" + ` -{{ range $v := .SynopsisArgs }}{{ $v }}{{ end }}` + "```" + ` -{{ end }}{{ if .App.UsageText }} -# DESCRIPTION - -{{ .App.UsageText }} -{{ end }} -**Usage**: - -` + "```" + ` -{{ .App.Name }} [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...] -` + "```" + ` -{{ if .GlobalArgs }} -# GLOBAL OPTIONS -{{ range $v := .GlobalArgs }} -{{ $v }}{{ end }} -{{ end }}{{ if .Commands }} -# COMMANDS -{{ range $v := .Commands }} -{{ $v }}{{ end }}{{ end }}` - -var FishCompletionTemplate = `# {{ .App.Name }} fish shell completion - -function __fish_{{ .App.Name }}_no_subcommand --description 'Test if there has been any subcommand yet' - for i in (commandline -opc) - if contains -- $i{{ range $v := .AllCommands }} {{ $v }}{{ end }} - return 1 - end - end - return 0 -end - -{{ range $v := .Completions }}{{ $v }} -{{ end }}` diff --git a/vendor/github.com/urfave/cli/.gitignore b/vendor/github.com/urfave/cli/v3/.gitignore similarity index 50% rename from vendor/github.com/urfave/cli/.gitignore rename to vendor/github.com/urfave/cli/v3/.gitignore index 9d1812002b4..6b191490464 100644 --- a/vendor/github.com/urfave/cli/.gitignore +++ b/vendor/github.com/urfave/cli/v3/.gitignore @@ -1,10 +1,11 @@ *.coverprofile -coverage.txt -node_modules/ -vendor +*.exe +*.orig +.*envrc +.envrc .idea /.local/ -/internal/ /site/ -package.json -package-lock.json +coverage.txt +examples/*/built-example +vendor diff --git a/vendor/github.com/urfave/cli/v3/.golangci.yaml b/vendor/github.com/urfave/cli/v3/.golangci.yaml new file mode 100644 index 00000000000..473a221ab9a --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/.golangci.yaml @@ -0,0 +1,13 @@ +version: "2" + +formatters: + enable: + - gofumpt + +linters: + enable: + - makezero + - misspell + exclusions: + presets: + - std-error-handling diff --git a/vendor/github.com/urfave/cli/CODE_OF_CONDUCT.md b/vendor/github.com/urfave/cli/v3/CODE_OF_CONDUCT.md similarity index 87% rename from vendor/github.com/urfave/cli/CODE_OF_CONDUCT.md rename to vendor/github.com/urfave/cli/v3/CODE_OF_CONDUCT.md index 41ba294f6db..9fee14807ed 100644 --- a/vendor/github.com/urfave/cli/CODE_OF_CONDUCT.md +++ b/vendor/github.com/urfave/cli/v3/CODE_OF_CONDUCT.md @@ -55,11 +55,12 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting Dan Buch at dan@meatballhat.com. All complaints will be -reviewed and investigated and will result in a response that is deemed necessary -and appropriate to the circumstances. The project team is obligated to maintain -confidentiality with regard to the reporter of an incident. Further details of -specific enforcement policies may be posted separately. +reported by contacting urfave-governance@googlegroups.com, a members-only group +that is world-postable. All complaints will be reviewed and investigated and +will result in a response that is deemed necessary and appropriate to the +circumstances. The project team is obligated to maintain confidentiality with +regard to the reporter of an incident. Further details of specific enforcement +policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other diff --git a/vendor/github.com/urfave/cli/LICENSE b/vendor/github.com/urfave/cli/v3/LICENSE similarity index 95% rename from vendor/github.com/urfave/cli/LICENSE rename to vendor/github.com/urfave/cli/v3/LICENSE index 99d8559da84..a23fc53dea9 100644 --- a/vendor/github.com/urfave/cli/LICENSE +++ b/vendor/github.com/urfave/cli/v3/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Jeremy Saenz & Contributors +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 diff --git a/vendor/github.com/urfave/cli/v3/Makefile b/vendor/github.com/urfave/cli/v3/Makefile new file mode 100644 index 00000000000..2e4af306792 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/Makefile @@ -0,0 +1,26 @@ +# NOTE: this Makefile is meant to provide a simplified entry point for humans to +# run all of the critical steps to verify one's changes are harmonious in +# nature. Keeping target bodies to one line each and abstaining from make magic +# are very important so that maintainers and contributors can focus their +# attention on files that are primarily Go. + +GO_RUN_BUILD := go run scripts/build.go + +.PHONY: all +all: generate vet test check-binary-size gfmrun + +# NOTE: this is a special catch-all rule to run any of the commands +# defined in scripts/build.go with optional arguments passed +# via GFLAGS (global flags) and FLAGS (command-specific flags), e.g.: +# +# $ make test GFLAGS='--packages cli' +%: + $(GO_RUN_BUILD) $(GFLAGS) $* $(FLAGS) + +.PHONY: docs +docs: + mkdocs build + +.PHONY: serve-docs +serve-docs: + mkdocs serve diff --git a/vendor/github.com/urfave/cli/v3/README.md b/vendor/github.com/urfave/cli/v3/README.md new file mode 100644 index 00000000000..e04c7295b56 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/README.md @@ -0,0 +1,56 @@ +# Welcome to urfave/cli + +[![Go Reference][goreference_badge]][goreference_link] +[![Go Report Card][goreportcard_badge]][goreportcard_link] +[![codecov][codecov_badge]][codecov_link] +[![Tests status][test_badge]][test_link] + +urfave/cli is a **declarative**, simple, fast, and fun package for building +command line tools in Go featuring: + +- commands and subcommands with alias and prefix match support +- flexible and permissive help system +- dynamic shell completion for `bash`, `zsh`, `fish`, and `powershell` +- no dependencies except Go standard library +- input flags for simple types, slices of simple types, time, duration, and + others +- compound short flag support (`-a` `-b` `-c` can be shortened to `-abc`) +- documentation generation in `man` and Markdown (supported via the + [`urfave/cli-docs`][urfave/cli-docs] module) +- input lookup from: + - environment variables + - plain text files + - structured file formats (supported via the + [`urfave/cli-altsrc`][urfave/cli-altsrc] module) + +## Documentation + +See the hosted documentation website at . Contents of +this website are built from the [`./docs`](./docs) directory. + +## Support + +Check the [Q&A discussions]. If you don't find answer to your question, [create +a new discussion]. + +If you found a bug or have a feature request, [create a new issue]. + +Please keep in mind that this project is run by unpaid volunteers. + +### License + +See [`LICENSE`](./LICENSE). + +[test_badge]: https://github.com/urfave/cli/actions/workflows/test.yml/badge.svg +[test_link]: https://github.com/urfave/cli/actions/workflows/test.yml +[goreference_badge]: https://pkg.go.dev/badge/github.com/urfave/cli/v3.svg +[goreference_link]: https://pkg.go.dev/github.com/urfave/cli/v3 +[goreportcard_badge]: https://goreportcard.com/badge/github.com/urfave/cli/v3 +[goreportcard_link]: https://goreportcard.com/report/github.com/urfave/cli/v3 +[codecov_badge]: https://codecov.io/gh/urfave/cli/branch/main/graph/badge.svg?token=t9YGWLh05g +[codecov_link]: https://codecov.io/gh/urfave/cli +[Q&A discussions]: https://github.com/urfave/cli/discussions/categories/q-a +[create a new discussion]: https://github.com/urfave/cli/discussions/new?category=q-a +[urfave/cli-docs]: https://github.com/urfave/cli-docs +[urfave/cli-altsrc]: https://github.com/urfave/cli-altsrc +[create a new issue]: https://github.com/urfave/cli/issues/new/choose diff --git a/vendor/github.com/urfave/cli/v3/args.go b/vendor/github.com/urfave/cli/v3/args.go new file mode 100644 index 00000000000..b3acfd5ccc5 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/args.go @@ -0,0 +1,400 @@ +package cli + +import ( + "fmt" + "time" +) + +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 stringSliceArgs struct { + v []string +} + +func (a *stringSliceArgs) Get(n int) string { + if len(a.v) > n { + return a.v[n] + } + return "" +} + +func (a *stringSliceArgs) First() string { + return a.Get(0) +} + +func (a *stringSliceArgs) Tail() []string { + if a.Len() >= 2 { + tail := a.v[1:] + ret := make([]string, len(tail)) + copy(ret, tail) + return ret + } + + return []string{} +} + +func (a *stringSliceArgs) Len() int { + return len(a.v) +} + +func (a *stringSliceArgs) Present() bool { + return a.Len() != 0 +} + +func (a *stringSliceArgs) Slice() []string { + ret := make([]string, len(a.v)) + copy(ret, a.v) + return ret +} + +// Argument captures a positional argument that can +// be parsed +type Argument interface { + // which this argument can be accessed using the given name + HasName(string) bool + + // Parse the given args and return unparsed args and/or error + Parse([]string) ([]string, error) + + // The usage template for this argument to use in help + Usage() string + + // The Value of this Arg + Get() any +} + +// AnyArguments to differentiate between no arguments(nil) vs aleast one +var AnyArguments = []Argument{ + &StringArgs{ + Max: -1, + }, +} + +type ArgumentBase[T any, C any, VC ValueCreator[T, C]] struct { + Name string `json:"name"` // the name of this argument + Value T `json:"value"` // the default value of this argument + Destination *T `json:"-"` // the destination point for this argument + UsageText string `json:"usageText"` // the usage text to show + Config C `json:"config"` // config for this argument similar to Flag Config + + value *T +} + +func (a *ArgumentBase[T, C, VC]) HasName(s string) bool { + return s == a.Name +} + +func (a *ArgumentBase[T, C, VC]) Usage() string { + if a.UsageText != "" { + return a.UsageText + } + + usageFormat := "%[1]s" + return fmt.Sprintf(usageFormat, a.Name) +} + +func (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error) { + tracef("calling arg%[1] parse with args %[2]", a.Name, s) + + var vc VC + var t T + value := vc.Create(a.Value, &t, a.Config) + a.value = &t + + tracef("attempting arg%[1] parse", &a.Name) + if len(s) > 0 { + if err := value.Set(s[0]); err != nil { + return s, fmt.Errorf("invalid value %q for argument %s: %v", s[0], a.Name, err) + } + *a.value = value.Get().(T) + tracef("set arg%[1] one value", a.Name, *a.value) + } + + if a.Destination != nil { + tracef("setting destination") + *a.Destination = *a.value + } + + if len(s) > 0 { + return s[1:], nil + } + return s, nil +} + +func (a *ArgumentBase[T, C, VC]) Get() any { + if a.value != nil { + return *a.value + } + return a.Value +} + +// ArgumentsBase is a base type for slice arguments +type ArgumentsBase[T any, C any, VC ValueCreator[T, C]] struct { + Name string `json:"name"` // the name of this argument + Value T `json:"value"` // the default value of this argument + Destination *[]T `json:"-"` // the destination point for this argument + UsageText string `json:"usageText"` // the usage text to show + Min int `json:"minTimes"` // the min num of occurrences of this argument + Max int `json:"maxTimes"` // the max num of occurrences of this argument, set to -1 for unlimited + Config C `json:"config"` // config for this argument similar to Flag Config + + values []T +} + +func (a *ArgumentsBase[T, C, VC]) HasName(s string) bool { + return s == a.Name +} + +func (a *ArgumentsBase[T, C, VC]) Usage() string { + if a.UsageText != "" { + return a.UsageText + } + + usageFormat := "" + if a.Min == 0 { + if a.Max == 1 { + usageFormat = "[%[1]s]" + } else { + usageFormat = "[%[1]s ...]" + } + } else { + usageFormat = "%[1]s [%[1]s ...]" + } + return fmt.Sprintf(usageFormat, a.Name) +} + +func (a *ArgumentsBase[T, C, VC]) Parse(s []string) ([]string, error) { + tracef("calling arg%[1] parse with args %[2]", &a.Name, s) + if a.Max == 0 { + return s, fmt.Errorf("args %s has max 0, not parsing argument", a.Name) + } + if a.Max != -1 && a.Min > a.Max { + return s, fmt.Errorf("args %s has min[%d] > max[%d], not parsing argument", a.Name, a.Min, a.Max) + } + + count := 0 + var vc VC + var t T + value := vc.Create(a.Value, &t, a.Config) + a.values = []T{} + + tracef("attempting arg%[1] parse", &a.Name) + for _, arg := range s { + if err := value.Set(arg); err != nil { + return s, fmt.Errorf("invalid value %q for argument %s: %v", arg, a.Name, err) + } + tracef("set arg%[1] one value", &a.Name, value.Get().(T)) + a.values = append(a.values, value.Get().(T)) + count++ + if count >= a.Max && a.Max > -1 { + break + } + } + if count < a.Min { + return s, fmt.Errorf("sufficient count of arg %s not provided, given %d expected %d", a.Name, count, a.Min) + } + + if a.Destination != nil { + tracef("appending destination") + *a.Destination = a.values // append(*a.Destination, a.values...) + } + + return s[count:], nil +} + +func (a *ArgumentsBase[T, C, VC]) Get() any { + if a.values != nil { + return a.values + } + return []T{} +} + +type ( + FloatArg = ArgumentBase[float64, NoConfig, floatValue[float64]] + Float32Arg = ArgumentBase[float32, NoConfig, floatValue[float32]] + Float64Arg = ArgumentBase[float64, NoConfig, floatValue[float64]] + IntArg = ArgumentBase[int, IntegerConfig, intValue[int]] + Int8Arg = ArgumentBase[int8, IntegerConfig, intValue[int8]] + Int16Arg = ArgumentBase[int16, IntegerConfig, intValue[int16]] + Int32Arg = ArgumentBase[int32, IntegerConfig, intValue[int32]] + Int64Arg = ArgumentBase[int64, IntegerConfig, intValue[int64]] + StringArg = ArgumentBase[string, StringConfig, stringValue] + StringMapArgs = ArgumentBase[map[string]string, StringConfig, StringMap] + TimestampArg = ArgumentBase[time.Time, TimestampConfig, timestampValue] + UintArg = ArgumentBase[uint, IntegerConfig, uintValue[uint]] + Uint8Arg = ArgumentBase[uint8, IntegerConfig, uintValue[uint8]] + Uint16Arg = ArgumentBase[uint16, IntegerConfig, uintValue[uint16]] + Uint32Arg = ArgumentBase[uint32, IntegerConfig, uintValue[uint32]] + Uint64Arg = ArgumentBase[uint64, IntegerConfig, uintValue[uint64]] + + FloatArgs = ArgumentsBase[float64, NoConfig, floatValue[float64]] + Float32Args = ArgumentsBase[float32, NoConfig, floatValue[float32]] + Float64Args = ArgumentsBase[float64, NoConfig, floatValue[float64]] + IntArgs = ArgumentsBase[int, IntegerConfig, intValue[int]] + Int8Args = ArgumentsBase[int8, IntegerConfig, intValue[int8]] + Int16Args = ArgumentsBase[int16, IntegerConfig, intValue[int16]] + Int32Args = ArgumentsBase[int32, IntegerConfig, intValue[int32]] + Int64Args = ArgumentsBase[int64, IntegerConfig, intValue[int64]] + StringArgs = ArgumentsBase[string, StringConfig, stringValue] + TimestampArgs = ArgumentsBase[time.Time, TimestampConfig, timestampValue] + UintArgs = ArgumentsBase[uint, IntegerConfig, uintValue[uint]] + Uint8Args = ArgumentsBase[uint8, IntegerConfig, uintValue[uint8]] + Uint16Args = ArgumentsBase[uint16, IntegerConfig, uintValue[uint16]] + Uint32Args = ArgumentsBase[uint32, IntegerConfig, uintValue[uint32]] + Uint64Args = ArgumentsBase[uint64, IntegerConfig, uintValue[uint64]] +) + +func (c *Command) getArgValue(name string) any { + tracef("command %s looking for args %s", c.Name, name) + for _, arg := range c.Arguments { + if arg.HasName(name) { + tracef("command %s found args %s", c.Name, name) + return arg.Get() + } + } + tracef("command %s did not find args %s", c.Name, name) + return nil +} + +func arg[T any](name string, c *Command) T { + val := c.getArgValue(name) + if a, ok := val.(T); ok { + return a + } + var zero T + return zero +} + +func (c *Command) StringArg(name string) string { + return arg[string](name, c) +} + +func (c *Command) StringArgs(name string) []string { + return arg[[]string](name, c) +} + +func (c *Command) FloatArg(name string) float64 { + return arg[float64](name, c) +} + +func (c *Command) FloatArgs(name string) []float64 { + return arg[[]float64](name, c) +} + +func (c *Command) Float32Arg(name string) float32 { + return arg[float32](name, c) +} + +func (c *Command) Float32Args(name string) []float32 { + return arg[[]float32](name, c) +} + +func (c *Command) Float64Arg(name string) float64 { + return arg[float64](name, c) +} + +func (c *Command) Float64Args(name string) []float64 { + return arg[[]float64](name, c) +} + +func (c *Command) IntArg(name string) int { + return arg[int](name, c) +} + +func (c *Command) IntArgs(name string) []int { + return arg[[]int](name, c) +} + +func (c *Command) Int8Arg(name string) int8 { + return arg[int8](name, c) +} + +func (c *Command) Int8Args(name string) []int8 { + return arg[[]int8](name, c) +} + +func (c *Command) Int16Arg(name string) int16 { + return arg[int16](name, c) +} + +func (c *Command) Int16Args(name string) []int16 { + return arg[[]int16](name, c) +} + +func (c *Command) Int32Arg(name string) int32 { + return arg[int32](name, c) +} + +func (c *Command) Int32Args(name string) []int32 { + return arg[[]int32](name, c) +} + +func (c *Command) Int64Arg(name string) int64 { + return arg[int64](name, c) +} + +func (c *Command) Int64Args(name string) []int64 { + return arg[[]int64](name, c) +} + +func (c *Command) UintArg(name string) uint { + return arg[uint](name, c) +} + +func (c *Command) Uint8Arg(name string) uint8 { + return arg[uint8](name, c) +} + +func (c *Command) Uint16Arg(name string) uint16 { + return arg[uint16](name, c) +} + +func (c *Command) Uint32Arg(name string) uint32 { + return arg[uint32](name, c) +} + +func (c *Command) Uint64Arg(name string) uint64 { + return arg[uint64](name, c) +} + +func (c *Command) UintArgs(name string) []uint { + return arg[[]uint](name, c) +} + +func (c *Command) Uint8Args(name string) []uint8 { + return arg[[]uint8](name, c) +} + +func (c *Command) Uint16Args(name string) []uint16 { + return arg[[]uint16](name, c) +} + +func (c *Command) Uint32Args(name string) []uint32 { + return arg[[]uint32](name, c) +} + +func (c *Command) Uint64Args(name string) []uint64 { + return arg[[]uint64](name, c) +} + +func (c *Command) TimestampArg(name string) time.Time { + return arg[time.Time](name, c) +} + +func (c *Command) TimestampArgs(name string) []time.Time { + return arg[[]time.Time](name, c) +} diff --git a/vendor/github.com/urfave/cli/v3/autocomplete/bash_autocomplete b/vendor/github.com/urfave/cli/v3/autocomplete/bash_autocomplete new file mode 100644 index 00000000000..d63937d9718 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/autocomplete/bash_autocomplete @@ -0,0 +1,34 @@ +#!/bin/bash + +# This is a shell completion script auto-generated by https://github.com/urfave/cli for bash. + +# Macs have bash3 for which the bash-completion package doesn't include +# _init_completion. This is a minimal version of that function. +__%[1]s_init_completion() { + COMPREPLY=() + _get_comp_words_by_ref "$@" cur prev words cword +} + +__%[1]s_bash_autocomplete() { + if [[ "${COMP_WORDS[0]}" != "source" ]]; then + local cur opts base words + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + if declare -F _init_completion >/dev/null 2>&1; then + _init_completion -n "=:" || return + else + __%[1]s_init_completion -n "=:" || return + fi + words=("${words[@]:0:$cword}") + if [[ "$cur" == "-"* ]]; then + requestComp="${words[*]} ${cur} --generate-shell-completion" + else + requestComp="${words[*]} --generate-shell-completion" + fi + opts=$(eval "${requestComp}" 2>/dev/null) + COMPREPLY=($(compgen -W "${opts}" -- ${cur})) + return 0 + fi +} + +complete -o bashdefault -o default -o nospace -F __%[1]s_bash_autocomplete %[1]s diff --git a/vendor/github.com/urfave/cli/v3/autocomplete/fish_autocomplete b/vendor/github.com/urfave/cli/v3/autocomplete/fish_autocomplete new file mode 100644 index 00000000000..7aa7d0a8ba8 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/autocomplete/fish_autocomplete @@ -0,0 +1,35 @@ +# This is a shell completion script auto-generated by https://github.com/urfave/cli for fish. + +function __%[1]_perform_completion + # Extract all args except the last one + set -l args (commandline -opc) + # Extract the last arg (partial input) + set -l lastArg (commandline -ct) + + set -l results ($args[1] $args[2..-1] $lastArg --generate-shell-completion 2> /dev/null) + + # Remove trailing empty lines + for line in $results[-1..1] + if test (string trim -- $line) = "" + set results $results[1..-2] + else + break + end + end + + for line in $results + if not string match -q -- "%[1]*" $line + set -l parts (string split -m 1 ":" -- "$line") + if test (count $parts) -eq 2 + printf "%s\t%s\n" "$parts[1]" "$parts[2]" + else + printf "%s\n" "$line" + end + end + end +end + +# Clear existing completions for %[1] +complete -c %[1] -e +# Register completion function +complete -c %[1] -f -a '(__%[1]_perform_completion)' \ No newline at end of file diff --git a/vendor/github.com/urfave/cli/v3/autocomplete/powershell_autocomplete.ps1 b/vendor/github.com/urfave/cli/v3/autocomplete/powershell_autocomplete.ps1 new file mode 100644 index 00000000000..6e0c422e256 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/autocomplete/powershell_autocomplete.ps1 @@ -0,0 +1,9 @@ +$fn = $($MyInvocation.MyCommand.Name) +$name = $fn -replace "(.*)\.ps1$", '$1' +Register-ArgumentCompleter -Native -CommandName $name -ScriptBlock { + param($commandName, $wordToComplete, $cursorPosition) + $other = "$wordToComplete --generate-shell-completion" + Invoke-Expression $other | ForEach-Object { + [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) + } + } diff --git a/vendor/github.com/urfave/cli/v3/autocomplete/zsh_autocomplete b/vendor/github.com/urfave/cli/v3/autocomplete/zsh_autocomplete new file mode 100644 index 00000000000..d24049a72fe --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/autocomplete/zsh_autocomplete @@ -0,0 +1,29 @@ +#compdef %[1]s +compdef _%[1]s %[1]s + +# This is a shell completion script auto-generated by https://github.com/urfave/cli for zsh. + +_%[1]s() { + local -a opts # Declare a local array + local current + current=${words[-1]} # -1 means "the last element" + if [[ "$current" == "-"* ]]; then + # Current word starts with a hyphen, so complete flags/options + opts=("${(@f)$(${words[@]:0:#words[@]-1} ${current} --generate-shell-completion)}") + else + # Current word does not start with a hyphen, so complete subcommands + opts=("${(@f)$(${words[@]:0:#words[@]-1} --generate-shell-completion)}") + fi + + if [[ "${opts[1]}" != "" ]]; then + _describe 'values' opts + else + _files + fi +} + +# Don't run the completion function when being source-ed or eval-ed. +# See https://github.com/urfave/cli/issues/1874 for discussion. +if [ "$funcstack[1]" = "_%[1]s" ]; then + _%[1]s +fi diff --git a/vendor/github.com/urfave/cli/v3/category.go b/vendor/github.com/urfave/cli/v3/category.go new file mode 100644 index 00000000000..14e3649ca74 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/category.go @@ -0,0 +1,195 @@ +package cli + +import "sort" + +// CommandCategories interface allows for category manipulation +type CommandCategories interface { + // AddCommand adds a command to a category, creating a new category if necessary. + AddCommand(category string, command *Command) + // Categories returns a slice of categories sorted by name + Categories() []CommandCategory +} + +type commandCategories []*commandCategory + +func newCommandCategories() CommandCategories { + ret := commandCategories([]*commandCategory{}) + return &ret +} + +func (c *commandCategories) Less(i, j int) bool { + return lexicographicLess((*c)[i].Name(), (*c)[j].Name()) +} + +func (c *commandCategories) Len() int { + return len(*c) +} + +func (c *commandCategories) Swap(i, j int) { + (*c)[i], (*c)[j] = (*c)[j], (*c)[i] +} + +func (c *commandCategories) AddCommand(category string, command *Command) { + for _, commandCategory := range []*commandCategory(*c) { + if commandCategory.name == category { + commandCategory.commands = append(commandCategory.commands, command) + return + } + } + newVal := append(*c, + &commandCategory{name: category, commands: []*Command{command}}) + *c = newVal +} + +func (c *commandCategories) Categories() []CommandCategory { + ret := make([]CommandCategory, len(*c)) + for i, cat := range *c { + ret[i] = cat + } + return ret +} + +// CommandCategory is a category containing commands. +type CommandCategory interface { + // Name returns the category name string + Name() string + // VisibleCommands returns a slice of the Commands with Hidden=false + VisibleCommands() []*Command +} + +type commandCategory struct { + name string + commands []*Command +} + +func (c *commandCategory) Name() string { + return c.name +} + +func (c *commandCategory) VisibleCommands() []*Command { + if c.commands == nil { + c.commands = []*Command{} + } + + var ret []*Command + for _, command := range c.commands { + if !command.Hidden { + ret = append(ret, command) + } + } + return ret +} + +// FlagCategories interface allows for category manipulation +type FlagCategories interface { + // AddFlags adds a flag to a category, creating a new category if necessary. + AddFlag(category string, fl Flag) + // VisibleCategories returns a slice of visible flag categories sorted by name + VisibleCategories() []VisibleFlagCategory +} + +type defaultFlagCategories struct { + m map[string]*defaultVisibleFlagCategory +} + +func newFlagCategories() FlagCategories { + return &defaultFlagCategories{ + m: map[string]*defaultVisibleFlagCategory{}, + } +} + +func newFlagCategoriesFromFlags(fs []Flag) FlagCategories { + fc := newFlagCategories() + + var categorized bool + + for _, fl := range fs { + if cf, ok := fl.(CategorizableFlag); ok { + visible := false + if vf, ok := fl.(VisibleFlag); ok { + visible = vf.IsVisible() + } + if cat := cf.GetCategory(); cat != "" && visible { + fc.AddFlag(cat, fl) + categorized = true + } + } + } + + if categorized { + for _, fl := range fs { + if cf, ok := fl.(CategorizableFlag); ok { + visible := false + if vf, ok := fl.(VisibleFlag); ok { + visible = vf.IsVisible() + } + if cf.GetCategory() == "" && visible { + fc.AddFlag("", fl) + } + } + } + } + + return fc +} + +func (f *defaultFlagCategories) AddFlag(category string, fl Flag) { + if _, ok := f.m[category]; !ok { + f.m[category] = &defaultVisibleFlagCategory{name: category, m: map[string]Flag{}} + } + + f.m[category].m[fl.String()] = fl +} + +func (f *defaultFlagCategories) VisibleCategories() []VisibleFlagCategory { + catNames := []string{} + for name := range f.m { + catNames = append(catNames, name) + } + + sort.Strings(catNames) + + ret := make([]VisibleFlagCategory, len(catNames)) + for i, name := range catNames { + ret[i] = f.m[name] + } + + return ret +} + +// VisibleFlagCategory is a category containing flags. +type VisibleFlagCategory interface { + // Name returns the category name string + Name() string + // Flags returns a slice of VisibleFlag sorted by name + Flags() []Flag +} + +type defaultVisibleFlagCategory struct { + name string + m map[string]Flag +} + +func (fc *defaultVisibleFlagCategory) Name() string { + return fc.name +} + +func (fc *defaultVisibleFlagCategory) Flags() []Flag { + vfNames := []string{} + for flName, fl := range fc.m { + if vf, ok := fl.(VisibleFlag); ok { + if vf.IsVisible() { + vfNames = append(vfNames, flName) + } + } + } + + sort.Strings(vfNames) + + ret := make([]Flag, len(vfNames)) + for i, flName := range vfNames { + ret[i] = fc.m[flName] + } + + return ret +} diff --git a/vendor/github.com/urfave/cli/v3/cli.go b/vendor/github.com/urfave/cli/v3/cli.go new file mode 100644 index 00000000000..d833aff5179 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/cli.go @@ -0,0 +1,60 @@ +// 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.Command{}).Run(context.Background(), os.Args) +// } +// +// Of course this application does not do much, so let's make this an actual application: +// +// func main() { +// cmd := &cli.Command{ +// Name: "greet", +// Usage: "say a greeting", +// Action: func(c *cli.Context) error { +// fmt.Println("Greetings") +// return nil +// }, +// } +// +// cmd.Run(context.Background(), os.Args) +// } +package cli + +import ( + "fmt" + "os" + "runtime" + "strings" +) + +var 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..., + ) +} diff --git a/vendor/github.com/urfave/cli/v3/command.go b/vendor/github.com/urfave/cli/v3/command.go new file mode 100644 index 00000000000..2a46b2eab14 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/command.go @@ -0,0 +1,598 @@ +package cli + +import ( + "context" + "fmt" + "io" + "slices" + "strings" +) + +const ( + // ignoreFlagPrefix is to ignore test flags when adding flags from other packages + ignoreFlagPrefix = "test." + + commandContextKey = contextKey("cli.context") +) + +type contextKey string + +// Command contains everything needed to run an application that +// accepts a string slice of arguments such as os.Args. A given +// Command may contain Flags and sub-commands in Commands. +type Command struct { + // The name of the command + Name string `json:"name"` + // A list of aliases for the command + Aliases []string `json:"aliases"` + // A short description of the usage of this command + Usage string `json:"usage"` + // Text to override the USAGE section of help + UsageText string `json:"usageText"` + // A short description of the arguments of this command + ArgsUsage string `json:"argsUsage"` + // Version of the command + Version string `json:"version"` + // Longer explanation of how the command works + Description string `json:"description"` + // DefaultCommand is the (optional) name of a command + // to run if no command names are passed as CLI arguments. + DefaultCommand string `json:"defaultCommand"` + // The category the command is part of + Category string `json:"category"` + // List of child commands + Commands []*Command `json:"commands"` + // List of flags to parse + Flags []Flag `json:"flags"` + // Boolean to hide built-in help command and help flag + HideHelp bool `json:"hideHelp"` + // Ignored if HideHelp is true. + HideHelpCommand bool `json:"hideHelpCommand"` + // Boolean to hide built-in version flag and the VERSION section of help + HideVersion bool `json:"hideVersion"` + // Boolean to enable shell completion commands + EnableShellCompletion bool `json:"-"` + // Shell Completion generation command name + ShellCompletionCommandName string `json:"-"` + // The function to call when checking for shell command completions + ShellComplete ShellCompleteFunc `json:"-"` + // The function to configure a shell completion command + ConfigureShellCompletionCommand ConfigureShellCompletionCommand `json:"-"` + // 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 `json:"-"` + // An action to execute after any subcommands are run, but after the subcommand has finished + // It is run even if Action() panics + After AfterFunc `json:"-"` + // The function to call when this command is invoked + Action ActionFunc `json:"-"` + // Execute this function if the proper command cannot be found + CommandNotFound CommandNotFoundFunc `json:"-"` + // Execute this function if a usage error occurs. + OnUsageError OnUsageErrorFunc `json:"-"` + // Execute this function when an invalid flag is accessed from the context + InvalidFlagAccessHandler InvalidFlagAccessFunc `json:"-"` + // Boolean to hide this command from help or completion + Hidden bool `json:"hidden"` + // List of all authors who contributed (string or fmt.Stringer) + // TODO: ~string | fmt.Stringer when interface unions are available + Authors []any `json:"authors"` + // Copyright of the binary if any + Copyright string `json:"copyright"` + // Reader reader to write input to (useful for tests) + Reader io.Reader `json:"-"` + // Writer writer to write output to + Writer io.Writer `json:"-"` + // ErrWriter writes error output + ErrWriter io.Writer `json:"-"` + // ExitErrHandler processes any error encountered while running a Command before it is + // returned to the caller. If no function is provided, HandleExitCoder is used as the + // default behavior. + ExitErrHandler ExitErrHandlerFunc `json:"-"` + // Other custom info + Metadata map[string]any `json:"metadata"` + // Carries a function which returns app specific info. + ExtraInfo func() map[string]string `json:"-"` + // CustomRootCommandHelpTemplate 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. + CustomRootCommandHelpTemplate string `json:"-"` + // SliceFlagSeparator is used to customize the separator for SliceFlag, the default is "," + SliceFlagSeparator string `json:"sliceFlagSeparator"` + // DisableSliceFlagSeparator is used to disable SliceFlagSeparator, the default is false + DisableSliceFlagSeparator bool `json:"disableSliceFlagSeparator"` + // MapFlagKeyValueSeparator is used to customize the separator for MapFlag, the default is "=" + MapFlagKeyValueSeparator string `json:"mapFlagKeyValueSeparator"` + // 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 `json:"useShortOptionHandling"` + // Enable suggestions for commands and flags + Suggest bool `json:"suggest"` + // Allows global flags set by libraries which use flag.XXXVar(...) directly + // to be parsed through this library + AllowExtFlags bool `json:"allowExtFlags"` + // Treat all flags as normal arguments if true + SkipFlagParsing bool `json:"skipFlagParsing"` + // 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 `json:"-"` + // Use longest prefix match for commands + PrefixMatchCommands bool `json:"prefixMatchCommands"` + // Custom suggest command for matching + SuggestCommandFunc SuggestCommandFunc `json:"-"` + // Flag exclusion group + MutuallyExclusiveFlags []MutuallyExclusiveFlags `json:"mutuallyExclusiveFlags"` + // Arguments to parse for this command + Arguments []Argument `json:"arguments"` + // Whether to read arguments from stdin + // applicable to root command only + ReadArgsFromStdin bool `json:"readArgsFromStdin"` + // StopOnNthArg provides v2-like behavior for specific commands by stopping + // flag parsing after N positional arguments are encountered. When set to N, + // all remaining arguments after the Nth positional argument will be treated + // as arguments, not flags. + // + // A value of 0 means all arguments are treated as positional (no flag parsing). + // A nil value means normal v3 flag parsing behavior (flags can appear anywhere). + StopOnNthArg *int `json:"stopOnNthArg"` + + // 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 + // flags that have been applied in current parse + appliedFlags []Flag + // flags that have been set + setFlags map[Flag]struct{} + // The parent of this command. This value will be nil for the + // command at the root of the graph. + parent *Command + // parsed args + parsedArgs Args + // track state of error handling + isInError bool + // track state of defaults + didSetupDefaults bool + // whether in shell completion mode + shellCompletion bool + // whether global help flag was added + globaHelpFlagAdded bool + // whether global version flag was added + globaVersionFlagAdded bool + // whether this is a completion command + isCompletionCommand bool +} + +// FullName returns the full name of the command. +// For commands with parents this ensures that the parent commands +// are part of the command path. +func (cmd *Command) FullName() string { + namePath := []string{} + + if cmd.parent != nil { + namePath = append(namePath, cmd.parent.FullName()) + } + + return strings.Join(append(namePath, cmd.Name), " ") +} + +func (cmd *Command) Command(name string) *Command { + for _, subCmd := range cmd.Commands { + if subCmd.HasName(name) { + return subCmd + } + } + + return nil +} + +func (cmd *Command) checkHelp() bool { + tracef("checking if help is wanted (cmd=%[1]q)", cmd.Name) + + return HelpFlag != nil && slices.ContainsFunc(HelpFlag.Names(), cmd.Bool) +} + +func (cmd *Command) allFlags() []Flag { + var flags []Flag + flags = append(flags, cmd.Flags...) + for _, grpf := range cmd.MutuallyExclusiveFlags { + for _, f1 := range grpf.Flags { + flags = append(flags, f1...) + } + } + return flags +} + +// useShortOptionHandling traverses Lineage() for *any* ancestors +// with UseShortOptionHandling +func (cmd *Command) useShortOptionHandling() bool { + for _, pCmd := range cmd.Lineage() { + if pCmd.UseShortOptionHandling { + return true + } + } + + return false +} + +func (cmd *Command) suggestFlagFromError(err error, commandName string) (string, error) { + fl, parseErr := flagFromError(err) + if parseErr != nil { + return "", err + } + + flags := cmd.Flags + hideHelp := cmd.hideHelp() + + if commandName != "" { + subCmd := cmd.Command(commandName) + if subCmd == nil { + return "", err + } + flags = subCmd.Flags + hideHelp = hideHelp || subCmd.HideHelp + } + + suggestion := SuggestFlag(flags, fl, hideHelp) + if len(suggestion) == 0 { + return "", err + } + + return fmt.Sprintf(SuggestDidYouMeanTemplate, suggestion) + "\n\n", nil +} + +// Names returns the names including short names and aliases. +func (cmd *Command) Names() []string { + return append([]string{cmd.Name}, cmd.Aliases...) +} + +// HasName returns true if Command.Name matches given name +func (cmd *Command) HasName(name string) bool { + return slices.Contains(cmd.Names(), name) +} + +// VisibleCategories returns a slice of categories and commands that are +// Hidden=false +func (cmd *Command) VisibleCategories() []CommandCategory { + ret := []CommandCategory{} + for _, category := range cmd.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 (cmd *Command) VisibleCommands() []*Command { + var ret []*Command + for _, command := range cmd.Commands { + if command.Hidden || command.Name == helpName { + continue + } + ret = append(ret, command) + } + return ret +} + +// VisibleFlagCategories returns a slice containing all the visible flag categories with the flags they contain +func (cmd *Command) VisibleFlagCategories() []VisibleFlagCategory { + if cmd.flagCategories == nil { + cmd.flagCategories = newFlagCategoriesFromFlags(cmd.allFlags()) + } + return cmd.flagCategories.VisibleCategories() +} + +// VisibleFlags returns a slice of the Flags with Hidden=false +func (cmd *Command) VisibleFlags() []Flag { + return visibleFlags(cmd.allFlags()) +} + +func (cmd *Command) appendFlag(fl Flag) { + if !hasFlag(cmd.Flags, fl) { + cmd.Flags = append(cmd.Flags, fl) + } +} + +// VisiblePersistentFlags returns a slice of [LocalFlag] with Persistent=true and Hidden=false. +func (cmd *Command) VisiblePersistentFlags() []Flag { + var flags []Flag + for _, fl := range cmd.Root().Flags { + pfl, ok := fl.(LocalFlag) + if !ok || pfl.IsLocal() { + continue + } + flags = append(flags, fl) + } + return visibleFlags(flags) +} + +func (cmd *Command) appendCommand(aCmd *Command) { + if !slices.Contains(cmd.Commands, aCmd) { + aCmd.parent = cmd + cmd.Commands = append(cmd.Commands, aCmd) + } +} + +func (cmd *Command) handleExitCoder(ctx context.Context, err error) error { + if cmd.parent != nil { + return cmd.parent.handleExitCoder(ctx, err) + } + + if cmd.ExitErrHandler != nil { + cmd.ExitErrHandler(ctx, cmd, err) + return err + } + + HandleExitCoder(err) + return err +} + +func (cmd *Command) argsWithDefaultCommand(oldArgs Args) Args { + rawArgs := append([]string{cmd.DefaultCommand}, oldArgs.Slice()...) + newArgs := &stringSliceArgs{v: rawArgs} + + return newArgs +} + +// Root returns the Command at the root of the graph +func (cmd *Command) Root() *Command { + if cmd.parent == nil { + return cmd + } + + return cmd.parent.Root() +} + +func (cmd *Command) set(fName string, f Flag, val string) error { + cmd.setFlags[f] = struct{}{} + cmd.setMultiValueParsingConfig(f) + if err := f.Set(fName, val); err != nil { + return fmt.Errorf("invalid value %q for flag -%s: %v", val, fName, err) + } + return nil +} + +func (cmd *Command) lFlag(name string) Flag { + for _, f := range cmd.allFlags() { + if slices.Contains(f.Names(), name) { + tracef("flag found for name %[1]q (cmd=%[2]q)", name, cmd.Name) + return f + } + } + return nil +} + +func (cmd *Command) lookupFlag(name string) Flag { + for _, pCmd := range cmd.Lineage() { + if f := pCmd.lFlag(name); f != nil { + return f + } + } + + tracef("flag NOT found for name %[1]q (cmd=%[2]q)", name, cmd.Name) + cmd.onInvalidFlag(context.TODO(), name) + return nil +} + +// this looks up only allowed flags, i.e. local flags for current command +// or persistent flags from ancestors +func (cmd *Command) lookupAppliedFlag(name string) Flag { + for _, f := range cmd.appliedFlags { + if slices.Contains(f.Names(), name) { + tracef("appliedFlag found for name %[1]q (cmd=%[2]q)", name, cmd.Name) + return f + } + } + + tracef("lookupAppliedflag NOT found for name %[1]q (cmd=%[2]q)", name, cmd.Name) + cmd.onInvalidFlag(context.TODO(), name) + return nil +} + +func (cmd *Command) checkRequiredFlag(f Flag) (bool, string) { + if rf, ok := f.(RequiredFlag); ok && rf.IsRequired() { + flagName := f.Names()[0] + if !f.IsSet() { + return false, flagName + } + } + return true, "" +} + +func (cmd *Command) checkAllRequiredFlags() requiredFlagsErr { + for pCmd := cmd; pCmd != nil; pCmd = pCmd.parent { + if err := pCmd.checkRequiredFlags(); err != nil { + return err + } + } + return nil +} + +func (cmd *Command) checkRequiredFlags() requiredFlagsErr { + tracef("checking for required flags (cmd=%[1]q)", cmd.Name) + + missingFlags := []string{} + + for _, f := range cmd.appliedFlags { + if ok, name := cmd.checkRequiredFlag(f); !ok { + missingFlags = append(missingFlags, name) + } + } + + if len(missingFlags) != 0 { + tracef("found missing required flags %[1]q (cmd=%[2]q)", missingFlags, cmd.Name) + + return &errRequiredFlags{missingFlags: missingFlags} + } + + tracef("all required flags set (cmd=%[1]q)", cmd.Name) + + return nil +} + +func (cmd *Command) onInvalidFlag(ctx context.Context, name string) { + for cmd != nil { + if cmd.InvalidFlagAccessHandler != nil { + cmd.InvalidFlagAccessHandler(ctx, cmd, name) + break + } + cmd = cmd.parent + } +} + +// NumFlags returns the number of flags set +func (cmd *Command) NumFlags() int { + tracef("numFlags numAppliedFlags %d", len(cmd.appliedFlags)) + count := 0 + for _, f := range cmd.appliedFlags { + if f.IsSet() { + count++ + } + } + return count // cmd.flagSet.NFlag() +} + +func (cmd *Command) setMultiValueParsingConfig(f Flag) { + tracef("setMultiValueParsingConfig %T, %+v", f, f) + if cf, ok := f.(multiValueParsingConfigSetter); ok { + cf.setMultiValueParsingConfig(multiValueParsingConfig{ + SliceFlagSeparator: cmd.SliceFlagSeparator, + DisableSliceFlagSeparator: cmd.DisableSliceFlagSeparator, + MapFlagKeyValueSeparator: cmd.MapFlagKeyValueSeparator, + }) + } +} + +// Set sets a context flag to a value. +func (cmd *Command) Set(name, value string) error { + if f := cmd.lookupFlag(name); f != nil { + cmd.setMultiValueParsingConfig(f) + return f.Set(name, value) + } + + return fmt.Errorf("no such flag -%s", name) +} + +// IsSet determines if the flag was actually set +func (cmd *Command) IsSet(name string) bool { + fl := cmd.lookupFlag(name) + if fl == nil { + tracef("flag with name %[1]q NOT found; assuming not set (cmd=%[2]q)", name, cmd.Name) + return false + } + + isSet := fl.IsSet() + if isSet { + tracef("flag with name %[1]q is set (cmd=%[2]q)", name, cmd.Name) + } else { + tracef("flag with name %[1]q is no set (cmd=%[2]q)", name, cmd.Name) + } + + return isSet +} + +// LocalFlagNames returns a slice of flag names used in this +// command. +func (cmd *Command) LocalFlagNames() []string { + names := []string{} + + // Check the flags which have been set via env or file + for _, f := range cmd.allFlags() { + if f.IsSet() { + names = append(names, f.Names()...) + } + } + + // Sort out the duplicates since flag could be set via multiple + // paths + m := map[string]struct{}{} + uniqNames := []string{} + + for _, name := range names { + if _, ok := m[name]; !ok { + m[name] = struct{}{} + uniqNames = append(uniqNames, name) + } + } + + return uniqNames +} + +// FlagNames returns a slice of flag names used by the this command +// and all of its parent commands. +func (cmd *Command) FlagNames() []string { + names := cmd.LocalFlagNames() + + if cmd.parent != nil { + names = append(cmd.parent.FlagNames(), names...) + } + + return names +} + +// Lineage returns *this* command and all of its ancestor commands +// in order from child to parent +func (cmd *Command) Lineage() []*Command { + lineage := []*Command{cmd} + + if cmd.parent != nil { + lineage = append(lineage, cmd.parent.Lineage()...) + } + + return lineage +} + +// Count returns the num of occurrences of this flag +func (cmd *Command) Count(name string) int { + if cf, ok := cmd.lookupFlag(name).(Countable); ok { + return cf.Count() + } + return 0 +} + +// Value returns the value of the flag corresponding to `name` +func (cmd *Command) Value(name string) any { + if fs := cmd.lookupFlag(name); fs != nil { + tracef("value found for name %[1]q (cmd=%[2]q)", name, cmd.Name) + return fs.Get() + } + + tracef("value NOT found for name %[1]q (cmd=%[2]q)", name, cmd.Name) + return nil +} + +// Args returns the command line arguments associated with the +// command. +func (cmd *Command) Args() Args { + return cmd.parsedArgs +} + +// NArg returns the number of the command line arguments. +func (cmd *Command) NArg() int { + return cmd.Args().Len() +} + +func (cmd *Command) runFlagActions(ctx context.Context) error { + tracef("runFlagActions") + // run the flag actions in the same order that they are defined + // to maintain consistency. + for _, fl := range cmd.appliedFlags { + if _, inSet := cmd.setFlags[fl]; inSet { + if af, ok := fl.(ActionableFlag); ok { + if err := af.RunAction(ctx, cmd); err != nil { + return err + } + } + } + } + + return nil +} diff --git a/vendor/github.com/urfave/cli/v3/command_parse.go b/vendor/github.com/urfave/cli/v3/command_parse.go new file mode 100644 index 00000000000..92c58eeaace --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/command_parse.go @@ -0,0 +1,224 @@ +package cli + +import ( + "fmt" + "strings" + "unicode" +) + +const ( + providedButNotDefinedErrMsg = "flag provided but not defined: -" + argumentNotProvidedErrMsg = "flag needs an argument: " +) + +// flagFromError tries to parse a provided flag from an error message. If the +// parsing fails, it returns the input error and an empty string +func flagFromError(err error) (string, error) { + errStr := err.Error() + trimmed := strings.TrimPrefix(errStr, providedButNotDefinedErrMsg) + if errStr == trimmed { + return "", err + } + return trimmed, nil +} + +func (cmd *Command) parseFlags(args Args) (Args, error) { + tracef("parsing flags from arguments %[1]q (cmd=%[2]q)", args, cmd.Name) + + cmd.setFlags = map[Flag]struct{}{} + cmd.appliedFlags = cmd.allFlags() + + tracef("walking command lineage for persistent flags (cmd=%[1]q)", cmd.Name) + + for pCmd := cmd.parent; pCmd != nil; pCmd = pCmd.parent { + tracef( + "checking ancestor command=%[1]q for persistent flags (cmd=%[2]q)", + pCmd.Name, cmd.Name, + ) + + for _, fl := range pCmd.allFlags() { + flNames := fl.Names() + + pfl, ok := fl.(LocalFlag) + if !ok || pfl.IsLocal() { + tracef("skipping non-persistent flag %[1]q (cmd=%[2]q)", flNames, cmd.Name) + continue + } + + tracef( + "checking for applying persistent flag=%[1]q pCmd=%[2]q (cmd=%[3]q)", + flNames, pCmd.Name, cmd.Name, + ) + + applyPersistentFlag := true + + for _, name := range flNames { + if cmd.lFlag(name) != nil { + applyPersistentFlag = false + break + } + } + + if !applyPersistentFlag { + tracef("not applying as persistent flag=%[1]q (cmd=%[2]q)", flNames, cmd.Name) + continue + } + + tracef("applying as persistent flag=%[1]q (cmd=%[2]q)", flNames, cmd.Name) + + tracef("appending to applied flags flag=%[1]q (cmd=%[2]q)", flNames, cmd.Name) + cmd.appliedFlags = append(cmd.appliedFlags, fl) + } + } + + tracef("parsing flags iteratively tail=%[1]q (cmd=%[2]q)", args.Tail(), cmd.Name) + defer tracef("done parsing flags (cmd=%[1]q)", cmd.Name) + + posArgs := []string{} + for rargs := args.Slice(); len(rargs) > 0; rargs = rargs[1:] { + tracef("rearrange:1 (cmd=%[1]q) %[2]q", cmd.Name, rargs) + + firstArg := strings.TrimSpace(rargs[0]) + if len(firstArg) == 0 { + posArgs = append(posArgs, rargs[0]) + continue + } + + // stop parsing once we see a "--" + if firstArg == "--" { + posArgs = append(posArgs, rargs[1:]...) + return &stringSliceArgs{posArgs}, nil + } + + // Check if we've reached the Nth argument and should stop flag parsing + if cmd.StopOnNthArg != nil && len(posArgs) == *cmd.StopOnNthArg { + // Append current arg and all remaining args without parsing + posArgs = append(posArgs, rargs[0:]...) + return &stringSliceArgs{posArgs}, nil + } + + // handle positional args + if firstArg[0] != '-' { + // positional argument probably + tracef("rearrange-3 (cmd=%[1]q) check %[2]q", cmd.Name, firstArg) + + // if there is a command by that name let the command handle the + // rest of the parsing + if cmd.Command(firstArg) != nil { + posArgs = append(posArgs, rargs...) + return &stringSliceArgs{posArgs}, nil + } + + posArgs = append(posArgs, firstArg) + continue + } + + numMinuses := 1 + // this is same as firstArg == "-" + if len(firstArg) == 1 { + posArgs = append(posArgs, firstArg) + break + } + + shortOptionHandling := cmd.useShortOptionHandling() + + // stop parsing -- as short flags + if firstArg[1] == '-' { + numMinuses++ + shortOptionHandling = false + } else if !unicode.IsLetter(rune(firstArg[1])) { + // this is not a flag + tracef("parseFlags not a unicode letter. Stop parsing") + posArgs = append(posArgs, rargs...) + return &stringSliceArgs{posArgs}, nil + } + + tracef("parseFlags (shortOptionHandling=%[1]q)", shortOptionHandling) + + flagName := firstArg[numMinuses:] + flagVal := "" + valFromEqual := false + tracef("flagName:1 (fName=%[1]q)", flagName) + if index := strings.Index(flagName, "="); index != -1 { + flagVal = flagName[index+1:] + flagName = flagName[:index] + valFromEqual = true + } + + tracef("flagName:2 (fName=%[1]q) (fVal=%[2]q)", flagName, flagVal) + + f := cmd.lookupAppliedFlag(flagName) + // found a flag matching given flagName + if f != nil { + tracef("Trying flag type (fName=%[1]q) (type=%[2]T)", flagName, f) + if fb, ok := f.(boolFlag); ok && fb.IsBoolFlag() { + if flagVal == "" { + flagVal = "true" + } + tracef("parse Apply bool flag (fName=%[1]q) (fVal=%[2]q)", flagName, flagVal) + if err := cmd.set(flagName, f, flagVal); err != nil { + return &stringSliceArgs{posArgs}, err + } + continue + } + + tracef("processing non bool flag (fName=%[1]q)", flagName) + // not a bool flag so need to get the next arg + if flagVal == "" && !valFromEqual { + if len(rargs) == 1 { + return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", argumentNotProvidedErrMsg, firstArg) + } + flagVal = rargs[1] + rargs = rargs[1:] + } + + tracef("setting non bool flag (fName=%[1]q) (fVal=%[2]q)", flagName, flagVal) + if err := cmd.set(flagName, f, flagVal); err != nil { + return &stringSliceArgs{posArgs}, err + } + + continue + } + + // no flag lookup found and short handling is disabled + if !shortOptionHandling { + return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", providedButNotDefinedErrMsg, flagName) + } + + // try to split the flags + for index, c := range flagName { + tracef("processing flag (fName=%[1]q)", string(c)) + if sf := cmd.lookupFlag(string(c)); sf == nil { + return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", providedButNotDefinedErrMsg, flagName) + } else if fb, ok := sf.(boolFlag); ok && fb.IsBoolFlag() { + fv := flagVal + if index == (len(flagName)-1) && flagVal == "" { + fv = "true" + } + if fv == "" { + fv = "true" + } + if err := cmd.set(flagName, sf, fv); err != nil { + tracef("processing flag.2 (fName=%[1]q)", string(c)) + return &stringSliceArgs{posArgs}, err + } + } else if index == len(flagName)-1 { // last flag can take an arg + if flagVal == "" { + if len(rargs) == 1 { + return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", argumentNotProvidedErrMsg, string(c)) + } + flagVal = rargs[1] + rargs = rargs[1:] + } + tracef("parseFlags (flagName %[1]q) (flagVal %[2]q)", flagName, flagVal) + if err := cmd.set(flagName, sf, flagVal); err != nil { + tracef("processing flag.4 (fName=%[1]q)", string(c)) + return &stringSliceArgs{posArgs}, err + } + } + } + } + + tracef("returning-2 (cmd=%[1]q) args %[2]q", cmd.Name, posArgs) + return &stringSliceArgs{posArgs}, nil +} diff --git a/vendor/github.com/urfave/cli/v3/command_run.go b/vendor/github.com/urfave/cli/v3/command_run.go new file mode 100644 index 00000000000..676a14c676c --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/command_run.go @@ -0,0 +1,371 @@ +package cli + +import ( + "bufio" + "context" + "fmt" + "io" + "slices" + "unicode" +) + +func (cmd *Command) parseArgsFromStdin() ([]string, error) { + type state int + const ( + stateSearchForToken state = -1 + stateSearchForString state = 0 + ) + + st := stateSearchForToken + linenum := 1 + token := "" + args := []string{} + + breader := bufio.NewReader(cmd.Reader) + +outer: + for { + ch, _, err := breader.ReadRune() + if err == io.EOF { + switch st { + case stateSearchForToken: + if token != "--" { + args = append(args, token) + } + case stateSearchForString: + // make sure string is not empty + for _, t := range token { + if !unicode.IsSpace(t) { + args = append(args, token) + } + } + } + break outer + } + if err != nil { + return nil, err + } + switch st { + case stateSearchForToken: + if unicode.IsSpace(ch) || ch == '"' { + if ch == '\n' { + linenum++ + } + if token != "" { + // end the processing here + if token == "--" { + break outer + } + args = append(args, token) + token = "" + } + if ch == '"' { + st = stateSearchForString + } + continue + } + token += string(ch) + case stateSearchForString: + if ch != '"' { + token += string(ch) + } else { + if token != "" { + args = append(args, token) + token = "" + } + /*else { + //TODO. Should we pass in empty strings ? + }*/ + st = stateSearchForToken + } + } + } + + tracef("parsed stdin args as %v (cmd=%[2]q)", args, cmd.Name) + + return args, nil +} + +// Run is the entry point to the command graph. The positional +// arguments are parsed according to the Flag and Command +// definitions and the matching Action functions are run. +func (cmd *Command) Run(ctx context.Context, osArgs []string) (deferErr error) { + _, deferErr = cmd.run(ctx, osArgs) + return deferErr +} + +func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context, deferErr error) { + tracef("running with arguments %[1]q (cmd=%[2]q)", osArgs, cmd.Name) + cmd.setupDefaults(osArgs) + + // Validate StopOnNthArg + if cmd.StopOnNthArg != nil && *cmd.StopOnNthArg < 0 { + return ctx, fmt.Errorf("StopOnNthArg must be non-negative, got %d", *cmd.StopOnNthArg) + } + + if v, ok := ctx.Value(commandContextKey).(*Command); ok { + tracef("setting parent (cmd=%[1]q) command from context.Context value (cmd=%[2]q)", v.Name, cmd.Name) + cmd.parent = v + } + + if cmd.parent == nil { + if cmd.ReadArgsFromStdin { + if args, err := cmd.parseArgsFromStdin(); err != nil { + return ctx, err + } else { + osArgs = append(osArgs, args...) + } + } + // 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 + tracef("checking osArgs %v (cmd=%[2]q)", osArgs, cmd.Name) + cmd.shellCompletion, osArgs = checkShellCompleteFlag(cmd, osArgs) + + tracef("setting cmd.shellCompletion=%[1]v from checkShellCompleteFlag (cmd=%[2]q)", cmd.shellCompletion && cmd.EnableShellCompletion, cmd.Name) + cmd.shellCompletion = cmd.EnableShellCompletion && cmd.shellCompletion + } + + tracef("using post-checkShellCompleteFlag arguments %[1]q (cmd=%[2]q)", osArgs, cmd.Name) + + tracef("setting self as cmd in context (cmd=%[1]q)", cmd.Name) + ctx = context.WithValue(ctx, commandContextKey, cmd) + + if cmd.parent == nil { + cmd.setupCommandGraph() + } + + var rargs Args = &stringSliceArgs{v: osArgs} + var args Args = &stringSliceArgs{rargs.Tail()} + + if cmd.isCompletionCommand || cmd.Name == helpName { + tracef("special command detected, skipping pre-parse (cmd=%[1]q)", cmd.Name) + cmd.parsedArgs = args + return ctx, cmd.Action(ctx, cmd) + } + + for _, f := range cmd.allFlags() { + if err := f.PreParse(); err != nil { + return ctx, err + } + } + + var err error + + if cmd.SkipFlagParsing { + tracef("skipping flag parsing (cmd=%[1]q)", cmd.Name) + cmd.parsedArgs = args + } else { + cmd.parsedArgs, err = cmd.parseFlags(args) + } + + tracef("using post-parse arguments %[1]q (cmd=%[2]q)", args, cmd.Name) + + if checkCompletions(ctx, cmd) { + return ctx, nil + } + + if err != nil { + tracef("setting deferErr from %[1]q (cmd=%[2]q)", err, cmd.Name) + deferErr = err + + cmd.isInError = true + if cmd.OnUsageError != nil { + err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil) + err = cmd.handleExitCoder(ctx, err) + return ctx, err + } + fmt.Fprintf(cmd.Root().ErrWriter, "Incorrect Usage: %s\n\n", err.Error()) + if cmd.Suggest { + if suggestion, err := cmd.suggestFlagFromError(err, ""); err == nil { + fmt.Fprintf(cmd.Root().ErrWriter, "%s", suggestion) + } + } + if !cmd.hideHelp() { + if cmd.parent == nil { + tracef("running ShowRootCommandHelp") + if err := ShowRootCommandHelp(cmd); err != nil { + tracef("SILENTLY IGNORING ERROR running ShowRootCommandHelp %[1]v (cmd=%[2]q)", err, cmd.Name) + } + } else { + tracef("running ShowCommandHelp with %[1]q", cmd.Name) + if err := ShowCommandHelp(ctx, cmd, cmd.Name); err != nil { + tracef("SILENTLY IGNORING ERROR running ShowCommandHelp with %[1]q %[2]v", cmd.Name, err) + } + } + } + + return ctx, err + } + + if cmd.checkHelp() { + return ctx, helpCommandAction(ctx, cmd) + } else { + tracef("no help is wanted (cmd=%[1]q)", cmd.Name) + } + + if cmd.parent == nil && !cmd.HideVersion && checkVersion(cmd) { + ShowVersion(cmd) + return ctx, nil + } + + for _, flag := range cmd.allFlags() { + isSet := flag.IsSet() + if err := flag.PostParse(); err != nil { + return ctx, err + } + // add env set flags here + if !isSet && flag.IsSet() { + cmd.setFlags[flag] = struct{}{} + } + } + + if cmd.After != nil && !cmd.Root().shellCompletion { + defer func() { + if err := cmd.After(ctx, cmd); err != nil { + err = cmd.handleExitCoder(ctx, err) + + if deferErr != nil { + deferErr = newMultiError(deferErr, err) + } else { + deferErr = err + } + } + }() + } + + // Walk the parent chain to check mutually exclusive flag groups + // defined on ancestor commands, since persistent flags are inherited. + for pCmd := cmd; pCmd != nil; pCmd = pCmd.parent { + for _, grp := range pCmd.MutuallyExclusiveFlags { + if err := grp.check(cmd); err != nil { + if cmd.OnUsageError != nil { + err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil) + } else { + _ = ShowSubcommandHelp(cmd) + } + return ctx, err + } + } + } + + var subCmd *Command + if cmd.parsedArgs.Present() { + tracef("checking positional args %[1]q (cmd=%[2]q)", cmd.parsedArgs, cmd.Name) + + name := cmd.parsedArgs.First() + + tracef("using first positional argument as sub-command name=%[1]q (cmd=%[2]q)", name, cmd.Name) + + if cmd.SuggestCommandFunc != nil && name != "--" { + name = cmd.SuggestCommandFunc(cmd.Commands, name) + tracef("suggested command name=%1[q] (cmd=%[2]q)", name, cmd.Name) + } + subCmd = cmd.Command(name) + if subCmd == nil { + hasDefault := cmd.DefaultCommand != "" + isFlagName := slices.Contains(cmd.FlagNames(), name) + + if hasDefault { + tracef("using default command=%[1]q (cmd=%[2]q)", cmd.DefaultCommand, cmd.Name) + } + + if isFlagName || hasDefault { + argsWithDefault := cmd.argsWithDefaultCommand(cmd.parsedArgs) + tracef("using default command args=%[1]q (cmd=%[2]q)", argsWithDefault, cmd.Name) + subCmd = cmd.Command(argsWithDefault.First()) + cmd.parsedArgs = argsWithDefault + } + } + } else if cmd.DefaultCommand != "" { + tracef("no positional args present; checking default command %[1]q (cmd=%[2]q)", cmd.DefaultCommand, cmd.Name) + + if dc := cmd.Command(cmd.DefaultCommand); dc != cmd { + subCmd = dc + } + } + + // If a subcommand has been resolved, let it handle the remaining execution. + if subCmd != nil { + tracef("running sub-command %[1]q with arguments %[2]q (cmd=%[3]q)", subCmd.Name, cmd.Args(), cmd.Name) + + // It is important that we overwrite the ctx variable in the current + // function so any defer'd functions use the new context returned + // from the sub command. + ctx, err = subCmd.run(ctx, cmd.Args().Slice()) + return ctx, err + } + + // This code path is the innermost command execution. Here we actually + // perform the command action. + // + // First, resolve the chain of nested commands up to the parent. + var cmdChain []*Command + for p := cmd; p != nil; p = p.parent { + cmdChain = append(cmdChain, p) + } + slices.Reverse(cmdChain) + + // Run Before actions in order. + for _, cmd := range cmdChain { + if cmd.Before == nil { + continue + } + if bctx, err := cmd.Before(ctx, cmd); err != nil { + deferErr = cmd.handleExitCoder(ctx, err) + return ctx, deferErr + } else if bctx != nil { + ctx = bctx + } + } + + // Run flag actions in order. + // These take a context, so this has to happen after Before actions. + for _, cmd := range cmdChain { + tracef("running flag actions (cmd=%[1]q)", cmd.Name) + if err := cmd.runFlagActions(ctx); err != nil { + deferErr = cmd.handleExitCoder(ctx, err) + return ctx, deferErr + } + } + + if err := cmd.checkAllRequiredFlags(); err != nil { + cmd.isInError = true + if cmd.OnUsageError != nil { + err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil) + } else { + _ = ShowSubcommandHelp(cmd) + } + return ctx, err + } + + // Run the command action. + if len(cmd.Arguments) > 0 { + rargs := cmd.Args().Slice() + tracef("calling argparse with %[1]v", rargs) + for _, arg := range cmd.Arguments { + var err error + rargs, err = arg.Parse(rargs) + if err != nil { + tracef("calling with %[1]v (cmd=%[2]q)", err, cmd.Name) + if cmd.OnUsageError != nil { + err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil) + } + err = cmd.handleExitCoder(ctx, err) + return ctx, err + } + } + cmd.parsedArgs = &stringSliceArgs{v: rargs} + } + + if err := cmd.Action(ctx, cmd); err != nil { + tracef("calling handleExitCoder with %[1]v (cmd=%[2]q)", err, cmd.Name) + deferErr = cmd.handleExitCoder(ctx, err) + } + + tracef("returning deferErr (cmd=%[1]q) %[2]q", cmd.Name, deferErr) + return ctx, deferErr +} diff --git a/vendor/github.com/urfave/cli/v3/command_setup.go b/vendor/github.com/urfave/cli/v3/command_setup.go new file mode 100644 index 00000000000..cac4a303149 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/command_setup.go @@ -0,0 +1,223 @@ +package cli + +import ( + "flag" + "os" + "path/filepath" + "sort" + "strings" +) + +func (cmd *Command) setupDefaults(osArgs []string) { + if cmd.didSetupDefaults { + tracef("already did setup (cmd=%[1]q)", cmd.Name) + return + } + + cmd.didSetupDefaults = true + + isRoot := cmd.parent == nil + tracef("isRoot? %[1]v (cmd=%[2]q)", isRoot, cmd.Name) + + if cmd.ShellComplete == nil { + tracef("setting default ShellComplete (cmd=%[1]q)", cmd.Name) + cmd.ShellComplete = DefaultCompleteWithFlags + } + + if cmd.Name == "" && isRoot { + name := filepath.Base(osArgs[0]) + tracef("setting cmd.Name from first arg basename (cmd=%[1]q)", name) + cmd.Name = name + } + + if cmd.Usage == "" && isRoot { + tracef("setting default Usage (cmd=%[1]q)", cmd.Name) + cmd.Usage = "A new cli application" + } + + if cmd.Version == "" { + tracef("setting HideVersion=true due to empty Version (cmd=%[1]q)", cmd.Name) + cmd.HideVersion = true + } + + if cmd.Action == nil { + tracef("setting default Action as help command action (cmd=%[1]q)", cmd.Name) + cmd.Action = helpCommandAction + } + + if cmd.Reader == nil { + tracef("setting default Reader as os.Stdin (cmd=%[1]q)", cmd.Name) + cmd.Reader = os.Stdin + } + + if cmd.Writer == nil { + tracef("setting default Writer as os.Stdout (cmd=%[1]q)", cmd.Name) + cmd.Writer = os.Stdout + } + + if cmd.ErrWriter == nil { + tracef("setting default ErrWriter as os.Stderr (cmd=%[1]q)", cmd.Name) + cmd.ErrWriter = os.Stderr + } + + if cmd.AllowExtFlags { + tracef("visiting all flags given AllowExtFlags=true (cmd=%[1]q)", cmd.Name) + // add global flags added by other packages + flag.VisitAll(func(f *flag.Flag) { + // skip test flags + if !strings.HasPrefix(f.Name, ignoreFlagPrefix) { + cmd.Flags = append(cmd.Flags, &extFlag{f}) + } + }) + } + + for _, subCmd := range cmd.Commands { + tracef("setting sub-command (cmd=%[1]q) parent as self (cmd=%[2]q)", subCmd.Name, cmd.Name) + subCmd.parent = cmd + } + + cmd.ensureHelp() + + if !cmd.HideVersion && isRoot { + tracef("appending version flag (cmd=%[1]q)", cmd.Name) + if !cmd.globaVersionFlagAdded { + var localVersionFlag Flag + if globalVersionFlag, ok := VersionFlag.(*BoolFlag); ok { + flag := *globalVersionFlag + localVersionFlag = &flag + } else { + localVersionFlag = VersionFlag + } + + cmd.appendFlag(localVersionFlag) + cmd.globaVersionFlagAdded = true + } + } + + if cmd.PrefixMatchCommands && cmd.SuggestCommandFunc == nil { + tracef("setting default SuggestCommandFunc (cmd=%[1]q)", cmd.Name) + cmd.SuggestCommandFunc = suggestCommand + } + + if isRoot && cmd.EnableShellCompletion || cmd.ConfigureShellCompletionCommand != nil { + completionCommand := buildCompletionCommand(cmd.Name) + + if cmd.ShellCompletionCommandName != "" { + tracef( + "setting completion command name (%[1]q) from "+ + "cmd.ShellCompletionCommandName (cmd=%[2]q)", + cmd.ShellCompletionCommandName, cmd.Name, + ) + completionCommand.Name = cmd.ShellCompletionCommandName + } + + tracef("appending completionCommand (cmd=%[1]q)", cmd.Name) + cmd.appendCommand(completionCommand) + if cmd.ConfigureShellCompletionCommand != nil { + cmd.ConfigureShellCompletionCommand(completionCommand) + } + } + + tracef("setting command categories (cmd=%[1]q)", cmd.Name) + cmd.categories = newCommandCategories() + + for _, subCmd := range cmd.Commands { + cmd.categories.AddCommand(subCmd.Category, subCmd) + } + + tracef("sorting command categories (cmd=%[1]q)", cmd.Name) + sort.Sort(cmd.categories.(*commandCategories)) + + tracef("setting category on mutually exclusive flags (cmd=%[1]q)", cmd.Name) + for _, grp := range cmd.MutuallyExclusiveFlags { + grp.propagateCategory() + } + + tracef("setting flag categories (cmd=%[1]q)", cmd.Name) + cmd.flagCategories = newFlagCategoriesFromFlags(cmd.allFlags()) + + if cmd.Metadata == nil { + tracef("setting default Metadata (cmd=%[1]q)", cmd.Name) + cmd.Metadata = map[string]any{} + } + + cmd.setFlags = map[Flag]struct{}{} +} + +func (cmd *Command) setupCommandGraph() { + tracef("setting up command graph (cmd=%[1]q)", cmd.Name) + + for _, subCmd := range cmd.Commands { + subCmd.parent = cmd + subCmd.setupSubcommand() + subCmd.setupCommandGraph() + } +} + +func (cmd *Command) setupSubcommand() { + tracef("setting up self as sub-command (cmd=%[1]q)", cmd.Name) + + cmd.ensureHelp() + + tracef("setting command categories (cmd=%[1]q)", cmd.Name) + cmd.categories = newCommandCategories() + + for _, subCmd := range cmd.Commands { + cmd.categories.AddCommand(subCmd.Category, subCmd) + } + + tracef("sorting command categories (cmd=%[1]q)", cmd.Name) + sort.Sort(cmd.categories.(*commandCategories)) + + tracef("setting category on mutually exclusive flags (cmd=%[1]q)", cmd.Name) + for _, grp := range cmd.MutuallyExclusiveFlags { + grp.propagateCategory() + } + + tracef("setting flag categories (cmd=%[1]q)", cmd.Name) + cmd.flagCategories = newFlagCategoriesFromFlags(cmd.allFlags()) +} + +func (cmd *Command) hideHelp() bool { + tracef("hide help (cmd=%[1]q)", cmd.Name) + for c := cmd; c != nil; c = c.parent { + if c.HideHelp { + return true + } + } + + return false +} + +func (cmd *Command) ensureHelp() { + tracef("ensuring help (cmd=%[1]q)", cmd.Name) + + helpCommand := buildHelpCommand(true) + + if !cmd.hideHelp() { + if cmd.Command(helpCommand.Name) == nil { + if !cmd.HideHelpCommand { + tracef("appending helpCommand (cmd=%[1]q)", cmd.Name) + cmd.appendCommand(helpCommand) + } + } + + if HelpFlag != nil { + if !cmd.globaHelpFlagAdded { + var localHelpFlag Flag + if globalHelpFlag, ok := HelpFlag.(*BoolFlag); ok { + flag := *globalHelpFlag + localHelpFlag = &flag + } else { + localHelpFlag = HelpFlag + } + + tracef("appending HelpFlag (cmd=%[1]q)", cmd.Name) + cmd.appendFlag(localHelpFlag) + cmd.globaHelpFlagAdded = true + } else { + tracef("HelpFlag already added, skip (cmd=%[1]q)", cmd.Name) + } + } + } +} diff --git a/vendor/github.com/urfave/cli/v3/completion.go b/vendor/github.com/urfave/cli/v3/completion.go new file mode 100644 index 00000000000..de11edb406e --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/completion.go @@ -0,0 +1,102 @@ +package cli + +import ( + "context" + "embed" + "fmt" + "sort" + "strings" +) + +const ( + completionCommandName = "completion" + + // This flag is supposed to only be used by the completion script itself to generate completions on the fly. + completionFlag = "--generate-shell-completion" +) + +type renderCompletion func(cmd *Command, appName string) (string, error) + +var ( + //go:embed autocomplete + autoCompleteFS embed.FS + + shellCompletions = map[string]renderCompletion{ + "bash": func(c *Command, appName string) (string, error) { + b, err := autoCompleteFS.ReadFile("autocomplete/bash_autocomplete") + return fmt.Sprintf(string(b), appName), err + }, + "zsh": func(c *Command, appName string) (string, error) { + b, err := autoCompleteFS.ReadFile("autocomplete/zsh_autocomplete") + return fmt.Sprintf(string(b), appName), err + }, + "fish": func(c *Command, appName string) (string, error) { + b, err := autoCompleteFS.ReadFile("autocomplete/fish_autocomplete") + return fmt.Sprintf(string(b), appName), err + }, + "pwsh": func(c *Command, appName string) (string, error) { + b, err := autoCompleteFS.ReadFile("autocomplete/powershell_autocomplete.ps1") + return string(b), err + }, + } +) + +const completionDescription = `Output shell completion script for bash, zsh, fish, or Powershell. +Source the output to enable completion. + +# .bashrc +source <($COMMAND completion bash) + +# .zshrc +source <($COMMAND completion zsh) + +# fish +$COMMAND completion fish > ~/.config/fish/completions/$COMMAND.fish + +# Powershell +Output the script to path/to/autocomplete/$COMMAND.ps1 an run it. +` + +func buildCompletionCommand(appName string) *Command { + return &Command{ + Name: completionCommandName, + Hidden: true, + Usage: "Output shell completion script for bash, zsh, fish, or Powershell", + Description: strings.ReplaceAll(completionDescription, "$COMMAND", appName), + Action: func(ctx context.Context, cmd *Command) error { + return printShellCompletion(ctx, cmd, appName) + }, + isCompletionCommand: true, + } +} + +func printShellCompletion(_ context.Context, cmd *Command, appName string) error { + var shells []string + for k := range shellCompletions { + shells = append(shells, k) + } + + sort.Strings(shells) + + if cmd.Args().Len() == 0 { + return Exit(fmt.Sprintf("no shell provided for completion command. available shells are %+v", shells), 1) + } + s := cmd.Args().First() + + renderCompletion, ok := shellCompletions[s] + if !ok { + return Exit(fmt.Sprintf("unknown shell %s, available shells are %+v", s, shells), 1) + } + + completionScript, err := renderCompletion(cmd, appName) + if err != nil { + return Exit(err, 1) + } + + _, err = cmd.Writer.Write([]byte(completionScript)) + if err != nil { + return Exit(err, 1) + } + + return nil +} diff --git a/vendor/github.com/urfave/cli/v3/docs.go b/vendor/github.com/urfave/cli/v3/docs.go new file mode 100644 index 00000000000..88461386b82 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/docs.go @@ -0,0 +1,128 @@ +package cli + +import ( + "fmt" + "os" + "runtime" + "strings" +) + +func prefixFor(name string) (prefix string) { + if len(name) == 1 { + prefix = "-" + } else { + prefix = "--" + } + + return prefix +} + +// 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 strings.Builder + for i, name := range names { + if name == "" { + continue + } + + prefixed.WriteString(prefixFor(name) + name) + if placeholder != "" { + prefixed.WriteString(" " + placeholder) + } + if i < len(names)-1 { + prefixed.WriteString(", ") + } + } + return prefixed.String() +} + +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 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 is true, placeholder is empty + if needsPlaceholder && placeholder == "" { + // try to get type from flag + if tname := df.TypeName(); tname != "" { + placeholder = tname + } else { + placeholder = defaultPlaceholder + } + } + + defaultValueString := "" + + // don't print default text for required flags + if rf, ok := f.(RequiredFlag); !ok || !rf.IsRequired() { + if df.IsDefaultVisible() { + if s := df.GetDefaultText(); s != "" { + defaultValueString = fmt.Sprintf(formatDefault("%s"), s) + } else if df.TakesValue() && df.GetValue() != "" { + defaultValueString = fmt.Sprintf(formatDefault("%s"), df.GetValue()) + } + } + } + + usageWithDefault := strings.TrimSpace(usage + defaultValueString) + + pn := prefixedNames(f.Names(), placeholder) + sliceFlag, ok := f.(DocGenerationMultiValueFlag) + if ok && sliceFlag.IsMultiValueFlag() { + pn = pn + " [ " + pn + " ]" + } + + return withEnvHint(df.GetEnvVars(), fmt.Sprintf("%s\t%s", pn, usageWithDefault)) +} diff --git a/vendor/github.com/urfave/cli/v3/errors.go b/vendor/github.com/urfave/cli/v3/errors.go new file mode 100644 index 00000000000..f365a579908 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/errors.go @@ -0,0 +1,182 @@ +package cli + +import ( + "fmt" + "io" + "os" + "strings" +) + +// OsExiter is the function used when the app exits. If not set defaults to os.Exit. +var OsExiter = os.Exit + +// ErrWriter is used to write errors to the user. This can be anything +// implementing the io.Writer interface and defaults to os.Stderr. +var ErrWriter io.Writer = os.Stderr + +// MultiError is an error that wraps multiple errors. +type MultiError interface { + error + Errors() []error +} + +// newMultiError creates a new MultiError. Pass in one or more errors. +func newMultiError(err ...error) MultiError { + ret := multiError(err) + return &ret +} + +type multiError []error + +// Error implements the error interface. +func (m *multiError) Error() string { + errs := make([]string, len(*m)) + for i, err := range *m { + errs[i] = err.Error() + } + + return strings.Join(errs, "\n") +} + +// Errors returns a copy of the errors slice +func (m *multiError) Errors() []error { + errs := make([]error, len(*m)) + copy(errs, *m) + return errs +} + +type requiredFlagsErr interface { + error +} + +type errRequiredFlags struct { + missingFlags []string +} + +func (e *errRequiredFlags) Error() string { + if len(e.missingFlags) == 1 { + return fmt.Sprintf("Required flag %q not set", e.missingFlags[0]) + } + joinedMissingFlags := strings.Join(e.missingFlags, ", ") + return fmt.Sprintf("Required flags %q not set", joinedMissingFlags) +} + +type mutuallyExclusiveGroup struct { + flag1Name string + flag2Name string +} + +func (e *mutuallyExclusiveGroup) Error() string { + return fmt.Sprintf("option %s cannot be set along with option %s", e.flag1Name, e.flag2Name) +} + +type mutuallyExclusiveGroupRequiredFlag struct { + flags *MutuallyExclusiveFlags +} + +func (e *mutuallyExclusiveGroupRequiredFlag) Error() string { + var missingFlags []string + for _, grpf := range e.flags.Flags { + var grpString []string + for _, f := range grpf { + grpString = append(grpString, f.Names()...) + } + missingFlags = append(missingFlags, strings.Join(grpString, " ")) + } + + return fmt.Sprintf("one of these flags needs to be provided: %s", strings.Join(missingFlags, ", ")) +} + +// ErrorFormatter is the interface that will suitably format the error output +type ErrorFormatter interface { + Format(s fmt.State, verb rune) +} + +// ExitCoder is the interface checked by `Command` for a custom exit code. +type ExitCoder interface { + error + ExitCode() int +} + +type exitError struct { + exitCode int + err error +} + +// Exit wraps a message and exit code into an error, which by default is +// handled with a call to os.Exit during default error handling. +// +// This is the simplest way to trigger a non-zero exit code for a Command without +// having to call os.Exit manually. During testing, this behavior can be avoided +// by overriding the ExitErrHandler function on a Command or the package-global +// OsExiter function. +func Exit(message any, exitCode int) ExitCoder { + var err error + + switch e := message.(type) { + case ErrorFormatter: + err = fmt.Errorf("%+v", message) + case error: + err = e + default: + err = fmt.Errorf("%+v", message) + } + + return &exitError{ + err: err, + exitCode: exitCode, + } +} + +func (ee *exitError) Error() string { + return ee.err.Error() +} + +func (ee *exitError) ExitCode() int { + return ee.exitCode +} + +// HandleExitCoder handles errors implementing ExitCoder by printing their +// message and calling OsExiter with the given exit code. +// +// If the given error instead implements MultiError, each error will be checked +// for the ExitCoder interface, and OsExiter will be called with the last exit +// code found, or exit code 1 if no ExitCoder is found. +// +// This function is the default error-handling behavior for a Command. +func HandleExitCoder(err error) { + if err == nil { + return + } + + if exitErr, ok := err.(ExitCoder); ok { + if _, ok := exitErr.(ErrorFormatter); ok { + _, _ = fmt.Fprintf(ErrWriter, "%+v\n", err) + } else { + _, _ = fmt.Fprintln(ErrWriter, err) + } + OsExiter(exitErr.ExitCode()) + return + } + + if multiErr, ok := err.(MultiError); ok { + code := handleMultiError(multiErr) + OsExiter(code) + return + } +} + +func handleMultiError(multiErr MultiError) int { + code := 1 + for _, merr := range multiErr.Errors() { + if multiErr2, ok := merr.(MultiError); ok { + code = handleMultiError(multiErr2) + } else if merr != nil { + fmt.Fprintln(ErrWriter, merr) + if exitErr, ok := merr.(ExitCoder); ok { + code = exitErr.ExitCode() + } + } + } + return code +} diff --git a/vendor/github.com/urfave/cli/v3/fish.go b/vendor/github.com/urfave/cli/v3/fish.go new file mode 100644 index 00000000000..8002a33ca1c --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/fish.go @@ -0,0 +1,221 @@ +package cli + +import ( + "bytes" + "fmt" + "io" + "strings" + "text/template" +) + +// ToFishCompletion creates a fish completion string for the `*Command` +// The function errors if either parsing or writing of the string fails. +func (cmd *Command) ToFishCompletion() (string, error) { + var w bytes.Buffer + if err := cmd.writeFishCompletionTemplate(&w); err != nil { + return "", err + } + return w.String(), nil +} + +type fishCommandCompletionTemplate struct { + Command *Command + Completions []string + AllCommands []string +} + +func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error { + const name = "cli" + t, err := template.New(name).Parse(FishCompletionTemplate) + if err != nil { + return err + } + + // Add global flags + completions := prepareFishFlags(cmd.Name, cmd) + + if cmd.ShellComplete != nil { + var completion strings.Builder + fmt.Fprintf(&completion, + "complete -c %s -n '%s' -xa '(%s %s 2>/dev/null)'", + cmd.Name, + fishFlagHelper(cmd.Name, cmd), + cmd.Name, + completionFlag, + ) + completions = append(completions, completion.String()) + } + + // Add commands and their flags + completions = append( + completions, + prepareFishCommands(cmd.Name, cmd)..., + ) + + toplevelCommandNames := []string{} + for _, child := range cmd.Commands { + toplevelCommandNames = append(toplevelCommandNames, child.Names()...) + } + + return t.ExecuteTemplate(w, name, &fishCommandCompletionTemplate{ + Command: cmd, + Completions: completions, + AllCommands: toplevelCommandNames, + }) +} + +func prepareFishCommands(binary string, parent *Command) []string { + commands := parent.Commands + completions := []string{} + for _, command := range commands { + if !command.Hidden { + var completion strings.Builder + fmt.Fprintf(&completion, + "complete -x -c %s -n '%s' -a '%s'", + binary, + fishSubcommandHelper(binary, parent, commands), + command.Name, + ) + + if command.Usage != "" { + fmt.Fprintf(&completion, + " -d '%s'", + escapeSingleQuotes(command.Usage)) + } + completions = append(completions, completion.String()) + } + + if command.ShellComplete != nil { + var completion strings.Builder + var path []string + lineage := command.Lineage() + for i := len(lineage) - 2; i >= 0; i-- { + path = append(path, lineage[i].Name) + } + + fmt.Fprintf(&completion, + "complete -c %s -n '%s' -xa '(%s %s %s 2>/dev/null)'", + binary, + fishFlagHelper(binary, command), + binary, + strings.Join(path, " "), + completionFlag, + ) + completions = append(completions, completion.String()) + } + + completions = append( + completions, + prepareFishFlags(binary, command)..., + ) + + // recursively iterate subcommands + completions = append( + completions, + prepareFishCommands(binary, command)..., + ) + } + + return completions +} + +func prepareFishFlags(binary string, owner *Command) []string { + flags := owner.VisibleFlags() + completions := []string{} + for _, f := range flags { + completion := &strings.Builder{} + fmt.Fprintf(completion, + "complete -c %s -n '%s'", + binary, + fishFlagHelper(binary, owner), + ) + + fishAddFileFlag(f, completion) + + for idx, opt := range f.Names() { + if idx == 0 { + fmt.Fprintf(completion, + " -l %s", strings.TrimSpace(opt), + ) + } else { + fmt.Fprintf(completion, + " -s %s", strings.TrimSpace(opt), + ) + } + } + + if flag, ok := f.(DocGenerationFlag); ok { + if flag.TakesValue() { + completion.WriteString(" -r") + } + + if flag.GetUsage() != "" { + fmt.Fprintf(completion, + " -d '%s'", + escapeSingleQuotes(flag.GetUsage())) + } + } + + completions = append(completions, completion.String()) + } + + return completions +} + +func fishAddFileFlag(flag Flag, completion *strings.Builder) { + switch f := flag.(type) { + case *StringFlag: + if f.TakesFile { + return + } + case *StringSliceFlag: + if f.TakesFile { + return + } + } + completion.WriteString(" -f") +} + +func fishSubcommandHelper(binary string, command *Command, siblings []*Command) string { + fishHelper := fmt.Sprintf("__fish_%s_no_subcommand", binary) + if len(command.Lineage()) > 1 { + var siblingNames []string + for _, sibling := range siblings { + siblingNames = append(siblingNames, sibling.Names()...) + } + ancestry := commandAncestry(command) + fishHelper = fmt.Sprintf( + "%s; and not __fish_seen_subcommand_from %s", + ancestry, + strings.Join(siblingNames, " "), + ) + } + return fishHelper +} + +func fishFlagHelper(binary string, command *Command) string { + fishHelper := fmt.Sprintf("__fish_%s_no_subcommand", binary) + if len(command.Lineage()) > 1 { + fishHelper = commandAncestry(command) + } + return fishHelper +} + +func commandAncestry(command *Command) string { + var ancestry []string + ancestors := command.Lineage() + for i := len(ancestors) - 2; i >= 0; i-- { + ancestry = append( + ancestry, + fmt.Sprintf( + "__fish_seen_subcommand_from %s", + strings.Join(ancestors[i].Names(), " "), + ), + ) + } + return strings.Join(ancestry, "; and ") +} + +func escapeSingleQuotes(input string) string { + return strings.ReplaceAll(input, `'`, `\'`) +} diff --git a/vendor/github.com/urfave/cli/v3/flag.go b/vendor/github.com/urfave/cli/v3/flag.go new file mode 100644 index 00000000000..1b849f1228f --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag.go @@ -0,0 +1,223 @@ +package cli + +import ( + "context" + "fmt" + "slices" + "strings" + "time" +) + +const defaultPlaceholder = "value" + +const ( + defaultSliceFlagSeparator = "," + defaultMapFlagKeyValueSeparator = "=" + disableSliceFlagSeparator = false +) + +var slPfx = fmt.Sprintf("sl:::%d:::", time.Now().UTC().UnixNano()) + +// GenerateShellCompletionFlag enables shell completion +var GenerateShellCompletionFlag Flag = &BoolFlag{ + Name: "generate-shell-completion", + Hidden: true, +} + +// VersionFlag prints the version for the application +var VersionFlag Flag = &BoolFlag{ + Name: "version", + Aliases: []string{"v"}, + Usage: "print the version", + HideDefault: true, + Local: 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", + HideDefault: true, + Local: 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 { + 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 { + RunAction(context.Context, *Command) 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 + + // Retrieve the value of the Flag + Get() any + + // Lifecycle methods. + // flag callback prior to parsing + PreParse() error + + // flag callback post parsing + PostParse() error + + // Apply Flag settings to the given flag set + Set(string, string) error + + // All possible names for this flag + Names() []string + + // Whether the flag has been set or not + 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 { + // whether the flag is a required flag or not + IsRequired() bool +} + +// DocGenerationFlag is an interface that allows documentation generation for the flag +type DocGenerationFlag interface { + // 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 + + // IsDefaultVisible returns whether the default value should be shown in + // help text + IsDefaultVisible() bool + // TypeName to detect if a flag is a string, bool, etc. + TypeName() string +} + +// DocGenerationMultiValueFlag extends DocGenerationFlag for slice/map based flags. +type DocGenerationMultiValueFlag interface { + DocGenerationFlag + + // IsMultiValueFlag returns true for flags that can be given multiple times. + IsMultiValueFlag() bool +} + +// Countable is an interface to enable detection of flag values which support +// repetitive flags +type Countable interface { + Count() int +} + +// VisibleFlag is an interface that allows to check if a flag is visible +type VisibleFlag interface { + // 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 { + // Returns the category of the flag + GetCategory() string + + // Sets the category of the flag + SetCategory(string) +} + +// LocalFlag is an interface to enable detection of flags which are local +// to current command +type LocalFlag interface { + IsLocal() bool +} + +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 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". + if i := strings.IndexAny(part, ", "); i >= 0 { + ret = append(ret, part[:i]) + } else { + ret = append(ret, part) + } + } + + return ret +} + +func hasFlag(flags []Flag, fl Flag) bool { + return slices.Contains(flags, fl) +} + +func flagSplitMultiValues(val string, sliceSeparator string, disableSliceSeparator bool) []string { + if disableSliceSeparator { + return []string{val} + } + + if len(sliceSeparator) == 0 { + sliceSeparator = defaultSliceFlagSeparator + } + return strings.Split(val, sliceSeparator) +} diff --git a/vendor/github.com/urfave/cli/v3/flag_bool.go b/vendor/github.com/urfave/cli/v3/flag_bool.go new file mode 100644 index 00000000000..f0ec22fafa9 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_bool.go @@ -0,0 +1,78 @@ +package cli + +import ( + "errors" + "strconv" +) + +type BoolFlag = FlagBase[bool, BoolConfig, boolValue] + +// BoolConfig defines the configuration for bool flags +type BoolConfig struct { + Count *int +} + +// 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 (cmd *Command) Bool(name string) bool { + if v, ok := cmd.Value(name).(bool); ok { + tracef("bool available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name) + return v + } + + tracef("bool NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name) + return false +} + +// Below functions are to satisfy the ValueCreator interface + +// Create creates the bool value +func (b boolValue) Create(val bool, p *bool, c BoolConfig) Value { + *p = val + if c.Count == nil { + c.Count = new(int) + } + return &boolValue{ + destination: p, + count: c.Count, + } +} + +// ToString formats the bool value +func (b boolValue) ToString(value bool) string { + b.destination = &value + return b.String() +} + +// Below functions are to satisfy the flag.Value interface + +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() any { return *b.destination } + +func (b *boolValue) String() string { + return strconv.FormatBool(*b.destination) +} + +func (b *boolValue) IsBoolFlag() bool { return true } diff --git a/vendor/github.com/urfave/cli/v3/flag_bool_with_inverse.go b/vendor/github.com/urfave/cli/v3/flag_bool_with_inverse.go new file mode 100644 index 00000000000..272dd98fec3 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_bool_with_inverse.go @@ -0,0 +1,240 @@ +package cli + +import ( + "context" + "fmt" + "slices" + "strings" +) + +var DefaultInverseBoolPrefix = "no-" + +type BoolWithInverseFlag struct { + Name string `json:"name"` // name of the flag + Category string `json:"category"` // category of the flag, if any + DefaultText string `json:"defaultText"` // default text of the flag for usage purposes + HideDefault bool `json:"hideDefault"` // whether to hide the default value in output + Usage string `json:"usage"` // usage string for help output + Sources ValueSourceChain `json:"-"` // sources to load flag value from + Required bool `json:"required"` // whether the flag is required or not + Hidden bool `json:"hidden"` // whether to hide the flag in help output + Local bool `json:"local"` // whether the flag needs to be applied to subcommands as well + Value bool `json:"defaultValue"` // default value for this flag if not set by from any source + Destination *bool `json:"-"` // destination pointer for value when set + Aliases []string `json:"aliases"` // Aliases that are allowed for this flag + TakesFile bool `json:"takesFileArg"` // whether this flag takes a file argument, mainly for shell completion purposes + Action func(context.Context, *Command, bool) error `json:"-"` // Action callback to be called when flag is set + OnlyOnce bool `json:"onlyOnce"` // whether this flag can be duplicated on the command line + Validator func(bool) error `json:"-"` // custom function to validate this flag value + ValidateDefaults bool `json:"validateDefaults"` // whether to validate defaults or not + Config BoolConfig `json:"config"` // Additional/Custom configuration associated with this flag type + InversePrefix string `json:"invPrefix"` // The prefix used to indicate a negative value. Default: `env` becomes `no-env` + + // unexported fields for internal use + count int // number of times the flag has been set + hasBeenSet bool // whether the flag has been set from env or file + applied bool // whether the flag has been applied to a flag set already + value Value // value representing this flag's value + pset bool + nset bool +} + +func (bif *BoolWithInverseFlag) IsSet() bool { + return bif.hasBeenSet +} + +func (bif *BoolWithInverseFlag) Get() any { + return bif.value.Get() +} + +func (bif *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error { + if bif.Action != nil { + return bif.Action(ctx, cmd, bif.Get().(bool)) + } + + return nil +} + +func (bif *BoolWithInverseFlag) IsLocal() bool { + return bif.Local +} + +func (bif *BoolWithInverseFlag) inversePrefix() string { + if bif.InversePrefix == "" { + bif.InversePrefix = DefaultInverseBoolPrefix + } + + return bif.InversePrefix +} + +func (bif *BoolWithInverseFlag) PreParse() error { + count := bif.Config.Count + if count == nil { + count = &bif.count + } + dest := bif.Destination + if dest == nil { + dest = new(bool) + } + *dest = bif.Value + bif.value = &boolValue{ + destination: dest, + count: count, + } + + // Validate the given default or values set from external sources as well + if bif.Validator != nil && bif.ValidateDefaults { + if err := bif.Validator(bif.value.Get().(bool)); err != nil { + return err + } + } + bif.applied = true + return nil +} + +func (bif *BoolWithInverseFlag) PostParse() error { + tracef("postparse (flag=%[1]q)", bif.Name) + + if !bif.hasBeenSet { + if val, source, found := bif.Sources.LookupWithSource(); found { + if val == "" { + val = "false" + } + if err := bif.Set(bif.Name, val); err != nil { + return fmt.Errorf( + "could not parse %[1]q as %[2]T value from %[3]s for flag %[4]s: %[5]s", + val, bif.Value, source, bif.Name, err, + ) + } + + bif.hasBeenSet = true + } + } + + return nil +} + +func (bif *BoolWithInverseFlag) Set(name, val string) error { + if bif.count > 0 && bif.OnlyOnce { + return fmt.Errorf("cant duplicate this flag") + } + + bif.hasBeenSet = true + + if slices.Contains(append([]string{bif.Name}, bif.Aliases...), name) { + if bif.nset { + return fmt.Errorf("cannot set both flags `--%s` and `--%s`", bif.Name, bif.inversePrefix()+bif.Name) + } + if err := bif.value.Set(val); err != nil { + return err + } + bif.pset = true + } else { + if bif.pset { + return fmt.Errorf("cannot set both flags `--%s` and `--%s`", bif.Name, bif.inversePrefix()+bif.Name) + } + if err := bif.value.Set("false"); err != nil { + return err + } + bif.nset = true + } + + if bif.Validator != nil { + return bif.Validator(bif.value.Get().(bool)) + } + return nil +} + +func (bif *BoolWithInverseFlag) Names() []string { + names := append([]string{bif.Name}, bif.Aliases...) + + for _, name := range names { + names = append(names, bif.inversePrefix()+name) + } + + return names +} + +func (bif *BoolWithInverseFlag) IsRequired() bool { + return bif.Required +} + +func (bif *BoolWithInverseFlag) IsVisible() bool { + return !bif.Hidden +} + +// String implements the standard Stringer interface. +// +// Example for BoolFlag{Name: "env"} +// --[no-]env (default: false) +func (bif *BoolWithInverseFlag) String() string { + out := FlagStringer(bif) + + i := strings.Index(out, "\t") + + prefix := "--" + + // single character flags are prefixed with `-` instead of `--` + if len(bif.Name) == 1 { + prefix = "-" + } + + return fmt.Sprintf("%s[%s]%s%s", prefix, bif.inversePrefix(), bif.Name, out[i:]) +} + +// IsBoolFlag returns whether the flag doesnt need to accept args +func (bif *BoolWithInverseFlag) IsBoolFlag() bool { + return true +} + +// Count returns the number of times this flag has been invoked +func (bif *BoolWithInverseFlag) Count() int { + return bif.count +} + +// GetDefaultText returns the default text for this flag +func (bif *BoolWithInverseFlag) GetDefaultText() string { + if bif.Required { + return bif.DefaultText + } + return boolValue{}.ToString(bif.Value) +} + +// GetCategory returns the category of the flag +func (bif *BoolWithInverseFlag) GetCategory() string { + return bif.Category +} + +func (bif *BoolWithInverseFlag) SetCategory(c string) { + bif.Category = c +} + +// GetUsage returns the usage string for the flag +func (bif *BoolWithInverseFlag) GetUsage() string { + return bif.Usage +} + +// GetEnvVars returns the env vars for this flag +func (bif *BoolWithInverseFlag) GetEnvVars() []string { + return bif.Sources.EnvKeys() +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (bif *BoolWithInverseFlag) GetValue() string { + return "" +} + +func (bif *BoolWithInverseFlag) TakesValue() bool { + return false +} + +// IsDefaultVisible returns true if the flag is not hidden, otherwise false +func (bif *BoolWithInverseFlag) IsDefaultVisible() bool { + return !bif.HideDefault +} + +// TypeName is used for stringify/docs. For bool its a no-op +func (bif *BoolWithInverseFlag) TypeName() string { + return "bool" +} diff --git a/vendor/github.com/urfave/cli/v3/flag_duration.go b/vendor/github.com/urfave/cli/v3/flag_duration.go new file mode 100644 index 00000000000..634789d161f --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_duration.go @@ -0,0 +1,50 @@ +package cli + +import ( + "fmt" + "time" +) + +type DurationFlag = FlagBase[time.Duration, NoConfig, durationValue] + +// -- time.Duration Value +type durationValue time.Duration + +// Below functions are to satisfy the ValueCreator interface + +func (d durationValue) Create(val time.Duration, p *time.Duration, c NoConfig) Value { + *p = val + return (*durationValue)(p) +} + +func (d durationValue) ToString(val time.Duration) string { + d = durationValue(val) + return d.String() +} + +// Below functions are to satisfy the flag.Value interface + +func (d *durationValue) Set(s string) error { + v, err := time.ParseDuration(s) + if err != nil { + return err + } + *d = durationValue(v) + return err +} + +func (d *durationValue) Get() any { return time.Duration(*d) } + +func (d *durationValue) String() string { + return fmt.Sprintf("%v", time.Duration(*d)) +} + +func (cmd *Command) Duration(name string) time.Duration { + if v, ok := cmd.Value(name).(time.Duration); ok { + tracef("duration available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name) + return v + } + + tracef("duration NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name) + return 0 +} diff --git a/vendor/github.com/urfave/cli/v3/flag_ext.go b/vendor/github.com/urfave/cli/v3/flag_ext.go new file mode 100644 index 00000000000..9972af7c560 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_ext.go @@ -0,0 +1,63 @@ +package cli + +import "flag" + +type extFlag struct { + f *flag.Flag +} + +func (e *extFlag) PreParse() error { + if e.f.DefValue != "" { + return e.Set("", e.f.DefValue) + } + + return nil +} + +func (e *extFlag) PostParse() error { + return nil +} + +func (e *extFlag) Set(_ string, val string) error { + return e.f.Value.Set(val) +} + +func (e *extFlag) Get() any { + return e.f.Value.(flag.Getter).Get() +} + +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 +} diff --git a/vendor/github.com/urfave/cli/v3/flag_float.go b/vendor/github.com/urfave/cli/v3/flag_float.go new file mode 100644 index 00000000000..6173e80dea6 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_float.go @@ -0,0 +1,76 @@ +package cli + +import ( + "strconv" + "unsafe" +) + +type ( + FloatFlag = FlagBase[float64, NoConfig, floatValue[float64]] + Float32Flag = FlagBase[float32, NoConfig, floatValue[float32]] + Float64Flag = FlagBase[float64, NoConfig, floatValue[float64]] +) + +// -- float Value +type floatValue[T float32 | float64] struct { + val *T +} + +// Below functions are to satisfy the ValueCreator interface + +func (f floatValue[T]) Create(val T, p *T, c NoConfig) Value { + *p = val + + return &floatValue[T]{val: p} +} + +func (f floatValue[T]) ToString(b T) string { + f.val = &b + return f.String() +} + +// Below functions are to satisfy the flag.Value interface + +func (f *floatValue[T]) Set(s string) error { + v, err := strconv.ParseFloat(s, int(unsafe.Sizeof(T(0))*8)) + if err != nil { + return err + } + *f.val = T(v) + return nil +} + +func (f *floatValue[T]) Get() any { return *f.val } + +func (f *floatValue[T]) String() string { + return strconv.FormatFloat(float64(*f.val), 'g', -1, int(unsafe.Sizeof(T(0))*8)) +} + +// Float looks up the value of a local FloatFlag, returns +// 0 if not found +func (cmd *Command) Float(name string) float64 { + return getFloat[float64](cmd, name) +} + +// Float32 looks up the value of a local Float32Flag, returns +// 0 if not found +func (cmd *Command) Float32(name string) float32 { + return getFloat[float32](cmd, name) +} + +// Float64 looks up the value of a local Float64Flag, returns +// 0 if not found +func (cmd *Command) Float64(name string) float64 { + return getFloat[float64](cmd, name) +} + +func getFloat[T float32 | float64](cmd *Command, name string) T { + if v, ok := cmd.Value(name).(T); ok { + tracef("float available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name) + + return v + } + + tracef("float NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name) + return 0 +} diff --git a/vendor/github.com/urfave/cli/v3/flag_float_slice.go b/vendor/github.com/urfave/cli/v3/flag_float_slice.go new file mode 100644 index 00000000000..9a6a46d8ac5 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_float_slice.go @@ -0,0 +1,34 @@ +package cli + +type ( + FloatSlice = SliceBase[float64, NoConfig, floatValue[float64]] + Float32Slice = SliceBase[float32, NoConfig, floatValue[float32]] + Float64Slice = SliceBase[float64, NoConfig, floatValue[float64]] + FloatSliceFlag = FlagBase[[]float64, NoConfig, FloatSlice] + Float32SliceFlag = FlagBase[[]float32, NoConfig, Float32Slice] + Float64SliceFlag = FlagBase[[]float64, NoConfig, Float64Slice] +) + +var ( + NewFloatSlice = NewSliceBase[float64, NoConfig, floatValue[float64]] + NewFloat32Slice = NewSliceBase[float32, NoConfig, floatValue[float32]] + NewFloat64Slice = NewSliceBase[float64, NoConfig, floatValue[float64]] +) + +// FloatSlice looks up the value of a local FloatSliceFlag, returns +// nil if not found +func (cmd *Command) FloatSlice(name string) []float64 { + return getNumberSlice[float64](cmd, name) +} + +// Float32Slice looks up the value of a local Float32Slice, returns +// nil if not found +func (cmd *Command) Float32Slice(name string) []float32 { + return getNumberSlice[float32](cmd, name) +} + +// Float64Slice looks up the value of a local Float64SliceFlag, returns +// nil if not found +func (cmd *Command) Float64Slice(name string) []float64 { + return getNumberSlice[float64](cmd, name) +} diff --git a/vendor/github.com/urfave/cli/v3/flag_generic.go b/vendor/github.com/urfave/cli/v3/flag_generic.go new file mode 100644 index 00000000000..5ee07c7a36c --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_generic.go @@ -0,0 +1,65 @@ +package cli + +type GenericFlag = FlagBase[Value, NoConfig, genericValue] + +// -- Value Value +type genericValue struct { + val Value +} + +// Below functions are to satisfy the ValueCreator interface + +func (f genericValue) Create(val Value, p *Value, c NoConfig) Value { + *p = val + return &genericValue{ + val: *p, + } +} + +func (f genericValue) ToString(b Value) string { + f.val = b + return f.String() +} + +// Below functions are to satisfy the flag.Value interface + +func (f *genericValue) Set(s string) error { + if f.val != nil { + return f.val.Set(s) + } + return nil +} + +func (f *genericValue) Get() any { + if f.val != nil { + return f.val.Get() + } + return nil +} + +func (f *genericValue) String() string { + if f.val != nil { + return f.val.String() + } + return "" +} + +func (f *genericValue) IsBoolFlag() bool { + if f.val == nil { + return false + } + bf, ok := f.val.(boolFlag) + return ok && bf.IsBoolFlag() +} + +// Generic looks up the value of a local GenericFlag, returns +// nil if not found +func (cmd *Command) Generic(name string) Value { + if v, ok := cmd.Value(name).(Value); ok { + tracef("generic available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name) + return v + } + + tracef("generic NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name) + return nil +} diff --git a/vendor/github.com/urfave/cli/v3/flag_impl.go b/vendor/github.com/urfave/cli/v3/flag_impl.go new file mode 100644 index 00000000000..1ca295aaf20 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_impl.go @@ -0,0 +1,313 @@ +package cli + +import ( + "context" + "flag" + "fmt" + "reflect" + "strings" +) + +// Value represents a value as used by cli. +// For now it implements the golang flag.Value interface +type Value interface { + flag.Value + flag.Getter +} + +type boolFlag interface { + IsBoolFlag() bool +} + +type multiValueParsingConfig struct { + // 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 + // MapFlagKeyValueSeparator is used to customize the separator for MapFlag, the default is "=" + MapFlagKeyValueSeparator string +} + +type multiValueParsingConfigSetter interface { + // configuration of parsing + setMultiValueParsingConfig(c multiValueParsingConfig) +} + +// ValueCreator is responsible for creating a flag.Value emulation +// as well as custom formatting +// +// T specifies the type +// C specifies the config for the type +type ValueCreator[T any, C any] interface { + Create(T, *T, C) Value + ToString(T) string +} + +// NoConfig is for flags which dont need a custom configuration +type NoConfig struct{} + +// FlagBase [T,C,VC] is a generic flag base which can be used +// as a boilerplate to implement the most common interfaces +// used by urfave/cli. +// +// T specifies the type +// C specifies the configuration required(if any for that flag type) +// VC specifies the value creator which creates the flag.Value emulation +type FlagBase[T any, C any, VC ValueCreator[T, C]] struct { + Name string `json:"name"` // name of the flag + Category string `json:"category"` // category of the flag, if any + DefaultText string `json:"defaultText"` // default text of the flag for usage purposes + HideDefault bool `json:"hideDefault"` // whether to hide the default value in output + Usage string `json:"usage"` // usage string for help output + Sources ValueSourceChain `json:"-"` // sources to load flag value from + Required bool `json:"required"` // whether the flag is required or not + Hidden bool `json:"hidden"` // whether to hide the flag in help output + Local bool `json:"local"` // whether the flag needs to be applied to subcommands as well + Value T `json:"defaultValue"` // default value for this flag if not set by from any source + Destination *T `json:"-"` // destination pointer for value when set + Aliases []string `json:"aliases"` // Aliases that are allowed for this flag + TakesFile bool `json:"takesFileArg"` // whether this flag takes a file argument, mainly for shell completion purposes + Action func(context.Context, *Command, T) error `json:"-"` // Action callback to be called when flag is set + Config C `json:"config"` // Additional/Custom configuration associated with this flag type + OnlyOnce bool `json:"onlyOnce"` // whether this flag can be duplicated on the command line + Validator func(T) error `json:"-"` // custom function to validate this flag value + ValidateDefaults bool `json:"validateDefaults"` // whether to validate defaults or not + + // unexported fields for internal use + count int // number of times the flag has been set + hasBeenSet bool // whether the flag has been set from env or file + applied bool // whether the flag has been applied to a flag set already + creator VC // value creator for this flag type + value Value // value representing this flag's value +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *FlagBase[T, C, V]) GetValue() string { + var v V + return v.ToString(f.Value) +} + +// TypeName returns the type of the flag. +func (f *FlagBase[T, C, V]) TypeName() string { + ty := reflect.TypeOf(f.Value) + if ty == nil { + return "" + } + // convert the typename to generic type + convertToGenericType := func(name string) string { + prefixMap := map[string]string{ + "float": "float", + "int": "int", + "uint": "uint", + } + for prefix, genericType := range prefixMap { + if strings.HasPrefix(name, prefix) { + return genericType + } + } + return strings.ToLower(name) + } + + switch ty.Kind() { + // if it is a Slice, then return the slice's inner type. Will nested slices be used in the future? + case reflect.Slice: + elemType := ty.Elem() + return convertToGenericType(elemType.Name()) + // if it is a Map, then return the map's key and value types. + case reflect.Map: + keyType := ty.Key() + valueType := ty.Elem() + return fmt.Sprintf("%s=%s", convertToGenericType(keyType.Name()), convertToGenericType(valueType.Name())) + default: + return convertToGenericType(ty.Name()) + } +} + +// PostParse populates the flag given the flag set and environment +func (f *FlagBase[T, C, V]) PostParse() error { + tracef("postparse (flag=%[1]q)", f.Name) + + if !f.hasBeenSet { + if val, source, found := f.Sources.LookupWithSource(); found { + if val != "" || reflect.TypeOf(f.Value).Kind() == reflect.String { + if err := f.Set(f.Name, val); err != nil { + return fmt.Errorf( + "could not parse %[1]q as %[2]T value from %[3]s for flag %[4]s: %[5]s", + val, f.Value, source, f.Name, err, + ) + } + } else if val == "" && reflect.TypeOf(f.Value).Kind() == reflect.Bool { + _ = f.Set(f.Name, "false") + } + + f.hasBeenSet = true + } + } + + return nil +} + +// pass configuration of parsing to value +func (f *FlagBase[T, C, V]) setMultiValueParsingConfig(c multiValueParsingConfig) { + tracef("setMultiValueParsingConfig %T, %+v", f.value, f.value) + if cf, ok := f.value.(multiValueParsingConfigSetter); ok { + cf.setMultiValueParsingConfig(c) + } +} + +func (f *FlagBase[T, C, V]) PreParse() error { + newVal := f.Value + + if f.Destination == nil { + f.value = f.creator.Create(newVal, new(T), f.Config) + } else { + f.value = f.creator.Create(newVal, f.Destination, f.Config) + } + + // Validate the given default or values set from external sources as well + if f.Validator != nil && f.ValidateDefaults { + if err := f.Validator(f.value.Get().(T)); err != nil { + return err + } + } + f.applied = true + return nil +} + +// Set applies given value from string +func (f *FlagBase[T, C, V]) Set(_ string, val string) error { + tracef("apply (flag=%[1]q)", f.Name) + + // TODO move this phase into a separate flag initialization function + // if flag has been applied previously then it would have already been set + // from env or file. So no need to apply the env set again. However + // lots of units tests prior to persistent flags assumed that the + // flag can be applied to different flag sets multiple times while still + // keeping the env set. + if !f.applied { + if err := f.PreParse(); err != nil { + return err + } + f.applied = true + } + + if f.count == 1 && f.OnlyOnce { + return fmt.Errorf("cant duplicate this flag") + } + + f.count++ + if err := f.value.Set(val); err != nil { + return err + } + f.hasBeenSet = true + if f.Validator != nil { + if err := f.Validator(f.value.Get().(T)); err != nil { + return err + } + } + return nil +} + +func (f *FlagBase[T, C, V]) Get() any { + if f.value != nil { + return f.value.Get() + } + return f.Value +} + +// IsDefaultVisible returns true if the flag is not hidden, otherwise false +func (f *FlagBase[T, C, V]) IsDefaultVisible() bool { + return !f.HideDefault +} + +// String returns a readable representation of this value (for usage defaults) +func (f *FlagBase[T, C, V]) String() string { + return FlagStringer(f) +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *FlagBase[T, C, V]) IsSet() bool { + return f.hasBeenSet +} + +// Names returns the names of the flag +func (f *FlagBase[T, C, V]) Names() []string { + return FlagNames(f.Name, f.Aliases) +} + +// IsRequired returns whether or not the flag is required +func (f *FlagBase[T, C, V]) IsRequired() bool { + return f.Required +} + +// IsVisible returns true if the flag is not hidden, otherwise false +func (f *FlagBase[T, C, V]) IsVisible() bool { + return !f.Hidden +} + +// GetCategory returns the category of the flag +func (f *FlagBase[T, C, V]) GetCategory() string { + return f.Category +} + +func (f *FlagBase[T, C, V]) SetCategory(c string) { + f.Category = c +} + +// GetUsage returns the usage string for the flag +func (f *FlagBase[T, C, V]) GetUsage() string { + return f.Usage +} + +// GetEnvVars returns the env vars for this flag +func (f *FlagBase[T, C, V]) GetEnvVars() []string { + return f.Sources.EnvKeys() +} + +// TakesValue returns true if the flag takes a value, otherwise false +func (f *FlagBase[T, C, V]) TakesValue() bool { + var t T + return reflect.TypeOf(t) == nil || reflect.TypeOf(t).Kind() != reflect.Bool +} + +// GetDefaultText returns the default text for this flag +func (f *FlagBase[T, C, V]) GetDefaultText() string { + return f.DefaultText +} + +// RunAction executes flag action if set +func (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error { + if f.Action != nil { + return f.Action(ctx, cmd, f.value.Get().(T)) + } + + return nil +} + +// IsMultiValueFlag returns true if the value type T can take multiple +// values from cmd line. This is true for slice and map type flags +func (f *FlagBase[T, C, VC]) IsMultiValueFlag() bool { + // TBD how to specify + if reflect.TypeOf(f.Value) == nil { + return false + } + kind := reflect.TypeOf(f.Value).Kind() + return kind == reflect.Slice || kind == reflect.Map +} + +// IsLocal returns false if flag needs to be persistent across subcommands +func (f *FlagBase[T, C, VC]) IsLocal() bool { + return f.Local +} + +// IsBoolFlag returns whether the flag doesnt need to accept args +func (f *FlagBase[T, C, VC]) IsBoolFlag() bool { + bf, ok := f.value.(boolFlag) + return ok && bf.IsBoolFlag() +} + +// Count returns the number of times this flag has been invoked +func (f *FlagBase[T, C, VC]) Count() int { + return f.count +} diff --git a/vendor/github.com/urfave/cli/v3/flag_int.go b/vendor/github.com/urfave/cli/v3/flag_int.go new file mode 100644 index 00000000000..8e5af17092d --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_int.go @@ -0,0 +1,104 @@ +package cli + +import ( + "strconv" + "unsafe" +) + +type ( + IntFlag = FlagBase[int, IntegerConfig, intValue[int]] + Int8Flag = FlagBase[int8, IntegerConfig, intValue[int8]] + Int16Flag = FlagBase[int16, IntegerConfig, intValue[int16]] + Int32Flag = FlagBase[int32, IntegerConfig, intValue[int32]] + Int64Flag = FlagBase[int64, IntegerConfig, intValue[int64]] +) + +// IntegerConfig is the configuration for all integer type flags +type IntegerConfig struct { + Base int +} + +// -- int Value +type intValue[T int | int8 | int16 | int32 | int64] struct { + val *T + base int +} + +// Below functions are to satisfy the ValueCreator interface + +func (i intValue[T]) Create(val T, p *T, c IntegerConfig) Value { + *p = val + + return &intValue[T]{ + val: p, + base: c.Base, + } +} + +func (i intValue[T]) ToString(b T) string { + i.val = &b + return i.String() +} + +// Below functions are to satisfy the flag.Value interface + +func (i *intValue[T]) Set(s string) error { + v, err := strconv.ParseInt(s, i.base, int(unsafe.Sizeof(T(0))*8)) + if err != nil { + return err + } + *i.val = T(v) + return err +} + +func (i *intValue[T]) Get() any { return *i.val } + +func (i *intValue[T]) String() string { + base := i.base + if base == 0 { + base = 10 + } + + return strconv.FormatInt(int64(*i.val), base) +} + +// Int looks up the value of a local Int64Flag, returns +// 0 if not found +func (cmd *Command) Int(name string) int { + return getInt[int](cmd, name) +} + +// Int8 looks up the value of a local Int8Flag, returns +// 0 if not found +func (cmd *Command) Int8(name string) int8 { + return getInt[int8](cmd, name) +} + +// Int16 looks up the value of a local Int16Flag, returns +// 0 if not found +func (cmd *Command) Int16(name string) int16 { + return getInt[int16](cmd, name) +} + +// Int32 looks up the value of a local Int32Flag, returns +// 0 if not found +func (cmd *Command) Int32(name string) int32 { + return getInt[int32](cmd, name) +} + +// Int64 looks up the value of a local Int64Flag, returns +// 0 if not found +func (cmd *Command) Int64(name string) int64 { + return getInt[int64](cmd, name) +} + +func getInt[T int | int8 | int16 | int32 | int64](cmd *Command, name string) T { + if v, ok := cmd.Value(name).(T); ok { + tracef("int available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name) + + return v + } + + tracef("int NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name) + return 0 +} diff --git a/vendor/github.com/urfave/cli/v3/flag_int_slice.go b/vendor/github.com/urfave/cli/v3/flag_int_slice.go new file mode 100644 index 00000000000..22dcb5a24c8 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_int_slice.go @@ -0,0 +1,52 @@ +package cli + +type ( + IntSlice = SliceBase[int, IntegerConfig, intValue[int]] + Int8Slice = SliceBase[int8, IntegerConfig, intValue[int8]] + Int16Slice = SliceBase[int16, IntegerConfig, intValue[int16]] + Int32Slice = SliceBase[int32, IntegerConfig, intValue[int32]] + Int64Slice = SliceBase[int64, IntegerConfig, intValue[int64]] + IntSliceFlag = FlagBase[[]int, IntegerConfig, IntSlice] + Int8SliceFlag = FlagBase[[]int8, IntegerConfig, Int8Slice] + Int16SliceFlag = FlagBase[[]int16, IntegerConfig, Int16Slice] + Int32SliceFlag = FlagBase[[]int32, IntegerConfig, Int32Slice] + Int64SliceFlag = FlagBase[[]int64, IntegerConfig, Int64Slice] +) + +var ( + NewIntSlice = NewSliceBase[int, IntegerConfig, intValue[int]] + NewInt8Slice = NewSliceBase[int8, IntegerConfig, intValue[int8]] + NewInt16Slice = NewSliceBase[int16, IntegerConfig, intValue[int16]] + NewInt32Slice = NewSliceBase[int32, IntegerConfig, intValue[int32]] + NewInt64Slice = NewSliceBase[int64, IntegerConfig, intValue[int64]] +) + +// IntSlice looks up the value of a local IntSliceFlag, returns +// nil if not found +func (cmd *Command) IntSlice(name string) []int { + return getNumberSlice[int](cmd, name) +} + +// Int8Slice looks up the value of a local Int8SliceFlag, returns +// nil if not found +func (cmd *Command) Int8Slice(name string) []int8 { + return getNumberSlice[int8](cmd, name) +} + +// Int16Slice looks up the value of a local Int16SliceFlag, returns +// nil if not found +func (cmd *Command) Int16Slice(name string) []int16 { + return getNumberSlice[int16](cmd, name) +} + +// Int32Slice looks up the value of a local Int32SliceFlag, returns +// nil if not found +func (cmd *Command) Int32Slice(name string) []int32 { + return getNumberSlice[int32](cmd, name) +} + +// Int64Slice looks up the value of a local Int64SliceFlag, returns +// nil if not found +func (cmd *Command) Int64Slice(name string) []int64 { + return getNumberSlice[int64](cmd, name) +} diff --git a/vendor/github.com/urfave/cli/v3/flag_map_impl.go b/vendor/github.com/urfave/cli/v3/flag_map_impl.go new file mode 100644 index 00000000000..cb65903b926 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_map_impl.go @@ -0,0 +1,138 @@ +package cli + +import ( + "encoding/json" + "fmt" + "reflect" + "sort" + "strings" +) + +// MapBase wraps map[string]T to satisfy flag.Value +type MapBase[T any, C any, VC ValueCreator[T, C]] struct { + dict *map[string]T + hasBeenSet bool + value Value + multiValueConfig multiValueParsingConfig +} + +func (i MapBase[T, C, VC]) Create(val map[string]T, p *map[string]T, c C) Value { + *p = map[string]T{} + for k, v := range val { + (*p)[k] = v + } + var t T + np := new(T) + var vc VC + return &MapBase[T, C, VC]{ + dict: p, + value: vc.Create(t, np, c), + } +} + +// NewMapBase makes a *MapBase with default values +func NewMapBase[T any, C any, VC ValueCreator[T, C]](defaults map[string]T) *MapBase[T, C, VC] { + return &MapBase[T, C, VC]{ + dict: &defaults, + } +} + +// configuration of slicing +func (i *MapBase[T, C, VC]) setMultiValueParsingConfig(c multiValueParsingConfig) { + i.multiValueConfig = c + mvc := &i.multiValueConfig + tracef( + "set map parsing config - keyValueSeparator '%s', slice separator '%s', disable separator:%v", + mvc.MapFlagKeyValueSeparator, + mvc.SliceFlagSeparator, + mvc.DisableSliceFlagSeparator, + ) +} + +// Set parses the value and appends it to the list of values +func (i *MapBase[T, C, VC]) Set(value string) error { + if !i.hasBeenSet { + *i.dict = map[string]T{} + i.hasBeenSet = true + } + + if strings.HasPrefix(value, slPfx) { + // Deserializing assumes overwrite + _ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &i.dict) + i.hasBeenSet = true + return nil + } + + mvc := &i.multiValueConfig + keyValueSeparator := mvc.MapFlagKeyValueSeparator + if len(keyValueSeparator) == 0 { + keyValueSeparator = defaultMapFlagKeyValueSeparator + } + + tracef( + "splitting map value '%s', keyValueSeparator '%s', slice separator '%s', disable separator:%v", + value, + keyValueSeparator, + mvc.SliceFlagSeparator, + mvc.DisableSliceFlagSeparator, + ) + for _, item := range flagSplitMultiValues(value, mvc.SliceFlagSeparator, mvc.DisableSliceFlagSeparator) { + key, value, ok := strings.Cut(item, keyValueSeparator) + if !ok { + return fmt.Errorf("item %q is missing separator %q", item, keyValueSeparator) + } + if err := i.value.Set(value); err != nil { + return err + } + (*i.dict)[key] = i.value.Get().(T) + } + + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (i *MapBase[T, C, VC]) String() string { + v := i.Value() + var t T + if reflect.TypeOf(t).Kind() == reflect.String { + return fmt.Sprintf("%v", v) + } + return fmt.Sprintf("%T{%s}", v, i.ToString(v)) +} + +// Serialize allows MapBase to fulfill Serializer +func (i *MapBase[T, C, VC]) Serialize() string { + jsonBytes, _ := json.Marshal(i.dict) + return fmt.Sprintf("%s%s", slPfx, string(jsonBytes)) +} + +// Value returns the mapping of values set by this flag +func (i *MapBase[T, C, VC]) Value() map[string]T { + if i.dict == nil { + return map[string]T{} + } + return *i.dict +} + +// Get returns the mapping of values set by this flag +func (i *MapBase[T, C, VC]) Get() any { + return *i.dict +} + +func (i MapBase[T, C, VC]) ToString(t map[string]T) string { + var defaultVals []string + var vc VC + for _, k := range sortedKeys(t) { + defaultVals = append(defaultVals, k+defaultMapFlagKeyValueSeparator+vc.ToString(t[k])) + } + return strings.Join(defaultVals, ", ") +} + +func sortedKeys[T any](dict map[string]T) []string { + keys := make([]string, 0, len(dict)) + for k := range dict { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} diff --git a/vendor/github.com/urfave/cli/v3/flag_mutex.go b/vendor/github.com/urfave/cli/v3/flag_mutex.go new file mode 100644 index 00000000000..247bcb569b3 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_mutex.go @@ -0,0 +1,54 @@ +package cli + +// MutuallyExclusiveFlags defines a mutually exclusive flag group +// Multiple option paths can be provided out of which +// only one can be defined on cmdline +// So for example +// [ --foo | [ --bar something --darth somethingelse ] ] +type MutuallyExclusiveFlags struct { + // Flag list + Flags [][]Flag + + // whether this group is required + Required bool + + // Category to apply to all flags within group + Category string +} + +func (grp MutuallyExclusiveFlags) check(_ *Command) error { + oneSet := false + e := &mutuallyExclusiveGroup{} + + for _, grpf := range grp.Flags { + for _, f := range grpf { + if f.IsSet() { + if oneSet { + e.flag2Name = f.Names()[0] + return e + } + e.flag1Name = f.Names()[0] + oneSet = true + break + } + if oneSet { + break + } + } + } + + if !oneSet && grp.Required { + return &mutuallyExclusiveGroupRequiredFlag{flags: &grp} + } + return nil +} + +func (grp MutuallyExclusiveFlags) propagateCategory() { + for _, grpf := range grp.Flags { + for _, f := range grpf { + if cf, ok := f.(CategorizableFlag); ok { + cf.SetCategory(grp.Category) + } + } + } +} diff --git a/vendor/github.com/urfave/cli/v3/flag_number_slice.go b/vendor/github.com/urfave/cli/v3/flag_number_slice.go new file mode 100644 index 00000000000..77e317020e5 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_number_slice.go @@ -0,0 +1,15 @@ +package cli + +type numberType interface { + int | int8 | int16 | int32 | int64 | float32 | float64 +} + +func getNumberSlice[T numberType](cmd *Command, name string) []T { + if v, ok := cmd.Value(name).([]T); ok { + tracef("%T slice available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", *new(T), name, v, cmd.Name) + return v + } + + tracef("%T slice NOT available for flag name %[1]q (cmd=%[2]q)", *new(T), name, cmd.Name) + return nil +} diff --git a/vendor/github.com/urfave/cli/v3/flag_slice_base.go b/vendor/github.com/urfave/cli/v3/flag_slice_base.go new file mode 100644 index 00000000000..1f9561ae213 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_slice_base.go @@ -0,0 +1,115 @@ +package cli + +import ( + "encoding/json" + "fmt" + "reflect" + "strings" +) + +// SliceBase wraps []T to satisfy flag.Value +type SliceBase[T any, C any, VC ValueCreator[T, C]] struct { + slice *[]T + hasBeenSet bool + value Value + sliceSeparator string + disableSliceSeparator bool +} + +func (i SliceBase[T, C, VC]) Create(val []T, p *[]T, c C) Value { + *p = []T{} + *p = append(*p, val...) + var t T + np := new(T) + var vc VC + return &SliceBase[T, C, VC]{ + slice: p, + value: vc.Create(t, np, c), + } +} + +// NewSliceBase makes a *SliceBase with default values +func NewSliceBase[T any, C any, VC ValueCreator[T, C]](defaults ...T) *SliceBase[T, C, VC] { + return &SliceBase[T, C, VC]{ + slice: &defaults, + } +} + +// configuration of slicing +func (i *SliceBase[T, C, VC]) setMultiValueParsingConfig(c multiValueParsingConfig) { + i.disableSliceSeparator = c.DisableSliceFlagSeparator + i.sliceSeparator = c.SliceFlagSeparator + tracef("set slice parsing config - slice separator '%s', disable separator:%v", i.sliceSeparator, i.disableSliceSeparator) +} + +// Set parses the value and appends it to the list of values +func (i *SliceBase[T, C, VC]) Set(value string) error { + if !i.hasBeenSet { + *i.slice = []T{} + 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 + } + + trimSpace := true + // hack. How do we know if we should trim spaces? + // it makes sense only for string slice flags which have + // an option to not trim spaces. So by default we trim spaces + // otherwise we let the underlying value type handle it. + var t T + if reflect.TypeOf(t).Kind() == reflect.String { + trimSpace = false + } + + tracef("splitting slice value '%s', separator '%s', disable separator:%v", value, i.sliceSeparator, i.disableSliceSeparator) + for _, s := range flagSplitMultiValues(value, i.sliceSeparator, i.disableSliceSeparator) { + if trimSpace { + s = strings.TrimSpace(s) + } + if err := i.value.Set(s); err != nil { + return err + } + *i.slice = append(*i.slice, i.value.Get().(T)) + } + + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (i *SliceBase[T, C, VC]) String() string { + var defaultVals []string + var v VC + for _, s := range *i.slice { + defaultVals = append(defaultVals, v.ToString(s)) + } + return strings.Join(defaultVals, ", ") +} + +// Serialize allows SliceBase to fulfill Serializer +func (i *SliceBase[T, C, VC]) Serialize() string { + jsonBytes, _ := json.Marshal(i.slice) + return fmt.Sprintf("%s%s", slPfx, string(jsonBytes)) +} + +// Value returns the slice of values set by this flag +func (i *SliceBase[T, C, VC]) Value() []T { + if i.slice == nil { + return nil + } + return *i.slice +} + +// Get returns the slice of values set by this flag +func (i *SliceBase[T, C, VC]) Get() any { + return *i.slice +} + +func (i SliceBase[T, C, VC]) ToString(t []T) string { + i.slice = &t + return i.String() +} diff --git a/vendor/github.com/urfave/cli/v3/flag_string.go b/vendor/github.com/urfave/cli/v3/flag_string.go new file mode 100644 index 00000000000..ca24b379cc9 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_string.go @@ -0,0 +1,64 @@ +package cli + +import ( + "fmt" + "strings" +) + +type StringFlag = FlagBase[string, StringConfig, stringValue] + +// StringConfig defines the configuration for string flags +type StringConfig struct { + // Whether to trim whitespace of parsed value + TrimSpace bool +} + +// -- string Value +type stringValue struct { + destination *string + trimSpace bool +} + +// Below functions are to satisfy the ValueCreator interface + +func (s stringValue) Create(val string, p *string, c StringConfig) Value { + *p = val + return &stringValue{ + destination: p, + trimSpace: c.TrimSpace, + } +} + +func (s stringValue) ToString(val string) string { + s.destination = &val + return s.String() +} + +// Below functions are to satisfy the flag.Value interface + +func (s *stringValue) Set(val string) error { + if s.trimSpace { + val = strings.TrimSpace(val) + } + *s.destination = val + return nil +} + +func (s *stringValue) Get() any { return *s.destination } + +func (s *stringValue) String() string { + if s.destination != nil && *s.destination != "" { + return fmt.Sprintf("%q", *s.destination) + } + return "" +} + +func (cmd *Command) String(name string) string { + if v, ok := cmd.Value(name).(string); ok { + tracef("string available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name) + return v + } + + tracef("string NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name) + return "" +} diff --git a/vendor/github.com/urfave/cli/v3/flag_string_map.go b/vendor/github.com/urfave/cli/v3/flag_string_map.go new file mode 100644 index 00000000000..52fd7362afa --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_string_map.go @@ -0,0 +1,20 @@ +package cli + +type ( + StringMap = MapBase[string, StringConfig, stringValue] + StringMapFlag = FlagBase[map[string]string, StringConfig, StringMap] +) + +var NewStringMap = NewMapBase[string, StringConfig, stringValue] + +// StringMap looks up the value of a local StringMapFlag, returns +// nil if not found +func (cmd *Command) StringMap(name string) map[string]string { + if v, ok := cmd.Value(name).(map[string]string); ok { + tracef("string map available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name) + return v + } + + tracef("string map NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name) + return nil +} diff --git a/vendor/github.com/urfave/cli/v3/flag_string_slice.go b/vendor/github.com/urfave/cli/v3/flag_string_slice.go new file mode 100644 index 00000000000..4cb6c5a0628 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_string_slice.go @@ -0,0 +1,20 @@ +package cli + +type ( + StringSlice = SliceBase[string, StringConfig, stringValue] + StringSliceFlag = FlagBase[[]string, StringConfig, StringSlice] +) + +var NewStringSlice = NewSliceBase[string, StringConfig, stringValue] + +// StringSlice looks up the value of a local StringSliceFlag, returns +// nil if not found +func (cmd *Command) StringSlice(name string) []string { + if v, ok := cmd.Value(name).([]string); ok { + tracef("string slice available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name) + return v + } + + tracef("string slice NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name) + return nil +} diff --git a/vendor/github.com/urfave/cli/v3/flag_timestamp.go b/vendor/github.com/urfave/cli/v3/flag_timestamp.go new file mode 100644 index 00000000000..82b1cb5cf0e --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_timestamp.go @@ -0,0 +1,143 @@ +package cli + +import ( + "errors" + "fmt" + "time" +) + +type TimestampFlag = FlagBase[time.Time, TimestampConfig, timestampValue] + +// TimestampConfig defines the config for timestamp flags +type TimestampConfig struct { + Timezone *time.Location + // Available layouts for flag value. + // + // Note that value for formats with missing year/date will be interpreted as current year/date respectively. + // + // Read more about time layouts: https://pkg.go.dev/time#pkg-constants + Layouts []string +} + +// timestampValue wrap to satisfy golang's flag interface. +type timestampValue struct { + timestamp *time.Time + hasBeenSet bool + layouts []string + location *time.Location +} + +var _ ValueCreator[time.Time, TimestampConfig] = timestampValue{} + +// Below functions are to satisfy the ValueCreator interface + +func (t timestampValue) Create(val time.Time, p *time.Time, c TimestampConfig) Value { + *p = val + return ×tampValue{ + timestamp: p, + layouts: c.Layouts, + location: c.Timezone, + } +} + +func (t timestampValue) ToString(b time.Time) string { + if b.IsZero() { + return "" + } + t.timestamp = &b + return t.String() +} + +// Below functions are to satisfy the Value interface + +// Parses the string value to timestamp +func (t *timestampValue) Set(value string) error { + var timestamp time.Time + var err error + + if t.location == nil { + t.location = time.UTC + } + + if len(t.layouts) == 0 { + return errors.New("got nil/empty layouts slice") + } + + for _, layout := range t.layouts { + var locErr error + + timestamp, locErr = time.ParseInLocation(layout, value, t.location) + if locErr != nil { + if err == nil { + err = locErr + continue + } + + err = newMultiError(err, locErr) + continue + } + + err = nil + break + } + + if err != nil { + return err + } + + defaultTS, _ := time.ParseInLocation(time.TimeOnly, time.TimeOnly, timestamp.Location()) + + n := time.Now().In(timestamp.Location()) + + // If format is missing date (or year only), set it explicitly to current + if timestamp.Truncate(time.Hour*24).UnixNano() == defaultTS.Truncate(time.Hour*24).UnixNano() { + timestamp = time.Date( + n.Year(), + n.Month(), + n.Day(), + timestamp.Hour(), + timestamp.Minute(), + timestamp.Second(), + timestamp.Nanosecond(), + timestamp.Location(), + ) + } else if timestamp.Year() == 0 { + timestamp = time.Date( + n.Year(), + timestamp.Month(), + timestamp.Day(), + timestamp.Hour(), + timestamp.Minute(), + timestamp.Second(), + timestamp.Nanosecond(), + timestamp.Location(), + ) + } + + if t.timestamp != nil { + *t.timestamp = timestamp + } + t.hasBeenSet = true + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (t *timestampValue) String() string { + return fmt.Sprintf("%v", t.timestamp) +} + +// Get returns the flag structure +func (t *timestampValue) Get() any { + return *t.timestamp +} + +// Timestamp gets the timestamp from a flag name +func (cmd *Command) Timestamp(name string) time.Time { + if v, ok := cmd.Value(name).(time.Time); ok { + tracef("time.Time available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name) + return v + } + + tracef("time.Time NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name) + return time.Time{} +} diff --git a/vendor/github.com/urfave/cli/v3/flag_uint.go b/vendor/github.com/urfave/cli/v3/flag_uint.go new file mode 100644 index 00000000000..9818579482b --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_uint.go @@ -0,0 +1,99 @@ +package cli + +import ( + "strconv" + "unsafe" +) + +type ( + UintFlag = FlagBase[uint, IntegerConfig, uintValue[uint]] + Uint8Flag = FlagBase[uint8, IntegerConfig, uintValue[uint8]] + Uint16Flag = FlagBase[uint16, IntegerConfig, uintValue[uint16]] + Uint32Flag = FlagBase[uint32, IntegerConfig, uintValue[uint32]] + Uint64Flag = FlagBase[uint64, IntegerConfig, uintValue[uint64]] +) + +// -- uint Value +type uintValue[T uint | uint8 | uint16 | uint32 | uint64] struct { + val *T + base int +} + +// Below functions are to satisfy the ValueCreator interface + +func (i uintValue[T]) Create(val T, p *T, c IntegerConfig) Value { + *p = val + + return &uintValue[T]{ + val: p, + base: c.Base, + } +} + +func (i uintValue[T]) ToString(b T) string { + i.val = &b + return i.String() +} + +// Below functions are to satisfy the flag.Value interface + +func (i *uintValue[T]) Set(s string) error { + v, err := strconv.ParseUint(s, i.base, int(unsafe.Sizeof(T(0))*8)) + if err != nil { + return err + } + *i.val = T(v) + return err +} + +func (i *uintValue[T]) Get() any { return *i.val } + +func (i *uintValue[T]) String() string { + base := i.base + if base == 0 { + base = 10 + } + + return strconv.FormatUint(uint64(*i.val), base) +} + +// Uint looks up the value of a local Uint64Flag, returns +// 0 if not found +func (cmd *Command) Uint(name string) uint { + return getUint[uint](cmd, name) +} + +// Uint8 looks up the value of a local Uint8Flag, returns +// 0 if not found +func (cmd *Command) Uint8(name string) uint8 { + return getUint[uint8](cmd, name) +} + +// Uint16 looks up the value of a local Uint16Flag, returns +// 0 if not found +func (cmd *Command) Uint16(name string) uint16 { + return getUint[uint16](cmd, name) +} + +// Uint32 looks up the value of a local Uint32Flag, returns +// 0 if not found +func (cmd *Command) Uint32(name string) uint32 { + return getUint[uint32](cmd, name) +} + +// Uint64 looks up the value of a local Uint64Flag, returns +// 0 if not found +func (cmd *Command) Uint64(name string) uint64 { + return getUint[uint64](cmd, name) +} + +func getUint[T uint | uint8 | uint16 | uint32 | uint64](cmd *Command, name string) T { + if v, ok := cmd.Value(name).(T); ok { + tracef("uint available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name) + + return v + } + + tracef("uint NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name) + return 0 +} diff --git a/vendor/github.com/urfave/cli/v3/flag_uint_slice.go b/vendor/github.com/urfave/cli/v3/flag_uint_slice.go new file mode 100644 index 00000000000..18c5b4d2324 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_uint_slice.go @@ -0,0 +1,63 @@ +package cli + +type ( + UintSlice = SliceBase[uint, IntegerConfig, uintValue[uint]] + Uint8Slice = SliceBase[uint8, IntegerConfig, uintValue[uint8]] + Uint16Slice = SliceBase[uint16, IntegerConfig, uintValue[uint16]] + Uint32Slice = SliceBase[uint32, IntegerConfig, uintValue[uint32]] + Uint64Slice = SliceBase[uint64, IntegerConfig, uintValue[uint64]] + UintSliceFlag = FlagBase[[]uint, IntegerConfig, UintSlice] + Uint8SliceFlag = FlagBase[[]uint8, IntegerConfig, Uint8Slice] + Uint16SliceFlag = FlagBase[[]uint16, IntegerConfig, Uint16Slice] + Uint32SliceFlag = FlagBase[[]uint32, IntegerConfig, Uint32Slice] + Uint64SliceFlag = FlagBase[[]uint64, IntegerConfig, Uint64Slice] +) + +var ( + NewUintSlice = NewSliceBase[uint, IntegerConfig, uintValue[uint]] + NewUint8Slice = NewSliceBase[uint8, IntegerConfig, uintValue[uint8]] + NewUint16Slice = NewSliceBase[uint16, IntegerConfig, uintValue[uint16]] + NewUint32Slice = NewSliceBase[uint32, IntegerConfig, uintValue[uint32]] + NewUint64Slice = NewSliceBase[uint64, IntegerConfig, uintValue[uint64]] +) + +// UintSlice looks up the value of a local UintSliceFlag, returns +// nil if not found +func (cmd *Command) UintSlice(name string) []uint { + return getUintSlice[uint](cmd, name) +} + +// Uint8Slice looks up the value of a local Uint8SliceFlag, returns +// nil if not found +func (cmd *Command) Uint8Slice(name string) []uint8 { + return getUintSlice[uint8](cmd, name) +} + +// Uint16Slice looks up the value of a local Uint16SliceFlag, returns +// nil if not found +func (cmd *Command) Uint16Slice(name string) []uint16 { + return getUintSlice[uint16](cmd, name) +} + +// Uint32Slice looks up the value of a local Uint32SliceFlag, returns +// nil if not found +func (cmd *Command) Uint32Slice(name string) []uint32 { + return getUintSlice[uint32](cmd, name) +} + +// Uint64Slice looks up the value of a local Uint64SliceFlag, returns +// nil if not found +func (cmd *Command) Uint64Slice(name string) []uint64 { + return getUintSlice[uint64](cmd, name) +} + +func getUintSlice[T uint | uint8 | uint16 | uint32 | uint64](cmd *Command, name string) []T { + if v, ok := cmd.Value(name).([]T); ok { + tracef("uint slice available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name) + + return v + } + + tracef("uint slice NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name) + return nil +} diff --git a/vendor/github.com/urfave/cli/v3/funcs.go b/vendor/github.com/urfave/cli/v3/funcs.go new file mode 100644 index 00000000000..fe1224c44e3 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/funcs.go @@ -0,0 +1,53 @@ +package cli + +import "context" + +// ShellCompleteFunc is an action to execute when the shell completion flag is set +type ShellCompleteFunc func(context.Context, *Command) + +// BeforeFunc is an action that executes prior to any subcommands being run once +// the context is ready. If a non-nil error is returned, no subcommands are +// run. +type BeforeFunc func(context.Context, *Command) (context.Context, error) + +// AfterFunc is an action that executes after any subcommands are run and have +// finished. The AfterFunc is run even if Action() panics. +type AfterFunc func(context.Context, *Command) error + +// ActionFunc is the action to execute when no subcommands are specified +type ActionFunc func(context.Context, *Command) error + +// CommandNotFoundFunc is executed if the proper command cannot be found +type CommandNotFoundFunc func(context.Context, *Command, string) + +// ConfigureShellCompletionCommand is a function to configure a shell completion command +type ConfigureShellCompletionCommand func(*Command) + +// OnUsageErrorFunc is executed if a usage error occurs. This is useful for displaying +// customized usage error messages. This function is able to replace the +// original error messages. If this function is not set, the "Incorrect usage" +// is displayed and the execution is interrupted. +type OnUsageErrorFunc func(ctx context.Context, cmd *Command, err error, isSubcommand bool) error + +// InvalidFlagAccessFunc is executed when an invalid flag is accessed from the context. +type InvalidFlagAccessFunc func(context.Context, *Command, string) + +// ExitErrHandlerFunc is executed if provided in order to handle exitError values +// returned by Actions and Before/After functions. +type ExitErrHandlerFunc func(context.Context, *Command, error) + +// FlagStringFunc is used by the help generation to display a flag, which is +// expected to be a single line. +type FlagStringFunc func(Flag) string + +// FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix +// text for a flag's full name. +type FlagNamePrefixFunc func(fullName []string, placeholder string) string + +// FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help +// with the environment variable details. +type FlagEnvHintFunc func(envVars []string, str string) string + +// FlagFileHintFunc is used by the default FlagStringFunc to annotate flag help +// with the file path details. +type FlagFileHintFunc func(filePath, str string) string diff --git a/vendor/github.com/urfave/cli/v3/godoc-current.txt b/vendor/github.com/urfave/cli/v3/godoc-current.txt new file mode 100644 index 00000000000..a31fb210899 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/godoc-current.txt @@ -0,0 +1,1500 @@ +package cli // import "github.com/urfave/cli/v3" + +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.Command{}).Run(context.Background(), os.Args) + } + +Of course this application does not do much, so let's make this an actual +application: + + func main() { + cmd := &cli.Command{ + Name: "greet", + Usage: "say a greeting", + Action: func(c *cli.Context) error { + fmt.Println("Greetings") + return nil + }, + } + + cmd.Run(context.Background(), os.Args) + } + +VARIABLES + +var ( + NewFloatSlice = NewSliceBase[float64, NoConfig, floatValue[float64]] + NewFloat32Slice = NewSliceBase[float32, NoConfig, floatValue[float32]] + NewFloat64Slice = NewSliceBase[float64, NoConfig, floatValue[float64]] +) +var ( + NewIntSlice = NewSliceBase[int, IntegerConfig, intValue[int]] + NewInt8Slice = NewSliceBase[int8, IntegerConfig, intValue[int8]] + NewInt16Slice = NewSliceBase[int16, IntegerConfig, intValue[int16]] + NewInt32Slice = NewSliceBase[int32, IntegerConfig, intValue[int32]] + NewInt64Slice = NewSliceBase[int64, IntegerConfig, intValue[int64]] +) +var ( + NewUintSlice = NewSliceBase[uint, IntegerConfig, uintValue[uint]] + NewUint8Slice = NewSliceBase[uint8, IntegerConfig, uintValue[uint8]] + NewUint16Slice = NewSliceBase[uint16, IntegerConfig, uintValue[uint16]] + NewUint32Slice = NewSliceBase[uint32, IntegerConfig, uintValue[uint32]] + NewUint64Slice = NewSliceBase[uint64, IntegerConfig, uintValue[uint64]] +) +var ( + SuggestFlag SuggestFlagFunc = suggestFlag + SuggestCommand SuggestCommandFunc = suggestCommand + SuggestDidYouMeanTemplate string = suggestDidYouMeanTemplate +) +var AnyArguments = []Argument{ + &StringArgs{ + Max: -1, + }, +} + AnyArguments to differentiate between no arguments(nil) vs aleast one + +var ArgsUsageCommandHelp = "[command]" + ArgsUsageCommandHelp is a short description of the arguments of the help + command + +var CommandHelpTemplate = `NAME: + {{template "helpNameTemplate" .}} + +USAGE: + {{template "usageTemplate" .}}{{if .Category}} + +CATEGORY: + {{.Category}}{{end}}{{if .Description}} + +DESCRIPTION: + {{template "descriptionTemplate" .}}{{end}}{{if .VisibleFlagCategories}} + +OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}} + +OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .VisiblePersistentFlags}} + +GLOBAL OPTIONS:{{template "visiblePersistentFlagTemplate" .}}{{end}} +` + CommandHelpTemplate is 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. + +var DefaultAppComplete = DefaultRootCommandComplete + DefaultAppComplete is a backward-compatible name for + DefaultRootCommandComplete. + +var DefaultInverseBoolPrefix = "no-" +var ErrWriter io.Writer = os.Stderr + ErrWriter is used to write errors to the user. This can be anything + implementing the io.Writer interface and defaults to os.Stderr. + +var FishCompletionTemplate = `# {{ .Command.Name }} fish shell completion + +function __fish_{{ .Command.Name }}_no_subcommand --description 'Test if there has been any subcommand yet' + for i in (commandline -opc) + if contains -- $i{{ range $v := .AllCommands }} {{ $v }}{{ end }} + return 1 + end + end + return 0 +end + +{{ range $v := .Completions }}{{ $v }} +{{ end }}` +var NewStringMap = NewMapBase[string, StringConfig, stringValue] +var NewStringSlice = NewSliceBase[string, StringConfig, stringValue] +var OsExiter = os.Exit + OsExiter is the function used when the app exits. If not set defaults to + os.Exit. + +var RootCommandHelpTemplate = `NAME: + {{template "helpNameTemplate" .}} + +USAGE: + {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.FullName}} {{if .VisibleFlags}}[global options]{{end}}{{if .VisibleCommands}} [command [command options]]{{end}}{{if .ArgsUsage}} {{.ArgsUsage}}{{else}}{{if .Arguments}} [arguments...]{{end}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} + +VERSION: + {{.Version}}{{end}}{{end}}{{if .Description}} + +DESCRIPTION: + {{template "descriptionTemplate" .}}{{end}} +{{- if len .Authors}} + +AUTHOR{{template "authorsTemplate" .}}{{end}}{{if .VisibleCommands}} + +COMMANDS:{{template "visibleCommandCategoryTemplate" .}}{{end}}{{if .VisibleFlagCategories}} + +GLOBAL OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}} + +GLOBAL OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .Copyright}} + +COPYRIGHT: + {{template "copyrightTemplate" .}}{{end}} +` + RootCommandHelpTemplate is the text template for the Default help topic. + cli.go uses text/template to render templates. You can render custom help + text by setting this variable. + +var ShowAppHelp = ShowRootCommandHelp + ShowAppHelp is a backward-compatible name for ShowRootCommandHelp. + +var ShowAppHelpAndExit = ShowRootCommandHelpAndExit + ShowAppHelpAndExit is a backward-compatible name for ShowRootCommandHelp. + +var ShowCommandHelp = DefaultShowCommandHelp + ShowCommandHelp prints help for the given command + +var ShowRootCommandHelp = DefaultShowRootCommandHelp + ShowRootCommandHelp is an action that displays help for the root command. + +var ShowSubcommandHelp = DefaultShowSubcommandHelp + ShowSubcommandHelp prints help for the given subcommand + +var SubcommandHelpTemplate = `NAME: + {{template "helpNameTemplate" .}} + +USAGE: + {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.FullName}}{{if .VisibleCommands}} [command [command options]]{{end}}{{if .ArgsUsage}} {{.ArgsUsage}}{{else}}{{if .Arguments}} [arguments...]{{end}}{{end}}{{end}}{{if .Category}} + +CATEGORY: + {{.Category}}{{end}}{{if .Description}} + +DESCRIPTION: + {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}} + +COMMANDS:{{template "visibleCommandTemplate" .}}{{end}}{{if .VisibleFlagCategories}} + +OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}} + +OPTIONS:{{template "visibleFlagTemplate" .}}{{end}} +` + SubcommandHelpTemplate is the text template for the subcommand help topic. + cli.go uses text/template to render templates. You can render custom help + text by setting this variable. + +var UsageCommandHelp = "Shows a list of commands or help for one command" + UsageCommandHelp is the text to override the USAGE section of the help + command + +var VersionPrinter = DefaultPrintVersion + VersionPrinter prints the version for the root Command. + + +FUNCTIONS + +func DefaultCompleteWithFlags(ctx context.Context, cmd *Command) +func DefaultPrintHelp(out io.Writer, templ string, data any) + DefaultPrintHelp is the default implementation of HelpPrinter. + +func DefaultPrintHelpCustom(out io.Writer, templ string, data any, customFuncs map[string]any) + DefaultPrintHelpCustom is the default implementation of HelpPrinterCustom. + + The customFuncs map will be combined with a default template.FuncMap to + allow using arbitrary functions in template rendering. + +func DefaultPrintVersion(cmd *Command) + DefaultPrintVersion is the default implementation of VersionPrinter. + +func DefaultRootCommandComplete(ctx context.Context, cmd *Command) + DefaultRootCommandComplete prints the list of subcommands as the default + completion method. + +func DefaultShowCommandHelp(ctx context.Context, cmd *Command, commandName string) error + DefaultShowCommandHelp is the default implementation of ShowCommandHelp. + +func DefaultShowRootCommandHelp(cmd *Command) error + DefaultShowRootCommandHelp is the default implementation of + ShowRootCommandHelp. + +func DefaultShowSubcommandHelp(cmd *Command) error + DefaultShowSubcommandHelp is the default implementation of + ShowSubcommandHelp. + +func FlagNames(name string, aliases []string) []string +func HandleExitCoder(err error) + HandleExitCoder handles errors implementing ExitCoder by printing their + message and calling OsExiter with the given exit code. + + If the given error instead implements MultiError, each error will be checked + for the ExitCoder interface, and OsExiter will be called with the last exit + code found, or exit code 1 if no ExitCoder is found. + + This function is the default error-handling behavior for a Command. + +func ShowCommandHelpAndExit(ctx context.Context, cmd *Command, command string, code int) + ShowCommandHelpAndExit exits with code after showing help via + ShowCommandHelp. + +func ShowRootCommandHelpAndExit(cmd *Command, exitCode int) + ShowRootCommandHelpAndExit prints the list of subcommands and exits with + exit code. + +func ShowSubcommandHelpAndExit(cmd *Command, exitCode int) + ShowSubcommandHelpAndExit prints help for the given subcommand via + ShowSubcommandHelp and exits with exit code. + +func ShowVersion(cmd *Command) + ShowVersion prints the version number of the root Command. + + +TYPES + +type ActionFunc func(context.Context, *Command) error + ActionFunc is the action to execute when no subcommands are specified + +type ActionableFlag interface { + RunAction(context.Context, *Command) error +} + ActionableFlag is an interface that wraps Flag interface and RunAction + operation. + +type AfterFunc func(context.Context, *Command) error + AfterFunc is an action that executes after any subcommands are run and have + finished. The AfterFunc is run even if Action() panics. + +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 Argument interface { + // which this argument can be accessed using the given name + HasName(string) bool + + // Parse the given args and return unparsed args and/or error + Parse([]string) ([]string, error) + + // The usage template for this argument to use in help + Usage() string + + // The Value of this Arg + Get() any +} + Argument captures a positional argument that can be parsed + +type ArgumentBase[T any, C any, VC ValueCreator[T, C]] struct { + Name string `json:"name"` // the name of this argument + Value T `json:"value"` // the default value of this argument + Destination *T `json:"-"` // the destination point for this argument + UsageText string `json:"usageText"` // the usage text to show + Config C `json:"config"` // config for this argument similar to Flag Config + + // Has unexported fields. +} + +func (a *ArgumentBase[T, C, VC]) Get() any + +func (a *ArgumentBase[T, C, VC]) HasName(s string) bool + +func (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error) + +func (a *ArgumentBase[T, C, VC]) Usage() string + +type ArgumentsBase[T any, C any, VC ValueCreator[T, C]] struct { + Name string `json:"name"` // the name of this argument + Value T `json:"value"` // the default value of this argument + Destination *[]T `json:"-"` // the destination point for this argument + UsageText string `json:"usageText"` // the usage text to show + Min int `json:"minTimes"` // the min num of occurrences of this argument + Max int `json:"maxTimes"` // the max num of occurrences of this argument, set to -1 for unlimited + Config C `json:"config"` // config for this argument similar to Flag Config + + // Has unexported fields. +} + ArgumentsBase is a base type for slice arguments + +func (a *ArgumentsBase[T, C, VC]) Get() any + +func (a *ArgumentsBase[T, C, VC]) HasName(s string) bool + +func (a *ArgumentsBase[T, C, VC]) Parse(s []string) ([]string, error) + +func (a *ArgumentsBase[T, C, VC]) Usage() string + +type BeforeFunc func(context.Context, *Command) (context.Context, error) + BeforeFunc is an action that executes prior to any subcommands being run + once the context is ready. If a non-nil error is returned, no subcommands + are run. + +type BoolConfig struct { + Count *int +} + BoolConfig defines the configuration for bool flags + +type BoolFlag = FlagBase[bool, BoolConfig, boolValue] + +type BoolWithInverseFlag struct { + Name string `json:"name"` // name of the flag + Category string `json:"category"` // category of the flag, if any + DefaultText string `json:"defaultText"` // default text of the flag for usage purposes + HideDefault bool `json:"hideDefault"` // whether to hide the default value in output + Usage string `json:"usage"` // usage string for help output + Sources ValueSourceChain `json:"-"` // sources to load flag value from + Required bool `json:"required"` // whether the flag is required or not + Hidden bool `json:"hidden"` // whether to hide the flag in help output + Local bool `json:"local"` // whether the flag needs to be applied to subcommands as well + Value bool `json:"defaultValue"` // default value for this flag if not set by from any source + Destination *bool `json:"-"` // destination pointer for value when set + Aliases []string `json:"aliases"` // Aliases that are allowed for this flag + TakesFile bool `json:"takesFileArg"` // whether this flag takes a file argument, mainly for shell completion purposes + Action func(context.Context, *Command, bool) error `json:"-"` // Action callback to be called when flag is set + OnlyOnce bool `json:"onlyOnce"` // whether this flag can be duplicated on the command line + Validator func(bool) error `json:"-"` // custom function to validate this flag value + ValidateDefaults bool `json:"validateDefaults"` // whether to validate defaults or not + Config BoolConfig `json:"config"` // Additional/Custom configuration associated with this flag type + InversePrefix string `json:"invPrefix"` // The prefix used to indicate a negative value. Default: `env` becomes `no-env` + + // Has unexported fields. +} + +func (bif *BoolWithInverseFlag) Count() int + Count returns the number of times this flag has been invoked + +func (bif *BoolWithInverseFlag) Get() any + +func (bif *BoolWithInverseFlag) GetCategory() string + GetCategory returns the category of the flag + +func (bif *BoolWithInverseFlag) GetDefaultText() string + GetDefaultText returns the default text for this flag + +func (bif *BoolWithInverseFlag) GetEnvVars() []string + GetEnvVars returns the env vars for this flag + +func (bif *BoolWithInverseFlag) GetUsage() string + GetUsage returns the usage string for the flag + +func (bif *BoolWithInverseFlag) GetValue() string + GetValue returns the flags value as string representation and an empty + string if the flag takes no value at all. + +func (bif *BoolWithInverseFlag) IsBoolFlag() bool + IsBoolFlag returns whether the flag doesnt need to accept args + +func (bif *BoolWithInverseFlag) IsDefaultVisible() bool + IsDefaultVisible returns true if the flag is not hidden, otherwise false + +func (bif *BoolWithInverseFlag) IsLocal() bool + +func (bif *BoolWithInverseFlag) IsRequired() bool + +func (bif *BoolWithInverseFlag) IsSet() bool + +func (bif *BoolWithInverseFlag) IsVisible() bool + +func (bif *BoolWithInverseFlag) Names() []string + +func (bif *BoolWithInverseFlag) PostParse() error + +func (bif *BoolWithInverseFlag) PreParse() error + +func (bif *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error + +func (bif *BoolWithInverseFlag) Set(name, val string) error + +func (bif *BoolWithInverseFlag) SetCategory(c string) + +func (bif *BoolWithInverseFlag) String() string + String implements the standard Stringer interface. + + Example for BoolFlag{Name: "env"} --[no-]env (default: false) + +func (bif *BoolWithInverseFlag) TakesValue() bool + +func (bif *BoolWithInverseFlag) TypeName() string + TypeName is used for stringify/docs. For bool its a no-op + +type CategorizableFlag interface { + // Returns the category of the flag + GetCategory() string + + // Sets the category of the flag + SetCategory(string) +} + CategorizableFlag is an interface that allows us to potentially use a flag + in a categorized representation. + +type Command struct { + // The name of the command + Name string `json:"name"` + // A list of aliases for the command + Aliases []string `json:"aliases"` + // A short description of the usage of this command + Usage string `json:"usage"` + // Text to override the USAGE section of help + UsageText string `json:"usageText"` + // A short description of the arguments of this command + ArgsUsage string `json:"argsUsage"` + // Version of the command + Version string `json:"version"` + // Longer explanation of how the command works + Description string `json:"description"` + // DefaultCommand is the (optional) name of a command + // to run if no command names are passed as CLI arguments. + DefaultCommand string `json:"defaultCommand"` + // The category the command is part of + Category string `json:"category"` + // List of child commands + Commands []*Command `json:"commands"` + // List of flags to parse + Flags []Flag `json:"flags"` + // Boolean to hide built-in help command and help flag + HideHelp bool `json:"hideHelp"` + // Ignored if HideHelp is true. + HideHelpCommand bool `json:"hideHelpCommand"` + // Boolean to hide built-in version flag and the VERSION section of help + HideVersion bool `json:"hideVersion"` + // Boolean to enable shell completion commands + EnableShellCompletion bool `json:"-"` + // Shell Completion generation command name + ShellCompletionCommandName string `json:"-"` + // The function to call when checking for shell command completions + ShellComplete ShellCompleteFunc `json:"-"` + // The function to configure a shell completion command + ConfigureShellCompletionCommand ConfigureShellCompletionCommand `json:"-"` + // 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 `json:"-"` + // An action to execute after any subcommands are run, but after the subcommand has finished + // It is run even if Action() panics + After AfterFunc `json:"-"` + // The function to call when this command is invoked + Action ActionFunc `json:"-"` + // Execute this function if the proper command cannot be found + CommandNotFound CommandNotFoundFunc `json:"-"` + // Execute this function if a usage error occurs. + OnUsageError OnUsageErrorFunc `json:"-"` + // Execute this function when an invalid flag is accessed from the context + InvalidFlagAccessHandler InvalidFlagAccessFunc `json:"-"` + // Boolean to hide this command from help or completion + Hidden bool `json:"hidden"` + // List of all authors who contributed (string or fmt.Stringer) + // TODO: ~string | fmt.Stringer when interface unions are available + Authors []any `json:"authors"` + // Copyright of the binary if any + Copyright string `json:"copyright"` + // Reader reader to write input to (useful for tests) + Reader io.Reader `json:"-"` + // Writer writer to write output to + Writer io.Writer `json:"-"` + // ErrWriter writes error output + ErrWriter io.Writer `json:"-"` + // ExitErrHandler processes any error encountered while running a Command before it is + // returned to the caller. If no function is provided, HandleExitCoder is used as the + // default behavior. + ExitErrHandler ExitErrHandlerFunc `json:"-"` + // Other custom info + Metadata map[string]any `json:"metadata"` + // Carries a function which returns app specific info. + ExtraInfo func() map[string]string `json:"-"` + // CustomRootCommandHelpTemplate 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. + CustomRootCommandHelpTemplate string `json:"-"` + // SliceFlagSeparator is used to customize the separator for SliceFlag, the default is "," + SliceFlagSeparator string `json:"sliceFlagSeparator"` + // DisableSliceFlagSeparator is used to disable SliceFlagSeparator, the default is false + DisableSliceFlagSeparator bool `json:"disableSliceFlagSeparator"` + // MapFlagKeyValueSeparator is used to customize the separator for MapFlag, the default is "=" + MapFlagKeyValueSeparator string `json:"mapFlagKeyValueSeparator"` + // 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 `json:"useShortOptionHandling"` + // Enable suggestions for commands and flags + Suggest bool `json:"suggest"` + // Allows global flags set by libraries which use flag.XXXVar(...) directly + // to be parsed through this library + AllowExtFlags bool `json:"allowExtFlags"` + // Treat all flags as normal arguments if true + SkipFlagParsing bool `json:"skipFlagParsing"` + // 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 `json:"-"` + // Use longest prefix match for commands + PrefixMatchCommands bool `json:"prefixMatchCommands"` + // Custom suggest command for matching + SuggestCommandFunc SuggestCommandFunc `json:"-"` + // Flag exclusion group + MutuallyExclusiveFlags []MutuallyExclusiveFlags `json:"mutuallyExclusiveFlags"` + // Arguments to parse for this command + Arguments []Argument `json:"arguments"` + // Whether to read arguments from stdin + // applicable to root command only + ReadArgsFromStdin bool `json:"readArgsFromStdin"` + // StopOnNthArg provides v2-like behavior for specific commands by stopping + // flag parsing after N positional arguments are encountered. When set to N, + // all remaining arguments after the Nth positional argument will be treated + // as arguments, not flags. + // + // A value of 0 means all arguments are treated as positional (no flag parsing). + // A nil value means normal v3 flag parsing behavior (flags can appear anywhere). + StopOnNthArg *int `json:"stopOnNthArg"` + + // Has unexported fields. +} + Command contains everything needed to run an application that accepts a + string slice of arguments such as os.Args. A given Command may contain Flags + and sub-commands in Commands. + +func (cmd *Command) Args() Args + Args returns the command line arguments associated with the command. + +func (cmd *Command) Bool(name string) bool + +func (cmd *Command) Command(name string) *Command + +func (cmd *Command) Count(name string) int + Count returns the num of occurrences of this flag + +func (cmd *Command) Duration(name string) time.Duration + +func (cmd *Command) FlagNames() []string + FlagNames returns a slice of flag names used by the this command and all of + its parent commands. + +func (cmd *Command) Float(name string) float64 + Float looks up the value of a local FloatFlag, returns 0 if not found + +func (cmd *Command) Float32(name string) float32 + Float32 looks up the value of a local Float32Flag, returns 0 if not found + +func (c *Command) Float32Arg(name string) float32 + +func (c *Command) Float32Args(name string) []float32 + +func (cmd *Command) Float32Slice(name string) []float32 + Float32Slice looks up the value of a local Float32Slice, returns nil if not + found + +func (cmd *Command) Float64(name string) float64 + Float64 looks up the value of a local Float64Flag, returns 0 if not found + +func (c *Command) Float64Arg(name string) float64 + +func (c *Command) Float64Args(name string) []float64 + +func (cmd *Command) Float64Slice(name string) []float64 + Float64Slice looks up the value of a local Float64SliceFlag, returns nil if + not found + +func (c *Command) FloatArg(name string) float64 + +func (c *Command) FloatArgs(name string) []float64 + +func (cmd *Command) FloatSlice(name string) []float64 + FloatSlice looks up the value of a local FloatSliceFlag, returns nil if not + found + +func (cmd *Command) FullName() string + FullName returns the full name of the command. For commands with parents + this ensures that the parent commands are part of the command path. + +func (cmd *Command) Generic(name string) Value + Generic looks up the value of a local GenericFlag, returns nil if not found + +func (cmd *Command) HasName(name string) bool + HasName returns true if Command.Name matches given name + +func (cmd *Command) Int(name string) int + Int looks up the value of a local Int64Flag, returns 0 if not found + +func (cmd *Command) Int16(name string) int16 + Int16 looks up the value of a local Int16Flag, returns 0 if not found + +func (c *Command) Int16Arg(name string) int16 + +func (c *Command) Int16Args(name string) []int16 + +func (cmd *Command) Int16Slice(name string) []int16 + Int16Slice looks up the value of a local Int16SliceFlag, returns nil if not + found + +func (cmd *Command) Int32(name string) int32 + Int32 looks up the value of a local Int32Flag, returns 0 if not found + +func (c *Command) Int32Arg(name string) int32 + +func (c *Command) Int32Args(name string) []int32 + +func (cmd *Command) Int32Slice(name string) []int32 + Int32Slice looks up the value of a local Int32SliceFlag, returns nil if not + found + +func (cmd *Command) Int64(name string) int64 + Int64 looks up the value of a local Int64Flag, returns 0 if not found + +func (c *Command) Int64Arg(name string) int64 + +func (c *Command) Int64Args(name string) []int64 + +func (cmd *Command) Int64Slice(name string) []int64 + Int64Slice looks up the value of a local Int64SliceFlag, returns nil if not + found + +func (cmd *Command) Int8(name string) int8 + Int8 looks up the value of a local Int8Flag, returns 0 if not found + +func (c *Command) Int8Arg(name string) int8 + +func (c *Command) Int8Args(name string) []int8 + +func (cmd *Command) Int8Slice(name string) []int8 + Int8Slice looks up the value of a local Int8SliceFlag, returns nil if not + found + +func (c *Command) IntArg(name string) int + +func (c *Command) IntArgs(name string) []int + +func (cmd *Command) IntSlice(name string) []int + IntSlice looks up the value of a local IntSliceFlag, returns nil if not + found + +func (cmd *Command) IsSet(name string) bool + IsSet determines if the flag was actually set + +func (cmd *Command) Lineage() []*Command + Lineage returns *this* command and all of its ancestor commands in order + from child to parent + +func (cmd *Command) LocalFlagNames() []string + LocalFlagNames returns a slice of flag names used in this command. + +func (cmd *Command) NArg() int + NArg returns the number of the command line arguments. + +func (cmd *Command) Names() []string + Names returns the names including short names and aliases. + +func (cmd *Command) NumFlags() int + NumFlags returns the number of flags set + +func (cmd *Command) Root() *Command + Root returns the Command at the root of the graph + +func (cmd *Command) Run(ctx context.Context, osArgs []string) (deferErr error) + Run is the entry point to the command graph. The positional arguments are + parsed according to the Flag and Command definitions and the matching Action + functions are run. + +func (cmd *Command) Set(name, value string) error + Set sets a context flag to a value. + +func (cmd *Command) String(name string) string + +func (c *Command) StringArg(name string) string + +func (c *Command) StringArgs(name string) []string + +func (cmd *Command) StringMap(name string) map[string]string + StringMap looks up the value of a local StringMapFlag, returns nil if not + found + +func (cmd *Command) StringSlice(name string) []string + StringSlice looks up the value of a local StringSliceFlag, returns nil if + not found + +func (cmd *Command) Timestamp(name string) time.Time + Timestamp gets the timestamp from a flag name + +func (c *Command) TimestampArg(name string) time.Time + +func (c *Command) TimestampArgs(name string) []time.Time + +func (cmd *Command) ToFishCompletion() (string, error) + ToFishCompletion creates a fish completion string for the `*Command` The + function errors if either parsing or writing of the string fails. + +func (cmd *Command) Uint(name string) uint + Uint looks up the value of a local Uint64Flag, returns 0 if not found + +func (cmd *Command) Uint16(name string) uint16 + Uint16 looks up the value of a local Uint16Flag, returns 0 if not found + +func (c *Command) Uint16Arg(name string) uint16 + +func (c *Command) Uint16Args(name string) []uint16 + +func (cmd *Command) Uint16Slice(name string) []uint16 + Uint16Slice looks up the value of a local Uint16SliceFlag, returns nil if + not found + +func (cmd *Command) Uint32(name string) uint32 + Uint32 looks up the value of a local Uint32Flag, returns 0 if not found + +func (c *Command) Uint32Arg(name string) uint32 + +func (c *Command) Uint32Args(name string) []uint32 + +func (cmd *Command) Uint32Slice(name string) []uint32 + Uint32Slice looks up the value of a local Uint32SliceFlag, returns nil if + not found + +func (cmd *Command) Uint64(name string) uint64 + Uint64 looks up the value of a local Uint64Flag, returns 0 if not found + +func (c *Command) Uint64Arg(name string) uint64 + +func (c *Command) Uint64Args(name string) []uint64 + +func (cmd *Command) Uint64Slice(name string) []uint64 + Uint64Slice looks up the value of a local Uint64SliceFlag, returns nil if + not found + +func (cmd *Command) Uint8(name string) uint8 + Uint8 looks up the value of a local Uint8Flag, returns 0 if not found + +func (c *Command) Uint8Arg(name string) uint8 + +func (c *Command) Uint8Args(name string) []uint8 + +func (cmd *Command) Uint8Slice(name string) []uint8 + Uint8Slice looks up the value of a local Uint8SliceFlag, returns nil if not + found + +func (c *Command) UintArg(name string) uint + +func (c *Command) UintArgs(name string) []uint + +func (cmd *Command) UintSlice(name string) []uint + UintSlice looks up the value of a local UintSliceFlag, returns nil if not + found + +func (cmd *Command) Value(name string) any + Value returns the value of the flag corresponding to `name` + +func (cmd *Command) VisibleCategories() []CommandCategory + VisibleCategories returns a slice of categories and commands that are + Hidden=false + +func (cmd *Command) VisibleCommands() []*Command + VisibleCommands returns a slice of the Commands with Hidden=false + +func (cmd *Command) VisibleFlagCategories() []VisibleFlagCategory + VisibleFlagCategories returns a slice containing all the visible flag + categories with the flags they contain + +func (cmd *Command) VisibleFlags() []Flag + VisibleFlags returns a slice of the Flags with Hidden=false + +func (cmd *Command) VisiblePersistentFlags() []Flag + VisiblePersistentFlags returns a slice of LocalFlag with Persistent=true and + Hidden=false. + +type CommandCategories interface { + // AddCommand adds a command to a category, creating a new category if necessary. + AddCommand(category string, command *Command) + // Categories returns a slice of categories sorted by name + Categories() []CommandCategory +} + CommandCategories interface allows for category manipulation + +type CommandCategory interface { + // Name returns the category name string + Name() string + // VisibleCommands returns a slice of the Commands with Hidden=false + VisibleCommands() []*Command +} + CommandCategory is a category containing commands. + +type CommandNotFoundFunc func(context.Context, *Command, string) + CommandNotFoundFunc is executed if the proper command cannot be found + +type ConfigureShellCompletionCommand func(*Command) + ConfigureShellCompletionCommand is a function to configure a shell + completion command + +type Countable interface { + Count() int +} + Countable is an interface to enable detection of flag values which support + repetitive flags + +type DocGenerationFlag interface { + // 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 + + // IsDefaultVisible returns whether the default value should be shown in + // help text + IsDefaultVisible() bool + // TypeName to detect if a flag is a string, bool, etc. + TypeName() string +} + DocGenerationFlag is an interface that allows documentation generation for + the flag + +type DocGenerationMultiValueFlag interface { + DocGenerationFlag + + // IsMultiValueFlag returns true for flags that can be given multiple times. + IsMultiValueFlag() bool +} + DocGenerationMultiValueFlag extends DocGenerationFlag for slice/map based + flags. + +type DurationFlag = FlagBase[time.Duration, NoConfig, durationValue] + +type EnvValueSource interface { + IsFromEnv() bool + Key() string +} + EnvValueSource is to specifically detect env sources when printing help text + +type ErrorFormatter interface { + Format(s fmt.State, verb rune) +} + ErrorFormatter is the interface that will suitably format the error output + +type ExitCoder interface { + error + ExitCode() int +} + ExitCoder is the interface checked by `Command` for a custom exit code. + +func Exit(message any, exitCode int) ExitCoder + Exit wraps a message and exit code into an error, which by default is + handled with a call to os.Exit during default error handling. + + This is the simplest way to trigger a non-zero exit code for a Command + without having to call os.Exit manually. During testing, this behavior can + be avoided by overriding the ExitErrHandler function on a Command or the + package-global OsExiter function. + +type ExitErrHandlerFunc func(context.Context, *Command, error) + ExitErrHandlerFunc is executed if provided in order to handle exitError + values returned by Actions and Before/After functions. + +type Flag interface { + fmt.Stringer + + // Retrieve the value of the Flag + Get() any + + // Lifecycle methods. + // flag callback prior to parsing + PreParse() error + + // flag callback post parsing + PostParse() error + + // Apply Flag settings to the given flag set + Set(string, string) error + + // All possible names for this flag + Names() []string + + // Whether the flag has been set or not + IsSet() bool +} + 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. + +var GenerateShellCompletionFlag Flag = &BoolFlag{ + Name: "generate-shell-completion", + Hidden: true, +} + GenerateShellCompletionFlag enables shell completion + +var HelpFlag Flag = &BoolFlag{ + Name: "help", + Aliases: []string{"h"}, + Usage: "show help", + HideDefault: true, + Local: 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 VersionFlag Flag = &BoolFlag{ + Name: "version", + Aliases: []string{"v"}, + Usage: "print the version", + HideDefault: true, + Local: true, +} + VersionFlag prints the version for the application + +type FlagBase[T any, C any, VC ValueCreator[T, C]] struct { + Name string `json:"name"` // name of the flag + Category string `json:"category"` // category of the flag, if any + DefaultText string `json:"defaultText"` // default text of the flag for usage purposes + HideDefault bool `json:"hideDefault"` // whether to hide the default value in output + Usage string `json:"usage"` // usage string for help output + Sources ValueSourceChain `json:"-"` // sources to load flag value from + Required bool `json:"required"` // whether the flag is required or not + Hidden bool `json:"hidden"` // whether to hide the flag in help output + Local bool `json:"local"` // whether the flag needs to be applied to subcommands as well + Value T `json:"defaultValue"` // default value for this flag if not set by from any source + Destination *T `json:"-"` // destination pointer for value when set + Aliases []string `json:"aliases"` // Aliases that are allowed for this flag + TakesFile bool `json:"takesFileArg"` // whether this flag takes a file argument, mainly for shell completion purposes + Action func(context.Context, *Command, T) error `json:"-"` // Action callback to be called when flag is set + Config C `json:"config"` // Additional/Custom configuration associated with this flag type + OnlyOnce bool `json:"onlyOnce"` // whether this flag can be duplicated on the command line + Validator func(T) error `json:"-"` // custom function to validate this flag value + ValidateDefaults bool `json:"validateDefaults"` // whether to validate defaults or not + + // Has unexported fields. +} + FlagBase [T,C,VC] is a generic flag base which can be used as a boilerplate + to implement the most common interfaces used by urfave/cli. + + T specifies the type + C specifies the configuration required(if any for that flag type) + VC specifies the value creator which creates the flag.Value emulation + +func (f *FlagBase[T, C, VC]) Count() int + Count returns the number of times this flag has been invoked + +func (f *FlagBase[T, C, V]) Get() any + +func (f *FlagBase[T, C, V]) GetCategory() string + GetCategory returns the category of the flag + +func (f *FlagBase[T, C, V]) GetDefaultText() string + GetDefaultText returns the default text for this flag + +func (f *FlagBase[T, C, V]) GetEnvVars() []string + GetEnvVars returns the env vars for this flag + +func (f *FlagBase[T, C, V]) GetUsage() string + GetUsage returns the usage string for the flag + +func (f *FlagBase[T, C, V]) GetValue() string + GetValue returns the flags value as string representation and an empty + string if the flag takes no value at all. + +func (f *FlagBase[T, C, VC]) IsBoolFlag() bool + IsBoolFlag returns whether the flag doesnt need to accept args + +func (f *FlagBase[T, C, V]) IsDefaultVisible() bool + IsDefaultVisible returns true if the flag is not hidden, otherwise false + +func (f *FlagBase[T, C, VC]) IsLocal() bool + IsLocal returns false if flag needs to be persistent across subcommands + +func (f *FlagBase[T, C, VC]) IsMultiValueFlag() bool + IsMultiValueFlag returns true if the value type T can take multiple values + from cmd line. This is true for slice and map type flags + +func (f *FlagBase[T, C, V]) IsRequired() bool + IsRequired returns whether or not the flag is required + +func (f *FlagBase[T, C, V]) IsSet() bool + IsSet returns whether or not the flag has been set through env or file + +func (f *FlagBase[T, C, V]) IsVisible() bool + IsVisible returns true if the flag is not hidden, otherwise false + +func (f *FlagBase[T, C, V]) Names() []string + Names returns the names of the flag + +func (f *FlagBase[T, C, V]) PostParse() error + PostParse populates the flag given the flag set and environment + +func (f *FlagBase[T, C, V]) PreParse() error + +func (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error + RunAction executes flag action if set + +func (f *FlagBase[T, C, V]) Set(_ string, val string) error + Set applies given value from string + +func (f *FlagBase[T, C, V]) SetCategory(c string) + +func (f *FlagBase[T, C, V]) String() string + String returns a readable representation of this value (for usage defaults) + +func (f *FlagBase[T, C, V]) TakesValue() bool + TakesValue returns true if the flag takes a value, otherwise false + +func (f *FlagBase[T, C, V]) TypeName() string + TypeName returns the type of the flag. + +type FlagCategories interface { + // AddFlags adds a flag to a category, creating a new category if necessary. + AddFlag(category string, fl Flag) + // VisibleCategories returns a slice of visible flag categories sorted by name + VisibleCategories() []VisibleFlagCategory +} + FlagCategories interface allows for category manipulation + +type FlagEnvHintFunc func(envVars []string, str string) string + FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help + with the environment variable details. + +var FlagEnvHinter FlagEnvHintFunc = withEnvHint + FlagEnvHinter annotates flag help message with the environment variable + details. This is used by the default FlagStringer. + +type FlagFileHintFunc func(filePath, str string) string + FlagFileHintFunc is used by the default FlagStringFunc to annotate flag help + with the file path details. + +var FlagFileHinter FlagFileHintFunc = withFileHint + FlagFileHinter annotates flag help message with the environment variable + details. This is used by the default FlagStringer. + +type FlagNamePrefixFunc func(fullName []string, placeholder string) string + FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix + text for a flag's full name. + +var FlagNamePrefixer FlagNamePrefixFunc = prefixedNames + FlagNamePrefixer converts a full flag name and its placeholder into the help + message flag prefix. This is used by the default FlagStringer. + +type FlagStringFunc func(Flag) string + FlagStringFunc is used by the help generation to display a flag, which is + expected to be a single line. + +var FlagStringer FlagStringFunc = stringifyFlag + FlagStringer converts a flag definition to a string. This is used by help to + display a flag. + +type FlagsByName []Flag + FlagsByName is a slice of Flag. + +func (f FlagsByName) Len() int + +func (f FlagsByName) Less(i, j int) bool + +func (f FlagsByName) Swap(i, j int) + +type Float32Arg = ArgumentBase[float32, NoConfig, floatValue[float32]] + +type Float32Args = ArgumentsBase[float32, NoConfig, floatValue[float32]] + +type Float32Flag = FlagBase[float32, NoConfig, floatValue[float32]] + +type Float32Slice = SliceBase[float32, NoConfig, floatValue[float32]] + +type Float32SliceFlag = FlagBase[[]float32, NoConfig, Float32Slice] + +type Float64Arg = ArgumentBase[float64, NoConfig, floatValue[float64]] + +type Float64Args = ArgumentsBase[float64, NoConfig, floatValue[float64]] + +type Float64Flag = FlagBase[float64, NoConfig, floatValue[float64]] + +type Float64Slice = SliceBase[float64, NoConfig, floatValue[float64]] + +type Float64SliceFlag = FlagBase[[]float64, NoConfig, Float64Slice] + +type FloatArg = ArgumentBase[float64, NoConfig, floatValue[float64]] + +type FloatArgs = ArgumentsBase[float64, NoConfig, floatValue[float64]] + +type FloatFlag = FlagBase[float64, NoConfig, floatValue[float64]] + +type FloatSlice = SliceBase[float64, NoConfig, floatValue[float64]] + +type FloatSliceFlag = FlagBase[[]float64, NoConfig, FloatSlice] + +type GenericFlag = FlagBase[Value, NoConfig, genericValue] + +type HelpPrinterCustomFunc func(w io.Writer, templ string, data any, customFunc map[string]any) + Prints help for the Command with custom template function. + +var HelpPrinterCustom HelpPrinterCustomFunc = DefaultPrintHelpCustom + HelpPrinterCustom is a function that writes the help output. It is used as + the default implementation of HelpPrinter, and may be called directly if the + ExtraInfo field is set on a Command. + + In the default implementation, if the customFuncs argument contains a + "wrapAt" key, which is a function which takes no arguments and returns an + int, this int value will be used to produce a "wrap" function used by the + default template to wrap long lines. + +type HelpPrinterFunc func(w io.Writer, templ string, data any) + HelpPrinterFunc prints help for the Command. + +var HelpPrinter HelpPrinterFunc = DefaultPrintHelp + HelpPrinter is a function that writes the help output. If not set + explicitly, this calls HelpPrinterCustom using only the default template + functions. + + If custom logic for printing help is required, this function can be + overridden. If the ExtraInfo field is defined on a Command, this function + should not be modified, as HelpPrinterCustom will be used directly in order + to capture the extra information. + +type Int16Arg = ArgumentBase[int16, IntegerConfig, intValue[int16]] + +type Int16Args = ArgumentsBase[int16, IntegerConfig, intValue[int16]] + +type Int16Flag = FlagBase[int16, IntegerConfig, intValue[int16]] + +type Int16Slice = SliceBase[int16, IntegerConfig, intValue[int16]] + +type Int16SliceFlag = FlagBase[[]int16, IntegerConfig, Int16Slice] + +type Int32Arg = ArgumentBase[int32, IntegerConfig, intValue[int32]] + +type Int32Args = ArgumentsBase[int32, IntegerConfig, intValue[int32]] + +type Int32Flag = FlagBase[int32, IntegerConfig, intValue[int32]] + +type Int32Slice = SliceBase[int32, IntegerConfig, intValue[int32]] + +type Int32SliceFlag = FlagBase[[]int32, IntegerConfig, Int32Slice] + +type Int64Arg = ArgumentBase[int64, IntegerConfig, intValue[int64]] + +type Int64Args = ArgumentsBase[int64, IntegerConfig, intValue[int64]] + +type Int64Flag = FlagBase[int64, IntegerConfig, intValue[int64]] + +type Int64Slice = SliceBase[int64, IntegerConfig, intValue[int64]] + +type Int64SliceFlag = FlagBase[[]int64, IntegerConfig, Int64Slice] + +type Int8Arg = ArgumentBase[int8, IntegerConfig, intValue[int8]] + +type Int8Args = ArgumentsBase[int8, IntegerConfig, intValue[int8]] + +type Int8Flag = FlagBase[int8, IntegerConfig, intValue[int8]] + +type Int8Slice = SliceBase[int8, IntegerConfig, intValue[int8]] + +type Int8SliceFlag = FlagBase[[]int8, IntegerConfig, Int8Slice] + +type IntArg = ArgumentBase[int, IntegerConfig, intValue[int]] + +type IntArgs = ArgumentsBase[int, IntegerConfig, intValue[int]] + +type IntFlag = FlagBase[int, IntegerConfig, intValue[int]] + +type IntSlice = SliceBase[int, IntegerConfig, intValue[int]] + +type IntSliceFlag = FlagBase[[]int, IntegerConfig, IntSlice] + +type IntegerConfig struct { + Base int +} + IntegerConfig is the configuration for all integer type flags + +type InvalidFlagAccessFunc func(context.Context, *Command, string) + InvalidFlagAccessFunc is executed when an invalid flag is accessed from the + context. + +type LocalFlag interface { + IsLocal() bool +} + LocalFlag is an interface to enable detection of flags which are local to + current command + +type MapBase[T any, C any, VC ValueCreator[T, C]] struct { + // Has unexported fields. +} + MapBase wraps map[string]T to satisfy flag.Value + +func NewMapBase[T any, C any, VC ValueCreator[T, C]](defaults map[string]T) *MapBase[T, C, VC] + NewMapBase makes a *MapBase with default values + +func (i MapBase[T, C, VC]) Create(val map[string]T, p *map[string]T, c C) Value + +func (i *MapBase[T, C, VC]) Get() any + Get returns the mapping of values set by this flag + +func (i *MapBase[T, C, VC]) Serialize() string + Serialize allows MapBase to fulfill Serializer + +func (i *MapBase[T, C, VC]) Set(value string) error + Set parses the value and appends it to the list of values + +func (i *MapBase[T, C, VC]) String() string + String returns a readable representation of this value (for usage defaults) + +func (i MapBase[T, C, VC]) ToString(t map[string]T) string + +func (i *MapBase[T, C, VC]) Value() map[string]T + Value returns the mapping of values set by this flag + +type MapSource interface { + fmt.Stringer + fmt.GoStringer + + // Lookup returns the value from the source based on key + // and if it was found + // or returns an empty string and false + Lookup(string) (any, bool) +} + MapSource is a source which can be used to look up a value based on a key + typically for use with a cli.Flag + +func NewMapSource(name string, m map[any]any) MapSource + +type MultiError interface { + error + Errors() []error +} + MultiError is an error that wraps multiple errors. + +type MutuallyExclusiveFlags struct { + // Flag list + Flags [][]Flag + + // whether this group is required + Required bool + + // Category to apply to all flags within group + Category string +} + MutuallyExclusiveFlags defines a mutually exclusive flag group Multiple + option paths can be provided out of which only one can be defined on cmdline + So for example [ --foo | [ --bar something --darth somethingelse ] ] + +type NoConfig struct{} + NoConfig is for flags which dont need a custom configuration + +type OnUsageErrorFunc func(ctx context.Context, cmd *Command, err error, isSubcommand bool) error + OnUsageErrorFunc is executed if a usage error occurs. This is useful for + displaying customized usage error messages. This function is able to replace + the original error messages. If this function is not set, the "Incorrect + usage" is displayed and the execution is interrupted. + +type RequiredFlag interface { + // whether the flag is a required flag or not + IsRequired() 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 Serializer interface { + Serialize() string +} + Serializer is used to circumvent the limitations of flag.FlagSet.Set + +type ShellCompleteFunc func(context.Context, *Command) + ShellCompleteFunc is an action to execute when the shell completion flag is + set + +type SliceBase[T any, C any, VC ValueCreator[T, C]] struct { + // Has unexported fields. +} + SliceBase wraps []T to satisfy flag.Value + +func NewSliceBase[T any, C any, VC ValueCreator[T, C]](defaults ...T) *SliceBase[T, C, VC] + NewSliceBase makes a *SliceBase with default values + +func (i SliceBase[T, C, VC]) Create(val []T, p *[]T, c C) Value + +func (i *SliceBase[T, C, VC]) Get() any + Get returns the slice of values set by this flag + +func (i *SliceBase[T, C, VC]) Serialize() string + Serialize allows SliceBase to fulfill Serializer + +func (i *SliceBase[T, C, VC]) Set(value string) error + Set parses the value and appends it to the list of values + +func (i *SliceBase[T, C, VC]) String() string + String returns a readable representation of this value (for usage defaults) + +func (i SliceBase[T, C, VC]) ToString(t []T) string + +func (i *SliceBase[T, C, VC]) Value() []T + Value returns the slice of values set by this flag + +type StringArg = ArgumentBase[string, StringConfig, stringValue] + +type StringArgs = ArgumentsBase[string, StringConfig, stringValue] + +type StringConfig struct { + // Whether to trim whitespace of parsed value + TrimSpace bool +} + StringConfig defines the configuration for string flags + +type StringFlag = FlagBase[string, StringConfig, stringValue] + +type StringMap = MapBase[string, StringConfig, stringValue] + +type StringMapArgs = ArgumentBase[map[string]string, StringConfig, StringMap] + +type StringMapFlag = FlagBase[map[string]string, StringConfig, StringMap] + +type StringSlice = SliceBase[string, StringConfig, stringValue] + +type StringSliceFlag = FlagBase[[]string, StringConfig, StringSlice] + +type SuggestCommandFunc func(commands []*Command, provided string) string + +type SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string + +type TimestampArg = ArgumentBase[time.Time, TimestampConfig, timestampValue] + +type TimestampArgs = ArgumentsBase[time.Time, TimestampConfig, timestampValue] + +type TimestampConfig struct { + Timezone *time.Location + // Available layouts for flag value. + // + // Note that value for formats with missing year/date will be interpreted as current year/date respectively. + // + // Read more about time layouts: https://pkg.go.dev/time#pkg-constants + Layouts []string +} + TimestampConfig defines the config for timestamp flags + +type TimestampFlag = FlagBase[time.Time, TimestampConfig, timestampValue] + +type Uint16Arg = ArgumentBase[uint16, IntegerConfig, uintValue[uint16]] + +type Uint16Args = ArgumentsBase[uint16, IntegerConfig, uintValue[uint16]] + +type Uint16Flag = FlagBase[uint16, IntegerConfig, uintValue[uint16]] + +type Uint16Slice = SliceBase[uint16, IntegerConfig, uintValue[uint16]] + +type Uint16SliceFlag = FlagBase[[]uint16, IntegerConfig, Uint16Slice] + +type Uint32Arg = ArgumentBase[uint32, IntegerConfig, uintValue[uint32]] + +type Uint32Args = ArgumentsBase[uint32, IntegerConfig, uintValue[uint32]] + +type Uint32Flag = FlagBase[uint32, IntegerConfig, uintValue[uint32]] + +type Uint32Slice = SliceBase[uint32, IntegerConfig, uintValue[uint32]] + +type Uint32SliceFlag = FlagBase[[]uint32, IntegerConfig, Uint32Slice] + +type Uint64Arg = ArgumentBase[uint64, IntegerConfig, uintValue[uint64]] + +type Uint64Args = ArgumentsBase[uint64, IntegerConfig, uintValue[uint64]] + +type Uint64Flag = FlagBase[uint64, IntegerConfig, uintValue[uint64]] + +type Uint64Slice = SliceBase[uint64, IntegerConfig, uintValue[uint64]] + +type Uint64SliceFlag = FlagBase[[]uint64, IntegerConfig, Uint64Slice] + +type Uint8Arg = ArgumentBase[uint8, IntegerConfig, uintValue[uint8]] + +type Uint8Args = ArgumentsBase[uint8, IntegerConfig, uintValue[uint8]] + +type Uint8Flag = FlagBase[uint8, IntegerConfig, uintValue[uint8]] + +type Uint8Slice = SliceBase[uint8, IntegerConfig, uintValue[uint8]] + +type Uint8SliceFlag = FlagBase[[]uint8, IntegerConfig, Uint8Slice] + +type UintArg = ArgumentBase[uint, IntegerConfig, uintValue[uint]] + +type UintArgs = ArgumentsBase[uint, IntegerConfig, uintValue[uint]] + +type UintFlag = FlagBase[uint, IntegerConfig, uintValue[uint]] + +type UintSlice = SliceBase[uint, IntegerConfig, uintValue[uint]] + +type UintSliceFlag = FlagBase[[]uint, IntegerConfig, UintSlice] + +type Value interface { + flag.Value + flag.Getter +} + Value represents a value as used by cli. For now it implements the golang + flag.Value interface + +type ValueCreator[T any, C any] interface { + Create(T, *T, C) Value + ToString(T) string +} + ValueCreator is responsible for creating a flag.Value emulation as well as + custom formatting + + T specifies the type + C specifies the config for the type + +type ValueSource interface { + fmt.Stringer + fmt.GoStringer + + // Lookup returns the value from the source and if it was found + // or returns an empty string and false + Lookup() (string, bool) +} + ValueSource is a source which can be used to look up a value, typically for + use with a cli.Flag + +func EnvVar(key string) ValueSource + +func File(path string) ValueSource + +func NewMapValueSource(key string, ms MapSource) ValueSource + +type ValueSourceChain struct { + Chain []ValueSource +} + ValueSourceChain contains an ordered series of ValueSource that allows for + lookup where the first ValueSource to resolve is returned + +func EnvVars(keys ...string) ValueSourceChain + EnvVars is a helper function to encapsulate a number of envVarValueSource + together as a ValueSourceChain + +func Files(paths ...string) ValueSourceChain + Files is a helper function to encapsulate a number of fileValueSource + together as a ValueSourceChain + +func NewValueSourceChain(src ...ValueSource) ValueSourceChain + +func (vsc *ValueSourceChain) Append(other ValueSourceChain) + +func (vsc *ValueSourceChain) EnvKeys() []string + +func (vsc *ValueSourceChain) GoString() string + +func (vsc *ValueSourceChain) Lookup() (string, bool) + +func (vsc *ValueSourceChain) LookupWithSource() (string, ValueSource, bool) + +func (vsc *ValueSourceChain) String() string + +type VisibleFlag interface { + // IsVisible returns true if the flag is not hidden, otherwise false + IsVisible() bool +} + VisibleFlag is an interface that allows to check if a flag is visible + +type VisibleFlagCategory interface { + // Name returns the category name string + Name() string + // Flags returns a slice of VisibleFlag sorted by name + Flags() []Flag +} + VisibleFlagCategory is a category containing flags. + diff --git a/vendor/github.com/urfave/cli/v3/help.go b/vendor/github.com/urfave/cli/v3/help.go new file mode 100644 index 00000000000..0f7f629caf2 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/help.go @@ -0,0 +1,624 @@ +package cli + +import ( + "context" + "fmt" + "io" + "os" + "slices" + "strings" + "text/tabwriter" + "text/template" + "unicode/utf8" +) + +const ( + helpName = "help" + helpAlias = "h" +) + +// HelpPrinterFunc prints help for the Command. +type HelpPrinterFunc func(w io.Writer, templ string, data any) + +// Prints help for the Command with custom template function. +type HelpPrinterCustomFunc func(w io.Writer, templ string, data any, customFunc map[string]any) + +// HelpPrinter is a function that writes the help output. If not set explicitly, +// this calls HelpPrinterCustom using only the default template functions. +// +// If custom logic for printing help is required, this function can be +// overridden. If the ExtraInfo field is defined on a Command, this function +// should not be modified, as HelpPrinterCustom will be used directly in order +// to capture the extra information. +var HelpPrinter HelpPrinterFunc = DefaultPrintHelp + +// HelpPrinterCustom is a function that writes the help output. It is used as +// the default implementation of HelpPrinter, and may be called directly if +// the ExtraInfo field is set on a Command. +// +// In the default implementation, if the customFuncs argument contains a +// "wrapAt" key, which is a function which takes no arguments and returns +// an int, this int value will be used to produce a "wrap" function used +// by the default template to wrap long lines. +var HelpPrinterCustom HelpPrinterCustomFunc = DefaultPrintHelpCustom + +// VersionPrinter prints the version for the root Command. +var VersionPrinter = DefaultPrintVersion + +// ShowRootCommandHelp is an action that displays help for the root command. +var ShowRootCommandHelp = DefaultShowRootCommandHelp + +// ShowAppHelp is a backward-compatible name for ShowRootCommandHelp. +var ShowAppHelp = ShowRootCommandHelp + +// ShowCommandHelp prints help for the given command +var ShowCommandHelp = DefaultShowCommandHelp + +// ShowSubcommandHelp prints help for the given subcommand +var ShowSubcommandHelp = DefaultShowSubcommandHelp + +// UsageCommandHelp is the text to override the USAGE section of the help command +var UsageCommandHelp = "Shows a list of commands or help for one command" + +// ArgsUsageCommandHelp is a short description of the arguments of the help command +var ArgsUsageCommandHelp = "[command]" + +func buildHelpCommand(withAction bool) *Command { + cmd := &Command{ + Name: helpName, + Aliases: []string{helpAlias}, + Usage: UsageCommandHelp, + ArgsUsage: ArgsUsageCommandHelp, + HideHelp: true, + } + + if withAction { + cmd.Action = helpCommandAction + } + + return cmd +} + +func helpCommandAction(ctx context.Context, cmd *Command) error { + args := cmd.Args() + firstArg := args.First() + + tracef("doing help for cmd %[1]q with args %[2]q", cmd, args) + + // This action can be triggered by a "default" action of a command + // or via cmd.Run when cmd == helpCmd. So we have following possibilities + // + // 1 $ app + // 2 $ app help + // 3 $ app foo + // 4 $ app help foo + // 5 $ app foo help + + // Case 4. when executing a help command set the context to parent + // to allow resolution of subsequent args. This will transform + // $ app help foo + // to + // $ app foo + // which will then be handled as case 3 + if cmd.parent != nil && (cmd.HasName(helpName) || cmd.HasName(helpAlias)) { + tracef("setting cmd to cmd.parent") + cmd = cmd.parent + } + + // Case 4. $ app help foo + // foo is the command for which help needs to be shown + if firstArg != "" { + /* if firstArg == "--" { + return nil + }*/ + tracef("returning ShowCommandHelp with %[1]q", firstArg) + return ShowCommandHelp(ctx, cmd, firstArg) + } + + // Case 1 & 2 + // Special case when running help on main app itself as opposed to individual + // commands/subcommands + if cmd.parent == nil { + tracef("returning ShowRootCommandHelp") + _ = ShowRootCommandHelp(cmd) + return nil + } + + // Case 3, 5 + if len(cmd.VisibleCommands()) == 0 { + + tmpl := cmd.CustomHelpTemplate + if tmpl == "" { + tmpl = CommandHelpTemplate + } + + tracef("running HelpPrinter with command %[1]q", cmd.Name) + HelpPrinter(cmd.Root().Writer, tmpl, cmd) + + return nil + } + + tracef("running ShowSubcommandHelp") + return ShowSubcommandHelp(cmd) +} + +// ShowRootCommandHelpAndExit prints the list of subcommands and exits with exit code. +func ShowRootCommandHelpAndExit(cmd *Command, exitCode int) { + _ = ShowRootCommandHelp(cmd) + OsExiter(exitCode) +} + +// ShowAppHelpAndExit is a backward-compatible name for ShowRootCommandHelp. +var ShowAppHelpAndExit = ShowRootCommandHelpAndExit + +// DefaultShowRootCommandHelp is the default implementation of ShowRootCommandHelp. +func DefaultShowRootCommandHelp(cmd *Command) error { + tmpl := cmd.CustomRootCommandHelpTemplate + if tmpl == "" { + tracef("using RootCommandHelpTemplate") + tmpl = RootCommandHelpTemplate + } + + if cmd.ExtraInfo == nil { + HelpPrinter(cmd.Root().Writer, tmpl, cmd.Root()) + return nil + } + + tracef("setting ExtraInfo in customAppData") + customAppData := func() map[string]any { + return map[string]any{ + "ExtraInfo": cmd.ExtraInfo, + } + } + HelpPrinterCustom(cmd.Root().Writer, tmpl, cmd.Root(), customAppData()) + + return nil +} + +// DefaultRootCommandComplete prints the list of subcommands as the default completion method. +func DefaultRootCommandComplete(ctx context.Context, cmd *Command) { + DefaultCompleteWithFlags(ctx, cmd) +} + +// DefaultAppComplete is a backward-compatible name for DefaultRootCommandComplete. +var DefaultAppComplete = DefaultRootCommandComplete + +func printCommandSuggestions(commands []*Command, writer io.Writer) { + shell := os.Getenv("SHELL") + for _, command := range commands { + if command.Hidden { + continue + } + if (strings.HasSuffix(shell, "zsh") || strings.HasSuffix(shell, "fish")) && len(command.Usage) > 0 { + _, _ = fmt.Fprintf(writer, "%s:%s\n", command.Name, command.Usage) + } else { + _, _ = fmt.Fprintf(writer, "%s\n", command.Name) + } + } +} + +func cliArgContains(flagName string, args []string) bool { + for _, name := range strings.Split(flagName, ",") { + name = strings.TrimSpace(name) + count := utf8.RuneCountInString(name) + if count > 2 { + count = 2 + } + flag := fmt.Sprintf("%s%s", strings.Repeat("-", count), name) + if slices.Contains(args, flag) { + return true + } + } + return false +} + +func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) { + // Trim to handle both "-short" and "--long" flags. + cur := strings.TrimLeft(lastArg, "-") + for _, flag := range flags { + if bflag, ok := flag.(*BoolFlag); ok && bflag.Hidden { + continue + } + + usage := "" + if docFlag, ok := flag.(DocGenerationFlag); ok { + usage = docFlag.GetUsage() + } + + name := strings.TrimSpace(flag.Names()[0]) + // this will get total count utf8 letters in flag name + count := utf8.RuneCountInString(name) + if count > 2 { + count = 2 // reuse this count to generate single - or -- in flag completion + } + // if flag name has more than one utf8 letter and last argument in cli has -- prefix then + // skip flag completion for short flags example -v or -x + if strings.HasPrefix(lastArg, "--") && count == 1 { + continue + } + // match if last argument matches this flag and it is not repeated + if strings.HasPrefix(name, cur) && cur != name /* && !cliArgContains(name, os.Args)*/ { + flagCompletion := fmt.Sprintf("%s%s", strings.Repeat("-", count), name) + shell := os.Getenv("SHELL") + if usage != "" && (strings.HasSuffix(shell, "zsh") || strings.HasSuffix(shell, "fish")) { + flagCompletion = fmt.Sprintf("%s:%s", flagCompletion, usage) + } + fmt.Fprintln(writer, flagCompletion) + } + } +} + +func DefaultCompleteWithFlags(ctx context.Context, cmd *Command) { + args := os.Args + if cmd != nil && cmd.parent != nil { + args = cmd.Args().Slice() + tracef("running default complete with flags[%v] on command %[2]q", args, cmd.Name) + } else { + tracef("running default complete with os.Args flags[%v]", args) + } + argsLen := len(args) + lastArg := "" + // parent command will have --generate-shell-completion so we need + // to account for that + if argsLen > 1 { + lastArg = args[argsLen-2] + } else if argsLen > 0 { + lastArg = args[argsLen-1] + } + + if lastArg == "--" { + tracef("No completions due to termination") + return + } + + if lastArg == completionFlag { + lastArg = "" + } + + if strings.HasPrefix(lastArg, "-") { + tracef("printing flag suggestion for flag[%v] on command %[1]q", lastArg, cmd.Name) + printFlagSuggestions(lastArg, cmd.Flags, cmd.Root().Writer) + return + } + + if cmd != nil { + tracef("printing command suggestions on command %[1]q", cmd.Name) + printCommandSuggestions(cmd.Commands, cmd.Root().Writer) + return + } +} + +// ShowCommandHelpAndExit exits with code after showing help via ShowCommandHelp. +func ShowCommandHelpAndExit(ctx context.Context, cmd *Command, command string, code int) { + _ = ShowCommandHelp(ctx, cmd, command) + OsExiter(code) +} + +// DefaultShowCommandHelp is the default implementation of ShowCommandHelp. +func DefaultShowCommandHelp(ctx context.Context, cmd *Command, commandName string) error { + for _, subCmd := range cmd.Commands { + if !subCmd.HasName(commandName) { + continue + } + + tmpl := subCmd.CustomHelpTemplate + if tmpl == "" { + if len(subCmd.Commands) == 0 { + tracef("using CommandHelpTemplate") + tmpl = CommandHelpTemplate + } else { + tracef("using SubcommandHelpTemplate") + tmpl = SubcommandHelpTemplate + } + } + + tracef("running HelpPrinter") + HelpPrinter(cmd.Root().Writer, tmpl, subCmd) + + tracef("returning nil after printing help") + return nil + } + + tracef("no matching command found") + + if cmd.CommandNotFound == nil { + errMsg := fmt.Sprintf("No help topic for '%v'", commandName) + + if cmd.Suggest { + if suggestion := SuggestCommand(cmd.Commands, commandName); suggestion != "" { + errMsg += ". " + suggestion + } + } + + tracef("exiting 3 with errMsg %[1]q", errMsg) + return Exit(errMsg, 3) + } + + tracef("running CommandNotFound func for %[1]q", commandName) + cmd.CommandNotFound(ctx, cmd, commandName) + + return nil +} + +// ShowSubcommandHelpAndExit prints help for the given subcommand via ShowSubcommandHelp and exits with exit code. +func ShowSubcommandHelpAndExit(cmd *Command, exitCode int) { + _ = ShowSubcommandHelp(cmd) + OsExiter(exitCode) +} + +// DefaultShowSubcommandHelp is the default implementation of ShowSubcommandHelp. +func DefaultShowSubcommandHelp(cmd *Command) error { + HelpPrinter(cmd.Root().Writer, SubcommandHelpTemplate, cmd) + return nil +} + +// ShowVersion prints the version number of the root Command. +func ShowVersion(cmd *Command) { + tracef("showing version via VersionPrinter (cmd=%[1]q)", cmd.Name) + VersionPrinter(cmd) +} + +// DefaultPrintVersion is the default implementation of VersionPrinter. +func DefaultPrintVersion(cmd *Command) { + _, _ = fmt.Fprintf(cmd.Root().Writer, "%v version %v\n", cmd.Name, cmd.Version) +} + +func handleTemplateError(err error) { + if err != nil { + tracef("error encountered during template parse: %[1]v", err) + // If the writer is closed, t.Execute will fail, and there's nothing + // we can do to recover. + if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" { + _, _ = fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err) + } + return + } +} + +// DefaultPrintHelpCustom is the default implementation of HelpPrinterCustom. +// +// The customFuncs map will be combined with a default template.FuncMap to +// allow using arbitrary functions in template rendering. +func DefaultPrintHelpCustom(out io.Writer, templ string, data any, customFuncs map[string]any) { + const maxLineLength = 10000 + + tracef("building default funcMap") + funcMap := template.FuncMap{ + "join": strings.Join, + "subtract": subtract, + "indent": indent, + "nindent": nindent, + "trim": strings.TrimSpace, + "wrap": func(input string, offset int) string { return wrap(input, offset, maxLineLength) }, + "offset": offset, + "offsetCommands": offsetCommands, + } + + if wa, ok := customFuncs["wrapAt"]; ok { + if wrapAtFunc, ok := wa.(func() int); ok { + wrapAt := wrapAtFunc() + customFuncs["wrap"] = func(input string, offset int) string { + return wrap(input, offset, wrapAt) + } + } + } + + for key, value := range customFuncs { + funcMap[key] = value + } + + w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) + t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) + + if _, err := t.New("helpNameTemplate").Parse(helpNameTemplate); err != nil { + handleTemplateError(err) + } + + if _, err := t.New("argsTemplate").Parse(argsTemplate); err != nil { + handleTemplateError(err) + } + + if _, err := t.New("usageTemplate").Parse(usageTemplate); err != nil { + handleTemplateError(err) + } + + if _, err := t.New("descriptionTemplate").Parse(descriptionTemplate); err != nil { + handleTemplateError(err) + } + + if _, err := t.New("visibleCommandTemplate").Parse(visibleCommandTemplate); err != nil { + handleTemplateError(err) + } + + if _, err := t.New("copyrightTemplate").Parse(copyrightTemplate); err != nil { + handleTemplateError(err) + } + + if _, err := t.New("versionTemplate").Parse(versionTemplate); err != nil { + handleTemplateError(err) + } + + if _, err := t.New("visibleFlagCategoryTemplate").Parse(visibleFlagCategoryTemplate); err != nil { + handleTemplateError(err) + } + + if _, err := t.New("visibleFlagTemplate").Parse(visibleFlagTemplate); err != nil { + handleTemplateError(err) + } + + if _, err := t.New("visiblePersistentFlagTemplate").Parse(visiblePersistentFlagTemplate); err != nil { + handleTemplateError(err) + } + + if _, err := t.New("visibleGlobalFlagCategoryTemplate").Parse(strings.ReplaceAll(visibleFlagCategoryTemplate, "OPTIONS", "GLOBAL OPTIONS")); err != nil { + handleTemplateError(err) + } + + if _, err := t.New("authorsTemplate").Parse(authorsTemplate); err != nil { + handleTemplateError(err) + } + + if _, err := t.New("visibleCommandCategoryTemplate").Parse(visibleCommandCategoryTemplate); err != nil { + handleTemplateError(err) + } + + tracef("executing template") + handleTemplateError(t.Execute(w, data)) + + _ = w.Flush() +} + +// DefaultPrintHelp is the default implementation of HelpPrinter. +func DefaultPrintHelp(out io.Writer, templ string, data any) { + HelpPrinterCustom(out, templ, data, nil) +} + +func checkVersion(cmd *Command) bool { + found := false + for _, name := range VersionFlag.Names() { + if cmd.Bool(name) { + found = true + } + } + return found +} + +func checkShellCompleteFlag(c *Command, arguments []string) (bool, []string) { + if (c.parent == nil && !c.EnableShellCompletion) || (c.parent != nil && !c.Root().shellCompletion) { + return false, arguments + } + + pos := len(arguments) - 1 + lastArg := arguments[pos] + + if lastArg != completionFlag { + return false, arguments + } + + // If arguments include "--", shell completion is disabled + // because after "--" only positional arguments are accepted. + // https://unix.stackexchange.com/a/11382 + if slices.Contains(arguments, "--") { + return false, arguments[:pos] + } + + return true, arguments[:pos] +} + +func checkCompletions(ctx context.Context, cmd *Command) bool { + tracef("checking completions on command %[1]q", cmd.Name) + + if !cmd.Root().shellCompletion { + tracef("completion not enabled skipping %[1]q", cmd.Name) + return false + } + + if argsArguments := cmd.Args(); argsArguments.Present() { + name := argsArguments.First() + if cmd := cmd.Command(name); cmd != nil { + // let the command handle the completion + return false + } + } + + tracef("no subcommand found for completion %[1]q", cmd.Name) + + if cmd.ShellComplete != nil { + tracef("running shell completion func for command %[1]q", cmd.Name) + cmd.ShellComplete(ctx, cmd) + } + + return true +} + +func subtract(a, b int) int { + return a - b +} + +func indent(spaces int, v string) string { + pad := strings.Repeat(" ", spaces) + return pad + strings.ReplaceAll(v, "\n", "\n"+pad) +} + +func nindent(spaces int, v string) string { + return "\n" + indent(spaces, v) +} + +func wrap(input string, offset int, wrapAt int) string { + var ss []string + + lines := strings.Split(input, "\n") + + padding := strings.Repeat(" ", offset) + + for i, line := range lines { + if line == "" { + ss = append(ss, line) + } else { + wrapped := wrapLine(line, offset, wrapAt, padding) + if i == 0 { + ss = append(ss, wrapped) + } else { + ss = append(ss, padding+wrapped) + } + + } + } + + return strings.Join(ss, "\n") +} + +func wrapLine(input string, offset int, wrapAt int, padding string) string { + if wrapAt <= offset || len(input) <= wrapAt-offset { + return input + } + + lineWidth := wrapAt - offset + words := strings.Fields(input) + if len(words) == 0 { + return input + } + + wrapped := words[0] + spaceLeft := lineWidth - len(wrapped) + for _, word := range words[1:] { + if len(word)+1 > spaceLeft { + wrapped += "\n" + padding + word + spaceLeft = lineWidth - len(word) + } else { + wrapped += " " + word + spaceLeft -= 1 + len(word) + } + } + + return wrapped +} + +func offset(input string, fixed int) int { + return len(input) + fixed +} + +// this function tries to find the max width of the names column +// so say we have the following rows for help +// +// foo1, foo2, foo3 some string here +// bar1, b2 some other string here +// +// We want to offset the 2nd row usage by some amount so that everything +// is aligned +// +// foo1, foo2, foo3 some string here +// bar1, b2 some other string here +// +// to find that offset we find the length of all the rows and use the max +// to calculate the offset +func offsetCommands(cmds []*Command, fixed int) int { + max := 0 + for _, cmd := range cmds { + s := strings.Join(cmd.Names(), ", ") + if len(s) > max { + max = len(s) + } + } + return max + fixed +} diff --git a/vendor/github.com/urfave/cli/v3/mkdocs-requirements.txt b/vendor/github.com/urfave/cli/v3/mkdocs-requirements.txt new file mode 100644 index 00000000000..e5848c726a6 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/mkdocs-requirements.txt @@ -0,0 +1,5 @@ +mkdocs-git-revision-date-localized-plugin==1.5.1 +mkdocs-material==9.7.5 +mkdocs==1.6.1 +mkdocs-redirects==1.2.2 +pygments==2.19.2 diff --git a/vendor/github.com/urfave/cli/v3/mkdocs.yml b/vendor/github.com/urfave/cli/v3/mkdocs.yml new file mode 100644 index 00000000000..e1eac95871c --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/mkdocs.yml @@ -0,0 +1,139 @@ +# NOTE: the mkdocs dependencies will need to be installed out of +# band until this whole thing gets more automated: +# +# pip install -r mkdocs-requirements.txt +# + +site_name: urfave/cli +site_url: https://cli.urfave.org/ +repo_url: https://github.com/urfave/cli +edit_uri: edit/main/docs/ +nav: + - Home: + - Welcome: index.md + - Contributing: CONTRIBUTING.md + - Code of Conduct: CODE_OF_CONDUCT.md + - Releasing: RELEASING.md + - Security: SECURITY.md + - Migrate v2 to v3: migrate-v2-to-v3.md + - Migrate v1 to v2: migrate-v1-to-v2.md + - v3 Manual: + - Getting Started: v3/getting-started.md + - Migrating From Older Releases: v3/migrating-from-older-releases.md + - Examples: + - Greet: v3/examples/greet.md + - Flags: + - Basics: v3/examples/flags/basics.md + - Value Sources: v3/examples/flags/value-sources.md + - Short Options: v3/examples/flags/short-options.md + - Advanced: v3/examples/flags/advanced.md + - Arguments: + - Basics: v3/examples/arguments/basics.md + - Advanced: v3/examples/arguments/advanced.md + - Subcommands: + - Basics: v3/examples/subcommands/basics.md + - Categories: v3/examples/subcommands/categories.md + - Completions: + - Shell Completions: v3/examples/completions/shell-completions.md + - Customizations: v3/examples/completions/customizations.md + - Help Text: + - Generated Help Text: v3/examples/help/generated-help-text.md + - Suggestions: v3/examples/help/suggestions.md + - Error Handling: + - Exit Codes: v3/examples/exit-codes.md + - Full API Example: v3/examples/full-api-example.md + - v2 Manual: + - Getting Started: v2/getting-started.md + - Migrating to v3: v2/migrating-to-v3.md + - Migrating From Older Releases: v2/migrating-from-older-releases.md + - Examples: + - Greet: v2/examples/greet.md + - Arguments: v2/examples/arguments.md + - Flags: v2/examples/flags.md + - Subcommands: v2/examples/subcommands.md + - Subcommands Categories: v2/examples/subcommands-categories.md + - Exit Codes: v2/examples/exit-codes.md + - Combining Short Options: v2/examples/combining-short-options.md + - Bash Completions: v2/examples/bash-completions.md + - Generated Help Text: v2/examples/generated-help-text.md + - Version Flag: v2/examples/version-flag.md + - Timestamp Flag: v2/examples/timestamp-flag.md + - Suggestions: v2/examples/suggestions.md + - Full API Example: v2/examples/full-api-example.md + - v1 Manual: + - Getting Started: v1/getting-started.md + - Migrating to v2: v1/migrating-to-v2.md + - Examples: + - Greet: v1/examples/greet.md + - Arguments: v1/examples/arguments.md + - Flags: v1/examples/flags.md + - Subcommands: v1/examples/subcommands.md + - Subcommands (Categories): v1/examples/subcommands-categories.md + - Exit Codes: v1/examples/exit-codes.md + - Combining Short Options: v1/examples/combining-short-options.md + - Bash Completions: v1/examples/bash-completions.md + - Generated Help Text: v1/examples/generated-help-text.md + - Version Flag: v1/examples/version-flag.md + +theme: + name: material + palette: + - media: "(prefers-color-scheme: light)" + scheme: default + toggle: + icon: material/brightness-4 + name: dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + toggle: + icon: material/brightness-7 + name: light mode + features: + - content.code.annotate + - navigation.top + - navigation.instant + - navigation.expand + - navigation.sections + - navigation.tabs + - navigation.tabs.sticky + +plugins: + - git-revision-date-localized + - search + - redirects: + redirect_maps: + 'v3/examples/bash-completions.md': 'v3/examples/completions/shell-completions.md' + - tags + +# NOTE: this is the recommended configuration from +# https://squidfunk.github.io/mkdocs-material/setup/extensions/#recommended-configuration +markdown_extensions: + - abbr + - admonition + - attr_list + - def_list + - footnotes + - meta + - md_in_html + - toc: + permalink: true + - pymdownx.arithmatex: + generic: true + - pymdownx.betterem: + smart_enable: all + - pymdownx.caret + - pymdownx.details + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - pymdownx.highlight + - pymdownx.inlinehilite + - pymdownx.keys + - pymdownx.mark + - pymdownx.smartsymbols + - pymdownx.superfences + - pymdownx.tabbed: + alternate_style: true + - pymdownx.tasklist: + custom_checkbox: true + - pymdownx.tilde diff --git a/vendor/github.com/urfave/cli/sort.go b/vendor/github.com/urfave/cli/v3/sort.go similarity index 100% rename from vendor/github.com/urfave/cli/sort.go rename to vendor/github.com/urfave/cli/v3/sort.go diff --git a/vendor/github.com/urfave/cli/v3/staticcheck.conf b/vendor/github.com/urfave/cli/v3/staticcheck.conf new file mode 100644 index 00000000000..233d9e73a8a --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/staticcheck.conf @@ -0,0 +1 @@ +checks=["all"] diff --git a/vendor/github.com/urfave/cli/v3/suggestions.go b/vendor/github.com/urfave/cli/v3/suggestions.go new file mode 100644 index 00000000000..401dcef253d --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/suggestions.go @@ -0,0 +1,147 @@ +package cli + +import ( + "math" +) + +const suggestDidYouMeanTemplate = "Did you mean %q?" + +var ( + SuggestFlag SuggestFlagFunc = suggestFlag + SuggestCommand SuggestCommandFunc = suggestCommand + SuggestDidYouMeanTemplate string = suggestDidYouMeanTemplate +) + +type SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string + +type SuggestCommandFunc func(commands []*Command, provided string) string + +// jaroDistance is the measure of similarity between two strings. It returns a +// value between 0 and 1, where 1 indicates identical strings and 0 indicates +// completely different strings. +// +// Adapted from https://github.com/xrash/smetrics/blob/5f08fbb34913bc8ab95bb4f2a89a0637ca922666/jaro.go. +func jaroDistance(a, b string) float64 { + if len(a) == 0 && len(b) == 0 { + return 1 + } + if len(a) == 0 || len(b) == 0 { + return 0 + } + + lenA := float64(len(a)) + lenB := float64(len(b)) + hashA := make([]bool, len(a)) + hashB := make([]bool, len(b)) + maxDistance := int(math.Max(0, math.Floor(math.Max(lenA, lenB)/2.0)-1)) + + var matches float64 + for i := 0; i < len(a); i++ { + start := int(math.Max(0, float64(i-maxDistance))) + end := int(math.Min(lenB-1, float64(i+maxDistance))) + + for j := start; j <= end; j++ { + if hashB[j] { + continue + } + if a[i] == b[j] { + hashA[i] = true + hashB[j] = true + matches++ + break + } + } + } + if matches == 0 { + return 0 + } + + var transpositions float64 + var j int + for i := 0; i < len(a); i++ { + if !hashA[i] { + continue + } + for !hashB[j] { + j++ + } + if a[i] != b[j] { + transpositions++ + } + j++ + } + + transpositions /= 2 + return ((matches / lenA) + (matches / lenB) + ((matches - transpositions) / matches)) / 3.0 +} + +// jaroWinkler is more accurate when strings have a common prefix up to a +// defined maximum length. +// +// Adapted from https://github.com/xrash/smetrics/blob/5f08fbb34913bc8ab95bb4f2a89a0637ca922666/jaro-winkler.go. +func jaroWinkler(a, b string) float64 { + const ( + boostThreshold = 0.7 + prefixSize = 4 + ) + jaroDist := jaroDistance(a, b) + if jaroDist <= boostThreshold { + return jaroDist + } + + prefix := int(math.Min(float64(len(a)), math.Min(float64(prefixSize), float64(len(b))))) + + var prefixMatch float64 + for i := range prefix { + if a[i] == b[i] { + prefixMatch++ + } else { + break + } + } + return jaroDist + 0.1*prefixMatch*(1.0-jaroDist) +} + +func suggestFlag(flags []Flag, provided string, hideHelp bool) string { + distance := 0.0 + suggestion := "" + + for _, flag := range flags { + flagNames := flag.Names() + if !hideHelp && HelpFlag != nil { + flagNames = append(flagNames, HelpFlag.Names()...) + } + for _, name := range flagNames { + newDistance := jaroWinkler(name, provided) + if newDistance > distance { + distance = newDistance + suggestion = name + } + } + } + + if len(suggestion) == 1 { + suggestion = "-" + suggestion + } else if len(suggestion) > 1 { + suggestion = "--" + suggestion + } + + return suggestion +} + +// suggestCommand takes a list of commands and a provided string to suggest a +// command name +func suggestCommand(commands []*Command, provided string) (suggestion string) { + distance := 0.0 + for _, command := range commands { + for _, name := range append(command.Names(), helpName, helpAlias) { + newDistance := jaroWinkler(name, provided) + if newDistance > distance { + distance = newDistance + suggestion = name + } + } + } + + return suggestion +} diff --git a/vendor/github.com/urfave/cli/v3/template.go b/vendor/github.com/urfave/cli/v3/template.go new file mode 100644 index 00000000000..dd144e77dd8 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/template.go @@ -0,0 +1,125 @@ +package cli + +var ( + helpNameTemplate = `{{$v := offset .FullName 6}}{{wrap .FullName 3}}{{if .Usage}} - {{wrap .Usage $v}}{{end}}` + argsTemplate = `{{if .Arguments}}{{range .Arguments}}{{.Usage}} {{end}}{{end}}` + usageTemplate = `{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.FullName}}{{if .VisibleFlags}} [options]{{end}}{{if .VisibleCommands}} [command [command options]]{{end}}{{if .ArgsUsage}} {{.ArgsUsage}}{{else}}{{if .Arguments}} {{template "argsTemplate" .}}{{end}}{{end}}{{end}}` + descriptionTemplate = `{{wrap .Description 3}}` + authorsTemplate = `{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: + {{range $index, $author := .Authors}}{{if $index}} + {{end}}{{$author}}{{end}}` +) + +var visibleCommandTemplate = `{{ $cv := offsetCommands .VisibleCommands 5}}{{range .VisibleCommands}} + {{$s := join .Names ", "}}{{$s}}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp ""}}{{wrap .Usage $cv}}{{end}}` + +var visibleCommandCategoryTemplate = `{{range .VisibleCategories}}{{if .Name}} + + {{.Name}}:{{range .VisibleCommands}} + {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{template "visibleCommandTemplate" .}}{{end}}{{end}}` + +var visibleFlagCategoryTemplate = `{{range .VisibleFlagCategories}} + {{if .Name}}{{.Name}} + + {{end}}{{$flglen := len .Flags}}{{range $i, $e := .Flags}}{{if eq (subtract $flglen $i) 1}}{{$e}} +{{else}}{{$e}} + {{end}}{{end}}{{end}}` + +var visibleFlagTemplate = `{{range $i, $e := .VisibleFlags}} + {{wrap $e.String 6}}{{end}}` + +var visiblePersistentFlagTemplate = `{{range $i, $e := .VisiblePersistentFlags}} + {{wrap $e.String 6}}{{end}}` + +var versionTemplate = `{{if .Version}}{{if not .HideVersion}} + +VERSION: + {{.Version}}{{end}}{{end}}` + +var copyrightTemplate = `{{wrap .Copyright 3}}` + +// RootCommandHelpTemplate is the text template for the Default help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var RootCommandHelpTemplate = `NAME: + {{template "helpNameTemplate" .}} + +USAGE: + {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.FullName}} {{if .VisibleFlags}}[global options]{{end}}{{if .VisibleCommands}} [command [command options]]{{end}}{{if .ArgsUsage}} {{.ArgsUsage}}{{else}}{{if .Arguments}} [arguments...]{{end}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} + +VERSION: + {{.Version}}{{end}}{{end}}{{if .Description}} + +DESCRIPTION: + {{template "descriptionTemplate" .}}{{end}} +{{- if len .Authors}} + +AUTHOR{{template "authorsTemplate" .}}{{end}}{{if .VisibleCommands}} + +COMMANDS:{{template "visibleCommandCategoryTemplate" .}}{{end}}{{if .VisibleFlagCategories}} + +GLOBAL OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}} + +GLOBAL OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .Copyright}} + +COPYRIGHT: + {{template "copyrightTemplate" .}}{{end}} +` + +// CommandHelpTemplate is 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. +var CommandHelpTemplate = `NAME: + {{template "helpNameTemplate" .}} + +USAGE: + {{template "usageTemplate" .}}{{if .Category}} + +CATEGORY: + {{.Category}}{{end}}{{if .Description}} + +DESCRIPTION: + {{template "descriptionTemplate" .}}{{end}}{{if .VisibleFlagCategories}} + +OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}} + +OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .VisiblePersistentFlags}} + +GLOBAL OPTIONS:{{template "visiblePersistentFlagTemplate" .}}{{end}} +` + +// SubcommandHelpTemplate is the text template for the subcommand help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var SubcommandHelpTemplate = `NAME: + {{template "helpNameTemplate" .}} + +USAGE: + {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.FullName}}{{if .VisibleCommands}} [command [command options]]{{end}}{{if .ArgsUsage}} {{.ArgsUsage}}{{else}}{{if .Arguments}} [arguments...]{{end}}{{end}}{{end}}{{if .Category}} + +CATEGORY: + {{.Category}}{{end}}{{if .Description}} + +DESCRIPTION: + {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}} + +COMMANDS:{{template "visibleCommandTemplate" .}}{{end}}{{if .VisibleFlagCategories}} + +OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}} + +OPTIONS:{{template "visibleFlagTemplate" .}}{{end}} +` + +var FishCompletionTemplate = `# {{ .Command.Name }} fish shell completion + +function __fish_{{ .Command.Name }}_no_subcommand --description 'Test if there has been any subcommand yet' + for i in (commandline -opc) + if contains -- $i{{ range $v := .AllCommands }} {{ $v }}{{ end }} + return 1 + end + end + return 0 +end + +{{ range $v := .Completions }}{{ $v }} +{{ end }}` diff --git a/vendor/github.com/urfave/cli/v3/value_source.go b/vendor/github.com/urfave/cli/v3/value_source.go new file mode 100644 index 00000000000..44b0173b413 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/value_source.go @@ -0,0 +1,257 @@ +package cli + +import ( + "fmt" + "os" + "strings" +) + +// ValueSource is a source which can be used to look up a value, +// typically for use with a cli.Flag +type ValueSource interface { + fmt.Stringer + fmt.GoStringer + + // Lookup returns the value from the source and if it was found + // or returns an empty string and false + Lookup() (string, bool) +} + +// EnvValueSource is to specifically detect env sources when +// printing help text +type EnvValueSource interface { + IsFromEnv() bool + Key() string +} + +// MapSource is a source which can be used to look up a value +// based on a key +// typically for use with a cli.Flag +type MapSource interface { + fmt.Stringer + fmt.GoStringer + + // Lookup returns the value from the source based on key + // and if it was found + // or returns an empty string and false + Lookup(string) (any, bool) +} + +// ValueSourceChain contains an ordered series of ValueSource that +// allows for lookup where the first ValueSource to resolve is +// returned +type ValueSourceChain struct { + Chain []ValueSource +} + +func NewValueSourceChain(src ...ValueSource) ValueSourceChain { + return ValueSourceChain{ + Chain: src, + } +} + +func (vsc *ValueSourceChain) Append(other ValueSourceChain) { + vsc.Chain = append(vsc.Chain, other.Chain...) +} + +func (vsc *ValueSourceChain) EnvKeys() []string { + vals := []string{} + + for _, src := range vsc.Chain { + if v, ok := src.(EnvValueSource); ok && v.IsFromEnv() { + vals = append(vals, v.Key()) + } + } + + return vals +} + +func (vsc *ValueSourceChain) String() string { + s := []string{} + + for _, vs := range vsc.Chain { + s = append(s, vs.String()) + } + + return strings.Join(s, ",") +} + +func (vsc *ValueSourceChain) GoString() string { + s := []string{} + + for _, vs := range vsc.Chain { + s = append(s, vs.GoString()) + } + + return fmt.Sprintf("&ValueSourceChain{Chain:{%[1]s}}", strings.Join(s, ",")) +} + +func (vsc *ValueSourceChain) Lookup() (string, bool) { + s, _, ok := vsc.LookupWithSource() + return s, ok +} + +func (vsc *ValueSourceChain) LookupWithSource() (string, ValueSource, bool) { + for _, src := range vsc.Chain { + if value, found := src.Lookup(); found { + return value, src, true + } + } + + return "", nil, false +} + +// envVarValueSource encapsulates a ValueSource from an environment variable +type envVarValueSource struct { + key string +} + +func (e *envVarValueSource) Lookup() (string, bool) { + return os.LookupEnv(strings.TrimSpace(string(e.key))) +} + +func (e *envVarValueSource) IsFromEnv() bool { + return true +} + +func (e *envVarValueSource) Key() string { + return e.key +} + +func (e *envVarValueSource) String() string { return fmt.Sprintf("environment variable %[1]q", e.key) } +func (e *envVarValueSource) GoString() string { + return fmt.Sprintf("&envVarValueSource{Key:%[1]q}", e.key) +} + +func EnvVar(key string) ValueSource { + return &envVarValueSource{ + key: key, + } +} + +// EnvVars is a helper function to encapsulate a number of +// envVarValueSource together as a ValueSourceChain +func EnvVars(keys ...string) ValueSourceChain { + vsc := ValueSourceChain{Chain: []ValueSource{}} + + for _, key := range keys { + vsc.Chain = append(vsc.Chain, EnvVar(key)) + } + + return vsc +} + +// fileValueSource encapsulates a ValueSource from a file +type fileValueSource struct { + Path string +} + +func (f *fileValueSource) Lookup() (string, bool) { + data, err := os.ReadFile(f.Path) + return string(data), err == nil +} + +func (f *fileValueSource) String() string { return fmt.Sprintf("file %[1]q", f.Path) } +func (f *fileValueSource) GoString() string { + return fmt.Sprintf("&fileValueSource{Path:%[1]q}", f.Path) +} + +func File(path string) ValueSource { + return &fileValueSource{Path: path} +} + +// Files is a helper function to encapsulate a number of +// fileValueSource together as a ValueSourceChain +func Files(paths ...string) ValueSourceChain { + vsc := ValueSourceChain{Chain: []ValueSource{}} + + for _, path := range paths { + vsc.Chain = append(vsc.Chain, File(path)) + } + + return vsc +} + +type mapSource struct { + name string + m map[any]any +} + +func NewMapSource(name string, m map[any]any) MapSource { + return &mapSource{ + name: name, + m: m, + } +} + +func (ms *mapSource) String() string { return fmt.Sprintf("map source %[1]q", ms.name) } +func (ms *mapSource) GoString() string { + return fmt.Sprintf("&mapSource{name:%[1]q}", ms.name) +} + +// Lookup returns a value from the map source. The lookup name may be a dot-separated path into the map. +// If that is the case, it will recursively traverse the map based on the '.' delimited sections to find +// a nested value for the key. +func (ms *mapSource) Lookup(name string) (any, bool) { + sections := strings.Split(name, ".") + if name == "" || len(sections) == 0 { + return nil, false + } + + node := ms.m + + // traverse into the map based on the dot-separated sections + if len(sections) >= 2 { // the last section is the value we want, we will return it directly at the end + for _, section := range sections[:len(sections)-1] { + child, ok := node[section] + if !ok { + return nil, false + } + + switch child := child.(type) { + case map[string]any: + node = make(map[any]any, len(child)) + for k, v := range child { + node[k] = v + } + case map[any]any: + node = child + default: + return nil, false + } + } + } + + if val, ok := node[sections[len(sections)-1]]; ok { + return val, true + } + return nil, false +} + +type mapValueSource struct { + key string + ms MapSource +} + +func NewMapValueSource(key string, ms MapSource) ValueSource { + return &mapValueSource{ + key: key, + ms: ms, + } +} + +func (mvs *mapValueSource) String() string { + return fmt.Sprintf("key %[1]q from %[2]s", mvs.key, mvs.ms.String()) +} + +func (mvs *mapValueSource) GoString() string { + return fmt.Sprintf("&mapValueSource{key:%[1]q, src:%[2]s}", mvs.key, mvs.ms.GoString()) +} + +func (mvs *mapValueSource) Lookup() (string, bool) { + if v, ok := mvs.ms.Lookup(mvs.key); !ok { + return "", false + } else { + return fmt.Sprintf("%+v", v), true + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 977edd5db60..2e4f573128f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -29,9 +29,6 @@ github.com/containerd/console # github.com/coreos/go-systemd/v22 v22.7.0 ## explicit; go 1.23 github.com/coreos/go-systemd/v22/dbus -# github.com/cpuguy83/go-md2man/v2 v2.0.7 -## explicit; go 1.12 -github.com/cpuguy83/go-md2man/v2/md2man # github.com/cyphar/filepath-securejoin v0.6.1 ## explicit; go 1.18 github.com/cyphar/filepath-securejoin @@ -90,9 +87,6 @@ github.com/opencontainers/runtime-spec/specs-go/features github.com/opencontainers/selinux/go-selinux github.com/opencontainers/selinux/go-selinux/label github.com/opencontainers/selinux/pkg/pwalkdir -# github.com/russross/blackfriday/v2 v2.1.0 -## explicit -github.com/russross/blackfriday/v2 # github.com/seccomp/libseccomp-golang v0.11.1 ## explicit; go 1.19 github.com/seccomp/libseccomp-golang @@ -100,9 +94,9 @@ github.com/seccomp/libseccomp-golang ## explicit; go 1.17 github.com/sirupsen/logrus github.com/sirupsen/logrus/hooks/test -# github.com/urfave/cli v1.22.17 -## explicit; go 1.11 -github.com/urfave/cli +# github.com/urfave/cli/v3 v3.8.0 +## explicit; go 1.22 +github.com/urfave/cli/v3 # github.com/vishvananda/netlink v1.3.1 ## explicit; go 1.12 github.com/vishvananda/netlink From 9ec8045d1438a03b148033370c3476e665254242 Mon Sep 17 00:00:00 2001 From: lifubang Date: Wed, 18 Mar 2026 04:48:56 +0000 Subject: [PATCH 2/2] remove urfave_cli_no_docs from build tags After migrate from urfave/cli v1 (maintenance mode) to v3, we don't need this build tag anymore. Signed-off-by: lifubang --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b512691573e..805da380c93 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null) GIT_BRANCH_CLEAN := $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g") RUNC_IMAGE := runc_dev$(if $(GIT_BRANCH_CLEAN),:$(GIT_BRANCH_CLEAN)) PROJECT := github.com/opencontainers/runc -BUILDTAGS := seccomp urfave_cli_no_docs libpathrs +BUILDTAGS := seccomp libpathrs # Tags prefixed with - in RUNC_BUILDTAGS are removed from BUILDTAGS; others are added. RUNC_BUILDTAGS ?= BUILDTAGS_REMOVE := $(patsubst -%,%,$(filter -%,$(RUNC_BUILDTAGS)))