tools/go-agent/tools/flags.go (83 lines of code) (raw):
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you 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 tools
import (
"fmt"
"path/filepath"
"reflect"
"strings"
)
const flagTagKey = "swflag"
func ParseFlags(result interface{}, args []string) (noOpIndex int, err error) {
if len(args) == 0 {
return 0, fmt.Errorf("no args")
}
flags := parseFlagsFromStruct(result)
if len(flags) == 0 {
return 0, nil
}
i := 0
firstNonOptionIndex := -1
for i < len(args)-1 {
shift, isOption := parseFlag(flags, args[i], args[i+1])
if !isOption && firstNonOptionIndex == -1 {
firstNonOptionIndex = i
}
i += shift
}
if i < len(args) {
parseFlag(flags, args[i], "")
}
// process the all args flag
if v, exist := flags["all-args"]; exist {
v.Set(reflect.ValueOf(args))
}
return firstNonOptionIndex, nil
}
func ParseProxyCommandName(args []string, firstNonOptionIndex int) string {
if len(args) == 0 {
return ""
}
cmd := filepath.Base(args[firstNonOptionIndex])
if ext := filepath.Ext(cmd); ext != "" {
cmd = strings.TrimSuffix(cmd, ext)
}
return cmd
}
func parseFlag(flags map[string]reflect.Value, curArg, nextArg string) (shift int, isOption bool) {
if curArg[0] != '-' {
return 1, false
}
kv := strings.SplitN(curArg, "=", 2)
option := kv[0]
if v, exist := flags[option]; !exist {
if len(kv) == 2 {
return 1, true
} else if nextArg == "" || (len(nextArg) > 1 && nextArg[0] != '-') {
return 2, true
}
return 1, true
} else if len(kv) == 2 {
v.SetString(kv[1])
return 1, true
} else {
switch v.Kind() {
case reflect.String:
v.SetString(nextArg)
return 2, true
case reflect.Bool:
v.SetBool(true)
return 1, true
}
return 1, true
}
}
func parseFlagsFromStruct(result interface{}) map[string]reflect.Value {
e := reflect.ValueOf(result).Elem()
typ := e.Type()
flagSetValueMap := make(map[string]reflect.Value, e.NumField())
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
if tag, ok := field.Tag.Lookup(flagTagKey); ok {
flagSetValueMap[tag] = e.Field(i)
}
}
return flagSetValueMap
}