Compare commits

..

4 commits

22 changed files with 500 additions and 360 deletions

View file

@ -40,7 +40,7 @@ func generateExecutors(schema enbasCLISchema, output string) error {
"flagFieldName": flagFieldName, "flagFieldName": flagFieldName,
"getFlagType": schema.Flags.getType, "getFlagType": schema.Flags.getType,
"getFlagDescription": schema.Flags.getDescription, "getFlagDescription": schema.Flags.getDescription,
"customFlagValueType": customFlagValueType, "internalFlagValue": internalFlagValue,
} }
tmpl := template.Must(template.New("executor-template").Funcs(funcMap).Parse(executorsFileTemplate)) tmpl := template.Must(template.New("executor-template").Funcs(funcMap).Parse(executorsFileTemplate))
@ -109,15 +109,15 @@ func convertFlagToMixedCaps(value string) string {
return builder.String() return builder.String()
} }
func customFlagValueType(flagType string) bool { func internalFlagValue(flagType string) bool {
customFlagValueTypes := map[string]struct{}{ internalFlagValues := map[string]struct{}{
"MultiStringFlagValue": {}, "StringSliceValue": {},
"MultiIntFlagValue": {}, "IntSliceValue": {},
"TimeDurationFlagValue": {}, "TimeDurationValue": {},
"BoolPtrFlagValue": {}, "BoolPtrValue": {},
} }
_, exists := customFlagValueTypes[flagType] _, exists := internalFlagValues[flagType]
return exists return exists
} }

View file

