1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
package git
import (
"errors"
"fmt"
"regexp"
)
var (
// ErrInvalidArg represent family of errors to report about bad argument used to make a call.
ErrInvalidArg = errors.New("invalid argument")
// ErrHookPayloadRequired indicates a HookPayload is needed but
// absent from the command.
ErrHookPayloadRequired = errors.New("hook payload is required but not configured")
actionRegex = regexp.MustCompile(`^[[:alnum:]]+[-[:alnum:]]*$`)
)
// Command represent a Git command.
type Command struct {
// Name is the name of the Git command to run, e.g. "log", "cat-file" or "worktree".
Name string
// Action is the action of the Git command, e.g. "set-url" in `git remote set-url`
Action string
// Flags is the number of optional flags to pass before positional arguments, e.g.
// `--oneline` or `--format=fuller`.
Flags []Option
// Args is the arguments that shall be passed after all flags. These arguments must not be
// flags and thus cannot start with `-`. Note that it may be unsafe to use this field in the
// case where arguments are directly user-controlled. In that case it is advisable to use
// `PostSepArgs` instead.
Args []string
// PostSepArgs is the arguments that shall be passed as positional arguments after the `--`
// separator. Git recognizes that separator as the point where it should stop expecting any
// options and treat the remaining arguments as positionals. This should be used when
// passing user-controlled input of arbitrary form like for example paths, which may start
// with a `-`.
PostSepArgs []string
}
// CommandArgs checks all arguments in the sub command and validates them
func (c Command) CommandArgs() ([]string, error) {
var safeArgs []string
commandDescription, ok := commandDescriptions[c.Name]
if !ok {
return nil, fmt.Errorf("invalid sub command name %q: %w", c.Name, ErrInvalidArg)
}
safeArgs = append(safeArgs, c.Name)
if c.Action != "" {
if !actionRegex.MatchString(c.Action) {
return nil, fmt.Errorf("invalid action %q: %w", c.Action, ErrInvalidArg)
}
safeArgs = append(safeArgs, c.Action)
}
commandArgs, err := commandDescription.args(c.Flags, c.Args, c.PostSepArgs)
if err != nil {
return nil, err
}
safeArgs = append(safeArgs, commandArgs...)
return safeArgs, nil
}
// IsInvalidArgErr relays if the error is due to an argument validation failure
func IsInvalidArgErr(err error) bool {
return errors.Is(err, ErrInvalidArg)
}
|