// Copyright 2023 Harness, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package command import ( "strings" ) // Parse os args to Command object. // This is very basic parser which doesn't care about // flags or positional args values it just injects into proper // slice of command struct. Every git command can contain // globals: // // git --help // // command: // // git version // git diff // // action: // // git remote set-url ... // // command or action flags: // // git diff --shortstat // // command or action args: // // git diff --shortstat main...dev // // post args: // // git diff main...dev -- file1 func Parse(args ...string) *Command { actions := map[string]uint{} c := &Command{} globalPos := -1 namePos := -1 actionPos := -1 flagsPos := -1 argsPos := -1 postPos := -1 if len(args) == 0 { return c } if strings.ToLower(args[0]) == "git" { args = args[1:] } for i, arg := range args { isFlag := arg != "--" && strings.HasPrefix(arg, "-") b, isCommand := descriptions[arg] _, isAction := actions[arg] switch { case globalPos == -1 && namePos == -1 && isFlag: globalPos = i case namePos == -1 && isCommand: namePos = i actions = b.actions case actionPos == -1 && isAction && !isFlag: actionPos = i case flagsPos == -1 && (namePos >= 0 || actionPos > 0) && isFlag: flagsPos = i case argsPos == -1 && (namePos >= 0 || actionPos > 0) && !isFlag: argsPos = i case postPos == -1 && arg == "--": postPos = i } } end := len(args) if globalPos >= 0 { c.Globals = args[globalPos:cmpPos(namePos, end)] } if namePos >= 0 { c.Name = args[namePos] } if actionPos > 0 { c.Action = args[actionPos] } if flagsPos > 0 { c.Flags = args[flagsPos:cmpPos(argsPos, end)] } if argsPos > 0 { c.Args = args[argsPos:cmpPos(postPos, end)] } if postPos > 0 { c.PostSepArgs = args[postPos+1:] } return c } func cmpPos(check, or int) int { if check == -1 { return or } return check }