Adding initial version got from MysqlMigrationToolkit.
This commit is contained in:
parent
a4cdbb3dbb
commit
827c0abb56
|
@ -0,0 +1,143 @@
|
|||
package getopt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type flag struct {
|
||||
name string
|
||||
shortname string
|
||||
description string
|
||||
required bool
|
||||
value interface{}
|
||||
}
|
||||
|
||||
type GetoptInterface interface {
|
||||
StringLong(name *string, shortname *rune, required bool, description string) **string
|
||||
Usage()
|
||||
BoolLong(name *string, shortname *rune, description string) *bool
|
||||
NoOptionArgs() []string
|
||||
Parse([]string)
|
||||
ParseArgv()
|
||||
UInt64Long(name *string, shortname *rune, required bool, description string) **uint64
|
||||
CheckRequiredOptions() (bool, string, string)
|
||||
}
|
||||
|
||||
type Getopt struct {
|
||||
array_flags []*flag
|
||||
flags map[string]*flag
|
||||
flagsByShortname map[string]*flag
|
||||
commonArgs []string
|
||||
}
|
||||
|
||||
func New() Getopt {
|
||||
return Getopt{
|
||||
array_flags: make([]*flag, 0),
|
||||
commonArgs: make([]string, 0),
|
||||
flags: make(map[string]*flag),
|
||||
flagsByShortname: make(map[string]*flag),
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Getopt) CheckRequiredOptions() (bool, string, string) {
|
||||
for _, value := range self.array_flags {
|
||||
switch value.value.(interface{}).(type) {
|
||||
case *bool:
|
||||
continue
|
||||
case **string:
|
||||
if value.required && *value.value.(**string) == nil {
|
||||
return false, value.name, value.shortname
|
||||
}
|
||||
|
||||
case **uint64:
|
||||
if value.required && *value.value.(**uint64) == nil {
|
||||
return false, value.name, value.shortname
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, "", ""
|
||||
}
|
||||
|
||||
func (self *Getopt) StringLong(name *string, shortname *rune, required bool, description string) **string {
|
||||
var value *string = nil
|
||||
flagToAssign := flag{self.nilToEmptyString(name), self.nilRuneToEmptyString(shortname), description, required, &value}
|
||||
if name != nil {
|
||||
self.flags[*name] = &flagToAssign
|
||||
}
|
||||
if shortname != nil {
|
||||
self.flagsByShortname[string(*shortname)] = &flagToAssign
|
||||
}
|
||||
self.array_flags = append(self.array_flags, &flagToAssign)
|
||||
return &value
|
||||
}
|
||||
|
||||
func (self *Getopt) Usage() {
|
||||
fmt.Print(self.UsageString())
|
||||
}
|
||||
|
||||
func (self *Getopt) UsageString() string {
|
||||
var return_string string
|
||||
var usage [][]string
|
||||
for _, value := range self.array_flags {
|
||||
usage = append(usage, self.usageOption(*value))
|
||||
}
|
||||
max := self.maxLen(usage)
|
||||
for _, value := range usage {
|
||||
for j, j_value := range value {
|
||||
return_string += fmt.Sprintf("\t%-"+strconv.FormatInt(max[j], 10)+"s", j_value)
|
||||
}
|
||||
return_string += fmt.Sprintf("\n")
|
||||
}
|
||||
return return_string
|
||||
}
|
||||
|
||||
func (self *Getopt) BoolLong(name *string, shortname *rune, description string) *bool {
|
||||
value := false
|
||||
flagToAssign := flag{self.nilToEmptyString(name), self.nilRuneToEmptyString(shortname), description, true, &value}
|
||||
if name != nil {
|
||||
self.flags[*name] = &flagToAssign
|
||||
}
|
||||
if shortname != nil {
|
||||
self.flagsByShortname[string(*shortname)] = &flagToAssign
|
||||
}
|
||||
self.array_flags = append(self.array_flags, &flagToAssign)
|
||||
return &value
|
||||
}
|
||||
|
||||
func (self *Getopt) UInt64Long(name *string, shortname *rune, required bool, description string) **uint64 {
|
||||
var value *uint64 = nil
|
||||
flagToAssign := flag{self.nilToEmptyString(name), self.nilRuneToEmptyString(shortname), description, required, &value}
|
||||
if name != nil {
|
||||
self.flags[*name] = &flagToAssign
|
||||
}
|
||||
if shortname != nil {
|
||||
self.flagsByShortname[string(*shortname)] = &flagToAssign
|
||||
}
|
||||
self.array_flags = append(self.array_flags, &flagToAssign)
|
||||
return &value
|
||||
}
|
||||
|
||||
func (self *Getopt) ParseArgv() {
|
||||
args := os.Args[1:]
|
||||
self.Parse(args)
|
||||
}
|
||||
|
||||
func (self *Getopt) Parse(args []string) {
|
||||
expectingArgument := false
|
||||
var expectingFor string
|
||||
short := false
|
||||
for _, value := range args {
|
||||
if !expectingArgument {
|
||||
self.parseNotOptionArgument(value, &expectingArgument, &expectingFor, &short)
|
||||
} else {
|
||||
self.parseOptionArgument(value, expectingFor, short)
|
||||
expectingArgument = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Getopt) NoOptionArgs() []string {
|
||||
return self.commonArgs
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package getopt_test
|
||||
|
||||
import (
|
||||
g "getopt"
|
||||
"regexp"
|
||||
"testing"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func TestStringArgNull(t *testing.T) {
|
||||
getopt := g.New()
|
||||
hello := getopt.StringLong(s("hello"), nil, false, "Try")
|
||||
getopt.Parse([]string{})
|
||||
if hello == nil {
|
||||
t.Error("Unable to dereference hello")
|
||||
}
|
||||
if *hello != nil {
|
||||
t.Error("Hola was not set to nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringArgNotNull(t *testing.T) {
|
||||
getopt := g.New()
|
||||
hello := getopt.StringLong(s("hello"), nil, false, "Try")
|
||||
getopt.Parse([]string{"--hello", "hello"})
|
||||
if hello == nil {
|
||||
t.Error("Unable to dereference hello")
|
||||
}
|
||||
if *hello == nil {
|
||||
t.Error("--hello is not received.")
|
||||
}
|
||||
if **hello != "hello" {
|
||||
t.Error("Unexpected value in --hello " + **hello + ".")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringArgNotNullWithRune(t *testing.T) {
|
||||
getopt := g.New()
|
||||
hello := getopt.StringLong(nil, r('h'), false, "Try")
|
||||
getopt.Parse([]string{"-hhello"})
|
||||
if hello == nil {
|
||||
t.Error("Unable to dereference hello")
|
||||
}
|
||||
if *hello == nil {
|
||||
t.Error("-h is not received.")
|
||||
}
|
||||
if **hello != "hello" {
|
||||
t.Error("Unexpected value in --hello " + **hello + ".")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringArgNotNullWithRuneUsingExternalArgument(t *testing.T) {
|
||||
getopt := g.New()
|
||||
hello := getopt.StringLong(nil, r('h'), false, "Try")
|
||||
getopt.Parse([]string{"-h", "hello"})
|
||||
if hello == nil {
|
||||
t.Error("Unable to dereference hello")
|
||||
}
|
||||
if *hello == nil {
|
||||
t.Error("-h is not received.")
|
||||
}
|
||||
if **hello != "hello" {
|
||||
t.Error("Unexpected value in --hello " + **hello + ".")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsingNonOptionAndNotOptionArgument(t *testing.T) {
|
||||
getopt := g.New()
|
||||
getopt.StringLong(nil, r('h'), false, "Try")
|
||||
getopt.Parse([]string{"-h", "a", "hello", "world"})
|
||||
args := getopt.NoOptionArgs()
|
||||
if args[0] != "hello" {
|
||||
t.Error("Argument hello not received.")
|
||||
}
|
||||
if args[1] != "world" {
|
||||
t.Error("Argument world not received.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsingBoolOptionFalse(t *testing.T) {
|
||||
getopt := g.New()
|
||||
h := getopt.BoolLong(nil, r('h'), "Try")
|
||||
getopt.Parse([]string{""})
|
||||
if *h {
|
||||
t.Error("Unexpected value of -h.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsingBoolOptionTrue(t *testing.T) {
|
||||
getopt := g.New()
|
||||
h := getopt.BoolLong(nil, r('h'), "Try")
|
||||
getopt.Parse([]string{"-h"})
|
||||
if !*h {
|
||||
t.Error("Unexpected value of -h.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsingBoolOptionUsage(t *testing.T) {
|
||||
getopt := g.New()
|
||||
getopt.BoolLong(s("help"), r('h'), "Try")
|
||||
getopt.Parse([]string{""})
|
||||
result_string := getopt.UsageString()
|
||||
expected := []string{"--help", "-h", "(required)", "Try"}
|
||||
re := regexp.MustCompile(`\t(\S+)\t(\S+)\t\t(\S+)\t(\S+)`)
|
||||
if reflect.DeepEqual(re.FindStringSubmatch(result_string), expected) {
|
||||
t.Error("Unmatched expected and result.")
|
||||
}
|
||||
}
|
||||
func s(a string) *string {
|
||||
return &a
|
||||
}
|
||||
|
||||
func r(a rune) *rune {
|
||||
return &a
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
package getopt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (self *Getopt) usageOption(flagToStringify flag) []string {
|
||||
var printArgument bool
|
||||
switch flagToStringify.value.(interface{}).(type) {
|
||||
case *bool:
|
||||
printArgument = false
|
||||
default:
|
||||
printArgument = true
|
||||
}
|
||||
var returned []string
|
||||
if flagToStringify.shortname != "" {
|
||||
returned = append(returned, "-"+flagToStringify.shortname)
|
||||
} else {
|
||||
returned = append(returned, "")
|
||||
}
|
||||
if flagToStringify.name != "" {
|
||||
returned = append(returned, "--"+flagToStringify.name)
|
||||
} else {
|
||||
returned = append(returned, "")
|
||||
}
|
||||
if printArgument {
|
||||
returned = append(returned, "<argument>")
|
||||
} else {
|
||||
returned = append(returned, "")
|
||||
}
|
||||
|
||||
if flagToStringify.required {
|
||||
returned = append(returned, "(required)")
|
||||
} else {
|
||||
returned = append(returned, "")
|
||||
}
|
||||
|
||||
returned = append(returned, flagToStringify.description)
|
||||
return returned
|
||||
}
|
||||
|
||||
func (self *Getopt) maxLen(lol [][]string) []int64 {
|
||||
var returned []int64 = make([]int64, 5)
|
||||
for _, i_val := range lol {
|
||||
for j, j_val := range i_val {
|
||||
if returned[j] < int64(len(j_val)) {
|
||||
returned[j] = int64(len(j_val))
|
||||
}
|
||||
}
|
||||
}
|
||||
return returned
|
||||
}
|
||||
|
||||
func (self *Getopt) parseOptionArgument(value string, expectingFor string, short bool) {
|
||||
var gotFlag *flag
|
||||
var ok bool
|
||||
if short {
|
||||
gotFlag, ok = self.flagsByShortname[expectingFor]
|
||||
} else {
|
||||
gotFlag, ok = self.flags[expectingFor]
|
||||
}
|
||||
if !ok {
|
||||
fmt.Printf("Error retrieving the key, this IS a bug. %s\n", expectingFor)
|
||||
}
|
||||
self.assignToFlag(gotFlag, value)
|
||||
|
||||
}
|
||||
|
||||
func (self *Getopt) parseNotOptionArgument(currentIteration string, expectingArgument *bool, expectingFor *string, short *bool) {
|
||||
matchName, err := regexp.MatchString("^--", currentIteration)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
matchShortname, err := regexp.MatchString("^-", currentIteration)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
if matchName {
|
||||
*short = false
|
||||
self.parseOption(currentIteration, expectingFor, expectingArgument, `^--([^=]*)(?:=(.*))?$`, self.flags)
|
||||
} else if matchShortname {
|
||||
*short = true
|
||||
self.parseOption(currentIteration, expectingFor, expectingArgument, `^-(.)(.+)?$`, self.flagsByShortname)
|
||||
} else {
|
||||
self.commonArgs = append(self.commonArgs, currentIteration)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Getopt) parseOption(currentIteration string, expectingFor *string, expectingArgument *bool, option_regex string, flags map[string]*flag) {
|
||||
re := regexp.MustCompile(option_regex)
|
||||
listName := re.FindStringSubmatch(currentIteration)
|
||||
name := listName[1]
|
||||
gotFlag, ok := flags[name]
|
||||
if !ok {
|
||||
fmt.Printf("%s not in the option list.\n", name)
|
||||
self.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
var nextParameter bool
|
||||
switch gotFlag.value.(interface{}).(type) {
|
||||
case *bool:
|
||||
nextParameter = false
|
||||
*(gotFlag.value.(*bool)) = true
|
||||
default:
|
||||
nextParameter = true
|
||||
}
|
||||
if listName[2] != "" {
|
||||
if !nextParameter {
|
||||
fmt.Printf("%s does not get any parameters.\n", name)
|
||||
self.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
gotParameter := listName[2]
|
||||
self.assignToFlag(gotFlag, gotParameter)
|
||||
} else if nextParameter {
|
||||
*expectingArgument = true
|
||||
*expectingFor = name
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Getopt) assignToFlag(toAssignFlag *flag, value string) {
|
||||
switch toAssignFlag.value.(interface{}).(type) {
|
||||
case **string:
|
||||
*(toAssignFlag.value.(**string)) = &value
|
||||
case **uint64:
|
||||
value_uint, err := strconv.ParseUint(value, 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("%s is not parseable into a unsigned interger of 64 bits.\n", value)
|
||||
self.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
*(toAssignFlag.value.(**uint64)) = &value_uint
|
||||
default:
|
||||
fmt.Printf("Unsupported type %v.\n", toAssignFlag.value)
|
||||
self.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Getopt) nilRuneToEmptyString(input *rune) string {
|
||||
if input == nil {
|
||||
return ""
|
||||
}
|
||||
return string(*input)
|
||||
}
|
||||
|
||||
func (self *Getopt) nilToEmptyString(input *string) string {
|
||||
if input == nil {
|
||||
return ""
|
||||
}
|
||||
return *input
|
||||
}
|
Loading…
Reference in New Issue