Adding initial version got from MysqlMigrationToolkit.
This commit is contained in:
parent
a4cdbb3dbb
commit
827c0abb56
143
getopt.go
Normal file
143
getopt.go
Normal file
@ -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
|
||||||
|
}
|
115
getopt_test/getopt_test.go
Normal file
115
getopt_test/getopt_test.go
Normal file
@ -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
|
||||||
|
}
|
156
private.go
Normal file
156
private.go
Normal file
@ -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
Block a user