@ -1,11 +1,14 @@
package main package main
var executorsFileTemplate = `package executor var executorsFileTemplate = `/*
{{ print "" }}
/*
This file is generated by ./cmd/enbas-cli-generators This file is generated by ./cmd/enbas-cli-generators
DO NOT EDIT. DO NOT EDIT.
*/ */
{{ print "" }}
package executor
{{ print "" }}
{{ print "" }}
import internalFlag "codeflow.dananglin.me.uk/apollo/enbas/internal/flag"
{{ range $name, $command := . }} {{ range $name, $command := . }}
{{- $struct_name := capitalise $name | printf "%sExecutor" -}} {{- $struct_name := capitalise $name | printf "%sExecutor" -}}
{{- $new_executor_function_name := capitalise $name | printf "New%sExecutor" -}} {{- $new_executor_function_name := capitalise $name | printf "New%sExecutor" -}}
@ -20,8 +23,14 @@ type {{ $struct_name }} struct {
config *config.Config config *config.Config
{{- end }} {{- end }}
{{- range $flag := $command.Flags -}} {{- range $flag := $command.Flags -}}
{{- $flag_type := getFlagType $flag.Flag -}}
{{- if internalFlagValue $flag_type -}}
{{ print "" }} {{ print "" }}
{{ flagFieldName $flag }} {{ getFlagType $flag.Flag }} {{ flagFieldName $flag }} internalFlag.{{ $flag_type }}
{{- else -}}
{{ print "" }}
{{ flagFieldName $flag }} {{ $flag_type }}
{{- end -}}
{{- end -}} {{- end -}}
{{- range $field := $command.AdditionalFields -}} {{- range $field := $command.AdditionalFields -}}
{{ print "" }} {{ print "" }}
@ -53,9 +62,9 @@ func {{ $new_executor_function_name }}(
{{- end }} {{- end }}
{{- range $flag := $command.Flags -}} {{- range $flag := $command.Flags -}}
{{- $flag_type := getFlagType $flag.Flag -}} {{- $flag_type := getFlagType $flag.Flag -}}
{{- if customFlagValueType $flag_type -}} {{- if internalFlagValue $flag_type -}}
{{ print "" }} {{ print "" }}
{{ flagFieldName $flag }}: New{{ $flag_type }}(), {{ flagFieldName $flag }}: internalFlag.New{{ $flag_type }}(),
{{- end -}} {{- end -}}
{{- end -}} {{- end -}}
{{- range $field := $command.AdditionalFields -}} {{- range $field := $command.AdditionalFields -}}
@ -78,7 +87,7 @@ func {{ $new_executor_function_name }}(
{{- else if eq $flag_type "int" -}} {{- else if eq $flag_type "int" -}}
{{ print "" }} {{ print "" }}
exe.IntVar(&exe.{{ flagFieldName $flag }}, {{ printf "%q" $flag.Flag }}, {{ $flag.Default }}, {{ getFlagDescription $flag.Flag | printf "%q" }}) 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 "" }} {{ print "" }}
exe.Var(&exe.{{ flagFieldName $flag }}, {{ printf "%q" $flag.Flag }}, {{ getFlagDescription $flag.Flag | printf "%q" }}) exe.Var(&exe.{{ flagFieldName $flag }}, {{ printf "%q" $flag.Flag }}, {{ getFlagDescription $flag.Flag | printf "%q" }})
{{- end -}} {{- end -}}

View file

@ -2,12 +2,11 @@ package main
import ( import (
"flag" "flag"
"fmt"
"os" "os"
"strconv"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config" "codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/executor" "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" "codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
) )
@ -27,21 +26,11 @@ func main() {
func run() error { func run() error {
var ( var (
configDir string configDir string
noColor *bool noColorFlag internalFlag.BoolPtrValue
) )
flag.StringVar(&configDir, "config-dir", "", "Specify your config directory") 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 { flag.Var(&noColorFlag, "no-color", "Disable ANSI colour output when displaying text on screen")
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.Usage = usageFunc(executor.CommandSummaryMap()) flag.Usage = usageFunc(executor.CommandSummaryMap())
@ -53,15 +42,12 @@ func run() error {
return nil return nil
} }
// If NoColor is still unspecified, var noColor bool
// check to see if the NO_COLOR environment variable is set
if noColor == nil { if noColorFlag.Value != nil {
noColor = new(bool) noColor = *noColorFlag.Value
if os.Getenv("NO_COLOR") != "" { } else if os.Getenv("NO_COLOR") != "" {
*noColor = true noColor = true
} else {
*noColor = false
}
} }
command := flag.Arg(0) command := flag.Arg(0)
@ -75,17 +61,21 @@ func run() error {
switch command { switch command {
case executor.CommandInit, executor.CommandVersion: case executor.CommandInit, executor.CommandVersion:
enbasPrinter = printer.NewPrinter(*noColor, "", 0) enbasPrinter = printer.NewPrinter(noColor, "", 0)
default: default:
enbasConfig, err = config.NewConfigFromFile(configDir) enbasConfig, err = config.NewConfigFromFile(configDir)
if err != nil { if err != nil {
enbasPrinter = printer.NewPrinter(*noColor, "", 0) enbasPrinter = printer.NewPrinter(noColor, "", 0)
enbasPrinter.PrintFailure("unable to load the configuration: " + err.Error() + ".") enbasPrinter.PrintFailure("unable to load the configuration: " + err.Error() + ".")
return err 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{ executorMap := map[string]executor.Executor{
@ -96,8 +86,6 @@ func run() error {
executor.CommandAdd: executor.NewAddExecutor( executor.CommandAdd: executor.NewAddExecutor(
enbasPrinter, enbasPrinter,
enbasConfig, enbasConfig,
executor.CommandAdd,
executor.CommandSummaryLookup(executor.CommandAdd),
), ),
executor.CommandBlock: executor.NewBlockExecutor( executor.CommandBlock: executor.NewBlockExecutor(
enbasPrinter, enbasPrinter,
@ -138,8 +126,6 @@ func run() error {
executor.CommandRemove: executor.NewRemoveExecutor( executor.CommandRemove: executor.NewRemoveExecutor(
enbasPrinter, enbasPrinter,
enbasConfig, enbasConfig,
executor.CommandRemove,
executor.CommandSummaryLookup(executor.CommandRemove),
), ),
executor.CommandSwitch: executor.NewSwitchExecutor( executor.CommandSwitch: executor.NewSwitchExecutor(
enbasPrinter, enbasPrinter,

View file

@ -25,7 +25,15 @@ func (a *AcceptExecutor) Execute() error {
} }
func (a *AcceptExecutor) acceptFollowRequest(gtsClient *client.Client) error { func (a *AcceptExecutor) acceptFollowRequest(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, a.accountName, a.config.CredentialsFile) expectedNumAccountNames := 1
if !a.accountName.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
}
accountID, err := getAccountID(gtsClient, false, a.accountName[0], a.config.CredentialsFile)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }

View file

@ -2,54 +2,11 @@ package executor
import ( import (
"errors" "errors"
"flag"
"fmt" "fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client" "codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
) )
type AddExecutor struct {
*flag.FlagSet
printer *printer.Printer
config *config.Config
resourceType string
toResourceType string
listID string
statusID string
pollID string
choices MultiIntFlagValue
accountNames MultiStringFlagValue
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),
}
addExe.StringVar(&addExe.resourceType, flagType, "", "Specify the resource type to add (e.g. account, note)")
addExe.StringVar(&addExe.toResourceType, flagTo, "", "Specify the target resource type to add to (e.g. list, account, etc)")
addExe.StringVar(&addExe.listID, flagListID, "", "The ID of the list")
addExe.StringVar(&addExe.statusID, flagStatusID, "", "The ID of the status")
addExe.StringVar(&addExe.content, flagContent, "", "The content of the resource")
addExe.StringVar(&addExe.pollID, flagPollID, "", "The ID of the poll")
addExe.Var(&addExe.accountNames, flagAccountName, "The name of the account")
addExe.Var(&addExe.choices, flagVote, "Add a vote to an option in a poll")
addExe.Usage = commandUsageFunc(name, summary, addExe.FlagSet)
return &addExe
}
func (a *AddExecutor) Execute() error { func (a *AddExecutor) Execute() error {
if a.toResourceType == "" { if a.toResourceType == "" {
return FlagNotSetError{flagText: flagTo} return FlagNotSetError{flagText: flagTo}
@ -97,7 +54,7 @@ func (a *AddExecutor) addAccountsToList(gtsClient *client.Client) error {
return FlagNotSetError{flagText: flagListID} return FlagNotSetError{flagText: flagListID}
} }
if len(a.accountNames) == 0 { if a.accountNames.Empty() {
return NoAccountSpecifiedError{} return NoAccountSpecifiedError{}
} }
@ -147,8 +104,12 @@ func (a *AddExecutor) addToAccount(gtsClient *client.Client) error {
} }
func (a *AddExecutor) addNoteToAccount(gtsClient *client.Client) error { func (a *AddExecutor) addNoteToAccount(gtsClient *client.Client) error {
if len(a.accountNames) != 1 { expectedNumAccountNames := 1
return fmt.Errorf("unexpected number of accounts specified: want 1, got %d", len(a.accountNames)) if !a.accountNames.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
} }
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.config.CredentialsFile) accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.config.CredentialsFile)
@ -265,7 +226,7 @@ func (a *AddExecutor) addToPoll(gtsClient *client.Client) error {
} }
func (a *AddExecutor) addVoteToPoll(gtsClient *client.Client) error { func (a *AddExecutor) addVoteToPoll(gtsClient *client.Client) error {
if len(a.choices) == 0 { if a.votes.Empty() {
return errors.New("please use --" + flagVote + " to make a choice in this poll") return errors.New("please use --" + flagVote + " to make a choice in this poll")
} }
@ -278,11 +239,11 @@ func (a *AddExecutor) addVoteToPoll(gtsClient *client.Client) error {
return PollClosedError{} return PollClosedError{}
} }
if !poll.Multiple && len(a.choices) > 1 { if !poll.Multiple && !a.votes.ExpectedLength(1) {
return MultipleChoiceError{} return MultipleChoiceError{}
} }
if err := gtsClient.VoteInPoll(a.pollID, []int(a.choices)); err != nil { if err := gtsClient.VoteInPoll(a.pollID, []int(a.votes)); err != nil {
return fmt.Errorf("unable to add your vote(s) to the poll: %w", err) return fmt.Errorf("unable to add your vote(s) to the poll: %w", err)
} }

View file

@ -25,11 +25,15 @@ func (b *BlockExecutor) Execute() error {
} }
func (b *BlockExecutor) blockAccount(gtsClient *client.Client) error { func (b *BlockExecutor) blockAccount(gtsClient *client.Client) error {
if b.accountName == "" { expectedNumAccountNames := 1
return FlagNotSetError{flagText: flagAccountName} if !b.accountName.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
} }
accountID, err := getAccountID(gtsClient, false, b.accountName, b.config.CredentialsFile) accountID, err := getAccountID(gtsClient, false, b.accountName[0], b.config.CredentialsFile)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }

View file

@ -1,23 +1,24 @@
/*
This file is generated by ./cmd/enbas-cli-generators
DO NOT EDIT.
*/
package executor package executor
import ( import (
"flag" "flag"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config" "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" "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. // AcceptExecutor is the executor for the accept command.
type AcceptExecutor struct { type AcceptExecutor struct {
*flag.FlagSet *flag.FlagSet
printer *printer.Printer printer *printer.Printer
config *config.Config config *config.Config
accountName string accountName internalFlag.StringSliceValue
resourceType string resourceType string
} }
@ -29,22 +30,64 @@ func NewAcceptExecutor(
FlagSet: flag.NewFlagSet("accept", flag.ExitOnError), FlagSet: flag.NewFlagSet("accept", flag.ExitOnError),
printer: printer, printer: printer,
config: config, config: config,
accountName: internalFlag.NewStringSliceValue(),
} }
exe.Usage = commandUsageFunc("accept", "Accepts a request (e.g. a follow request)", exe.FlagSet) exe.Usage = commandUsageFunc("accept", "Accepts a request (e.g. a follow request)", exe.FlagSet)
exe.StringVar(&exe.accountName, "account-name", "", "The name of the account") exe.Var(&exe.accountName, "account-name", "The name of the account")
exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)") exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)")
return &exe return &exe
} }
// AddExecutor is the executor for the add command.
type AddExecutor struct {
*flag.FlagSet
printer *printer.Printer
config *config.Config
accountNames internalFlag.StringSliceValue
content string
listID string
pollID string
statusID string
toResourceType string
resourceType string
votes internalFlag.IntSliceValue
}
func NewAddExecutor(
printer *printer.Printer,
config *config.Config,
) *AddExecutor {
exe := AddExecutor{
FlagSet: flag.NewFlagSet("add", flag.ExitOnError),
printer: printer,
config: config,
accountNames: internalFlag.NewStringSliceValue(),
votes: internalFlag.NewIntSliceValue(),
}
exe.Usage = commandUsageFunc("add", "Add a resource to another resource", exe.FlagSet)
exe.Var(&exe.accountNames, "account-name", "The name of the account")
exe.StringVar(&exe.content, "content", "", "The content of the created resource")
exe.StringVar(&exe.listID, "list-id", "", "The ID of the list in question")
exe.StringVar(&exe.pollID, "poll-id", "", "The ID of the poll")
exe.StringVar(&exe.statusID, "status-id", "", "The ID of the status")
exe.StringVar(&exe.toResourceType, "to", "", "TBC")
exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)")
exe.Var(&exe.votes, "vote", "Add a vote to an option in a poll")
return &exe
}
// BlockExecutor is the executor for the block command. // BlockExecutor is the executor for the block command.
type BlockExecutor struct { type BlockExecutor struct {
*flag.FlagSet *flag.FlagSet
printer *printer.Printer printer *printer.Printer
config *config.Config config *config.Config
accountName string accountName internalFlag.StringSliceValue
resourceType string resourceType string
} }
@ -56,11 +99,12 @@ func NewBlockExecutor(
FlagSet: flag.NewFlagSet("block", flag.ExitOnError), FlagSet: flag.NewFlagSet("block", flag.ExitOnError),
printer: printer, printer: printer,
config: config, config: config,
accountName: internalFlag.NewStringSliceValue(),
} }
exe.Usage = commandUsageFunc("block", "Blocks a resource (e.g. an account)", exe.FlagSet) exe.Usage = commandUsageFunc("block", "Blocks a resource (e.g. an account)", exe.FlagSet)
exe.StringVar(&exe.accountName, "account-name", "", "The name of the account") exe.Var(&exe.accountName, "account-name", "The name of the account")
exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)") exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)")
return &exe return &exe
@ -84,10 +128,10 @@ type CreateExecutor struct {
listRepliesPolicy string listRepliesPolicy string
listTitle string listTitle string
pollAllowsMultipleChoices bool pollAllowsMultipleChoices bool
pollExpiresIn TimeDurationFlagValue pollExpiresIn internalFlag.TimeDurationValue
pollHidesVoteCounts bool pollHidesVoteCounts bool
pollOptions MultiStringFlagValue pollOptions internalFlag.StringSliceValue
sensitive BoolPtrFlagValue sensitive internalFlag.BoolPtrValue
spoilerText string spoilerText string
resourceType string resourceType string
visibility string visibility string
@ -101,9 +145,9 @@ func NewCreateExecutor(
FlagSet: flag.NewFlagSet("create", flag.ExitOnError), FlagSet: flag.NewFlagSet("create", flag.ExitOnError),
printer: printer, printer: printer,
config: config, config: config,
pollExpiresIn: NewTimeDurationFlagValue(), pollExpiresIn: internalFlag.NewTimeDurationValue(),
pollOptions: NewMultiStringFlagValue(), pollOptions: internalFlag.NewStringSliceValue(),
sensitive: NewBoolPtrFlagValue(), sensitive: internalFlag.NewBoolPtrValue(),
} }
exe.Usage = commandUsageFunc("create", "Creates a specific resource", exe.FlagSet) exe.Usage = commandUsageFunc("create", "Creates a specific resource", exe.FlagSet)
@ -195,7 +239,7 @@ type FollowExecutor struct {
*flag.FlagSet *flag.FlagSet
printer *printer.Printer printer *printer.Printer
config *config.Config config *config.Config
accountName string accountName internalFlag.StringSliceValue
notify bool notify bool
showReposts bool showReposts bool
resourceType string resourceType string
@ -209,11 +253,12 @@ func NewFollowExecutor(
FlagSet: flag.NewFlagSet("follow", flag.ExitOnError), FlagSet: flag.NewFlagSet("follow", flag.ExitOnError),
printer: printer, printer: printer,
config: config, config: config,
accountName: internalFlag.NewStringSliceValue(),
} }
exe.Usage = commandUsageFunc("follow", "Follow a resource (e.g. an account)", exe.FlagSet) exe.Usage = commandUsageFunc("follow", "Follow a resource (e.g. an account)", exe.FlagSet)
exe.StringVar(&exe.accountName, "account-name", "", "The name of the account") exe.Var(&exe.accountName, "account-name", "The name of the account")
exe.BoolVar(&exe.notify, "notify", false, "Get notifications from statuses from the account you want to follow") exe.BoolVar(&exe.notify, "notify", false, "Get notifications from statuses from the account you want to follow")
exe.BoolVar(&exe.showReposts, "show-reposts", true, "Show reposts from the account you want to follow") exe.BoolVar(&exe.showReposts, "show-reposts", true, "Show reposts from the account you want to follow")
exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)") exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)")
@ -273,8 +318,8 @@ type MuteExecutor struct {
*flag.FlagSet *flag.FlagSet
printer *printer.Printer printer *printer.Printer
config *config.Config config *config.Config
accountName string accountName internalFlag.StringSliceValue
muteDuration TimeDurationFlagValue muteDuration internalFlag.TimeDurationValue
muteNotifications bool muteNotifications bool
resourceType string resourceType string
} }
@ -287,12 +332,13 @@ func NewMuteExecutor(
FlagSet: flag.NewFlagSet("mute", flag.ExitOnError), FlagSet: flag.NewFlagSet("mute", flag.ExitOnError),
printer: printer, printer: printer,
config: config, config: config,
muteDuration: NewTimeDurationFlagValue(), accountName: internalFlag.NewStringSliceValue(),
muteDuration: internalFlag.NewTimeDurationValue(),
} }
exe.Usage = commandUsageFunc("mute", "Mutes a specific resource (e.g. an account)", exe.FlagSet) exe.Usage = commandUsageFunc("mute", "Mutes a specific resource (e.g. an account)", exe.FlagSet)
exe.StringVar(&exe.accountName, "account-name", "", "The name of the account") exe.Var(&exe.accountName, "account-name", "The name of the account")
exe.Var(&exe.muteDuration, "mute-duration", "Specify how long the mute should last for. To mute indefinitely, set this to 0s") exe.Var(&exe.muteDuration, "mute-duration", "Specify how long the mute should last for. To mute indefinitely, set this to 0s")
exe.BoolVar(&exe.muteNotifications, "mute-notifications", false, "Set to true to mute notifications as well as posts") exe.BoolVar(&exe.muteNotifications, "mute-notifications", false, "Set to true to mute notifications as well as posts")
exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)") exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)")
@ -305,7 +351,7 @@ type RejectExecutor struct {
*flag.FlagSet *flag.FlagSet
printer *printer.Printer printer *printer.Printer
config *config.Config config *config.Config
accountName string accountName internalFlag.StringSliceValue
resourceType string resourceType string
} }
@ -317,11 +363,46 @@ func NewRejectExecutor(
FlagSet: flag.NewFlagSet("reject", flag.ExitOnError), FlagSet: flag.NewFlagSet("reject", flag.ExitOnError),
printer: printer, printer: printer,
config: config, config: config,
accountName: internalFlag.NewStringSliceValue(),
} }
exe.Usage = commandUsageFunc("reject", "Rejects a request (e.g. a follow request)", exe.FlagSet) exe.Usage = commandUsageFunc("reject", "Rejects a request (e.g. a follow request)", exe.FlagSet)
exe.StringVar(&exe.accountName, "account-name", "", "The name of the account") exe.Var(&exe.accountName, "account-name", "The name of the account")
exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)")
return &exe
}
// RemoveExecutor is the executor for the remove command.
type RemoveExecutor struct {
*flag.FlagSet
printer *printer.Printer
config *config.Config
accountNames internalFlag.StringSliceValue
fromResourceType string
listID string
statusID string
resourceType string
}
func NewRemoveExecutor(
printer *printer.Printer,
config *config.Config,
) *RemoveExecutor {
exe := RemoveExecutor{
FlagSet: flag.NewFlagSet("remove", flag.ExitOnError),
printer: printer,
config: config,
accountNames: internalFlag.NewStringSliceValue(),
}
exe.Usage = commandUsageFunc("remove", "", exe.FlagSet)
exe.Var(&exe.accountNames, "account-name", "The name of the account")
exe.StringVar(&exe.fromResourceType, "from", "", "Specify the resource type to action the target resource from")
exe.StringVar(&exe.listID, "list-id", "", "The ID of the list in question")
exe.StringVar(&exe.statusID, "status-id", "", "The ID of the status")
exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)") exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)")
return &exe return &exe
@ -332,10 +413,10 @@ type ShowExecutor struct {
*flag.FlagSet *flag.FlagSet
printer *printer.Printer printer *printer.Printer
config *config.Config config *config.Config
accountName string accountName internalFlag.StringSliceValue
getAllImages bool getAllImages bool
getAllVideos bool getAllVideos bool
attachmentIDs MultiStringFlagValue attachmentIDs internalFlag.StringSliceValue
showInBrowser bool showInBrowser bool
excludeBoosts bool excludeBoosts bool
excludeReplies bool excludeReplies bool
@ -364,12 +445,13 @@ func NewShowExecutor(
FlagSet: flag.NewFlagSet("show", flag.ExitOnError), FlagSet: flag.NewFlagSet("show", flag.ExitOnError),
printer: printer, printer: printer,
config: config, config: config,
attachmentIDs: NewMultiStringFlagValue(), accountName: internalFlag.NewStringSliceValue(),
attachmentIDs: internalFlag.NewStringSliceValue(),
} }
exe.Usage = commandUsageFunc("show", "Shows details about a specified resource", exe.FlagSet) exe.Usage = commandUsageFunc("show", "Shows details about a specified resource", exe.FlagSet)
exe.StringVar(&exe.accountName, "account-name", "", "The name of the account") exe.Var(&exe.accountName, "account-name", "The name of the account")
exe.BoolVar(&exe.getAllImages, "all-images", false, "Set to true to show all images from a status") exe.BoolVar(&exe.getAllImages, "all-images", false, "Set to true to show all images from a status")
exe.BoolVar(&exe.getAllVideos, "all-videos", false, "Set to true to show all videos from a status") exe.BoolVar(&exe.getAllVideos, "all-videos", false, "Set to true to show all videos from a status")
exe.Var(&exe.attachmentIDs, "attachment-id", "The ID of the media attachment") exe.Var(&exe.attachmentIDs, "attachment-id", "The ID of the media attachment")
@ -400,7 +482,7 @@ type SwitchExecutor struct {
*flag.FlagSet *flag.FlagSet
printer *printer.Printer printer *printer.Printer
config *config.Config config *config.Config
accountName string accountName internalFlag.StringSliceValue
to string to string
} }
@ -412,11 +494,12 @@ func NewSwitchExecutor(
FlagSet: flag.NewFlagSet("switch", flag.ExitOnError), FlagSet: flag.NewFlagSet("switch", flag.ExitOnError),
printer: printer, printer: printer,
config: config, config: config,
accountName: internalFlag.NewStringSliceValue(),
} }
exe.Usage = commandUsageFunc("switch", "Performs a switch operation (e.g. switching between logged in accounts)", exe.FlagSet) exe.Usage = commandUsageFunc("switch", "Performs a switch operation (e.g. switching between logged in accounts)", exe.FlagSet)
exe.StringVar(&exe.accountName, "account-name", "", "The name of the account") exe.Var(&exe.accountName, "account-name", "The name of the account")
exe.StringVar(&exe.to, "to", "", "TBC") exe.StringVar(&exe.to, "to", "", "TBC")
return &exe return &exe
@ -427,7 +510,7 @@ type UnblockExecutor struct {
*flag.FlagSet *flag.FlagSet
printer *printer.Printer printer *printer.Printer
config *config.Config config *config.Config
accountName string accountName internalFlag.StringSliceValue
resourceType string resourceType string
} }
@ -439,11 +522,12 @@ func NewUnblockExecutor(
FlagSet: flag.NewFlagSet("unblock", flag.ExitOnError), FlagSet: flag.NewFlagSet("unblock", flag.ExitOnError),
printer: printer, printer: printer,
config: config, config: config,
accountName: internalFlag.NewStringSliceValue(),
} }
exe.Usage = commandUsageFunc("unblock", "Unblocks a resource (e.g. an account)", exe.FlagSet) exe.Usage = commandUsageFunc("unblock", "Unblocks a resource (e.g. an account)", exe.FlagSet)
exe.StringVar(&exe.accountName, "account-name", "", "The name of the account") exe.Var(&exe.accountName, "account-name", "The name of the account")
exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)") exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)")
return &exe return &exe
@ -454,7 +538,7 @@ type UnfollowExecutor struct {
*flag.FlagSet *flag.FlagSet
printer *printer.Printer printer *printer.Printer
config *config.Config config *config.Config
accountName string accountName internalFlag.StringSliceValue
resourceType string resourceType string
} }
@ -466,11 +550,12 @@ func NewUnfollowExecutor(
FlagSet: flag.NewFlagSet("unfollow", flag.ExitOnError), FlagSet: flag.NewFlagSet("unfollow", flag.ExitOnError),
printer: printer, printer: printer,
config: config, config: config,
accountName: internalFlag.NewStringSliceValue(),
} }
exe.Usage = commandUsageFunc("unfollow", "Unfollow a resource (e.g. an account)", exe.FlagSet) exe.Usage = commandUsageFunc("unfollow", "Unfollow a resource (e.g. an account)", exe.FlagSet)
exe.StringVar(&exe.accountName, "account-name", "", "The name of the account") exe.Var(&exe.accountName, "account-name", "The name of the account")
exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)") exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)")
return &exe return &exe
@ -481,7 +566,7 @@ type UnmuteExecutor struct {
*flag.FlagSet *flag.FlagSet
printer *printer.Printer printer *printer.Printer
config *config.Config config *config.Config
accountName string accountName internalFlag.StringSliceValue
resourceType string resourceType string
} }
@ -493,11 +578,12 @@ func NewUnmuteExecutor(
FlagSet: flag.NewFlagSet("unmute", flag.ExitOnError), FlagSet: flag.NewFlagSet("unmute", flag.ExitOnError),
printer: printer, printer: printer,
config: config, config: config,
accountName: internalFlag.NewStringSliceValue(),
} }
exe.Usage = commandUsageFunc("unmute", "Umutes a specific resource (e.g. an account)", exe.FlagSet) exe.Usage = commandUsageFunc("unmute", "Umutes a specific resource (e.g. an account)", exe.FlagSet)
exe.StringVar(&exe.accountName, "account-name", "", "The name of the account") exe.Var(&exe.accountName, "account-name", "The name of the account")
exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)") exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)")
return &exe return &exe

