Files
wehub-resource-sync 5357c39144
Fuzzer / Run Fuzzer (push) Has been cancelled
Race tests / Go race tests (ubuntu-22.04) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:01:40 +08:00

302 lines
7.0 KiB
Go

// Copyright 2019 Dolthub, 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 argparser
import (
"math"
"strconv"
"strings"
"github.com/dolthub/dolt/go/libraries/utils/set"
)
const (
NO_POSITIONAL_ARGS = -1
)
type ArgParseResults struct {
options map[string]string
Args []string
parser *ArgParser
PositionalArgsSeparatorIndex int
}
// Equals res and other are only considered equal if the order and contents of their arguments
// are the same.
func (res *ArgParseResults) Equals(other *ArgParseResults) bool {
if len(res.Args) != len(other.Args) || len(res.options) != len(other.options) {
return false
}
for i, arg := range res.Args {
if other.Args[i] != arg {
return false
}
}
for k, v := range res.options {
if otherVal, ok := other.options[k]; !ok || v != otherVal {
return false
}
}
return true
}
// NewEmptyResults creates a new ArgParseResults object with no arguments or options. Mostly useful for testing.
func NewEmptyResults() *ArgParseResults {
return &ArgParseResults{options: make(map[string]string), Args: make([]string, 0)}
}
func (res *ArgParseResults) Contains(name string) bool {
_, ok := res.options[name]
return ok
}
func (res *ArgParseResults) ContainsArg(name string) bool {
for _, val := range res.Args {
if val == name {
return true
}
}
return false
}
func (res *ArgParseResults) ContainsAll(names ...string) bool {
for _, name := range names {
if _, ok := res.options[name]; !ok {
return false
}
}
return true
}
func (res *ArgParseResults) ContainsAny(names ...string) bool {
for _, name := range names {
if _, ok := res.options[name]; ok {
return true
}
}
return false
}
func (res *ArgParseResults) ContainsMany(names ...string) []string {
var contains []string
for _, name := range names {
if _, ok := res.options[name]; ok {
contains = append(contains, name)
}
}
return contains
}
func (res *ArgParseResults) GetValue(name string) (string, bool) {
val, ok := res.options[name]
return val, ok
}
func (res *ArgParseResults) GetValueList(name string) ([]string, bool) {
val, ok := res.options[name]
if !ok {
return nil, false
}
return strings.Split(val, ","), ok
}
func (res *ArgParseResults) GetValues(names ...string) map[string]string {
vals := make(map[string]string)
for _, name := range names {
if val, ok := res.options[name]; ok {
vals[name] = val
}
}
return vals
}
// DropValue removes the value for the given name from the results. A new ArgParseResults object is returned without the
// names value. If the value is not present in the results then the original results object is returned.
func (res *ArgParseResults) DropValue(name string) *ArgParseResults {
if _, ok := res.options[name]; !ok {
return res
}
newNamedArgs := make(map[string]string, len(res.options)-1)
for flag, val := range res.options {
if flag != name {
newNamedArgs[flag] = val
}
}
return &ArgParseResults{newNamedArgs, res.Args, res.parser, NO_POSITIONAL_ARGS}
}
// SetArgument inserts or replaces an argument. A new ArgParseResults object is returned with the new
// argument added. The parser of the original ArgParseResults is used to verify that the option is supported.
//
// If the option is not supported, this is considered a runtime error, and an error is returned to that effect.
func (res *ArgParseResults) SetArgument(name, val string) (*ArgParseResults, error) {
newNamedArgs := make(map[string]string, len(res.options)+1)
for flag, origVal := range res.options {
newNamedArgs[flag] = origVal
}
found := false
// Verify that the options is supported - using the long name
for _, opt := range res.parser.Supported {
if opt.Name == name {
found = true
break
}
}
if !found {
return nil, UnknownArgumentParam{name: name}
}
newNamedArgs[name] = val
return &ArgParseResults{newNamedArgs, res.Args, res.parser, res.PositionalArgsSeparatorIndex}, nil
}
func (res *ArgParseResults) MustGetValue(name string) string {
val, ok := res.options[name]
if !ok {
panic("Value not available.")
}
return val
}
func (res *ArgParseResults) GetValueOrDefault(name, defVal string) string {
val, ok := res.options[name]
if ok {
return val
}
return defVal
}
func (res *ArgParseResults) GetInt(name string) (int, bool) {
val, ok := res.options[name]
if !ok {
return math.MinInt32, false
}
intVal, err := strconv.ParseInt(val, 10, 32)
if err != nil {
return math.MinInt32, false
}
return int(intVal), true
}
func (res *ArgParseResults) GetUint(name string) (uint64, bool) {
val, ok := res.options[name]
if !ok {
return math.MaxUint64, false
}
uintVal, err := strconv.ParseUint(val, 10, 64)
if err != nil {
return math.MaxUint64, false
}
return uintVal, true
}
func (res *ArgParseResults) GetIntOrDefault(name string, defVal int) int {
n, ok := res.GetInt(name)
if ok {
return n
}
return defVal
}
func (res *ArgParseResults) NArg() int {
return len(res.Args)
}
func (res *ArgParseResults) Arg(idx int) string {
return res.Args[idx]
}
func (res *ArgParseResults) AnyFlagsEqualTo(val bool) *set.StrSet {
results := make([]string, 0, len(res.parser.Supported))
for _, opt := range res.parser.Supported {
if opt.OptType == OptionalFlag || opt.OptType == OptionalRepeatableFlag {
name := opt.Name
_, ok := res.options[name]
if ok == val {
results = append(results, name)
}
}
}
return set.NewStrSet(results)
}
func (res *ArgParseResults) FlagsEqualTo(names []string, val bool) *set.StrSet {
results := make([]string, 0, len(res.parser.Supported))
for _, name := range names {
opt, ok := res.parser.nameOrAbbrevToOpt[name]
if ok && (opt.OptType == OptionalFlag || opt.OptType == OptionalRepeatableFlag) {
_, ok := res.options[name]
if ok == val {
results = append(results, name)
}
}
}
return set.NewStrSet(results)
}
// GetFlagCount returns the count for a repeatable flag (e.g., -v returns 1, -vv returns 2).
// For non-repeatable flags, returns 1 if set, 0 if not set.
// The second return value indicates whether the flag exists and parsing was successful.
func (res *ArgParseResults) GetFlagCount(name string) (int, bool) {
opt, ok := res.parser.nameOrAbbrevToOpt[name]
if !ok {
panic("runtime error: attempted to get flag count for unsupported option: " + name)
}
val, exists := res.options[name]
if !exists {
return 0, false
}
if opt.OptType == OptionalRepeatableFlag && val != "" {
count, err := strconv.Atoi(val)
if err != nil {
return 0, false
}
return count, true
}
// For non-repeatable flags, return 1 if set
return 1, true
}