feat: gitea client
This commit is contained in:
503
vendor/github.com/alecthomas/kong/kong.go
generated
vendored
Normal file
503
vendor/github.com/alecthomas/kong/kong.go
generated
vendored
Normal file
@@ -0,0 +1,503 @@
|
||||
package kong
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
callbackReturnSignature = reflect.TypeOf((*error)(nil)).Elem()
|
||||
)
|
||||
|
||||
func failField(parent reflect.Value, field reflect.StructField, format string, args ...any) error {
|
||||
name := parent.Type().Name()
|
||||
if name == "" {
|
||||
name = "<anonymous struct>"
|
||||
}
|
||||
return fmt.Errorf("%s.%s: %s", name, field.Name, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Must creates a new Parser or panics if there is an error.
|
||||
func Must(ast any, options ...Option) *Kong {
|
||||
k, err := New(ast, options...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
type usageOnError int
|
||||
|
||||
const (
|
||||
shortUsage usageOnError = iota + 1
|
||||
fullUsage
|
||||
)
|
||||
|
||||
// Kong is the main parser type.
|
||||
type Kong struct {
|
||||
// Grammar model.
|
||||
Model *Application
|
||||
|
||||
// Termination function (defaults to os.Exit)
|
||||
Exit func(int)
|
||||
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
|
||||
bindings bindings
|
||||
loader ConfigurationLoader
|
||||
resolvers []Resolver
|
||||
registry *Registry
|
||||
ignoreFields []*regexp.Regexp
|
||||
|
||||
noDefaultHelp bool
|
||||
allowHyphenated bool
|
||||
usageOnError usageOnError
|
||||
help HelpPrinter
|
||||
shortHelp HelpPrinter
|
||||
helpFormatter HelpValueFormatter
|
||||
helpOptions HelpOptions
|
||||
helpFlag *Flag
|
||||
groups []Group
|
||||
vars Vars
|
||||
flagNamer func(string) string
|
||||
|
||||
// Set temporarily by Options. These are applied after build().
|
||||
postBuildOptions []Option
|
||||
embedded []embedded
|
||||
dynamicCommands []*dynamicCommand
|
||||
|
||||
hooks map[string][]reflect.Value
|
||||
}
|
||||
|
||||
// New creates a new Kong parser on grammar.
|
||||
//
|
||||
// See the README (https://github.com/alecthomas/kong) for usage instructions.
|
||||
func New(grammar any, options ...Option) (*Kong, error) {
|
||||
k := &Kong{
|
||||
Exit: os.Exit,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
registry: NewRegistry().RegisterDefaults(),
|
||||
vars: Vars{},
|
||||
bindings: bindings{},
|
||||
hooks: make(map[string][]reflect.Value),
|
||||
helpFormatter: DefaultHelpValueFormatter,
|
||||
ignoreFields: make([]*regexp.Regexp, 0),
|
||||
flagNamer: func(s string) string {
|
||||
return strings.ToLower(dashedString(s))
|
||||
},
|
||||
}
|
||||
|
||||
options = append(options, Bind(k))
|
||||
|
||||
for _, option := range options {
|
||||
if err := option.Apply(k); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if k.help == nil {
|
||||
k.help = DefaultHelpPrinter
|
||||
}
|
||||
|
||||
if k.shortHelp == nil {
|
||||
k.shortHelp = DefaultShortHelpPrinter
|
||||
}
|
||||
|
||||
model, err := build(k, grammar)
|
||||
if err != nil {
|
||||
return k, err
|
||||
}
|
||||
model.Name = filepath.Base(os.Args[0])
|
||||
k.Model = model
|
||||
k.Model.HelpFlag = k.helpFlag
|
||||
|
||||
// Embed any embedded structs.
|
||||
for _, embed := range k.embedded {
|
||||
tag, err := parseTagString(strings.Join(embed.tags, " "))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tag.Embed = true
|
||||
v := reflect.Indirect(reflect.ValueOf(embed.strct))
|
||||
node, err := buildNode(k, v, CommandNode, tag, map[string]bool{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, child := range node.Children {
|
||||
child.Parent = k.Model.Node
|
||||
k.Model.Children = append(k.Model.Children, child)
|
||||
}
|
||||
k.Model.Flags = append(k.Model.Flags, node.Flags...)
|
||||
}
|
||||
|
||||
// Synthesise command nodes.
|
||||
for _, dcmd := range k.dynamicCommands {
|
||||
tag, terr := parseTagString(strings.Join(dcmd.tags, " "))
|
||||
if terr != nil {
|
||||
return nil, terr
|
||||
}
|
||||
tag.Name = dcmd.name
|
||||
tag.Help = dcmd.help
|
||||
tag.Group = dcmd.group
|
||||
tag.Cmd = true
|
||||
v := reflect.Indirect(reflect.ValueOf(dcmd.cmd))
|
||||
err = buildChild(k, k.Model.Node, CommandNode, reflect.Value{}, reflect.StructField{
|
||||
Name: dcmd.name,
|
||||
Type: v.Type(),
|
||||
}, v, tag, dcmd.name, map[string]bool{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, option := range k.postBuildOptions {
|
||||
if err = option.Apply(k); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
k.postBuildOptions = nil
|
||||
|
||||
if err = k.interpolate(k.Model.Node); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
k.bindings.add(k.vars)
|
||||
|
||||
if err = checkOverlappingXorAnd(k); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func checkOverlappingXorAnd(k *Kong) error {
|
||||
xorGroups := map[string][]string{}
|
||||
andGroups := map[string][]string{}
|
||||
for _, flag := range k.Model.Node.Flags {
|
||||
for _, xor := range flag.Xor {
|
||||
xorGroups[xor] = append(xorGroups[xor], flag.Name)
|
||||
}
|
||||
for _, and := range flag.And {
|
||||
andGroups[and] = append(andGroups[and], flag.Name)
|
||||
}
|
||||
}
|
||||
for xor, xorSet := range xorGroups {
|
||||
for and, andSet := range andGroups {
|
||||
overlappingEntries := []string{}
|
||||
for _, xorTag := range xorSet {
|
||||
for _, andTag := range andSet {
|
||||
if xorTag == andTag {
|
||||
overlappingEntries = append(overlappingEntries, xorTag)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(overlappingEntries) > 1 {
|
||||
return fmt.Errorf("invalid xor and combination, %s and %s overlap with more than one: %s", xor, and, overlappingEntries)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type varStack []Vars
|
||||
|
||||
func (v *varStack) head() Vars { return (*v)[len(*v)-1] }
|
||||
func (v *varStack) pop() { *v = (*v)[:len(*v)-1] }
|
||||
func (v *varStack) push(vars Vars) Vars {
|
||||
if len(*v) != 0 {
|
||||
vars = (*v)[len(*v)-1].CloneWith(vars)
|
||||
}
|
||||
*v = append(*v, vars)
|
||||
return vars
|
||||
}
|
||||
|
||||
// Interpolate variables into model.
|
||||
func (k *Kong) interpolate(node *Node) (err error) {
|
||||
stack := varStack{}
|
||||
return Visit(node, func(node Visitable, next Next) error {
|
||||
switch node := node.(type) {
|
||||
case *Node:
|
||||
vars := stack.push(node.Vars())
|
||||
node.Help, err = interpolate(node.Help, vars, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("help for %s: %s", node.Path(), err)
|
||||
}
|
||||
err = next(nil)
|
||||
stack.pop()
|
||||
return err
|
||||
|
||||
case *Value:
|
||||
return next(k.interpolateValue(node, stack.head()))
|
||||
}
|
||||
return next(nil)
|
||||
})
|
||||
}
|
||||
|
||||
func (k *Kong) interpolateValue(value *Value, vars Vars) (err error) {
|
||||
if len(value.Tag.Vars) > 0 {
|
||||
vars = vars.CloneWith(value.Tag.Vars)
|
||||
}
|
||||
if varsContributor, ok := value.Mapper.(VarsContributor); ok {
|
||||
vars = vars.CloneWith(varsContributor.Vars(value))
|
||||
}
|
||||
|
||||
initialVars := vars.CloneWith(nil)
|
||||
for n, v := range initialVars {
|
||||
if vars[n], err = interpolate(v, initialVars, nil); err != nil {
|
||||
return fmt.Errorf("variable %s for %s: %s", n, value.Summary(), err)
|
||||
}
|
||||
}
|
||||
|
||||
if value.Default, err = interpolate(value.Default, vars, nil); err != nil {
|
||||
return fmt.Errorf("default value for %s: %s", value.Summary(), err)
|
||||
}
|
||||
if value.Enum, err = interpolate(value.Enum, vars, nil); err != nil {
|
||||
return fmt.Errorf("enum value for %s: %s", value.Summary(), err)
|
||||
}
|
||||
updatedVars := map[string]string{
|
||||
"default": value.Default,
|
||||
"enum": value.Enum,
|
||||
}
|
||||
if value.Flag != nil {
|
||||
for i, env := range value.Flag.Envs {
|
||||
if value.Flag.Envs[i], err = interpolate(env, vars, updatedVars); err != nil {
|
||||
return fmt.Errorf("env value for %s: %s", value.Summary(), err)
|
||||
}
|
||||
}
|
||||
value.Tag.Envs = value.Flag.Envs
|
||||
updatedVars["env"] = ""
|
||||
if len(value.Flag.Envs) != 0 {
|
||||
updatedVars["env"] = value.Flag.Envs[0]
|
||||
}
|
||||
|
||||
value.Flag.PlaceHolder, err = interpolate(value.Flag.PlaceHolder, vars, updatedVars)
|
||||
if err != nil {
|
||||
return fmt.Errorf("placeholder value for %s: %s", value.Summary(), err)
|
||||
}
|
||||
}
|
||||
value.Help, err = interpolate(value.Help, vars, updatedVars)
|
||||
if err != nil {
|
||||
return fmt.Errorf("help for %s: %s", value.Summary(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Provide additional builtin flags, if any.
|
||||
func (k *Kong) extraFlags() []*Flag {
|
||||
if k.noDefaultHelp {
|
||||
return nil
|
||||
}
|
||||
var helpTarget helpFlag
|
||||
value := reflect.ValueOf(&helpTarget).Elem()
|
||||
helpFlag := &Flag{
|
||||
Short: 'h',
|
||||
Value: &Value{
|
||||
Name: "help",
|
||||
Help: "Show context-sensitive help.",
|
||||
OrigHelp: "Show context-sensitive help.",
|
||||
Target: value,
|
||||
Tag: &Tag{},
|
||||
Mapper: k.registry.ForValue(value),
|
||||
DefaultValue: reflect.ValueOf(false),
|
||||
},
|
||||
}
|
||||
helpFlag.Flag = helpFlag
|
||||
k.helpFlag = helpFlag
|
||||
return []*Flag{helpFlag}
|
||||
}
|
||||
|
||||
// Parse arguments into target.
|
||||
//
|
||||
// The return Context can be used to further inspect the parsed command-line, to format help, to find the
|
||||
// selected command, to run command Run() methods, and so on. See Context and README for more information.
|
||||
//
|
||||
// Will return a ParseError if a *semantically* invalid command-line is encountered (as opposed to a syntactically
|
||||
// invalid one, which will report a normal error).
|
||||
func (k *Kong) Parse(args []string) (ctx *Context, err error) {
|
||||
ctx, err = Trace(k, args)
|
||||
if err != nil { // Trace is not expected to return an err
|
||||
return nil, &ParseError{error: err, Context: ctx, exitCode: exitUsageError}
|
||||
}
|
||||
if ctx.Error != nil {
|
||||
return nil, &ParseError{error: ctx.Error, Context: ctx, exitCode: exitUsageError}
|
||||
}
|
||||
if err = k.applyHook(ctx, "BeforeReset"); err != nil {
|
||||
return nil, &ParseError{error: err, Context: ctx}
|
||||
}
|
||||
if err = ctx.Reset(); err != nil {
|
||||
return nil, &ParseError{error: err, Context: ctx}
|
||||
}
|
||||
if err = k.applyHook(ctx, "BeforeResolve"); err != nil {
|
||||
return nil, &ParseError{error: err, Context: ctx}
|
||||
}
|
||||
if err = ctx.Resolve(); err != nil {
|
||||
return nil, &ParseError{error: err, Context: ctx}
|
||||
}
|
||||
if err = k.applyHook(ctx, "BeforeApply"); err != nil {
|
||||
return nil, &ParseError{error: err, Context: ctx}
|
||||
}
|
||||
if _, err = ctx.Apply(); err != nil { // Apply is not expected to return an err
|
||||
return nil, &ParseError{error: err, Context: ctx}
|
||||
}
|
||||
if err = ctx.Validate(); err != nil {
|
||||
return nil, &ParseError{error: err, Context: ctx, exitCode: exitUsageError}
|
||||
}
|
||||
if err = k.applyHook(ctx, "AfterApply"); err != nil {
|
||||
return nil, &ParseError{error: err, Context: ctx}
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (k *Kong) applyHook(ctx *Context, name string) error {
|
||||
for _, trace := range ctx.Path {
|
||||
var value reflect.Value
|
||||
switch {
|
||||
case trace.App != nil:
|
||||
value = trace.App.Target
|
||||
case trace.Argument != nil:
|
||||
value = trace.Argument.Target
|
||||
case trace.Command != nil:
|
||||
value = trace.Command.Target
|
||||
case trace.Positional != nil:
|
||||
value = trace.Positional.Target
|
||||
case trace.Flag != nil:
|
||||
value = trace.Flag.Value.Target
|
||||
default:
|
||||
panic("unsupported Path")
|
||||
}
|
||||
for _, method := range k.getMethods(value, name) {
|
||||
binds := k.bindings.clone()
|
||||
binds.add(ctx, trace)
|
||||
binds.add(trace.Node().Vars().CloneWith(k.vars))
|
||||
binds.merge(ctx.bindings)
|
||||
if err := callFunction(method, binds); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
// Path[0] will always be the app root.
|
||||
return k.applyHookToDefaultFlags(ctx, ctx.Path[0].Node(), name)
|
||||
}
|
||||
|
||||
func (k *Kong) getMethods(value reflect.Value, name string) []reflect.Value {
|
||||
return append(
|
||||
// Identify callbacks by reflecting on value
|
||||
getMethods(value, name),
|
||||
|
||||
// Identify callbacks that were registered with a kong.Option
|
||||
k.hooks[name]...,
|
||||
)
|
||||
}
|
||||
|
||||
// Call hook on any unset flags with default values.
|
||||
func (k *Kong) applyHookToDefaultFlags(ctx *Context, node *Node, name string) error {
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
return Visit(node, func(n Visitable, next Next) error {
|
||||
node, ok := n.(*Node)
|
||||
if !ok {
|
||||
return next(nil)
|
||||
}
|
||||
binds := k.bindings.clone().add(ctx).add(node.Vars().CloneWith(k.vars))
|
||||
for _, flag := range node.Flags {
|
||||
if !flag.HasDefault || ctx.values[flag.Value].IsValid() || !flag.Target.IsValid() {
|
||||
continue
|
||||
}
|
||||
for _, method := range getMethods(flag.Target, name) {
|
||||
path := &Path{Flag: flag}
|
||||
if err := callFunction(method, binds.clone().add(path)); err != nil {
|
||||
return next(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return next(nil)
|
||||
})
|
||||
}
|
||||
|
||||
func formatMultilineMessage(w io.Writer, leaders []string, format string, args ...any) {
|
||||
lines := strings.Split(strings.TrimRight(fmt.Sprintf(format, args...), "\n"), "\n")
|
||||
leader := ""
|
||||
for _, l := range leaders {
|
||||
if l == "" {
|
||||
continue
|
||||
}
|
||||
leader += l + ": "
|
||||
}
|
||||
fmt.Fprintf(w, "%s%s\n", leader, lines[0])
|
||||
for _, line := range lines[1:] {
|
||||
fmt.Fprintf(w, "%*s%s\n", len(leader), " ", line)
|
||||
}
|
||||
}
|
||||
|
||||
// Printf writes a message to Kong.Stdout with the application name prefixed.
|
||||
func (k *Kong) Printf(format string, args ...any) *Kong {
|
||||
formatMultilineMessage(k.Stdout, []string{k.Model.Name}, format, args...)
|
||||
return k
|
||||
}
|
||||
|
||||
// Errorf writes a message to Kong.Stderr with the application name prefixed.
|
||||
func (k *Kong) Errorf(format string, args ...any) *Kong {
|
||||
formatMultilineMessage(k.Stderr, []string{k.Model.Name, "error"}, format, args...)
|
||||
return k
|
||||
}
|
||||
|
||||
// Fatalf writes a message to Kong.Stderr with the application name prefixed then exits with status 1.
|
||||
func (k *Kong) Fatalf(format string, args ...any) {
|
||||
k.Errorf(format, args...)
|
||||
k.Exit(1)
|
||||
}
|
||||
|
||||
// FatalIfErrorf terminates with an error message if err != nil.
|
||||
// If the error implements the ExitCoder interface, the ExitCode() method is called and
|
||||
// the application exits with that status. Otherwise, the application exits with status 1.
|
||||
func (k *Kong) FatalIfErrorf(err error, args ...any) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
msg := err.Error()
|
||||
if len(args) > 0 {
|
||||
msg = fmt.Sprintf(args[0].(string), args[1:]...) + ": " + err.Error() //nolint
|
||||
}
|
||||
// Maybe display usage information.
|
||||
var parseErr *ParseError
|
||||
if errors.As(err, &parseErr) {
|
||||
switch k.usageOnError {
|
||||
case fullUsage:
|
||||
_ = parseErr.Context.printHelp(k.helpOptions)
|
||||
fmt.Fprintln(k.Stdout)
|
||||
case shortUsage:
|
||||
_ = k.shortHelp(k.helpOptions, parseErr.Context)
|
||||
fmt.Fprintln(k.Stdout)
|
||||
}
|
||||
}
|
||||
k.Errorf("%s", msg)
|
||||
k.Exit(exitCodeFromError(err))
|
||||
}
|
||||
|
||||
// LoadConfig from path using the loader configured via Configuration(loader).
|
||||
//
|
||||
// "path" will have ~ and any variables expanded.
|
||||
func (k *Kong) LoadConfig(path string) (Resolver, error) {
|
||||
var err error
|
||||
path = ExpandPath(path)
|
||||
path, err = interpolate(path, k.vars, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err := os.Open(path) //nolint: gas
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
return k.loader(r)
|
||||
}
|
||||
Reference in New Issue
Block a user