View file

@ -1,14 +1,6 @@
package executor package executor
import (
"fmt"
"strconv"
"strings"
"time"
)
const ( const (
flagAccountName = "account-name"
flagAttachmentID = "attachment-id" flagAttachmentID = "attachment-id"
flagContent = "content" flagContent = "content"
flagFrom = "from" flagFrom = "from"
@ -24,111 +16,3 @@ const (
flagType = "type" flagType = "type"
flagVote = "vote" 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
}

View file

@ -25,7 +25,11 @@ func (f *FollowExecutor) Execute() error {
} }
func (f *FollowExecutor) followAccount(gtsClient *client.Client) error { func (f *FollowExecutor) followAccount(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, f.accountName, f.config.CredentialsFile) if !f.accountName.ExpectedLength(1) {
return fmt.Errorf("found an unexpected number of %s flags: expected %d", "--account-name", 1)
}
accountID, err := getAccountID(gtsClient, false, f.accountName[0], f.config.CredentialsFile)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }

View file

@ -25,11 +25,15 @@ func (m *MuteExecutor) Execute() error {
} }
func (m *MuteExecutor) muteAccount(gtsClient *client.Client) error { func (m *MuteExecutor) muteAccount(gtsClient *client.Client) error {
if m.accountName == "" { expectedNumAccountNames := 1
return FlagNotSetError{flagText: flagAccountName} if !m.accountName.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
} }
accountID, err := getAccountID(gtsClient, false, m.accountName, m.config.CredentialsFile) accountID, err := getAccountID(gtsClient, false, m.accountName[0], m.config.CredentialsFile)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }

