From 574e76ae935c4931ec50b14a94dee930ed6f3d5a Mon Sep 17 00:00:00 2001 From: ayyansea Date: Mon, 18 Nov 2024 21:53:29 +0300 Subject: feat: restructure project + add a basic cli arg parser --- .gitignore | 1 + Makefile | 2 +- cmd/filter.go | 49 ------------------------------ cmd/filters.go | 46 ---------------------------- cmd/linked_token_list.go | 28 ----------------- cmd/token.go | 30 ------------------- cmd/uptfs.go | 56 ---------------------------------- cmd/uptfs/main.go | 60 +++++++++++++++++++++++++++++++++++++ go.mod | 9 ++++-- go.sum | 8 +++++ internal/config/config.go | 56 ++++++++++++++++++++++++++++++++++ internal/filter/filter.go | 49 ++++++++++++++++++++++++++++++ internal/filter/filters.go | 46 ++++++++++++++++++++++++++++ internal/split/split.go | 55 ++++++++++++++++++++++++++++++++++ internal/token/linked_token_list.go | 36 ++++++++++++++++++++++ internal/token/token.go | 30 +++++++++++++++++++ main.go | 7 ----- util/config/config.go | 56 ---------------------------------- util/split/split.go | 45 ---------------------------- 19 files changed, 349 insertions(+), 320 deletions(-) delete mode 100644 cmd/filter.go delete mode 100644 cmd/filters.go delete mode 100644 cmd/linked_token_list.go delete mode 100644 cmd/token.go delete mode 100644 cmd/uptfs.go create mode 100644 cmd/uptfs/main.go create mode 100644 internal/config/config.go create mode 100644 internal/filter/filter.go create mode 100644 internal/filter/filters.go create mode 100644 internal/split/split.go create mode 100644 internal/token/linked_token_list.go create mode 100644 internal/token/token.go delete mode 100644 main.go delete mode 100644 util/config/config.go delete mode 100644 util/split/split.go diff --git a/.gitignore b/.gitignore index 50ea6e5..6038b91 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ go.work.sum # binary uptfs +!cmd/uptfs/ # config config.yaml diff --git a/Makefile b/Makefile index 0f55e78..8e66ee7 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ all: build .PHONY: build build: @echo "Building Go uptfs..." - go build + go build ./cmd/uptfs .PHONY: clean clean: diff --git a/cmd/filter.go b/cmd/filter.go deleted file mode 100644 index 9d8ccac..0000000 --- a/cmd/filter.go +++ /dev/null @@ -1,49 +0,0 @@ -package cmd - -import ( - "fmt" -) - -type Filter struct { - name string - action func(string) string - subfilters []Filter -} - -type Greeter interface { - Greet() -} - -type Filterer interface { - Greeter - Filter(string) string -} - -func (f Filter) Greet() { - subfilterCount := len(f.subfilters) - - fmt.Printf("I am a filter and my name is %v\n", f.name) - if subfilterCount > 0 { - fmt.Println("My subfilters are:") - - for _, subfilter := range f.subfilters { - fmt.Printf("- %v\n", subfilter.name) - } - } -} - -func (f Filter) Filter(token string) (modifiedToken string) { - subfilterCount := len(f.subfilters) - modifiedToken = token - - if subfilterCount > 0 { - for _, subfilter := range f.subfilters { - modifiedToken = subfilter.action(modifiedToken) - } - - return modifiedToken - } - - modifiedToken = f.action(token) - return modifiedToken -} diff --git a/cmd/filters.go b/cmd/filters.go deleted file mode 100644 index 28592ba..0000000 --- a/cmd/filters.go +++ /dev/null @@ -1,46 +0,0 @@ -package cmd - -import ( - "strings" -) - -var filterList = map[string]interface{}{ - "uppercase": NewUppercaseFilter, - "lowercase": NewLowercaseFilter, - "lowercase_extra": NewLowercaseFilterWithExtraSteps, -} - -func NewUppercaseFilter() Filter { - uppercaseFilter := Filter{ - name: "Uppercase", - action: strings.ToUpper, - subfilters: []Filter{}, - } - - return uppercaseFilter -} - -func NewLowercaseFilter() Filter { - lowercaseFilter := Filter{ - name: "Lowercase", - action: strings.ToLower, - subfilters: []Filter{}, - } - - return lowercaseFilter -} - -func NewLowercaseFilterWithExtraSteps() Filter { - var subfilters []Filter - - subfilters = append(subfilters, NewUppercaseFilter()) - subfilters = append(subfilters, NewLowercaseFilter()) - - filter := Filter{ - name: "Lowercase (extra dumb)", - action: func(string) string { return "" }, - subfilters: subfilters, - } - - return filter -} diff --git a/cmd/linked_token_list.go b/cmd/linked_token_list.go deleted file mode 100644 index c8c876f..0000000 --- a/cmd/linked_token_list.go +++ /dev/null @@ -1,28 +0,0 @@ -package cmd - -type LinkedTokenList struct { - head, tail *Token -} - -func (lts *LinkedTokenList) AddToken(content string) { - newToken := &Token{ - content: content, - prev: nil, - next: nil, - } - - if lts.head == nil { - lts.head = newToken - lts.tail = newToken - } else { - newToken.SetPreviousToken(lts.tail) - lts.tail.SetNextToken(newToken) - lts.tail = newToken - } -} - -func SliceToLinkedTokenSlice(slice []string, tokenSlice *LinkedTokenList) { - for _, item := range slice { - tokenSlice.AddToken(item) - } -} diff --git a/cmd/token.go b/cmd/token.go deleted file mode 100644 index 7652be7..0000000 --- a/cmd/token.go +++ /dev/null @@ -1,30 +0,0 @@ -package cmd - -type Token struct { - content string - prev, next *Token -} - -func (t *Token) GetContent() string { - return t.content -} - -func (t *Token) SetContent(content string) { - t.content = content -} - -func (t *Token) GetPreviousToken() *Token { - return t.prev -} - -func (t *Token) SetPreviousToken(newToken *Token) { - t.prev = newToken -} - -func (t *Token) GetNextToken() *Token { - return t.next -} - -func (t *Token) SetNextToken(newToken *Token) { - t.next = newToken -} diff --git a/cmd/uptfs.go b/cmd/uptfs.go deleted file mode 100644 index 531b102..0000000 --- a/cmd/uptfs.go +++ /dev/null @@ -1,56 +0,0 @@ -package cmd - -import ( - "bufio" - "errors" - "fmt" - "os" - "strings" - "uptfs/util/split" -) - -func Run() { - scanner := bufio.NewScanner(os.Stdin) - scanner.Scan() - inputString := scanner.Text() - - if inputString == "" { - err := errors.New("the input string is empty") - fmt.Printf("%v\n", err) - os.Exit(1) - } - - additionalDelimeters := []string{",", "."} - tokens := strings.Split(inputString, " ") - tokens = formatInput(tokens, additionalDelimeters) - - if len(tokens) == 0 { - err := errors.New("the slice is empty") - fmt.Printf("%v\n", err) - os.Exit(1) - } - - var linkedTokens LinkedTokenList - SliceToLinkedTokenSlice(tokens, &linkedTokens) - - lowercaseFilter := NewLowercaseFilterWithExtraSteps() - uppercaseFilter := NewUppercaseFilter() - - for current := linkedTokens.head; current != nil; current = current.GetNextToken() { - current.content = lowercaseFilter.Filter(current.content) - current.content = uppercaseFilter.Filter(current.content) - } - - fmt.Println("Head: ", linkedTokens.head.content) - fmt.Println("Tail: ", linkedTokens.tail.content) -} - -func formatInput(tokenArray []string, delimeterArray []string) []string { - for _, delimeter := range delimeterArray { - for index, element := range tokenArray { - tokenArray = split.NewArrayWithSplit(tokenArray, index, element, delimeter) - } - } - - return tokenArray -} diff --git a/cmd/uptfs/main.go b/cmd/uptfs/main.go new file mode 100644 index 0000000..4ecb045 --- /dev/null +++ b/cmd/uptfs/main.go @@ -0,0 +1,60 @@ +package main + +import ( + "bufio" + "errors" + "fmt" + "os" + "strings" + + "github.com/alexflint/go-arg" + "github.com/ayyansea/uptfs/internal/filter" + "github.com/ayyansea/uptfs/internal/split" + "github.com/ayyansea/uptfs/internal/token" +) + +var args struct { + Foo string `help:"it's a foo"` + Bar bool `help:"it's a bar"` +} + +func main() { + arg.MustParse(&args) + fmt.Println(args.Foo, args.Bar) + + scanner := bufio.NewScanner(os.Stdin) + scanner.Scan() + inputString := scanner.Text() + + if inputString == "" { + err := errors.New("the input string is empty") + fmt.Printf("%v\n", err) + os.Exit(1) + } + + additionalDelimeters := []string{",", "."} + tokens := strings.Split(inputString, " ") + tokens = split.FormatInput(tokens, additionalDelimeters) + + if len(tokens) == 0 { + err := errors.New("the slice is empty") + fmt.Printf("%v\n", err) + os.Exit(1) + } + + var linkedTokens token.LinkedTokenList + token.SliceToLinkedTokenSlice(tokens, &linkedTokens) + + lowercaseFilter := filter.NewLowercaseFilterWithExtraSteps() + uppercaseFilter := filter.NewUppercaseFilter() + + for current := linkedTokens.GetHead(); current != nil; current = current.GetNextToken() { + current.SetContent(lowercaseFilter.Filter(current.GetContent())) + current.SetContent(uppercaseFilter.Filter(current.GetContent())) + } + + head := linkedTokens.GetHead() + tail := linkedTokens.GetTail() + fmt.Println("Head: ", head.GetContent()) + fmt.Println("Tail: ", tail.GetContent()) +} diff --git a/go.mod b/go.mod index 53c34e3..79ff641 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,10 @@ -module uptfs +module github.com/ayyansea/uptfs go 1.23.2 -require gopkg.in/yaml.v3 v3.0.1 // indirect +require gopkg.in/yaml.v3 v3.0.1 + +require ( + github.com/alexflint/go-arg v1.5.1 // indirect + github.com/alexflint/go-scalar v1.2.0 // indirect +) diff --git a/go.sum b/go.sum index 4bc0337..e8c83d5 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,11 @@ +github.com/alexflint/go-arg v1.5.1 h1:nBuWUCpuRy0snAG+uIJ6N0UvYxpxA0/ghA/AaHxlT8Y= +github.com/alexflint/go-arg v1.5.1/go.mod h1:A7vTJzvjoaSTypg4biM5uYNTkJ27SkNTArtYXnlqVO8= +github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw= +github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..ad35ee7 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,56 @@ +package config + +import ( + "errors" + "fmt" + "os" + "path/filepath" + + "gopkg.in/yaml.v3" +) + +type Config struct { + Filters []string `yaml:"filters"` + Iterations int `yaml:"iterations"` +} + +func getDefaultConfigPath() (defaultPath string, err error) { + programName := "uptfs" + configFileName := "config.yaml" + + if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" { + return filepath.Join(xdg, programName, configFileName), nil + } + + if home := os.Getenv("HOME"); home != "" { + return filepath.Join(home, programName, configFileName), nil + } + + return "", errors.New("both XDG_CONFIG_HOME and HOME are not set, can't proceed") +} + +func (c *Config) LoadConfig(filepath string) *Config { + if filepath == "" { + var err error + filepath, err = getDefaultConfigPath() + + if err != nil { + fmt.Printf("%v\n", err) + os.Exit(1) + } + } + + yamlFile, err := os.ReadFile(filepath) + + if err != nil { + fmt.Printf("%v\n", err) + os.Exit(1) + } + err = yaml.Unmarshal(yamlFile, c) + if err != nil { + fmt.Printf("%v\n", err) + os.Exit(1) + } + + return c +} diff --git a/internal/filter/filter.go b/internal/filter/filter.go new file mode 100644 index 0000000..3fff07f --- /dev/null +++ b/internal/filter/filter.go @@ -0,0 +1,49 @@ +package filter + +import ( + "fmt" +) + +type Filter struct { + name string + action func(string) string + subfilters []Filter +} + +type Greeter interface { + Greet() +} + +type Filterer interface { + Greeter + Filter(string) string +} + +func (f Filter) Greet() { + subfilterCount := len(f.subfilters) + + fmt.Printf("I am a filter and my name is %v\n", f.name) + if subfilterCount > 0 { + fmt.Println("My subfilters are:") + + for _, subfilter := range f.subfilters { + fmt.Printf("- %v\n", subfilter.name) + } + } +} + +func (f Filter) Filter(token string) (modifiedToken string) { + subfilterCount := len(f.subfilters) + modifiedToken = token + + if subfilterCount > 0 { + for _, subfilter := range f.subfilters { + modifiedToken = subfilter.action(modifiedToken) + } + + return modifiedToken + } + + modifiedToken = f.action(token) + return modifiedToken +} diff --git a/internal/filter/filters.go b/internal/filter/filters.go new file mode 100644 index 0000000..8532fef --- /dev/null +++ b/internal/filter/filters.go @@ -0,0 +1,46 @@ +package filter + +import ( + "strings" +) + +var filterList = map[string]interface{}{ + "uppercase": NewUppercaseFilter, + "lowercase": NewLowercaseFilter, + "lowercase_extra": NewLowercaseFilterWithExtraSteps, +} + +func NewUppercaseFilter() Filter { + uppercaseFilter := Filter{ + name: "Uppercase", + action: strings.ToUpper, + subfilters: []Filter{}, + } + + return uppercaseFilter +} + +func NewLowercaseFilter() Filter { + lowercaseFilter := Filter{ + name: "Lowercase", + action: strings.ToLower, + subfilters: []Filter{}, + } + + return lowercaseFilter +} + +func NewLowercaseFilterWithExtraSteps() Filter { + var subfilters []Filter + + subfilters = append(subfilters, NewUppercaseFilter()) + subfilters = append(subfilters, NewLowercaseFilter()) + + filter := Filter{ + name: "Lowercase (extra dumb)", + action: func(string) string { return "" }, + subfilters: subfilters, + } + + return filter +} diff --git a/internal/split/split.go b/internal/split/split.go new file mode 100644 index 0000000..e03335c --- /dev/null +++ b/internal/split/split.go @@ -0,0 +1,55 @@ +package split + +import ( + "strings" +) + +func FormatInput(tokenArray []string, delimeterArray []string) []string { + for _, delimeter := range delimeterArray { + for index, element := range tokenArray { + tokenArray = NewArrayWithSplit(tokenArray, index, element, delimeter) + } + } + + return tokenArray +} + +func checkArrayElementsEmpty(array []string) bool { + for _, str := range array { + if str != "" { + return false + } + } + return true +} + +func NewArrayWithSplit(initialArray []string, index int, token string, delimeter string) (result []string) { + split := strings.Split(token, delimeter) + splitLength := len(split) + + /* + When a token only consists of delimeter * N (N >= 0), + the resulting split consists of N empty elements. + Here we check if it is so and essentialy remove that token + from resulting array. + */ + + splitIsEmpty := checkArrayElementsEmpty(split) + if splitIsEmpty { + result = append(initialArray[:index], initialArray[index+1:]...) + return result + } + + if splitLength > 1 { + if split[splitLength-1] == "" { + split = split[:splitLength-1] + } + + result = append(initialArray[:index], append(split, initialArray[index+1:]...)...) + } + if splitLength == 1 { + result = initialArray + } + + return result +} diff --git a/internal/token/linked_token_list.go b/internal/token/linked_token_list.go new file mode 100644 index 0000000..5fe42a9 --- /dev/null +++ b/internal/token/linked_token_list.go @@ -0,0 +1,36 @@ +package token + +type LinkedTokenList struct { + head, tail *Token +} + +func (lts *LinkedTokenList) GetHead() *Token { + return lts.head +} + +func (lts *LinkedTokenList) GetTail() *Token { + return lts.tail +} + +func (lts *LinkedTokenList) AddToken(content string) { + newToken := &Token{ + content: content, + prev: nil, + next: nil, + } + + if lts.head == nil { + lts.head = newToken + lts.tail = newToken + } else { + newToken.SetPreviousToken(lts.tail) + lts.tail.SetNextToken(newToken) + lts.tail = newToken + } +} + +func SliceToLinkedTokenSlice(slice []string, tokenSlice *LinkedTokenList) { + for _, item := range slice { + tokenSlice.AddToken(item) + } +} diff --git a/internal/token/token.go b/internal/token/token.go new file mode 100644 index 0000000..c4dffd8 --- /dev/null +++ b/internal/token/token.go @@ -0,0 +1,30 @@ +package token + +type Token struct { + content string + prev, next *Token +} + +func (t *Token) GetContent() string { + return t.content +} + +func (t *Token) SetContent(content string) { + t.content = content +} + +func (t *Token) GetPreviousToken() *Token { + return t.prev +} + +func (t *Token) SetPreviousToken(newToken *Token) { + t.prev = newToken +} + +func (t *Token) GetNextToken() *Token { + return t.next +} + +func (t *Token) SetNextToken(newToken *Token) { + t.next = newToken +} diff --git a/main.go b/main.go deleted file mode 100644 index 10c5c9a..0000000 --- a/main.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "uptfs/cmd" - -func main() { - cmd.Run() -} diff --git a/util/config/config.go b/util/config/config.go deleted file mode 100644 index ad35ee7..0000000 --- a/util/config/config.go +++ /dev/null @@ -1,56 +0,0 @@ -package config - -import ( - "errors" - "fmt" - "os" - "path/filepath" - - "gopkg.in/yaml.v3" -) - -type Config struct { - Filters []string `yaml:"filters"` - Iterations int `yaml:"iterations"` -} - -func getDefaultConfigPath() (defaultPath string, err error) { - programName := "uptfs" - configFileName := "config.yaml" - - if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" { - return filepath.Join(xdg, programName, configFileName), nil - } - - if home := os.Getenv("HOME"); home != "" { - return filepath.Join(home, programName, configFileName), nil - } - - return "", errors.New("both XDG_CONFIG_HOME and HOME are not set, can't proceed") -} - -func (c *Config) LoadConfig(filepath string) *Config { - if filepath == "" { - var err error - filepath, err = getDefaultConfigPath() - - if err != nil { - fmt.Printf("%v\n", err) - os.Exit(1) - } - } - - yamlFile, err := os.ReadFile(filepath) - - if err != nil { - fmt.Printf("%v\n", err) - os.Exit(1) - } - err = yaml.Unmarshal(yamlFile, c) - if err != nil { - fmt.Printf("%v\n", err) - os.Exit(1) - } - - return c -} diff --git a/util/split/split.go b/util/split/split.go deleted file mode 100644 index 2fc29db..0000000 --- a/util/split/split.go +++ /dev/null @@ -1,45 +0,0 @@ -package split - -import ( - "strings" -) - -func checkArrayElementsEmpty(array []string) bool { - for _, str := range array { - if str != "" { - return false - } - } - return true -} - -func NewArrayWithSplit(initialArray []string, index int, token string, delimeter string) (result []string) { - split := strings.Split(token, delimeter) - splitLength := len(split) - - /* - When a token only consists of delimeter * N (N >= 0), - the resulting split consists of N empty elements. - Here we check if it is so and essentialy remove that token - from resulting array. - */ - - splitIsEmpty := checkArrayElementsEmpty(split) - if splitIsEmpty { - result = append(initialArray[:index], initialArray[index+1:]...) - return result - } - - if splitLength > 1 { - if split[splitLength-1] == "" { - split = split[:splitLength-1] - } - - result = append(initialArray[:index], append(split, initialArray[index+1:]...)...) - } - if splitLength == 1 { - result = initialArray - } - - return result -} -- cgit v1.2.3