зеркало из https://github.com/mislav/hub.git
253 строки
4.7 KiB
Go
253 строки
4.7 KiB
Go
package commands
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/github/hub/cmd"
|
|
"github.com/github/hub/utils"
|
|
)
|
|
|
|
type Args struct {
|
|
Executable string
|
|
GlobalFlags []string
|
|
Command string
|
|
ProgramPath string
|
|
Params []string
|
|
beforeChain []*cmd.Cmd
|
|
afterChain []*cmd.Cmd
|
|
Noop bool
|
|
Terminator bool
|
|
noForward bool
|
|
Callbacks []func() error
|
|
Flag *utils.ArgsParser
|
|
}
|
|
|
|
func (a *Args) Words() []string {
|
|
aa := make([]string, 0)
|
|
for _, p := range a.Params {
|
|
if !looksLikeFlag(p) {
|
|
aa = append(aa, p)
|
|
}
|
|
}
|
|
|
|
return aa
|
|
}
|
|
|
|
func (a *Args) Before(command ...string) {
|
|
a.beforeChain = append(a.beforeChain, cmd.NewWithArray(command))
|
|
}
|
|
|
|
func (a *Args) After(command ...string) {
|
|
a.afterChain = append(a.afterChain, cmd.NewWithArray(command))
|
|
}
|
|
|
|
func (a *Args) AfterFn(fn func() error) {
|
|
a.Callbacks = append(a.Callbacks, fn)
|
|
}
|
|
|
|
func (a *Args) NoForward() {
|
|
a.noForward = true
|
|
}
|
|
|
|
func (a *Args) Replace(executable, command string, params ...string) {
|
|
a.Executable = executable
|
|
a.Command = command
|
|
a.Params = params
|
|
a.GlobalFlags = []string{}
|
|
a.noForward = false
|
|
}
|
|
|
|
func (a *Args) Commands() []*cmd.Cmd {
|
|
result := []*cmd.Cmd{}
|
|
appendFromChain := func(c *cmd.Cmd) {
|
|
if c.Name == "git" {
|
|
ga := []string{c.Name}
|
|
ga = append(ga, a.GlobalFlags...)
|
|
ga = append(ga, c.Args...)
|
|
result = append(result, cmd.NewWithArray(ga))
|
|
} else {
|
|
result = append(result, c)
|
|
}
|
|
}
|
|
|
|
for _, c := range a.beforeChain {
|
|
appendFromChain(c)
|
|
}
|
|
if !a.noForward {
|
|
result = append(result, a.ToCmd())
|
|
}
|
|
for _, c := range a.afterChain {
|
|
appendFromChain(c)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (a *Args) ToCmd() *cmd.Cmd {
|
|
c := cmd.New(a.Executable)
|
|
c.WithArgs(a.GlobalFlags...)
|
|
|
|
if a.Command != "" {
|
|
c.WithArg(a.Command)
|
|
}
|
|
|
|
for _, arg := range a.Params {
|
|
if arg != "" {
|
|
c.WithArg(arg)
|
|
}
|
|
}
|
|
|
|
return c
|
|
}
|
|
|
|
func (a *Args) GetParam(i int) string {
|
|
return a.Params[i]
|
|
}
|
|
|
|
func (a *Args) FirstParam() string {
|
|
if a.ParamsSize() == 0 {
|
|
panic(fmt.Sprintf("Index 0 is out of bound"))
|
|
}
|
|
|
|
return a.Params[0]
|
|
}
|
|
|
|
func (a *Args) LastParam() string {
|
|
if a.ParamsSize()-1 < 0 {
|
|
panic(fmt.Sprintf("Index %d is out of bound", a.ParamsSize()-1))
|
|
}
|
|
|
|
return a.Params[a.ParamsSize()-1]
|
|
}
|
|
|
|
func (a *Args) HasSubcommand() bool {
|
|
return !a.IsParamsEmpty() && a.Params[0][0] != '-'
|
|
}
|
|
|
|
func (a *Args) InsertParam(i int, items ...string) {
|
|
if i < 0 {
|
|
panic(fmt.Sprintf("Index %d is out of bound", i))
|
|
}
|
|
|
|
if i > a.ParamsSize() {
|
|
i = a.ParamsSize()
|
|
}
|
|
|
|
newParams := make([]string, 0)
|
|
newParams = append(newParams, a.Params[:i]...)
|
|
newParams = append(newParams, items...)
|
|
newParams = append(newParams, a.Params[i:]...)
|
|
|
|
a.Params = newParams
|
|
}
|
|
|
|
func (a *Args) RemoveParam(i int) string {
|
|
item := a.Params[i]
|
|
a.Params = append(a.Params[:i], a.Params[i+1:]...)
|
|
return item
|
|
}
|
|
|
|
func (a *Args) ReplaceParam(i int, item string) {
|
|
if i < 0 || i > a.ParamsSize()-1 {
|
|
panic(fmt.Sprintf("Index %d is out of bound", i))
|
|
}
|
|
|
|
a.Params[i] = item
|
|
}
|
|
|
|
func (a *Args) IndexOfParam(param string) int {
|
|
for i, p := range a.Params {
|
|
if p == param {
|
|
return i
|
|
}
|
|
}
|
|
|
|
return -1
|
|
}
|
|
|
|
func (a *Args) ParamsSize() int {
|
|
return len(a.Params)
|
|
}
|
|
|
|
func (a *Args) IsParamsEmpty() bool {
|
|
return a.ParamsSize() == 0
|
|
}
|
|
|
|
func (a *Args) PrependParams(params ...string) {
|
|
a.Params = append(params, a.Params...)
|
|
}
|
|
|
|
func (a *Args) AppendParams(params ...string) {
|
|
a.Params = append(a.Params, params...)
|
|
}
|
|
|
|
func NewArgs(args []string) *Args {
|
|
var (
|
|
command string
|
|
params []string
|
|
noop bool
|
|
)
|
|
|
|
cmdIdx := findCommandIndex(args)
|
|
globalFlags := args[:cmdIdx]
|
|
if cmdIdx > 0 {
|
|
args = args[cmdIdx:]
|
|
for i := len(globalFlags) - 1; i >= 0; i-- {
|
|
if globalFlags[i] == noopFlag {
|
|
noop = true
|
|
globalFlags = append(globalFlags[:i], globalFlags[i+1:]...)
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(args) != 0 {
|
|
command = args[0]
|
|
params = args[1:]
|
|
}
|
|
|
|
return &Args{
|
|
Executable: "git",
|
|
GlobalFlags: globalFlags,
|
|
Command: command,
|
|
Params: params,
|
|
Noop: noop,
|
|
beforeChain: make([]*cmd.Cmd, 0),
|
|
afterChain: make([]*cmd.Cmd, 0),
|
|
}
|
|
}
|
|
|
|
const (
|
|
noopFlag = "--noop"
|
|
versionFlag = "--version"
|
|
listCmds = "--list-cmds="
|
|
helpFlag = "--help"
|
|
configFlag = "-c"
|
|
chdirFlag = "-C"
|
|
flagPrefix = "-"
|
|
)
|
|
|
|
func looksLikeFlag(value string) bool {
|
|
return strings.HasPrefix(value, flagPrefix)
|
|
}
|
|
|
|
func findCommandIndex(args []string) int {
|
|
slurpNextValue := false
|
|
commandIndex := 0
|
|
|
|
for i, arg := range args {
|
|
if slurpNextValue {
|
|
commandIndex = i + 1
|
|
slurpNextValue = false
|
|
} else if arg == versionFlag || arg == helpFlag || strings.HasPrefix(arg, listCmds) || !looksLikeFlag(arg) {
|
|
break
|
|
} else {
|
|
commandIndex = i + 1
|
|
if arg == configFlag || arg == chdirFlag {
|
|
slurpNextValue = true
|
|
}
|
|
}
|
|
}
|
|
return commandIndex
|
|
}
|