View file

@ -25,7 +25,15 @@ func (r *RejectExecutor) Execute() error {
} }
func (r *RejectExecutor) rejectFollowRequest(gtsClient *client.Client) error { func (r *RejectExecutor) rejectFollowRequest(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, r.accountName, r.config.CredentialsFile) expectedNumAccountNames := 1
if !r.accountName.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
}
accountID, err := getAccountID(gtsClient, false, r.accountName[0], r.config.CredentialsFile)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }

View file

@ -1,48 +1,11 @@
package executor package executor
import ( import (
"flag"
"fmt" "fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client" "codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
) )
type RemoveExecutor struct {
*flag.FlagSet
printer *printer.Printer
config *config.Config
resourceType string
fromResourceType string
listID string
statusID string
accountNames MultiStringFlagValue
}
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),
}
removeExe.StringVar(&removeExe.resourceType, flagType, "", "Specify the resource type to remove (e.g. account, note)")
removeExe.StringVar(&removeExe.fromResourceType, flagFrom, "", "Specify the resource type to remove from (e.g. list, account, etc)")
removeExe.StringVar(&removeExe.listID, flagListID, "", "The ID of the list to remove from")
removeExe.StringVar(&removeExe.statusID, flagStatusID, "", "The ID of the status")
removeExe.Var(&removeExe.accountNames, flagAccountName, "The name of the account to remove from the resource")
removeExe.Usage = commandUsageFunc(name, summary, removeExe.FlagSet)
return &removeExe
}
func (r *RemoveExecutor) Execute() error { func (r *RemoveExecutor) Execute() error {
if r.fromResourceType == "" { if r.fromResourceType == "" {
return FlagNotSetError{flagText: flagFrom} return FlagNotSetError{flagText: flagFrom}
@ -89,7 +52,7 @@ func (r *RemoveExecutor) removeAccountsFromList(gtsClient *client.Client) error
return FlagNotSetError{flagText: flagListID} return FlagNotSetError{flagText: flagListID}
} }
if len(r.accountNames) == 0 { if r.accountNames.Empty() {
return NoAccountSpecifiedError{} return NoAccountSpecifiedError{}
} }
@ -130,8 +93,12 @@ func (r *RemoveExecutor) removeFromAccount(gtsClient *client.Client) error {
} }
func (r *RemoveExecutor) removeNoteFromAccount(gtsClient *client.Client) error { func (r *RemoveExecutor) removeNoteFromAccount(gtsClient *client.Client) error {
if len(r.accountNames) != 1 { expectedNumAccountNames := 1
return fmt.Errorf("unexpected number of accounts specified: want 1, got %d", len(r.accountNames)) if !r.accountNames.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
} }
accountID, err := getAccountID(gtsClient, false, r.accountNames[0], r.config.CredentialsFile) accountID, err := getAccountID(gtsClient, false, r.accountNames[0], r.config.CredentialsFile)

View file

@ -70,11 +70,14 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
return fmt.Errorf("received an error while getting the account details: %w", err) return fmt.Errorf("received an error while getting the account details: %w", err)
} }
} else { } else {
if s.accountName == "" { expectedNumAccountNames := 1
return FlagNotSetError{flagText: flagAccountName} if !s.accountName.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
} }
account, err = getAccount(gtsClient, s.accountName[0])
account, err = getAccount(gtsClient, s.accountName)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account details: %w", err) return fmt.Errorf("received an error while getting the account details: %w", err)
} }
@ -269,7 +272,15 @@ func (s *ShowExecutor) showFollowers(gtsClient *client.Client) error {
} }
func (s *ShowExecutor) showFollowersFromAccount(gtsClient *client.Client) error { func (s *ShowExecutor) showFollowersFromAccount(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.config.CredentialsFile) expectedNumAccountNames := 1
if !s.accountName.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
}
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName[0], s.config.CredentialsFile)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }
@ -309,7 +320,15 @@ func (s *ShowExecutor) showFollowing(gtsClient *client.Client) error {
} }
func (s *ShowExecutor) showFollowingFromAccount(gtsClient *client.Client) error { func (s *ShowExecutor) showFollowingFromAccount(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.config.CredentialsFile) expectedNumAccountNames := 1
if !s.accountName.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
}
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName[0], s.config.CredentialsFile)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }

