diff --git a/cmd/enbas-cli-generators/main.go b/cmd/enbas-cli-generators/main.go index d58c32d..ec562e0 100644 --- a/cmd/enbas-cli-generators/main.go +++ b/cmd/enbas-cli-generators/main.go @@ -36,11 +36,11 @@ func main() { func generateExecutors(schema enbasCLISchema, output string) error { funcMap := template.FuncMap{ - "capitalise": capitalise, - "flagFieldName": flagFieldName, - "getFlagType": schema.Flags.getType, - "getFlagDescription": schema.Flags.getDescription, - "customFlagValueType": customFlagValueType, + "capitalise": capitalise, + "flagFieldName": flagFieldName, + "getFlagType": schema.Flags.getType, + "getFlagDescription": schema.Flags.getDescription, + "internalFlagValue": internalFlagValue, } tmpl := template.Must(template.New("executor-template").Funcs(funcMap).Parse(executorsFileTemplate)) @@ -109,15 +109,15 @@ func convertFlagToMixedCaps(value string) string { return builder.String() } -func customFlagValueType(flagType string) bool { - customFlagValueTypes := map[string]struct{}{ - "MultiStringFlagValue": {}, - "MultiIntFlagValue": {}, - "TimeDurationFlagValue": {}, - "BoolPtrFlagValue": {}, +func internalFlagValue(flagType string) bool { + internalFlagValues := map[string]struct{}{ + "StringSliceValue": {}, + "IntSliceValue": {}, + "TimeDurationValue": {}, + "BoolPtrValue": {}, } - _, exists := customFlagValueTypes[flagType] + _, exists := internalFlagValues[flagType] return exists } diff --git a/cmd/enbas-cli-generators/templates.go b/cmd/enbas-cli-generators/templates.go index e20870b..19f4820 100644 --- a/cmd/enbas-cli-generators/templates.go +++ b/cmd/enbas-cli-generators/templates.go @@ -1,11 +1,14 @@ package main -var executorsFileTemplate = `package executor -{{ print "" }} -/* +var executorsFileTemplate = `/* This file is generated by ./cmd/enbas-cli-generators DO NOT EDIT. */ +{{ print "" }} +package executor +{{ print "" }} +{{ print "" }} +import internalFlag "codeflow.dananglin.me.uk/apollo/enbas/internal/flag" {{ range $name, $command := . }} {{- $struct_name := capitalise $name | printf "%sExecutor" -}} {{- $new_executor_function_name := capitalise $name | printf "New%sExecutor" -}} @@ -20,8 +23,14 @@ type {{ $struct_name }} struct { config *config.Config {{- end }} {{- range $flag := $command.Flags -}} + {{- $flag_type := getFlagType $flag.Flag -}} + {{- if internalFlagValue $flag_type -}} {{ print "" }} - {{ flagFieldName $flag }} {{ getFlagType $flag.Flag }} + {{ flagFieldName $flag }} internalFlag.{{ $flag_type }} + {{- else -}} + {{ print "" }} + {{ flagFieldName $flag }} {{ $flag_type }} + {{- end -}} {{- end -}} {{- range $field := $command.AdditionalFields -}} {{ print "" }} @@ -53,9 +62,9 @@ func {{ $new_executor_function_name }}( {{- end }} {{- range $flag := $command.Flags -}} {{- $flag_type := getFlagType $flag.Flag -}} - {{- if customFlagValueType $flag_type -}} + {{- if internalFlagValue $flag_type -}} {{ print "" }} - {{ flagFieldName $flag }}: New{{ $flag_type }}(), + {{ flagFieldName $flag }}: internalFlag.New{{ $flag_type }}(), {{- end -}} {{- end -}} {{- range $field := $command.AdditionalFields -}} @@ -78,7 +87,7 @@ func {{ $new_executor_function_name }}( {{- else if eq $flag_type "int" -}} {{ print "" }} exe.IntVar(&exe.{{ flagFieldName $flag }}, {{ printf "%q" $flag.Flag }}, {{ $flag.Default }}, {{ getFlagDescription $flag.Flag | printf "%q" }}) - {{- else if customFlagValueType $flag_type -}} + {{- else if internalFlagValue $flag_type -}} {{ print "" }} exe.Var(&exe.{{ flagFieldName $flag }}, {{ printf "%q" $flag.Flag }}, {{ getFlagDescription $flag.Flag | printf "%q" }}) {{- end -}} diff --git a/cmd/enbas/main.go b/cmd/enbas/main.go index 92fc39b..605f4a4 100644 --- a/cmd/enbas/main.go +++ b/cmd/enbas/main.go @@ -2,12 +2,11 @@ package main import ( "flag" - "fmt" "os" - "strconv" "codeflow.dananglin.me.uk/apollo/enbas/internal/config" "codeflow.dananglin.me.uk/apollo/enbas/internal/executor" + internalFlag "codeflow.dananglin.me.uk/apollo/enbas/internal/flag" "codeflow.dananglin.me.uk/apollo/enbas/internal/printer" ) @@ -26,22 +25,12 @@ func main() { func run() error { var ( - configDir string - noColor *bool + configDir string + noColorFlag internalFlag.BoolPtrValue ) flag.StringVar(&configDir, "config-dir", "", "Specify your config directory") - flag.BoolFunc("no-color", "Disable ANSI colour output when displaying text on screen", func(value string) error { - boolVal, err := strconv.ParseBool(value) - if err != nil { - return fmt.Errorf("unable to parse %q as a boolean: %w", value, err) - } - - noColor = new(bool) - *noColor = boolVal - - return nil - }) + flag.Var(&noColorFlag, "no-color", "Disable ANSI colour output when displaying text on screen") flag.Usage = usageFunc(executor.CommandSummaryMap()) @@ -53,15 +42,12 @@ func run() error { return nil } - // If NoColor is still unspecified, - // check to see if the NO_COLOR environment variable is set - if noColor == nil { - noColor = new(bool) - if os.Getenv("NO_COLOR") != "" { - *noColor = true - } else { - *noColor = false - } + var noColor bool + + if noColorFlag.Value != nil { + noColor = *noColorFlag.Value + } else if os.Getenv("NO_COLOR") != "" { + noColor = true } command := flag.Arg(0) @@ -75,17 +61,21 @@ func run() error { switch command { case executor.CommandInit, executor.CommandVersion: - enbasPrinter = printer.NewPrinter(*noColor, "", 0) + enbasPrinter = printer.NewPrinter(noColor, "", 0) default: enbasConfig, err = config.NewConfigFromFile(configDir) if err != nil { - enbasPrinter = printer.NewPrinter(*noColor, "", 0) + enbasPrinter = printer.NewPrinter(noColor, "", 0) enbasPrinter.PrintFailure("unable to load the configuration: " + err.Error() + ".") return err } - enbasPrinter = printer.NewPrinter(*noColor, enbasConfig.Integrations.Pager, enbasConfig.LineWrapMaxWidth) + enbasPrinter = printer.NewPrinter( + noColor, + enbasConfig.Integrations.Pager, + enbasConfig.LineWrapMaxWidth, + ) } executorMap := map[string]executor.Executor{ diff --git a/internal/executor/add.go b/internal/executor/add.go index a9a7231..b09f7b6 100644 --- a/internal/executor/add.go +++ b/internal/executor/add.go @@ -7,6 +7,7 @@ import ( "codeflow.dananglin.me.uk/apollo/enbas/internal/client" "codeflow.dananglin.me.uk/apollo/enbas/internal/config" + internalFlag "codeflow.dananglin.me.uk/apollo/enbas/internal/flag" "codeflow.dananglin.me.uk/apollo/enbas/internal/printer" ) @@ -20,20 +21,18 @@ type AddExecutor struct { listID string statusID string pollID string - choices MultiIntFlagValue - accountNames MultiStringFlagValue + choices internalFlag.IntSliceValue + accountNames internalFlag.StringSliceValue content string } func NewAddExecutor(printer *printer.Printer, config *config.Config, name, summary string) *AddExecutor { - emptyArr := make([]string, 0, 3) - addExe := AddExecutor{ FlagSet: flag.NewFlagSet(name, flag.ExitOnError), printer: printer, config: config, - accountNames: MultiStringFlagValue(emptyArr), + accountNames: internalFlag.NewStringSliceValue(), } addExe.StringVar(&addExe.resourceType, flagType, "", "Specify the resource type to add (e.g. account, note)") diff --git a/internal/executor/executors.go b/internal/executor/executors.go index dc28933..9586e51 100644 --- a/internal/executor/executors.go +++ b/internal/executor/executors.go @@ -1,17 +1,18 @@ +/* + This file is generated by ./cmd/enbas-cli-generators + DO NOT EDIT. +*/ + package executor import ( "flag" "codeflow.dananglin.me.uk/apollo/enbas/internal/config" + internalFlag "codeflow.dananglin.me.uk/apollo/enbas/internal/flag" "codeflow.dananglin.me.uk/apollo/enbas/internal/printer" ) -/* - This file is generated by ./cmd/enbas-cli-generators - DO NOT EDIT. -*/ - // AcceptExecutor is the executor for the accept command. type AcceptExecutor struct { *flag.FlagSet @@ -84,10 +85,10 @@ type CreateExecutor struct { listRepliesPolicy string listTitle string pollAllowsMultipleChoices bool - pollExpiresIn TimeDurationFlagValue + pollExpiresIn internalFlag.TimeDurationValue pollHidesVoteCounts bool - pollOptions MultiStringFlagValue - sensitive BoolPtrFlagValue + pollOptions internalFlag.StringSliceValue + sensitive internalFlag.BoolPtrValue spoilerText string resourceType string visibility string @@ -101,9 +102,9 @@ func NewCreateExecutor( FlagSet: flag.NewFlagSet("create", flag.ExitOnError), printer: printer, config: config, - pollExpiresIn: NewTimeDurationFlagValue(), - pollOptions: NewMultiStringFlagValue(), - sensitive: NewBoolPtrFlagValue(), + pollExpiresIn: internalFlag.NewTimeDurationValue(), + pollOptions: internalFlag.NewStringSliceValue(), + sensitive: internalFlag.NewBoolPtrValue(), } exe.Usage = commandUsageFunc("create", "Creates a specific resource", exe.FlagSet) @@ -274,7 +275,7 @@ type MuteExecutor struct { printer *printer.Printer config *config.Config accountName string - muteDuration TimeDurationFlagValue + muteDuration internalFlag.TimeDurationValue muteNotifications bool resourceType string } @@ -287,7 +288,7 @@ func NewMuteExecutor( FlagSet: flag.NewFlagSet("mute", flag.ExitOnError), printer: printer, config: config, - muteDuration: NewTimeDurationFlagValue(), + muteDuration: internalFlag.NewTimeDurationValue(), } exe.Usage = commandUsageFunc("mute", "Mutes a specific resource (e.g. an account)", exe.FlagSet) @@ -335,7 +336,7 @@ type ShowExecutor struct { accountName string getAllImages bool getAllVideos bool - attachmentIDs MultiStringFlagValue + attachmentIDs internalFlag.StringSliceValue showInBrowser bool excludeBoosts bool excludeReplies bool @@ -364,7 +365,7 @@ func NewShowExecutor( FlagSet: flag.NewFlagSet("show", flag.ExitOnError), printer: printer, config: config, - attachmentIDs: NewMultiStringFlagValue(), + attachmentIDs: internalFlag.NewStringSliceValue(), } exe.Usage = commandUsageFunc("show", "Shows details about a specified resource", exe.FlagSet) diff --git a/internal/executor/flags.go b/internal/executor/flags.go index 902bfbd..9a89193 100644 --- a/internal/executor/flags.go +++ b/internal/executor/flags.go @@ -1,12 +1,5 @@ package executor -import ( - "fmt" - "strconv" - "strings" - "time" -) - const ( flagAccountName = "account-name" flagAttachmentID = "attachment-id" @@ -24,111 +17,3 @@ const ( flagType = "type" flagVote = "vote" ) - -type MultiStringFlagValue []string - -func NewMultiStringFlagValue() MultiStringFlagValue { - arr := make([]string, 0, 3) - - return MultiStringFlagValue(arr) -} - -func (v MultiStringFlagValue) String() string { - return strings.Join(v, ", ") -} - -func (v *MultiStringFlagValue) Set(value string) error { - if len(value) > 0 { - *v = append(*v, value) - } - - return nil -} - -type MultiIntFlagValue []int - -func NewMultiIntFlagValue() MultiIntFlagValue { - arr := make([]int, 0, 3) - - return MultiIntFlagValue(arr) -} - -func (v MultiIntFlagValue) String() string { - value := "Choices: " - - for ind, vote := range v { - if ind == len(v)-1 { - value += strconv.Itoa(vote) - } else { - value += strconv.Itoa(vote) + ", " - } - } - - return value -} - -func (v *MultiIntFlagValue) Set(text string) error { - value, err := strconv.Atoi(text) - if err != nil { - return fmt.Errorf("unable to parse the value to an integer: %w", err) - } - - *v = append(*v, value) - - return nil -} - -type TimeDurationFlagValue struct { - Duration time.Duration -} - -func NewTimeDurationFlagValue() TimeDurationFlagValue { - return TimeDurationFlagValue{ - Duration: 0 * time.Second, - } -} - -func (v TimeDurationFlagValue) String() string { - return "Time duration: " + v.Duration.String() -} - -func (v *TimeDurationFlagValue) Set(text string) error { - duration, err := time.ParseDuration(text) - if err != nil { - return fmt.Errorf("unable to parse the value as time duration: %w", err) - } - - v.Duration = duration - - return nil -} - -type BoolPtrFlagValue struct { - Value *bool -} - -func NewBoolPtrFlagValue() BoolPtrFlagValue { - return BoolPtrFlagValue{ - Value: nil, - } -} - -func (b BoolPtrFlagValue) String() string { - if b.Value == nil { - return "NOT SET" - } - - return strconv.FormatBool(*b.Value) -} - -func (b *BoolPtrFlagValue) Set(value string) error { - boolVar, err := strconv.ParseBool(value) - if err != nil { - return fmt.Errorf("unable to parse %q as a boolean value: %w", value, err) - } - - b.Value = new(bool) - *b.Value = boolVar - - return nil -} diff --git a/internal/executor/remove.go b/internal/executor/remove.go index bc30e4b..f16f730 100644 --- a/internal/executor/remove.go +++ b/internal/executor/remove.go @@ -6,6 +6,7 @@ import ( "codeflow.dananglin.me.uk/apollo/enbas/internal/client" "codeflow.dananglin.me.uk/apollo/enbas/internal/config" + internalFlag "codeflow.dananglin.me.uk/apollo/enbas/internal/flag" "codeflow.dananglin.me.uk/apollo/enbas/internal/printer" ) @@ -18,18 +19,16 @@ type RemoveExecutor struct { fromResourceType string listID string statusID string - accountNames MultiStringFlagValue + accountNames internalFlag.StringSliceValue } func NewRemoveExecutor(printer *printer.Printer, config *config.Config, name, summary string) *RemoveExecutor { - emptyArr := make([]string, 0, 3) - removeExe := RemoveExecutor{ FlagSet: flag.NewFlagSet(name, flag.ExitOnError), printer: printer, config: config, - accountNames: MultiStringFlagValue(emptyArr), + accountNames: internalFlag.NewStringSliceValue(), } removeExe.StringVar(&removeExe.resourceType, flagType, "", "Specify the resource type to remove (e.g. account, note)") diff --git a/internal/flag/boolptrvalue.go b/internal/flag/boolptrvalue.go new file mode 100644 index 0000000..7669c09 --- /dev/null +++ b/internal/flag/boolptrvalue.go @@ -0,0 +1,36 @@ +package flag + +import ( + "fmt" + "strconv" +) + +type BoolPtrValue struct { + Value *bool +} + +func NewBoolPtrValue() BoolPtrValue { + return BoolPtrValue{ + Value: nil, + } +} + +func (b BoolPtrValue) String() string { + if b.Value == nil { + return "NOT SET" + } + + return strconv.FormatBool(*b.Value) +} + +func (b *BoolPtrValue) Set(value string) error { + boolVar, err := strconv.ParseBool(value) + if err != nil { + return fmt.Errorf("unable to parse %q as a boolean value: %w", value, err) + } + + b.Value = new(bool) + *b.Value = boolVar + + return nil +} diff --git a/internal/flag/intslice.go b/internal/flag/intslice.go new file mode 100644 index 0000000..a37d9c4 --- /dev/null +++ b/internal/flag/intslice.go @@ -0,0 +1,41 @@ +package flag + +import ( + "fmt" + "strconv" + "strings" +) + +type IntSliceValue []int + +func NewIntSliceValue() IntSliceValue { + arr := make([]int, 0, 3) + + return IntSliceValue(arr) +} + +func (v IntSliceValue) String() string { + var builder strings.Builder + + for ind, value := range v { + if ind == len(v)-1 { + builder.WriteString(strconv.Itoa(value)) + } else { + builder.WriteString(strconv.Itoa(value)) + builder.WriteString(", ") + } + } + + return builder.String() +} + +func (v *IntSliceValue) Set(text string) error { + value, err := strconv.Atoi(text) + if err != nil { + return fmt.Errorf("unable to parse the value to an integer: %w", err) + } + + *v = append(*v, value) + + return nil +} diff --git a/internal/flag/stringslice.go b/internal/flag/stringslice.go new file mode 100644 index 0000000..0dbeb3a --- /dev/null +++ b/internal/flag/stringslice.go @@ -0,0 +1,23 @@ +package flag + +import "strings" + +type StringSliceValue []string + +func NewStringSliceValue() StringSliceValue { + arr := make([]string, 0, 3) + + return StringSliceValue(arr) +} + +func (v StringSliceValue) String() string { + return strings.Join(v, ", ") +} + +func (v *StringSliceValue) Set(value string) error { + if len(value) > 0 { + *v = append(*v, value) + } + + return nil +} diff --git a/internal/flag/timedurationvalue.go b/internal/flag/timedurationvalue.go new file mode 100644 index 0000000..cdf02ac --- /dev/null +++ b/internal/flag/timedurationvalue.go @@ -0,0 +1,31 @@ +package flag + +import ( + "fmt" + "time" +) + +type TimeDurationValue struct { + Duration time.Duration +} + +func NewTimeDurationValue() TimeDurationValue { + return TimeDurationValue{ + Duration: 0 * time.Second, + } +} + +func (v TimeDurationValue) String() string { + return v.Duration.String() +} + +func (v *TimeDurationValue) Set(text string) error { + duration, err := time.ParseDuration(text) + if err != nil { + return fmt.Errorf("unable to parse the value as time duration: %w", err) + } + + v.Duration = duration + + return nil +} diff --git a/schema/enbas_cli_schema.json b/schema/enbas_cli_schema.json index a07e5ba..1865fca 100644 --- a/schema/enbas_cli_schema.json +++ b/schema/enbas_cli_schema.json @@ -13,7 +13,7 @@ "description": "Set to true to show all videos from a status" }, "attachment-id": { - "type": "MultiStringFlagValue", + "type": "StringSliceValue", "description": "The ID of the media attachment" }, "add-poll": { @@ -97,7 +97,7 @@ "description": "The replies policy of the list" }, "mute-duration": { - "type": "TimeDurationFlagValue", + "type": "TimeDurationValue", "description": "Specify how long the mute should last for. To mute indefinitely, set this to 0s" }, "mute-notifications": { @@ -129,7 +129,7 @@ "description": "Set to true to allow viewers to make multiple choices in the poll" }, "poll-expires-in": { - "type": "TimeDurationFlagValue", + "type": "TimeDurationValue", "description": "The duration in which the poll is open for" }, "poll-hides-vote-counts": { @@ -141,11 +141,11 @@ "description": "The ID of the poll" }, "poll-option": { - "type": "MultiStringFlagValue", + "type": "StringSliceValue", "description": "A poll option. Use this multiple times to set multiple options" }, "sensitive": { - "type": "BoolPtrFlagValue", + "type": "BoolPtrValue", "description": "Set to true if the status should be marked as sensitive" }, "show-preferences": {