commit
a82c9b1433
@ -1,17 +0,0 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 365
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 90
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: wontfix
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
@ -1,10 +1,10 @@
|
||||
*.coverprofile
|
||||
*.orig
|
||||
node_modules/
|
||||
vendor
|
||||
.idea
|
||||
internal/*/built-example
|
||||
coverage.txt
|
||||
/.local/
|
||||
/site/
|
||||
|
||||
*.exe
|
||||
|
@ -0,0 +1,40 @@
|
||||
# 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.
|
||||
|
||||
.PHONY: all
|
||||
all: generate vet tag-test test check-binary-size tag-check-binary-size gfmrun v2diff
|
||||
|
||||
# NOTE: this is a special catch-all rule to run any of the commands
|
||||
# defined in internal/build/build.go with optional arguments passed
|
||||
# via GFLAGS (global flags) and FLAGS (command-specific flags), e.g.:
|
||||
#
|
||||
# $ make test GFLAGS='--packages cli'
|
||||
%:
|
||||
go run internal/build/build.go $(GFLAGS) $* $(FLAGS)
|
||||
|
||||
.PHONY: tag-test
|
||||
tag-test:
|
||||
go run internal/build/build.go -tags urfave_cli_no_docs test
|
||||
|
||||
.PHONY: tag-check-binary-size
|
||||
tag-check-binary-size:
|
||||
go run internal/build/build.go -tags urfave_cli_no_docs check-binary-size
|
||||
|
||||
.PHONY: gfmrun
|
||||
gfmrun:
|
||||
go run internal/build/build.go gfmrun docs/v2/manual.md
|
||||
|
||||
.PHONY: docs
|
||||
docs:
|
||||
mkdocs build
|
||||
|
||||
.PHONY: docs-deps
|
||||
docs-deps:
|
||||
pip install -r mkdocs-requirements.txt
|
||||
|
||||
.PHONY: serve-docs
|
||||
serve-docs:
|
||||
mkdocs serve
|
@ -0,0 +1,87 @@
|
||||
package altsrc_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v2/altsrc"
|
||||
)
|
||||
|
||||
func ExampleApp_Run_yamlFileLoaderDuration() {
|
||||
execServe := func(c *cli.Context) error {
|
||||
keepaliveInterval := c.Duration("keepalive-interval")
|
||||
fmt.Printf("keepalive %s\n", keepaliveInterval)
|
||||
return nil
|
||||
}
|
||||
|
||||
fileExists := func(filename string) bool {
|
||||
stat, _ := os.Stat(filename)
|
||||
return stat != nil
|
||||
}
|
||||
|
||||
// initConfigFileInputSource is like altsrc.InitInputSourceWithContext and altsrc.NewYamlSourceFromFlagFunc, but checks
|
||||
// if the config flag is exists and only loads it if it does. If the flag is set and the file exists, it fails.
|
||||
initConfigFileInputSource := func(configFlag string, flags []cli.Flag) cli.BeforeFunc {
|
||||
return func(context *cli.Context) error {
|
||||
configFile := context.String(configFlag)
|
||||
if context.IsSet(configFlag) && !fileExists(configFile) {
|
||||
return fmt.Errorf("config file %s does not exist", configFile)
|
||||
} else if !context.IsSet(configFlag) && !fileExists(configFile) {
|
||||
return nil
|
||||
}
|
||||
inputSource, err := altsrc.NewYamlSourceFromFile(configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return altsrc.ApplyInputSourceValues(context, inputSource, flags)
|
||||
}
|
||||
}
|
||||
|
||||
flagsServe := []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "config",
|
||||
Aliases: []string{"c"},
|
||||
EnvVars: []string{"CONFIG_FILE"},
|
||||
Value: "../testdata/empty.yml",
|
||||
DefaultText: "../testdata/empty.yml",
|
||||
Usage: "config file",
|
||||
},
|
||||
altsrc.NewDurationFlag(
|
||||
&cli.DurationFlag{
|
||||
Name: "keepalive-interval",
|
||||
Aliases: []string{"k"},
|
||||
EnvVars: []string{"KEEPALIVE_INTERVAL"},
|
||||
Value: 45 * time.Second,
|
||||
Usage: "interval of keepalive messages",
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
cmdServe := &cli.Command{
|
||||
Name: "serve",
|
||||
Usage: "Run the server",
|
||||
UsageText: "serve [OPTIONS..]",
|
||||
Action: execServe,
|
||||
Flags: flagsServe,
|
||||
Before: initConfigFileInputSource("config", flagsServe),
|
||||
}
|
||||
|
||||
c := &cli.App{
|
||||
Name: "cmd",
|
||||
HideVersion: true,
|
||||
UseShortOptionHandling: true,
|
||||
Commands: []*cli.Command{
|
||||
cmdServe,
|
||||
},
|
||||
}
|
||||
|
||||
if err := c.Run([]string{"cmd", "serve", "--config", "../testdata/empty.yml"}); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// keepalive 45s
|
||||
}
|
@ -0,0 +1 @@
|
||||
cli.urfave.org
|
@ -0,0 +1 @@
|
||||
../CODE_OF_CONDUCT.md
|
@ -1,18 +1,143 @@
|
||||
## Contributing
|
||||
|
||||
Use @urfave/cli to ping the maintainers.
|
||||
|
||||
Feel free to put up a pull request to fix a bug or maybe add a feature. We will
|
||||
give it a code review and make sure that it does not break backwards
|
||||
compatibility. If collaborators agree that it is in line with
|
||||
the vision of the project, we will work with you to get the code into
|
||||
a mergeable state and merge it into the main branch.
|
||||
|
||||
If you have contributed something significant to the project, we will most
|
||||
likely add you as a collaborator. As a collaborator you are given the ability
|
||||
to merge others pull requests. It is very important that new code does not
|
||||
break existing code, so be careful about what code you do choose to merge.
|
||||
|
||||
If you feel like you have contributed to the project but have not yet been added
|
||||
as a collaborator, we probably forgot to add you :sweat_smile:. Please open an
|
||||
issue!
|
||||
Welcome to the `urfave/cli` contributor docs! This goal of this document is to help those
|
||||
interested in joining the 200+ humans who have contributed to this project over the years.
|
||||
|
||||
> As a general guiding principle, the current maintainers may be notified via the
|
||||
> @urfave/cli GitHub team.
|
||||
|
||||
All of the current maintainers are *volunteers* who live in various timezones with
|
||||
different scheduling needs, so please understand that your contribution or question may
|
||||
not get a response for many days.
|
||||
|
||||
### semantic versioning adherence
|
||||
|
||||
The `urfave/cli` project strives to strictly adhere to [semantic
|
||||
versioning](https://semver.org/spec/v2.0.0.html). The active development branches and the
|
||||
milestones and import paths to which they correspond are:
|
||||
|
||||
#### `main` branch
|
||||
|
||||
<https://github.com/urfave/cli/tree/main>
|
||||
|
||||
The majority of active development and issue management is targeting the `main` branch,
|
||||
which **MUST** *only* receive bug fixes and feature *additions*.
|
||||
|
||||
- :arrow_right: [`v2.x`](https://github.com/urfave/cli/milestone/16)
|
||||
- :arrow_right: `github.com/urfave/cli/v2`
|
||||
|
||||
The `main` branch in particular includes tooling to help with keeping the `v2.x` series
|
||||
backward compatible. More details on this process are in the development workflow section
|
||||
below.
|
||||
|
||||
#### `v1` branch
|
||||
|
||||
<https://github.com/urfave/cli/tree/v1>
|
||||
|
||||
The `v1` branch **MUST** only receive bug fixes in the `v1.22.x` series. There is no
|
||||
strict rule regarding bug fixes to the `v2.x` series being backported to the `v1.22.x`
|
||||
series.
|
||||
|
||||
- :arrow_right: [`v1.22.x`](https://github.com/urfave/cli/milestone/11)
|
||||
- :arrow_right: `github.com/urfave/cli`
|
||||
|
||||
#### `v3-dev-main` branch
|
||||
|
||||
<https://github.com/urfave/cli/tree/v3-dev-main>
|
||||
|
||||
The `v3-dev-branch` **MUST** receive all bug fixes and features added to the `main` branch
|
||||
and **MAY** receive feature *removals* and other changes that are otherwise
|
||||
*backward-incompatible* with the `v2.x` series.
|
||||
|
||||
- :arrow_right: [`v3.x`](https://github.com/urfave/cli/milestone/5)
|
||||
- unreleased / unsupported
|
||||
|
||||
### development workflow
|
||||
|
||||
Most of the tooling around the development workflow strives for effective
|
||||
[dogfooding](https://en.wikipedia.org/wiki/Eating_your_own_dog_food). There is a top-level
|
||||
`Makefile` that is maintained strictly for the purpose of easing verification of one's
|
||||
development environment and any changes one may have introduced:
|
||||
|
||||
```sh
|
||||
make
|
||||
```
|
||||
|
||||
Running the default `make` target (`all`) will ensure all of the critical steps are run to
|
||||
verify one's changes are harmonious in nature. The same steps are also run during the
|
||||
[continuous integration
|
||||
phase](https://github.com/urfave/cli/blob/main/.github/workflows/cli.yml).
|
||||
|
||||
In the event that the `v2diff` target exits non-zero, this is a signal that the public API
|
||||
surface area has changed. If the changes adhere to semantic versioning, meaning they are
|
||||
*additions* or *bug fixes*, then manually running the approval step will "promote" the
|
||||
current `go doc` output:
|
||||
|
||||
```sh
|
||||
make v2approve
|
||||
```
|
||||
|
||||
Because the `generate` step includes updating `godoc-current.txt` and
|
||||
`testdata/godoc-v2.x.txt`, these changes *MUST* be part of any proposed pull request so
|
||||
that reviewers have an opportunity to also make an informed decision about the "promotion"
|
||||
step.
|
||||
|
||||
#### generated code
|
||||
|
||||
A significant portion of the project's source code is generated, with the goal being to
|
||||
eliminate repetitive maintenance where other type-safe abstraction is impractical or
|
||||
impossible with Go versions `< 1.18`. In a future where the eldest Go version supported is
|
||||
`1.18.x`, there will likely be efforts to take advantage of
|
||||
[generics](https://go.dev/doc/tutorial/generics).
|
||||
|
||||
The built-in `go generate` command is used to run the commands specified in
|
||||
`//go:generate` directives. Each such command runs a file that also supports a command
|
||||
line help system which may be consulted for further information, e.g.:
|
||||
|
||||
```sh
|
||||
go run internal/genflags/cmd/genflags/main.go --help
|
||||
```
|
||||
|
||||
#### docs output
|
||||
|
||||
The documentation in the `docs` directory is automatically built via `mkdocs` into a
|
||||
static site and published when releases are pushed (see [RELEASING](./RELEASING/)). There
|
||||
is no strict requirement to build the documentation when developing locally, but the
|
||||
following `make` targets may be used if desired:
|
||||
|
||||
```sh
|
||||
# install documentation dependencies with `pip`
|
||||
make docs-deps
|
||||
```
|
||||
|
||||
```sh
|
||||
# build the static site in `./site`
|
||||
make docs
|
||||
```
|
||||
|
||||
```sh
|
||||
# start an mkdocs development server
|
||||
make serve-docs
|
||||
```
|
||||
|
||||
### pull requests
|
||||
|
||||
Please feel free to open a pull request to fix a bug or add a feature. The @urfave/cli
|
||||
team will review it as soon as possible, giving special attention to maintaining backward
|
||||
compatibility. If the @urfave/cli team agrees that your contribution is in line with the
|
||||
vision of the project, they will work with you to get the code into a mergeable state,
|
||||
merged, and then released.
|
||||
|
||||
### granting of commit bit / admin mode
|
||||
|
||||
Those with a history of contributing to this project will likely be invited to join the
|
||||
@urfave/cli team. As a member of the @urfave/cli team, you will have the ability to fully
|
||||
administer pull requests, issues, and other repository bits.
|
||||
|
||||
If you feel that you should be a member of the @urfave/cli team but have not yet been
|
||||
added, the most likely explanation is that this is an accidental oversight! :sweat_smile:.
|
||||
Please open an issue!
|
||||
|
||||
<!--
|
||||
vim:tw=90
|
||||
-->
|
||||
|
@ -0,0 +1,61 @@
|
||||
# Releasing urfave/cli
|
||||
|
||||
Releasing small batches often is [backed by
|
||||
research](https://itrevolution.com/accelerate-book/) as part of the
|
||||
virtuous cycles that keep teams and products healthy.
|
||||
|
||||
To that end, the overall goal of the release process is to send
|
||||
changes out into the world as close to the time the commits were
|
||||
merged to the `main` branch as possible. In this way, the community
|
||||
of humans depending on this library are able to make use of the
|
||||
changes they need **quickly**, which means they shouldn't have to
|
||||
maintain long-lived forks of the project, which means they can get
|
||||
back to focusing on the work on which they want to focus. This also
|
||||
means that the @urfave/cli team should be able to focus on
|
||||
delivering a steadily improving product with significantly eased
|
||||
ability to associate bugs and regressions with specific releases.
|
||||
|
||||
## Process
|
||||
|
||||
- Release versions follow [semantic versioning](https://semver.org/)
|
||||
- Releases are associated with **signed, annotated git tags**[^1].
|
||||
- Release notes are **automatically generated**[^2].
|
||||
|
||||
In the `main` or `v1` branch, the current version is always
|
||||
available via:
|
||||
|
||||
```sh
|
||||
git describe --always --dirty --tags
|
||||
```
|
||||
|
||||
**NOTE**: if the version reported contains `-dirty`, this is
|
||||
indicative of a "dirty" work tree, which is not a great state for
|
||||
creating a new release tag. Seek help from @urfave/cli teammates.
|
||||
|
||||
For example, given a described version of `v2.4.7-3-g68da1cd` and a
|
||||
diff of `v2.4.7...` that contains only bug fixes, the next version
|
||||
should be `v2.4.8`:
|
||||
|
||||
```sh
|
||||
git tag -a -s -m 'Release 2.4.8' v2.4.8
|
||||
git push origin v2.4.8
|
||||
```
|
||||
|
||||
The tag push will trigger a GitHub Actions workflow. The remaining
|
||||
steps require human intervention through the GitHub web view
|
||||
although [automated solutions
|
||||
exist](https://github.com/softprops/action-gh-release) that may be
|
||||
adopted in the future.
|
||||
|
||||
- Open the [the new release page](https://github.com/urfave/cli/releases/new)
|
||||
- At the top of the form, click on the `Choose a tag` select control and select `v2.4.8`
|
||||
- In the `Write` tab below, click the `Auto-generate release notes` button
|
||||
- At the bottom of the form, click the `Publish release` button
|
||||
- :white_check_mark: you're done!
|
||||
|
||||
[^1]: This was not always true. There are many **lightweight git
|
||||
tags** present in the repository history.
|
||||
|
||||
[^2]: This was not always true. The
|
||||
[`docs/CHANGELOG.md`](./CHANGELOG.md) document used to be
|
||||
manually maintained.
|
@ -0,0 +1,27 @@
|
||||
# Security Policy
|
||||
|
||||
Hello and thank you for your interest in the `urfave/cli` security
|
||||
policy! :tada: :lock:
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------------ | ------------------------------------- |
|
||||
| `>= v2.3.x` | :white_check_mark: |
|
||||
| `< v2.3` | :x: |
|
||||
| `>= v1.22.x` | :white_check_mark: :lady_beetle: [^1] |
|
||||
| `< v1.22` | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please disclose any vulnerabilities by sending an email to:
|
||||
|
||||
[urfave-security@googlegroups.com](mailto:urfave-security@googlegroups.com)
|
||||
|
||||
You should expect a response within 48 hours and further
|
||||
communications to be decided via email. The `urfave/cli` maintainer
|
||||
team comprises volunteers who contribute when possible, so please
|
||||
have patience :bow:
|
||||
|
||||
[^1]: The `v1.22.x` series will receive bug fixes and security
|
||||
patches only.
|
@ -0,0 +1,73 @@
|
||||
# Welcome to urfave/cli
|
||||
|
||||
[![GoDoc](https://godoc.org/github.com/urfave/cli?status.svg)](https://pkg.go.dev/github.com/urfave/cli/v2)
|
||||
[![codebeat](https://codebeat.co/badges/0a8f30aa-f975-404b-b878-5fab3ae1cc5f)](https://codebeat.co/projects/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/main/graph/badge.svg)](https://codecov.io/gh/urfave/cli)
|
||||
|
||||
`urfave/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.
|
||||
|
||||
These are the guides for each major supported version:
|
||||
|
||||
- [`v2`](./v2/)
|
||||
- [`v1`](./v1/)
|
||||
|
||||
In addition to the version-specific guides, these other documents are available:
|
||||
|
||||
- [CONTRIBUTING](./CONTRIBUTING/)
|
||||
- [CODE OF CONDUCT](./CODE_OF_CONDUCT/)
|
||||
- [RELEASING](./RELEASING/)
|
||||
|
||||
## Installation
|
||||
|
||||
Using this package requires a working Go environment. [See the install instructions for Go](http://golang.org/doc/install.html).
|
||||
|
||||
Go Modules are required when using this package. [See the go blog guide on using Go Modules](https://blog.golang.org/using-go-modules).
|
||||
|
||||
### Using `v2` releases
|
||||
|
||||
```
|
||||
$ go get github.com/urfave/cli/v2
|
||||
```
|
||||
|
||||
```go
|
||||
...
|
||||
import (
|
||||
"github.com/urfave/cli/v2" // imports as package "cli"
|
||||
)
|
||||
...
|
||||
```
|
||||
|
||||
### Using `v1` releases
|
||||
|
||||
```
|
||||
$ go get github.com/urfave/cli
|
||||
```
|
||||
|
||||
```go
|
||||
...
|
||||
import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
...
|
||||
```
|
||||
|
||||
### 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 fewer dependencies.
|
||||
|
||||
### 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. This project uses Github Actions
|
||||
for builds. To see our currently supported go versions and platforms, look at
|
||||
the [github workflow
|
||||
configuration](https://github.com/urfave/cli/blob/main/.github/workflows/cli.yml).
|
@ -0,0 +1 @@
|
||||
manual.md
|
@ -0,0 +1 @@
|
||||
manual.md
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,51 @@
|
||||
# NOTE: this file is used by the tool defined in
|
||||
# ./internal/genflags/cmd/genflags/main.go which uses the
|
||||
# `genflags.Spec` type that maps to this file structure.
|
||||
|
||||
flag_types:
|
||||
bool: {}
|
||||
float64: {}
|
||||
int64: {}
|
||||
int: {}
|
||||
time.Duration: {}
|
||||
uint64: {}
|
||||
uint: {}
|
||||
|
||||
string:
|
||||
struct_fields:
|
||||
- { name: TakesFile, type: bool }
|
||||
Generic:
|
||||
struct_fields:
|
||||
- { name: TakesFile, type: bool }
|
||||
Path:
|
||||
struct_fields:
|
||||
- { name: TakesFile, type: bool }
|
||||
|
||||
Float64Slice:
|
||||
value_pointer: true
|
||||
skip_interfaces:
|
||||
- fmt.Stringer
|
||||
Int64Slice:
|
||||
value_pointer: true
|
||||
skip_interfaces:
|
||||
- fmt.Stringer
|
||||
IntSlice:
|
||||
value_pointer: true
|
||||
skip_interfaces:
|
||||
- fmt.Stringer
|
||||
StringSlice:
|
||||
value_pointer: true
|
||||
skip_interfaces:
|
||||
- fmt.Stringer
|
||||
struct_fields:
|
||||
- { name: TakesFile, type: bool }
|
||||
Timestamp:
|
||||
value_pointer: true
|
||||
struct_fields:
|
||||
- { name: Layout, type: string }
|
||||
- { name: Timezone, type: "*time.Location" }
|
||||
|
||||
# TODO: enable UintSlice
|
||||
# UintSlice: {}
|
||||
# TODO: enable Uint64Slice once #1334 lands
|
||||
# Uint64Slice: {}
|
@ -1,9 +1,13 @@
|
||||
module github.com/urfave/cli/v2
|
||||
|
||||
go 1.11
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
github.com/BurntSushi/toml v1.1.0
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673
|
||||
golang.org/x/text v0.3.7
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
|
@ -1,10 +1,18 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
|
||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
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/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,163 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
_ "embed"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v2/internal/genflags"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultPackageName = "cli"
|
||||
)
|
||||
|
||||
func sh(ctx context.Context, exe string, args ...string) (string, error) {
|
||||
cmd := exec.CommandContext(ctx, exe, args...)
|
||||
cmd.Stderr = os.Stderr
|
||||
outBytes, err := cmd.Output()
|
||||
return string(outBytes), err
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
top := "../../"
|
||||
if v, err := sh(ctx, "git", "rev-parse", "--show-toplevel"); err == nil {
|
||||
top = strings.TrimSpace(v)
|
||||
}
|
||||
|
||||
app := &cli.App{
|
||||
Name: "genflags",
|
||||
Usage: "Generate flag types for urfave/cli",
|
||||
Flags: []cli.Flag{
|
||||
&cli.PathFlag{
|
||||
Name: "flag-spec-yaml",
|
||||
Aliases: []string{"f"},
|
||||
Value: filepath.Join(top, "flag-spec.yaml"),
|
||||
},
|
||||
&cli.PathFlag{
|
||||
Name: "generated-output",
|
||||
Aliases: []string{"o"},
|
||||
Value: filepath.Join(top, "zz_generated.flags.go"),
|
||||
},
|
||||
&cli.PathFlag{
|
||||
Name: "generated-test-output",
|
||||
Aliases: []string{"t"},
|
||||
Value: filepath.Join(top, "zz_generated.flags_test.go"),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "generated-package-name",
|
||||
Aliases: []string{"p"},
|
||||
Value: defaultPackageName,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "generated-test-package-name",
|
||||
Aliases: []string{"T"},
|
||||
Value: defaultPackageName + "_test",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "urfave-cli-namespace",
|
||||
Aliases: []string{"n"},
|
||||
Value: "",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "urfave-cli-test-namespace",
|
||||
Aliases: []string{"N"},
|
||||
Value: "cli.",
|
||||
},
|
||||
},
|
||||
Action: runGenFlags,
|
||||
}
|
||||
|
||||
if err := app.RunContext(ctx, os.Args); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func runGenFlags(cCtx *cli.Context) error {
|
||||
specBytes, err := os.ReadFile(cCtx.Path("flag-spec-yaml"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
spec := &genflags.Spec{}
|
||||
if err := yaml.Unmarshal(specBytes, spec); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cCtx.IsSet("generated-package-name") {
|
||||
spec.PackageName = strings.TrimSpace(cCtx.String("generated-package-name"))
|
||||
}
|
||||
|
||||
if strings.TrimSpace(spec.PackageName) == "" {
|
||||
spec.PackageName = defaultPackageName
|
||||
}
|
||||
|
||||
if cCtx.IsSet("generated-test-package-name") {
|
||||
spec.TestPackageName = strings.TrimSpace(cCtx.String("generated-test-package-name"))
|
||||
}
|
||||
|
||||
if strings.TrimSpace(spec.TestPackageName) == "" {
|
||||
spec.TestPackageName = defaultPackageName + "_test"
|
||||
}
|
||||
|
||||
if cCtx.IsSet("urfave-cli-namespace") {
|
||||
spec.UrfaveCLINamespace = strings.TrimSpace(cCtx.String("urfave-cli-namespace"))
|
||||
}
|
||||
|
||||
if cCtx.IsSet("urfave-cli-test-namespace") {
|
||||
spec.UrfaveCLITestNamespace = strings.TrimSpace(cCtx.String("urfave-cli-test-namespace"))
|
||||
} else {
|
||||
spec.UrfaveCLITestNamespace = "cli."
|
||||
}
|
||||
|
||||
genTmpl, err := template.New("gen").Parse(genflags.TemplateString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
genTestTmpl, err := template.New("gen_test").Parse(genflags.TestTemplateString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
genBuf := &bytes.Buffer{}
|
||||
if err := genTmpl.Execute(genBuf, spec); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
genTestBuf := &bytes.Buffer{}
|
||||
if err := genTestTmpl.Execute(genTestBuf, spec); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.WriteFile(cCtx.Path("generated-output"), genBuf.Bytes(), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.WriteFile(cCtx.Path("generated-test-output"), genTestBuf.Bytes(), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sh(cCtx.Context, "goimports", "-w", cCtx.Path("generated-output")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sh(cCtx.Context, "goimports", "-w", cCtx.Path("generated-test-output")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
// WARNING: this file is generated. DO NOT EDIT
|
||||
|
||||
package {{.PackageName}}
|
||||
|
||||
{{range .SortedFlagTypes}}
|
||||
// {{.TypeName}} is a flag with type {{if .ValuePointer}}*{{end}}{{.GoType}}
|
||||
type {{.TypeName}} struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value {{if .ValuePointer}}*{{end}}{{.GoType}}
|
||||
Destination *{{.GoType}}
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
|
||||
{{range .StructFields}}
|
||||
{{.Name}} {{.Type}}
|
||||
{{end}}
|
||||
}
|
||||
|
||||
{{if .GenerateFmtStringerInterface}}
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *{{.TypeName}}) String() string {
|
||||
return {{$.UrfaveCLINamespace}}FlagStringer(f)
|
||||
}
|
||||
{{end}}{{/* /if .GenerateFmtStringerInterface */}}
|
||||
|
||||
{{if .GenerateFlagInterface}}
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *{{.TypeName}}) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *{{.TypeName}}) Names() []string {
|
||||
return {{$.UrfaveCLINamespace}}FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
{{end}}{{/* /if .GenerateFlagInterface */}}
|
||||
|
||||
{{if .GenerateRequiredFlagInterface}}
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *{{.TypeName}}) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
{{end}}{{/* /if .GenerateRequiredFlagInterface */}}
|
||||
|
||||
{{if .GenerateVisibleFlagInterface}}
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *{{.TypeName}}) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
{{end}}{{/* /if .GenerateVisibleFlagInterface */}}
|
||||
{{end}}{{/* /range .SortedFlagTypes */}}
|
||||
|
||||
// vim{{/* 👻 */}}:ro
|
||||
{{/*
|
||||
vim:filetype=gotexttmpl
|
||||
*/}}
|
@ -0,0 +1,43 @@
|
||||
// WARNING: this file is generated. DO NOT EDIT
|
||||
|
||||
package {{.TestPackageName}}
|
||||
|
||||
{{range .SortedFlagTypes}}
|
||||
{{if .GenerateFlagInterface}}
|
||||
func Test{{.TypeName}}_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f {{$.UrfaveCLITestNamespace}}Flag = &{{$.UrfaveCLITestNamespace}}{{.TypeName}}{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{if .GenerateFmtStringerInterface}}
|
||||
func Test{{.TypeName}}_SatisfiesFmtStringerInterface(t *testing.T) {
|
||||
var f fmt.Stringer = &{{$.UrfaveCLITestNamespace}}{{.TypeName}}{}
|
||||
|
||||
_ = f.String()
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{if .GenerateRequiredFlagInterface}}
|
||||
func Test{{.TypeName}}_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f {{$.UrfaveCLITestNamespace}}RequiredFlag = &{{$.UrfaveCLITestNamespace}}{{.TypeName}}{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{if .GenerateVisibleFlagInterface}}
|
||||
func Test{{.TypeName}}_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f {{$.UrfaveCLITestNamespace}}VisibleFlag = &{{$.UrfaveCLITestNamespace}}{{.TypeName}}{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
// vim{{/* 👻 */}}:ro
|
||||
{{/*
|
||||
vim:filetype=gotexttmpl
|
||||
*/}}
|
@ -0,0 +1,34 @@
|
||||
package genflags
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed generated.gotmpl
|
||||
TemplateString string
|
||||
|
||||
//go:embed generated_test.gotmpl
|
||||
TestTemplateString string
|
||||
|
||||
titler = cases.Title(language.Und, cases.NoLower)
|
||||
)
|
||||
|
||||
func TypeName(goType string, fc *FlagTypeConfig) string {
|
||||
if fc != nil && strings.TrimSpace(fc.TypeName) != "" {
|
||||
return strings.TrimSpace(fc.TypeName)
|
||||
}
|
||||
|
||||
dotSplit := strings.Split(goType, ".")
|
||||
goType = dotSplit[len(dotSplit)-1]
|
||||
|
||||
if strings.HasPrefix(goType, "[]") {
|
||||
return titler.String(strings.TrimPrefix(goType, "[]")) + "SliceFlag"
|
||||
}
|
||||
|
||||
return titler.String(goType) + "Flag"
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package genflags_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2/internal/genflags"
|
||||
)
|
||||
|
||||
func TestTypeName(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
gt string
|
||||
fc *genflags.FlagTypeConfig
|
||||
expected string
|
||||
}{
|
||||
{gt: "int", fc: nil, expected: "IntFlag"},
|
||||
{gt: "int", fc: &genflags.FlagTypeConfig{}, expected: "IntFlag"},
|
||||
{gt: "int", fc: &genflags.FlagTypeConfig{TypeName: "VeryIntyFlag"}, expected: "VeryIntyFlag"},
|
||||
{gt: "[]bool", fc: nil, expected: "BoolSliceFlag"},
|
||||
{gt: "[]bool", fc: &genflags.FlagTypeConfig{}, expected: "BoolSliceFlag"},
|
||||
{gt: "[]bool", fc: &genflags.FlagTypeConfig{TypeName: "ManyTruthsFlag"}, expected: "ManyTruthsFlag"},
|
||||
{gt: "time.Rumination", fc: nil, expected: "RuminationFlag"},
|
||||
{gt: "time.Rumination", fc: &genflags.FlagTypeConfig{}, expected: "RuminationFlag"},
|
||||
{gt: "time.Rumination", fc: &genflags.FlagTypeConfig{TypeName: "PonderFlag"}, expected: "PonderFlag"},
|
||||
} {
|
||||
t.Run(
|
||||
fmt.Sprintf("type=%s,cfg=%v", tc.gt, func() string {
|
||||
if tc.fc != nil {
|
||||
return tc.fc.TypeName
|
||||
}
|
||||
return "nil"
|
||||
}()),
|
||||
func(ct *testing.T) {
|
||||
actual := genflags.TypeName(tc.gt, tc.fc)
|
||||
if tc.expected != actual {
|
||||
ct.Errorf("expected %q, got %q", tc.expected, actual)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package genflags
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Spec struct {
|
||||
FlagTypes map[string]*FlagTypeConfig `yaml:"flag_types"`
|
||||
PackageName string `yaml:"package_name"`
|
||||
TestPackageName string `yaml:"test_package_name"`
|
||||
UrfaveCLINamespace string `yaml:"urfave_cli_namespace"`
|
||||
UrfaveCLITestNamespace string `yaml:"urfave_cli_test_namespace"`
|
||||
}
|
||||
|
||||
func (gfs *Spec) SortedFlagTypes() []*FlagType {
|
||||
typeNames := []string{}
|
||||
|
||||
for name := range gfs.FlagTypes {
|
||||
if strings.HasPrefix(name, "[]") {
|
||||
name = strings.TrimPrefix(name, "[]") + "Slice"
|
||||
}
|
||||
|
||||
typeNames = append(typeNames, name)
|
||||
}
|
||||
|
||||
sort.Strings(typeNames)
|
||||
|
||||
ret := make([]*FlagType, len(typeNames))
|
||||
|
||||
for i, typeName := range typeNames {
|
||||
ret[i] = &FlagType{
|
||||
GoType: typeName,
|
||||
Config: gfs.FlagTypes[typeName],
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
type FlagTypeConfig struct {
|
||||
SkipInterfaces []string `yaml:"skip_interfaces"`
|
||||
StructFields []*FlagStructField `yaml:"struct_fields"`
|
||||
TypeName string `yaml:"type_name"`
|
||||
ValuePointer bool `yaml:"value_pointer"`
|
||||
}
|
||||
|
||||
type FlagStructField struct {
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
type FlagType struct {
|
||||
GoType string
|
||||
Config *FlagTypeConfig
|
||||
}
|
||||
|
||||
func (ft *FlagType) StructFields() []*FlagStructField {
|
||||
if ft.Config == nil || ft.Config.StructFields == nil {
|
||||
return []*FlagStructField{}
|
||||
}
|
||||
|
||||
return ft.Config.StructFields
|
||||
}
|
||||
|
||||
func (ft *FlagType) ValuePointer() bool {
|
||||
if ft.Config == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return ft.Config.ValuePointer
|
||||
}
|
||||
|
||||
func (ft *FlagType) TypeName() string {
|
||||
return TypeName(ft.GoType, ft.Config)
|
||||
}
|
||||
|
||||
func (ft *FlagType) GenerateFmtStringerInterface() bool {
|
||||
return ft.skipInterfaceNamed("fmt.Stringer")
|
||||
}
|
||||
|
||||
func (ft *FlagType) GenerateFlagInterface() bool {
|
||||
return ft.skipInterfaceNamed("Flag")
|
||||
}
|
||||
|
||||
func (ft *FlagType) GenerateRequiredFlagInterface() bool {
|
||||
return ft.skipInterfaceNamed("RequiredFlag")
|
||||
}
|
||||
|
||||
func (ft *FlagType) GenerateVisibleFlagInterface() bool {
|
||||
return ft.skipInterfaceNamed("VisibleFlag")
|
||||
}
|
||||
|
||||
func (ft *FlagType) skipInterfaceNamed(name string) bool {
|
||||
if ft.Config == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
lowName := strings.ToLower(name)
|
||||
|
||||
for _, interfaceName := range ft.Config.SkipInterfaces {
|
||||
if strings.ToLower(interfaceName) == lowName {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
package genflags_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2/internal/genflags"
|
||||
)
|
||||
|
||||
func TestSpec_SortedFlagTypes(t *testing.T) {
|
||||
spec := &genflags.Spec{
|
||||
FlagTypes: map[string]*genflags.FlagTypeConfig{
|
||||
"nerf": &genflags.FlagTypeConfig{},
|
||||
"gerf": nil,
|
||||
},
|
||||
}
|
||||
|
||||
actual := spec.SortedFlagTypes()
|
||||
expected := []*genflags.FlagType{
|
||||
{
|
||||
GoType: "gerf",
|
||||
Config: nil,
|
||||
},
|
||||
{
|
||||
GoType: "nerf",
|
||||
Config: &genflags.FlagTypeConfig{},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("expected %#v, got %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func genFlagType() *genflags.FlagType {
|
||||
return &genflags.FlagType{
|
||||
GoType: "blerf",
|
||||
Config: &genflags.FlagTypeConfig{
|
||||
SkipInterfaces: []string{"fmt.Stringer"},
|
||||
StructFields: []*genflags.FlagStructField{
|
||||
{
|
||||
Name: "Foibles",
|
||||
Type: "int",
|
||||
},
|
||||
{
|
||||
Name: "Hoopled",
|
||||
Type: "bool",
|
||||
},
|
||||
},
|
||||
TypeName: "YeOldeBlerfFlag",
|
||||
ValuePointer: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlagType_StructFields(t *testing.T) {
|
||||
ft := genFlagType()
|
||||
|
||||
sf := ft.StructFields()
|
||||
if 2 != len(sf) {
|
||||
t.Errorf("expected 2 struct fields, got %v", len(sf))
|
||||
return
|
||||
}
|
||||
|
||||
if "Foibles" != sf[0].Name {
|
||||
t.Errorf("expected struct field order to be retained")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlagType_ValuePointer(t *testing.T) {
|
||||
ft := genFlagType()
|
||||
|
||||
if !ft.ValuePointer() {
|
||||
t.Errorf("expected ValuePointer to be true")
|
||||
return
|
||||
}
|
||||
|
||||
ft.Config = nil
|
||||
|
||||
if ft.ValuePointer() {
|
||||
t.Errorf("expected ValuePointer to be false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlagType_GenerateFmtStringerInterface(t *testing.T) {
|
||||
ft := genFlagType()
|
||||
|
||||
if ft.GenerateFmtStringerInterface() {
|
||||
t.Errorf("expected GenerateFmtStringerInterface to be false")
|
||||
return
|
||||
}
|
||||
|
||||
ft.Config = nil
|
||||
|
||||
if !ft.GenerateFmtStringerInterface() {
|
||||
t.Errorf("expected GenerateFmtStringerInterface to be true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlagType_GenerateFlagInterface(t *testing.T) {
|
||||
ft := genFlagType()
|
||||
|
||||
if !ft.GenerateFlagInterface() {
|
||||
t.Errorf("expected GenerateFlagInterface to be true")
|
||||
return
|
||||
}
|
||||
|
||||
ft.Config = nil
|
||||
|
||||
if !ft.GenerateFlagInterface() {
|
||||
t.Errorf("expected GenerateFlagInterface to be true")
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
mkdocs-git-revision-date-localized-plugin~=1.0
|
||||
mkdocs-material-extensions~=1.0
|
||||
mkdocs-material~=8.2
|
||||
mkdocs~=1.3
|
||||
pygments~=2.12
|
@ -0,0 +1,62 @@
|
||||
# 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: index.md
|
||||
- v2 Manual: v2/index.md
|
||||
- v1 Manual: v1/index.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
|
||||
plugins:
|
||||
- git-revision-date-localized
|
||||
- search
|
||||
# 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:materialx.emoji.twemoji
|
||||
emoji_generator: !!python/name:materialx.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
|
@ -0,0 +1,293 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type (
|
||||
// SliceFlag extends implementations like StringSliceFlag and IntSliceFlag with support for using slices directly,
|
||||
// as Value and/or Destination.
|
||||
// See also SliceFlagTarget, MultiStringFlag, MultiFloat64Flag, MultiInt64Flag, MultiIntFlag.
|
||||
SliceFlag[T SliceFlagTarget[E], S ~[]E, E any] struct {
|
||||
Target T
|
||||
Value S
|
||||
Destination *S
|
||||
}
|
||||
|
||||
// SliceFlagTarget models a target implementation for use with SliceFlag.
|
||||
// The three methods, SetValue, SetDestination, and GetDestination, are necessary to propagate Value and
|
||||
// Destination, where Value is propagated inwards (initially), and Destination is propagated outwards (on every
|
||||
// update).
|
||||
SliceFlagTarget[E any] interface {
|
||||
Flag
|
||||
RequiredFlag
|
||||
DocGenerationFlag
|
||||
VisibleFlag
|
||||
CategorizableFlag
|
||||
|
||||
// SetValue should propagate the given slice to the target, ideally as a new value.
|
||||
// Note that a nil slice should nil/clear any existing value (modelled as ~[]E).
|
||||
SetValue(slice []E)
|
||||
// SetDestination should propagate the given slice to the target, ideally as a new value.
|
||||
// Note that a nil slice should nil/clear any existing value (modelled as ~*[]E).
|
||||
SetDestination(slice []E)
|
||||
// GetDestination should return the current value referenced by any destination, or nil if nil/unset.
|
||||
GetDestination() []E
|
||||
}
|
||||
|
||||
// MultiStringFlag extends StringSliceFlag with support for using slices directly, as Value and/or Destination.
|
||||
// See also SliceFlag.
|
||||
MultiStringFlag = SliceFlag[*StringSliceFlag, []string, string]
|
||||
|
||||
// MultiFloat64Flag extends Float64SliceFlag with support for using slices directly, as Value and/or Destination.
|
||||
// See also SliceFlag.
|
||||
MultiFloat64Flag = SliceFlag[*Float64SliceFlag, []float64, float64]
|
||||
|
||||
// MultiInt64Flag extends Int64SliceFlag with support for using slices directly, as Value and/or Destination.
|
||||
// See also SliceFlag.
|
||||
MultiInt64Flag = SliceFlag[*Int64SliceFlag, []int64, int64]
|
||||
|
||||
// MultiIntFlag extends IntSliceFlag with support for using slices directly, as Value and/or Destination.
|
||||
// See also SliceFlag.
|
||||
MultiIntFlag = SliceFlag[*IntSliceFlag, []int, int]
|
||||
|
||||
flagValueHook struct {
|
||||
value Generic
|
||||
hook func()
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// compile time assertions
|
||||
|
||||
_ SliceFlagTarget[string] = (*StringSliceFlag)(nil)
|
||||
_ SliceFlagTarget[string] = (*SliceFlag[*StringSliceFlag, []string, string])(nil)
|
||||
_ SliceFlagTarget[string] = (*MultiStringFlag)(nil)
|
||||
_ SliceFlagTarget[float64] = (*MultiFloat64Flag)(nil)
|
||||
_ SliceFlagTarget[int64] = (*MultiInt64Flag)(nil)
|
||||
_ SliceFlagTarget[int] = (*MultiIntFlag)(nil)
|
||||
|
||||
_ Generic = (*flagValueHook)(nil)
|
||||
_ Serializer = (*flagValueHook)(nil)
|
||||
)
|
||||
|
||||
func (x *SliceFlag[T, S, E]) Apply(set *flag.FlagSet) error {
|
||||
x.Target.SetValue(x.convertSlice(x.Value))
|
||||
|
||||
destination := x.Destination
|
||||
if destination == nil {
|
||||
x.Target.SetDestination(nil)
|
||||
|
||||
return x.Target.Apply(set)
|
||||
}
|
||||
|
||||
x.Target.SetDestination(x.convertSlice(*destination))
|
||||
|
||||
return applyFlagValueHook(set, x.Target.Apply, func() {
|
||||
*destination = x.Target.GetDestination()
|
||||
})
|
||||
}
|
||||
|
||||
func (x *SliceFlag[T, S, E]) convertSlice(slice S) []E {
|
||||
result := make([]E, len(slice))
|
||||
copy(result, slice)
|
||||
return result
|
||||
}
|
||||
|
||||
func (x *SliceFlag[T, S, E]) SetValue(slice S) {
|
||||
x.Value = slice
|
||||
}
|
||||
|
||||
func (x *SliceFlag[T, S, E]) SetDestination(slice S) {
|
||||
if slice != nil {
|
||||
x.Destination = &slice
|
||||
} else {
|
||||
x.Destination = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SliceFlag[T, S, E]) GetDestination() S {
|
||||
if destination := x.Destination; destination != nil {
|
||||
return *destination
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SliceFlag[T, S, E]) String() string { return x.Target.String() }
|
||||
func (x *SliceFlag[T, S, E]) Names() []string { return x.Target.Names() }
|
||||
func (x *SliceFlag[T, S, E]) IsSet() bool { return x.Target.IsSet() }
|
||||
func (x *SliceFlag[T, S, E]) IsRequired() bool { return x.Target.IsRequired() }
|
||||
func (x *SliceFlag[T, S, E]) TakesValue() bool { return x.Target.TakesValue() }
|
||||
func (x *SliceFlag[T, S, E]) GetUsage() string { return x.Target.GetUsage() }
|
||||
func (x *SliceFlag[T, S, E]) GetValue() string { return x.Target.GetValue() }
|
||||
func (x *SliceFlag[T, S, E]) GetDefaultText() string { return x.Target.GetDefaultText() }
|
||||
func (x *SliceFlag[T, S, E]) GetEnvVars() []string { return x.Target.GetEnvVars() }
|
||||
func (x *SliceFlag[T, S, E]) IsVisible() bool { return x.Target.IsVisible() }
|
||||
func (x *SliceFlag[T, S, E]) GetCategory() string { return x.Target.GetCategory() }
|
||||
|
||||
func (x *flagValueHook) Set(value string) error {
|
||||
if err := x.value.Set(value); err != nil {
|
||||
return err
|
||||
}
|
||||
x.hook()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *flagValueHook) String() string {
|
||||
// note: this is necessary due to the way Go's flag package handles defaults
|
||||
isZeroValue := func(f flag.Value, v string) bool {
|
||||
/*
|
||||
https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/flag/flag.go;drc=2580d0e08d5e9f979b943758d3c49877fb2324cb;l=453
|
||||
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
// Build a zero value of the flag's Value type, and see if the
|
||||
// result of calling its String method equals the value passed in.
|
||||
// This works unless the Value type is itself an interface type.
|
||||
typ := reflect.TypeOf(f)
|
||||
var z reflect.Value
|
||||
if typ.Kind() == reflect.Pointer {
|
||||
z = reflect.New(typ.Elem())
|
||||
} else {
|
||||
z = reflect.Zero(typ)
|
||||
}
|
||||
return v == z.Interface().(flag.Value).String()
|
||||
}
|
||||
if x.value != nil {
|
||||
// only return non-empty if not the same string as returned by the zero value
|
||||
if s := x.value.String(); !isZeroValue(x.value, s) {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ``
|
||||
}
|
||||
|
||||
func (x *flagValueHook) Serialize() string {
|
||||
if value, ok := x.value.(Serializer); ok {
|
||||
return value.Serialize()
|
||||
}
|
||||
return x.String()
|
||||
}
|
||||
|
||||
// applyFlagValueHook wraps calls apply then wraps flags to call a hook function on update and after initial apply.
|
||||
func applyFlagValueHook(set *flag.FlagSet, apply func(set *flag.FlagSet) error, hook func()) error {
|
||||
if apply == nil || set == nil || hook == nil {
|
||||
panic(`invalid input`)
|
||||
}
|
||||
var tmp flag.FlagSet
|
||||
if err := apply(&tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
tmp.VisitAll(func(f *flag.Flag) { set.Var(&flagValueHook{value: f.Value, hook: hook}, f.Name, f.Usage) })
|
||||
hook()
|
||||
return nil
|
||||
}
|
||||
|
||||
// newSliceFlagValue is for implementing SliceFlagTarget.SetValue and SliceFlagTarget.SetDestination.
|
||||
// It's e.g. as part of StringSliceFlag.SetValue, using the factory NewStringSlice.
|
||||
func newSliceFlagValue[R any, S ~[]E, E any](factory func(defaults ...E) *R, defaults S) *R {
|
||||
if defaults == nil {
|
||||
return nil
|
||||
}
|
||||
return factory(defaults...)
|
||||
}
|
||||
|
||||
// unwrapFlagValue strips any/all *flagValueHook wrappers.
|
||||
func unwrapFlagValue(v flag.Value) flag.Value {
|
||||
for {
|
||||
h, ok := v.(*flagValueHook)
|
||||
if !ok {
|
||||
return v
|
||||
}
|
||||
v = h.value
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: the methods below are in this file to make use of the build constraint
|
||||
|
||||
func (f *Float64SliceFlag) SetValue(slice []float64) {
|
||||
f.Value = newSliceFlagValue(NewFloat64Slice, slice)
|
||||
}
|
||||
|
||||
func (f *Float64SliceFlag) SetDestination(slice []float64) {
|
||||
f.Destination = newSliceFlagValue(NewFloat64Slice, slice)
|
||||
}
|
||||
|
||||
func (f *Float64SliceFlag) GetDestination() []float64 {
|
||||
if destination := f.Destination; destination != nil {
|
||||
return destination.Value()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Int64SliceFlag) SetValue(slice []int64) {
|
||||
f.Value = newSliceFlagValue(NewInt64Slice, slice)
|
||||
}
|
||||
|
||||
func (f *Int64SliceFlag) SetDestination(slice []int64) {
|
||||
f.Destination = newSliceFlagValue(NewInt64Slice, slice)
|
||||
}
|
||||
|
||||
func (f *Int64SliceFlag) GetDestination() []int64 {
|
||||
if destination := f.Destination; destination != nil {
|
||||
return destination.Value()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *IntSliceFlag) SetValue(slice []int) {
|
||||
f.Value = newSliceFlagValue(NewIntSlice, slice)
|
||||
}
|
||||
|
||||
func (f *IntSliceFlag) SetDestination(slice []int) {
|
||||
f.Destination = newSliceFlagValue(NewIntSlice, slice)
|
||||
}
|
||||
|
||||
func (f *IntSliceFlag) GetDestination() []int {
|
||||
if destination := f.Destination; destination != nil {
|
||||
return destination.Value()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *StringSliceFlag) SetValue(slice []string) {
|
||||
f.Value = newSliceFlagValue(NewStringSlice, slice)
|
||||
}
|
||||
|
||||
func (f *StringSliceFlag) SetDestination(slice []string) {
|
||||
f.Destination = newSliceFlagValue(NewStringSlice, slice)
|
||||
}
|
||||
|
||||
func (f *StringSliceFlag) GetDestination() []string {
|
||||
if destination := f.Destination; destination != nil {
|
||||
return destination.Value()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
)
|
||||
|
||||
func unwrapFlagValue(v flag.Value) flag.Value { return v }
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,60 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/xrash/smetrics"
|
||||
)
|
||||
|
||||
func jaroWinkler(a, b string) float64 {
|
||||
// magic values are from https://github.com/xrash/smetrics/blob/039620a656736e6ad994090895784a7af15e0b80/jaro-winkler.go#L8
|
||||
const (
|
||||
boostThreshold = 0.7
|
||||
prefixSize = 4
|
||||
)
|
||||
return smetrics.JaroWinkler(a, b, boostThreshold, prefixSize)
|
||||
}
|
||||
|
||||
func suggestFlag(flags []Flag, provided string, hideHelp bool) string {
|
||||
distance := 0.0
|
||||
suggestion := ""
|
||||
|
||||
for _, flag := range flags {
|
||||
flagNames := flag.Names()
|
||||
if !hideHelp {
|
||||
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 fmt.Sprintf(SuggestDidYouMeanTemplate, suggestion)
|
||||
}
|
@ -0,0 +1,187 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSuggestFlag(t *testing.T) {
|
||||
// Given
|
||||
app := testApp()
|
||||
|
||||
for _, testCase := range []struct {
|
||||
provided, expected string
|
||||
}{
|
||||
{"", ""},
|
||||
{"a", "--another-flag"},
|
||||
{"hlp", "--help"},
|
||||
{"k", ""},
|
||||
{"s", "-s"},
|
||||
} {
|
||||
// When
|
||||
res := suggestFlag(app.Flags, testCase.provided, false)
|
||||
|
||||
// Then
|
||||
expect(t, res, testCase.expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSuggestFlagHideHelp(t *testing.T) {
|
||||
// Given
|
||||
app := testApp()
|
||||
|
||||
// When
|
||||
res := suggestFlag(app.Flags, "hlp", true)
|
||||
|
||||
// Then
|
||||
expect(t, res, "--fl")
|
||||
}
|
||||
|
||||
func TestSuggestFlagFromError(t *testing.T) {
|
||||
// Given
|
||||
app := testApp()
|
||||
|
||||
for _, testCase := range []struct {
|
||||
command, provided, expected string
|
||||
}{
|
||||
{"", "hel", "--help"},
|
||||
{"", "soccer", "--socket"},
|
||||
{"config", "anot", "--another-flag"},
|
||||
} {
|
||||
// When
|
||||
res, _ := app.suggestFlagFromError(
|
||||
errors.New(providedButNotDefinedErrMsg+testCase.provided),
|
||||
testCase.command,
|
||||
)
|
||||
|
||||
// Then
|
||||
expect(t, res, fmt.Sprintf(SuggestDidYouMeanTemplate+"\n\n", testCase.expected))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSuggestFlagFromErrorWrongError(t *testing.T) {
|
||||
// Given
|
||||
app := testApp()
|
||||
|
||||
// When
|
||||
_, err := app.suggestFlagFromError(errors.New("invalid"), "")
|
||||
|
||||
// Then
|
||||
expect(t, true, err != nil)
|
||||
}
|
||||
|
||||
func TestSuggestFlagFromErrorWrongCommand(t *testing.T) {
|
||||
// Given
|
||||
app := testApp()
|
||||
|
||||
// When
|
||||
_, err := app.suggestFlagFromError(
|
||||
errors.New(providedButNotDefinedErrMsg+"flag"),
|
||||
"invalid",
|
||||
)
|
||||
|
||||
// Then
|
||||
expect(t, true, err != nil)
|
||||
}
|
||||
|
||||
func TestSuggestFlagFromErrorNoSuggestion(t *testing.T) {
|
||||
// Given
|
||||
app := testApp()
|
||||
|
||||
// When
|
||||
_, err := app.suggestFlagFromError(
|
||||
errors.New(providedButNotDefinedErrMsg+""),
|
||||
"",
|
||||
)
|
||||
|
||||
// Then
|
||||
expect(t, true, err != nil)
|
||||
}
|
||||
|
||||
func TestSuggestCommand(t *testing.T) {
|
||||
// Given
|
||||
app := testApp()
|
||||
|
||||
for _, testCase := range []struct {
|
||||
provided, expected string
|
||||
}{
|
||||
{"", ""},
|
||||
{"conf", "config"},
|
||||
{"i", "i"},
|
||||
{"information", "info"},
|
||||
{"not-existing", "info"},
|
||||
} {
|
||||
// When
|
||||
res := suggestCommand(app.Commands, testCase.provided)
|
||||
|
||||
// Then
|
||||
expect(t, res, fmt.Sprintf(SuggestDidYouMeanTemplate, testCase.expected))
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleApp_Suggest() {
|
||||
app := &App{
|
||||
Name: "greet",
|
||||
Suggest: true,
|
||||
HideHelp: true,
|
||||
HideHelpCommand: true,
|
||||
CustomAppHelpTemplate: "(this space intentionally left blank)\n",
|
||||
Flags: []Flag{
|
||||
&StringFlag{Name: "name", Value: "squirrel", Usage: "a name to say"},
|
||||
},
|
||||
Action: func(cCtx *Context) error {
|
||||
fmt.Printf("Hello %v\n", cCtx.String("name"))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
app.Run([]string{"greet", "--nema", "chipmunk"})
|
||||
// Output:
|
||||
// Incorrect Usage. flag provided but not defined: -nema
|
||||
//
|
||||
// Did you mean "--name"?
|
||||
//
|
||||
// (this space intentionally left blank)
|
||||
}
|
||||
|
||||
func ExampleApp_Suggest_command() {
|
||||
app := &App{
|
||||
Name: "greet",
|
||||
Suggest: true,
|
||||
HideHelp: true,
|
||||
HideHelpCommand: true,
|
||||
CustomAppHelpTemplate: "(this space intentionally left blank)\n",
|
||||
Flags: []Flag{
|
||||
&StringFlag{Name: "name", Value: "squirrel", Usage: "a name to say"},
|
||||
},
|
||||
Action: func(cCtx *Context) error {
|
||||
fmt.Printf("Hello %v\n", cCtx.String("name"))
|
||||
return nil
|
||||
},
|
||||
Commands: []*Command{
|
||||
{
|
||||
Name: "neighbors",
|
||||
CustomHelpTemplate: "(this space intentionally left blank)\n",
|
||||
Flags: []Flag{
|
||||
&BoolFlag{Name: "smiling"},
|
||||
},
|
||||
Action: func(cCtx *Context) error {
|
||||
if cCtx.Bool("smiling") {
|
||||
fmt.Println("😀")
|
||||
}
|
||||
fmt.Println("Hello, neighbors")
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run([]string{"greet", "neighbors", "--sliming"})
|
||||
// Output:
|
||||
// Incorrect Usage: flag provided but not defined: -sliming
|
||||
//
|
||||
// Did you mean "--smiling"?
|
||||
//
|
||||
// (this space intentionally left blank)
|
||||
}
|
@ -0,0 +1 @@
|
||||
# empty file
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,674 @@
|
||||
// WARNING: this file is generated. DO NOT EDIT
|
||||
|
||||
package cli
|
||||
|
||||
import "time"
|
||||
|
||||
// Float64SliceFlag is a flag with type *Float64Slice
|
||||
type Float64SliceFlag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value *Float64Slice
|
||||
Destination *Float64Slice
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *Float64SliceFlag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *Float64SliceFlag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *Float64SliceFlag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *Float64SliceFlag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// GenericFlag is a flag with type Generic
|
||||
type GenericFlag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value Generic
|
||||
Destination *Generic
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
|
||||
TakesFile bool
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *GenericFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *GenericFlag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *GenericFlag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *GenericFlag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *GenericFlag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// Int64SliceFlag is a flag with type *Int64Slice
|
||||
type Int64SliceFlag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value *Int64Slice
|
||||
Destination *Int64Slice
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *Int64SliceFlag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *Int64SliceFlag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *Int64SliceFlag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *Int64SliceFlag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// IntSliceFlag is a flag with type *IntSlice
|
||||
type IntSliceFlag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value *IntSlice
|
||||
Destination *IntSlice
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *IntSliceFlag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *IntSliceFlag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *IntSliceFlag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *IntSliceFlag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// PathFlag is a flag with type Path
|
||||
type PathFlag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value Path
|
||||
Destination *Path
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
|
||||
TakesFile bool
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *PathFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *PathFlag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *PathFlag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *PathFlag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *PathFlag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// StringSliceFlag is a flag with type *StringSlice
|
||||
type StringSliceFlag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value *StringSlice
|
||||
Destination *StringSlice
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
|
||||
TakesFile bool
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *StringSliceFlag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *StringSliceFlag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *StringSliceFlag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *StringSliceFlag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// TimestampFlag is a flag with type *Timestamp
|
||||
type TimestampFlag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value *Timestamp
|
||||
Destination *Timestamp
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
|
||||
Layout string
|
||||
|
||||
Timezone *time.Location
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *TimestampFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *TimestampFlag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *TimestampFlag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *TimestampFlag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *TimestampFlag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// BoolFlag is a flag with type bool
|
||||
type BoolFlag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value bool
|
||||
Destination *bool
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *BoolFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *BoolFlag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *BoolFlag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *BoolFlag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *BoolFlag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// Float64Flag is a flag with type float64
|
||||
type Float64Flag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value float64
|
||||
Destination *float64
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *Float64Flag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *Float64Flag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *Float64Flag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *Float64Flag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *Float64Flag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// IntFlag is a flag with type int
|
||||
type IntFlag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value int
|
||||
Destination *int
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *IntFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *IntFlag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *IntFlag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *IntFlag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *IntFlag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// Int64Flag is a flag with type int64
|
||||
type Int64Flag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value int64
|
||||
Destination *int64
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *Int64Flag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *Int64Flag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *Int64Flag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *Int64Flag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *Int64Flag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// StringFlag is a flag with type string
|
||||
type StringFlag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value string
|
||||
Destination *string
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
|
||||
TakesFile bool
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *StringFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *StringFlag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *StringFlag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *StringFlag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *StringFlag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// DurationFlag is a flag with type time.Duration
|
||||
type DurationFlag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value time.Duration
|
||||
Destination *time.Duration
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *DurationFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *DurationFlag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *DurationFlag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *DurationFlag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *DurationFlag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// UintFlag is a flag with type uint
|
||||
type UintFlag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value uint
|
||||
Destination *uint
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *UintFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *UintFlag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *UintFlag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *UintFlag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *UintFlag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// Uint64Flag is a flag with type uint64
|
||||
type Uint64Flag struct {
|
||||
Name string
|
||||
|
||||
Category string
|
||||
DefaultText string
|
||||
FilePath string
|
||||
Usage string
|
||||
|
||||
Required bool
|
||||
Hidden bool
|
||||
HasBeenSet bool
|
||||
|
||||
Value uint64
|
||||
Destination *uint64
|
||||
|
||||
Aliases []string
|
||||
EnvVars []string
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *Uint64Flag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// IsSet returns whether or not the flag has been set through env or file
|
||||
func (f *Uint64Flag) IsSet() bool {
|
||||
return f.HasBeenSet
|
||||
}
|
||||
|
||||
// Names returns the names of the flag
|
||||
func (f *Uint64Flag) Names() []string {
|
||||
return FlagNames(f.Name, f.Aliases)
|
||||
}
|
||||
|
||||
// IsRequired returns whether or not the flag is required
|
||||
func (f *Uint64Flag) IsRequired() bool {
|
||||
return f.Required
|
||||
}
|
||||
|
||||
// IsVisible returns true if the flag is not hidden, otherwise false
|
||||
func (f *Uint64Flag) IsVisible() bool {
|
||||
return !f.Hidden
|
||||
}
|
||||
|
||||
// vim:ro
|
@ -0,0 +1,363 @@
|
||||
// WARNING: this file is generated. DO NOT EDIT
|
||||
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func TestFloat64SliceFlag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.Float64SliceFlag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestFloat64SliceFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.Float64SliceFlag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestFloat64SliceFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.Float64SliceFlag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestGenericFlag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.GenericFlag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestGenericFlag_SatisfiesFmtStringerInterface(t *testing.T) {
|
||||
var f fmt.Stringer = &cli.GenericFlag{}
|
||||
|
||||
_ = f.String()
|
||||
}
|
||||
|
||||
func TestGenericFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.GenericFlag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestGenericFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.GenericFlag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestInt64SliceFlag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.Int64SliceFlag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestInt64SliceFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.Int64SliceFlag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestInt64SliceFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.Int64SliceFlag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestIntSliceFlag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.IntSliceFlag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestIntSliceFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.IntSliceFlag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestIntSliceFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.IntSliceFlag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestPathFlag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.PathFlag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestPathFlag_SatisfiesFmtStringerInterface(t *testing.T) {
|
||||
var f fmt.Stringer = &cli.PathFlag{}
|
||||
|
||||
_ = f.String()
|
||||
}
|
||||
|
||||
func TestPathFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.PathFlag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestPathFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.PathFlag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestStringSliceFlag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.StringSliceFlag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestStringSliceFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.StringSliceFlag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestStringSliceFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.StringSliceFlag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestTimestampFlag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.TimestampFlag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestTimestampFlag_SatisfiesFmtStringerInterface(t *testing.T) {
|
||||
var f fmt.Stringer = &cli.TimestampFlag{}
|
||||
|
||||
_ = f.String()
|
||||
}
|
||||
|
||||
func TestTimestampFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.TimestampFlag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestTimestampFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.TimestampFlag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestBoolFlag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.BoolFlag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestBoolFlag_SatisfiesFmtStringerInterface(t *testing.T) {
|
||||
var f fmt.Stringer = &cli.BoolFlag{}
|
||||
|
||||
_ = f.String()
|
||||
}
|
||||
|
||||
func TestBoolFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.BoolFlag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestBoolFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.BoolFlag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestFloat64Flag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.Float64Flag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestFloat64Flag_SatisfiesFmtStringerInterface(t *testing.T) {
|
||||
var f fmt.Stringer = &cli.Float64Flag{}
|
||||
|
||||
_ = f.String()
|
||||
}
|
||||
|
||||
func TestFloat64Flag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.Float64Flag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestFloat64Flag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.Float64Flag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestIntFlag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.IntFlag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestIntFlag_SatisfiesFmtStringerInterface(t *testing.T) {
|
||||
var f fmt.Stringer = &cli.IntFlag{}
|
||||
|
||||
_ = f.String()
|
||||
}
|
||||
|
||||
func TestIntFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.IntFlag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestIntFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.IntFlag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestInt64Flag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.Int64Flag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestInt64Flag_SatisfiesFmtStringerInterface(t *testing.T) {
|
||||
var f fmt.Stringer = &cli.Int64Flag{}
|
||||
|
||||
_ = f.String()
|
||||
}
|
||||
|
||||
func TestInt64Flag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.Int64Flag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestInt64Flag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.Int64Flag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestStringFlag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.StringFlag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestStringFlag_SatisfiesFmtStringerInterface(t *testing.T) {
|
||||
var f fmt.Stringer = &cli.StringFlag{}
|
||||
|
||||
_ = f.String()
|
||||
}
|
||||
|
||||
func TestStringFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.StringFlag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestStringFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.StringFlag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestDurationFlag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.DurationFlag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestDurationFlag_SatisfiesFmtStringerInterface(t *testing.T) {
|
||||
var f fmt.Stringer = &cli.DurationFlag{}
|
||||
|
||||
_ = f.String()
|
||||
}
|
||||
|
||||
func TestDurationFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.DurationFlag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestDurationFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.DurationFlag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestUintFlag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.UintFlag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestUintFlag_SatisfiesFmtStringerInterface(t *testing.T) {
|
||||
var f fmt.Stringer = &cli.UintFlag{}
|
||||
|
||||
_ = f.String()
|
||||
}
|
||||
|
||||
func TestUintFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.UintFlag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestUintFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.UintFlag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
func TestUint64Flag_SatisfiesFlagInterface(t *testing.T) {
|
||||
var f cli.Flag = &cli.Uint64Flag{}
|
||||
|
||||
_ = f.IsSet()
|
||||
_ = f.Names()
|
||||
}
|
||||
|
||||
func TestUint64Flag_SatisfiesFmtStringerInterface(t *testing.T) {
|
||||
var f fmt.Stringer = &cli.Uint64Flag{}
|
||||
|
||||
_ = f.String()
|
||||
}
|
||||
|
||||
func TestUint64Flag_SatisfiesRequiredFlagInterface(t *testing.T) {
|
||||
var f cli.RequiredFlag = &cli.Uint64Flag{}
|
||||
|
||||
_ = f.IsRequired()
|
||||
}
|
||||
|
||||
func TestUint64Flag_SatisfiesVisibleFlagInterface(t *testing.T) {
|
||||
var f cli.VisibleFlag = &cli.Uint64Flag{}
|
||||
|
||||
_ = f.IsVisible()
|
||||
}
|
||||
|
||||
// vim:ro
|
Loading…
Reference in new issue