View file

@ -20,15 +20,19 @@ func (s *SwitchExecutor) Execute() error {
} }
func (s *SwitchExecutor) switchToAccount() error { func (s *SwitchExecutor) switchToAccount() error {
if s.accountName == "" { expectedNumAccountNames := 1
return NoAccountSpecifiedError{} if !s.accountName.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
} }
if err := config.UpdateCurrentAccount(s.accountName, s.config.CredentialsFile); err != nil { if err := config.UpdateCurrentAccount(s.accountName[0], s.config.CredentialsFile); err != nil {
return fmt.Errorf("unable to switch account to the account: %w", err) return fmt.Errorf("unable to switch account to the account: %w", err)
} }
s.printer.PrintSuccess("The current account is now set to '" + s.accountName + "'.") s.printer.PrintSuccess("The current account is now set to '" + s.accountName[0] + "'.")
return nil return nil
} }

View file

@ -25,11 +25,15 @@ func (b *UnblockExecutor) Execute() error {
} }
func (b *UnblockExecutor) unblockAccount(gtsClient *client.Client) error { func (b *UnblockExecutor) unblockAccount(gtsClient *client.Client) error {
if b.accountName == "" { expectedNumAccountNames := 1
return FlagNotSetError{flagText: flagAccountName} if !b.accountName.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
} }
accountID, err := getAccountID(gtsClient, false, b.accountName, b.config.CredentialsFile) accountID, err := getAccountID(gtsClient, false, b.accountName[0], b.config.CredentialsFile)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }

