Adding initial version got from MysqlMigrationToolkit.

This commit is contained in:
sergiotarxz 2021-02-28 00:04:19 +01:00
parent a4cdbb3dbb
commit 827c0abb56
Signed by: sergiotarxz
GPG Key ID: E5903508B6510AC2
4 changed files with 417 additions and 0 deletions

143
getopt.go Normal file
View 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
View 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
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module getopt
go 1.15

156
private.go Normal file
View 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
}