View file

@ -25,7 +25,15 @@ func (f *UnfollowExecutor) Execute() error {
} }
func (f *UnfollowExecutor) unfollowAccount(gtsClient *client.Client) error { func (f *UnfollowExecutor) unfollowAccount(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, f.accountName, f.config.CredentialsFile) expectedNumAccountNames := 1
if !f.accountName.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
}
accountID, err := getAccountID(gtsClient, false, f.accountName[0], f.config.CredentialsFile)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }

View file

@ -25,11 +25,15 @@ func (m *UnmuteExecutor) Execute() error {
} }
func (m *UnmuteExecutor) unmuteAccount(gtsClient *client.Client) error { func (m *UnmuteExecutor) unmuteAccount(gtsClient *client.Client) error {
if m.accountName == "" { expectedNumAccountNames := 1
return FlagNotSetError{flagText: flagAccountName} if !m.accountName.ExpectedLength(expectedNumAccountNames) {
return fmt.Errorf(
"found an unexpected number of --account-name flags: expected %d",
expectedNumAccountNames,
)
} }
accountID, err := getAccountID(gtsClient, false, m.accountName, m.config.CredentialsFile) accountID, err := getAccountID(gtsClient, false, m.accountName[0], m.config.CredentialsFile)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }

View file

@ -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
}

49
internal/flag/intslice.go Normal file
View file

@ -0,0 +1,49 @@
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
}
func (v IntSliceValue) Empty() bool {
return len(v) == 0
}
func (v IntSliceValue) ExpectedLength(expectedLength int) bool {
return len(v) == expectedLength
}

View file

@ -0,0 +1,31 @@
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
}
func (v StringSliceValue) Empty() bool {
return len(v) == 0
}
func (v StringSliceValue) ExpectedLength(expectedLength int) bool {
return len(v) == expectedLength
}

View file

@ -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
}

View file

@ -1,7 +1,7 @@
{ {
"flags": { "flags": {
"account-name": { "account-name": {
"type": "string", "type": "StringSliceValue",
"description": "The name of the account" "description": "The name of the account"
}, },
"all-images": { "all-images": {
@ -13,7 +13,7 @@
"description": "Set to true to show all videos from a status" "description": "Set to true to show all videos from a status"
}, },
"attachment-id": { "attachment-id": {
"type": "MultiStringFlagValue", "type": "StringSliceValue",
"description": "The ID of the media attachment" "description": "The ID of the media attachment"
}, },
"add-poll": { "add-poll": {
@ -97,7 +97,7 @@
"description": "The replies policy of the list" "description": "The replies policy of the list"
}, },
"mute-duration": { "mute-duration": {
"type": "TimeDurationFlagValue", "type": "TimeDurationValue",
"description": "Specify how long the mute should last for. To mute indefinitely, set this to 0s" "description": "Specify how long the mute should last for. To mute indefinitely, set this to 0s"
}, },
"mute-notifications": { "mute-notifications": {
@ -129,7 +129,7 @@
"description": "Set to true to allow viewers to make multiple choices in the poll" "description": "Set to true to allow viewers to make multiple choices in the poll"
}, },
"poll-expires-in": { "poll-expires-in": {
"type": "TimeDurationFlagValue", "type": "TimeDurationValue",
"description": "The duration in which the poll is open for" "description": "The duration in which the poll is open for"
}, },
"poll-hides-vote-counts": { "poll-hides-vote-counts": {
@ -141,11 +141,11 @@
"description": "The ID of the poll" "description": "The ID of the poll"
}, },
"poll-option": { "poll-option": {
"type": "MultiStringFlagValue", "type": "StringSliceValue",
"description": "A poll option. Use this multiple times to set multiple options" "description": "A poll option. Use this multiple times to set multiple options"
}, },
"sensitive": { "sensitive": {
"type": "BoolPtrFlagValue", "type": "BoolPtrValue",
"description": "Set to true if the status should be marked as sensitive" "description": "Set to true if the status should be marked as sensitive"
}, },
"show-preferences": { "show-preferences": {
@ -180,17 +180,21 @@
"type": "string", "type": "string",
"description": "The timeline category" "description": "The timeline category"
}, },
"type": {
"type": "string",
"description": "The type of resource you want to action on (e.g. account, status)"
},
"to": { "to": {
"type": "string", "type": "string",
"description": "TBC" "description": "TBC"
}, },
"type": {
"type": "string",
"description": "The type of resource you want to action on (e.g. account, status)"
},
"visibility": { "visibility": {
"type": "string", "type": "string",
"description": "The visibility of the posted status" "description": "The visibility of the posted status"
},
"vote": {
"type": "IntSliceValue",
"description": "Add a vote to an option in a poll"
} }
}, },
@ -198,17 +202,33 @@
"accept": { "accept": {
"additionalFields": [], "additionalFields": [],
"flags": [ "flags": [
{ "flag": "account-name", "default": "" }, { "flag": "account-name" },
{ "flag": "type", "fieldName": "resourceType", "default": "" } { "flag": "type", "fieldName": "resourceType", "default": "" }
], ],
"summary": "Accepts a request (e.g. a follow request)", "summary": "Accepts a request (e.g. a follow request)",
"useConfig": true, "useConfig": true,
"usePrinter": true "usePrinter": true
}, },
"add": {
"additionalFields": [],
"flags": [
{ "flag": "account-name", "fieldName": "accountNames" },
{ "flag": "content", "default": "" },
{ "flag": "list-id", "fieldName": "listID", "default": "" },
{ "flag": "poll-id", "fieldName": "pollID", "default": "" },
{ "flag": "status-id", "fieldName": "statusID", "default": "" },
{ "flag": "to", "fieldName": "toResourceType", "default": "" },
{ "flag": "type", "fieldName": "resourceType", "default": "" },
{ "flag": "vote", "fieldName": "votes" }
],
"summary": "Add a resource to another resource",
"useConfig": true,
"usePrinter": true
},
"block": { "block": {
"additionalFields": [], "additionalFields": [],
"flags": [ "flags": [
{ "flag": "account-name", "default": "" }, { "flag": "account-name" },
{ "flag": "type", "fieldName": "resourceType", "default": "" } { "flag": "type", "fieldName": "resourceType", "default": "" }
], ],
"summary": "Blocks a resource (e.g. an account)", "summary": "Blocks a resource (e.g. an account)",
@ -268,7 +288,7 @@
"follow": { "follow": {
"additionalFields": [], "additionalFields": [],
"flags": [ "flags": [
{ "flag": "account-name", "default": "" }, { "flag": "account-name" },
{ "flag": "notify", "default": "false" }, { "flag": "notify", "default": "false" },
{ "flag": "show-reposts", "default": "true" }, { "flag": "show-reposts", "default": "true" },
{ "flag": "type", "fieldName": "resourceType", "default": "" } { "flag": "type", "fieldName": "resourceType", "default": "" }
@ -298,7 +318,7 @@
"mute": { "mute": {
"additionalFields": [], "additionalFields": [],
"flags": [ "flags": [
{ "flag": "account-name", "default": "" }, { "flag": "account-name" },
{ "flag": "mute-duration" }, { "flag": "mute-duration" },
{ "flag": "mute-notifications", "default": "false" }, { "flag": "mute-notifications", "default": "false" },
{ "flag": "type", "fieldName": "resourceType", "default": "" } { "flag": "type", "fieldName": "resourceType", "default": "" }
@ -310,17 +330,30 @@
"reject": { "reject": {
"additionalFields": [], "additionalFields": [],
"flags": [ "flags": [
{ "flag": "account-name", "default": "" }, { "flag": "account-name" },
{ "flag": "type", "fieldName": "resourceType", "default": "" } { "flag": "type", "fieldName": "resourceType", "default": "" }
], ],
"summary": "Rejects a request (e.g. a follow request)", "summary": "Rejects a request (e.g. a follow request)",
"useConfig": true, "useConfig": true,
"usePrinter": true "usePrinter": true
}, },
"remove": {
"additionalFields": [],
"flags": [
{ "flag": "account-name", "fieldName": "accountNames" },
{ "flag": "from", "fieldName": "fromResourceType", "default": "" },
{ "flag": "list-id", "fieldName": "listID", "default": "" },
{ "flag": "status-id", "fieldName": "statusID", "default": "" },
{ "flag": "type", "fieldName": "resourceType", "default": "" }
],
"summary": "",
"useConfig": true,
"usePrinter": true
},
"show": { "show": {
"additionalFields": [], "additionalFields": [],
"flags": [ "flags": [
{ "flag": "account-name", "default": "" }, { "flag": "account-name" },
{ "flag": "all-images", "fieldName": "getAllImages", "default": "false" }, { "flag": "all-images", "fieldName": "getAllImages", "default": "false" },
{ "flag": "all-videos", "fieldName": "getAllVideos", "default": "false" }, { "flag": "all-videos", "fieldName": "getAllVideos", "default": "false" },
{ "flag": "attachment-id", "fieldName": "attachmentIDs" }, { "flag": "attachment-id", "fieldName": "attachmentIDs" },
@ -350,7 +383,7 @@
"switch": { "switch": {
"additionalFields": [], "additionalFields": [],
"flags": [ "flags": [
{ "flag": "account-name", "default": "" }, { "flag": "account-name" },
{ "flag": "to", "default": "" } { "flag": "to", "default": "" }
], ],
"summary": "Performs a switch operation (e.g. switching between logged in accounts)", "summary": "Performs a switch operation (e.g. switching between logged in accounts)",
@ -360,7 +393,7 @@
"unblock": { "unblock": {
"additionalFields": [], "additionalFields": [],
"flags": [ "flags": [
{ "flag": "account-name", "default": "" }, { "flag": "account-name" },
{ "flag": "type", "fieldName": "resourceType", "default": "" } { "flag": "type", "fieldName": "resourceType", "default": "" }
], ],
"summary": "Unblocks a resource (e.g. an account)", "summary": "Unblocks a resource (e.g. an account)",
@ -370,7 +403,7 @@
"unfollow": { "unfollow": {
"additionalFields": [], "additionalFields": [],
"flags": [ "flags": [
{ "flag": "account-name", "default": "" }, { "flag": "account-name" },
{ "flag": "type", "fieldName": "resourceType", "default": "" } { "flag": "type", "fieldName": "resourceType", "default": "" }
], ],
"summary": "Unfollow a resource (e.g. an account)", "summary": "Unfollow a resource (e.g. an account)",
@ -380,7 +413,7 @@
"unmute": { "unmute": {
"additionalFields": [], "additionalFields": [],
"flags": [ "flags": [
{ "flag": "account-name", "default": "" }, { "flag": "account-name" },
{ "flag": "type", "fieldName": "resourceType", "default": "" } { "flag": "type", "fieldName": "resourceType", "default": "" }
], ],
"summary": "Umutes a specific resource (e.g. an account)", "summary": "Umutes a specific resource (e.g. an account)",