feat: add configuration support to enbas

SUMMARY

This commit adds configuration support to enbas. The configuration is
stored as a JSON file in the user specified configuration directory.

When using enbas for the first time, the user will first need to
execute the new init command in order to generate the configuration.
Once this has been generated the user can edit the settings to
personalise their experience, login to their account and use enbas as
normal.

For now the configurable settings included in the configuration
are as follows:

- The path to the credentials file (by default this is set to a file in
  the same directory as the configuration file).
- The path to the cache directory.
- The character limit used for line wrapping.
- The programs used for integrations such as paging, media viewing,
  opening URLs, etc.

CHANGES

- added the new config type.
- added the new init executor for generating a new configuration file.
- removed the following top level flags in favour of the new
  configration support.
    - cache-dir
    - pager
    - image-viewer
    - video-player
    - max-terminal-width
- added a new error type for use when an unknown media attachment ID
  is specified.
- updated the usage function for the executors to support a case
  where a flagsets has no flags.
- update .golangci.yaml to disable some linters
This commit is contained in:
Dan Anglin 2024-06-25 12:39:39 +01:00
parent 63f0526f39
commit 42251f6df8
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
30 changed files with 425 additions and 220 deletions

View file

@ -31,5 +31,8 @@ linters-settings:
linters:
enable-all: true
disable:
#- json
- exhaustivestruct
- exhaustruct
- gomnd
- tagliatelle
fast: false

View file

@ -10,15 +10,16 @@ import (
"os"
"strconv"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/executor"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
var (
binaryVersion string
buildTime string
goVersion string
gitCommit string
binaryVersion string //nolint:gochecknoglobals
buildTime string //nolint:gochecknoglobals
goVersion string //nolint:gochecknoglobals
gitCommit string //nolint:gochecknoglobals
)
func main() {
@ -29,22 +30,11 @@ func main() {
func run() error {
var (
configDir string
cacheDir string
pager string
imageViewer string
videoPlayer string
maxTerminalWidth int
noColor *bool
configDir string
noColor *bool
)
flag.StringVar(&configDir, "config-dir", "", "Specify your config directory")
flag.StringVar(&cacheDir, "cache-dir", "", "Specify your cache directory")
flag.StringVar(&pager, "pager", "", "Specify your preferred pager to page through long outputs. This is disabled by default.")
flag.StringVar(&imageViewer, "image-viewer", "", "Specify your favourite image viewer.")
flag.StringVar(&videoPlayer, "video-player", "", "Specify your favourite video player.")
flag.IntVar(&maxTerminalWidth, "max-terminal-width", 80, "Specify the maximum terminal width when displaying resources on screen.")
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 {
@ -67,7 +57,8 @@ func run() error {
return nil
}
// If NoColor is still unspecified, check to see if the NO_COLOR environment variable is set
// 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") != "" {
@ -80,110 +71,132 @@ func run() error {
command := flag.Arg(0)
args := flag.Args()[1:]
printer := printer.NewPrinter(*noColor, pager, maxTerminalWidth)
var (
enbasConfig *config.Config
enbasPrinter *printer.Printer
err error
)
switch command {
case executor.CommandInit, executor.CommandVersion:
enbasPrinter = printer.NewPrinter(*noColor, "", 0)
default:
enbasConfig, err = config.NewConfigFromFile(configDir)
if err != nil {
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)
}
executorMap := map[string]executor.Executor{
executor.CommandAccept: executor.NewAcceptOrRejectExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandAccept,
executor.CommandSummaryLookup(executor.CommandAccept),
),
executor.CommandAdd: executor.NewAddExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandAdd,
executor.CommandSummaryLookup(executor.CommandAdd),
),
executor.CommandBlock: executor.NewBlockOrUnblockExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandBlock,
executor.CommandSummaryLookup(executor.CommandBlock),
),
executor.CommandCreate: executor.NewCreateExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandCreate,
executor.CommandSummaryLookup(executor.CommandCreate),
),
executor.CommandDelete: executor.NewDeleteExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandDelete,
executor.CommandSummaryLookup(executor.CommandDelete),
),
executor.CommandEdit: executor.NewEditExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandEdit,
executor.CommandSummaryLookup(executor.CommandEdit),
),
executor.CommandFollow: executor.NewFollowOrUnfollowExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandFollow,
executor.CommandSummaryLookup(executor.CommandFollow),
),
executor.CommandLogin: executor.NewLoginExecutor(
printer,
executor.CommandInit: executor.NewInitExecutor(
enbasPrinter,
configDir,
executor.CommandInit,
executor.CommandSummaryLookup(executor.CommandInit),
),
executor.CommandLogin: executor.NewLoginExecutor(
enbasPrinter,
enbasConfig,
executor.CommandLogin,
executor.CommandSummaryLookup(executor.CommandLogin),
),
executor.CommandMute: executor.NewMuteOrUnmuteExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandMute,
executor.CommandSummaryLookup(executor.CommandMute),
),
executor.CommandReject: executor.NewAcceptOrRejectExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandReject,
executor.CommandSummaryLookup(executor.CommandReject),
),
executor.CommandRemove: executor.NewRemoveExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandRemove,
executor.CommandSummaryLookup(executor.CommandRemove),
),
executor.CommandSwitch: executor.NewSwitchExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandSwitch,
executor.CommandSummaryLookup(executor.CommandSwitch),
),
executor.CommandUnfollow: executor.NewFollowOrUnfollowExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandUnfollow,
executor.CommandSummaryLookup(executor.CommandUnfollow),
),
executor.CommandUnmute: executor.NewMuteOrUnmuteExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandUnmute,
executor.CommandSummaryLookup(executor.CommandUnmute),
),
executor.CommandUnblock: executor.NewBlockOrUnblockExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandUnblock,
executor.CommandSummaryLookup(executor.CommandUnblock),
),
executor.CommandShow: executor.NewShowExecutor(
printer,
configDir,
cacheDir,
imageViewer,
videoPlayer,
enbasPrinter,
enbasConfig,
executor.CommandShow,
executor.CommandSummaryLookup(executor.CommandShow),
),
executor.CommandVersion: executor.NewVersionExecutor(
printer,
enbasPrinter,
executor.CommandVersion,
executor.CommandSummaryLookup(executor.CommandVersion),
binaryVersion,
@ -192,8 +205,8 @@ func run() error {
gitCommit,
),
executor.CommandWhoami: executor.NewWhoAmIExecutor(
printer,
configDir,
enbasPrinter,
enbasConfig,
executor.CommandWhoami,
executor.CommandSummaryLookup(executor.CommandWhoami),
),
@ -201,16 +214,16 @@ func run() error {
exe, ok := executorMap[command]
if !ok {
err := executor.UnknownCommandError{Command: command}
err = executor.UnknownCommandError{Command: command}
printer.PrintFailure(err.Error() + ".")
enbasPrinter.PrintFailure(err.Error() + ".")
flag.Usage()
return err
}
if err := executor.Execute(exe, args); err != nil {
printer.PrintFailure("(" + command + ") " + err.Error() + ".")
if err = executor.Execute(exe, args); err != nil {
enbasPrinter.PrintFailure("(" + command + ") " + err.Error() + ".")
return err
}

View file

@ -25,8 +25,8 @@ type Client struct {
Timeout time.Duration
}
func NewClientFromConfig(configDir string) (*Client, error) {
config, err := config.NewCredentialsConfigFromFile(configDir)
func NewClientFromFile(path string) (*Client, error) {
config, err := config.NewCredentialsConfigFromFile(path)
if err != nil {
return nil, fmt.Errorf("unable to get the authentication configuration: %w", err)
}
@ -51,7 +51,7 @@ func NewClient(authentication config.Credentials) *Client {
func (g *Client) AuthCodeURL() string {
format := "%s/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code"
escapedRedirectURI := url.QueryEscape(internal.RedirectUri)
escapedRedirectURI := url.QueryEscape(internal.RedirectURI)
return fmt.Sprintf(
format,

View file

@ -24,7 +24,7 @@ type registerRequest struct {
func (g *Client) Register() error {
params := registerRequest{
ClientName: internal.ApplicationName,
RedirectUris: internal.RedirectUri,
RedirectUris: internal.RedirectURI,
Scopes: "read write",
Website: internal.ApplicationWebsite,
}

View file

@ -17,7 +17,7 @@ import (
var errEmptyAccessToken = errors.New("received an empty access token")
type tokenRequest struct {
RedirectUri string `json:"redirect_uri"`
RedirectURI string `json:"redirect_uri"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
GrantType string `json:"grant_type"`
@ -33,7 +33,7 @@ type tokenResponse struct {
func (g *Client) UpdateToken(code string) error {
params := tokenRequest{
RedirectUri: internal.RedirectUri,
RedirectURI: internal.RedirectURI,
ClientID: g.Authentication.ClientID,
ClientSecret: g.Authentication.ClientSecret,
GrantType: "authorization_code",

108
internal/config/config.go Normal file
View file

@ -0,0 +1,108 @@
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
//
// SPDX-License-Identifier: GPL-3.0-or-later
package config
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
)
const (
configFileName = "config.json"
)
type Config struct {
CredentialsFile string `json:"credentialsFile"`
CacheDirectory string `json:"cacheDirectory"`
LineWrapMaxWidth int `json:"lineWrapMaxWidth"`
HTTP HTTPConfig `json:"http"`
Integrations Integrations `json:"integrations"`
}
type HTTPConfig struct {
Timeout int `json:"timeout"`
MediaTimeout int `json:"mediaTimeout"`
}
type Integrations struct {
Browser string `json:"browser"`
Editor string `json:"editor"`
Pager string `json:"pager"`
ImageViewer string `json:"imageViewer"`
VideoPlayer string `json:"videoPlayer"`
}
func NewConfigFromFile(configDir string) (*Config, error) {
path := configFile(configDir)
file, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("unable to open %s: %w", path, err)
}
defer file.Close()
var config Config
if err := json.NewDecoder(file).Decode(&config); err != nil {
return nil, fmt.Errorf("unable to decode the JSON data: %w", err)
}
return &config, nil
}
func FileExists(configDir string) (bool, error) {
path := configFile(configDir)
return utilities.FileExists(path)
}
func SaveDefaultConfigToFile(configDir string) error {
path := configFile(configDir)
file, err := os.Create(path)
if err != nil {
return fmt.Errorf("unable to create the file at %s: %w", path, err)
}
defer file.Close()
config := defaultConfig(configDir)
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
if err := encoder.Encode(config); err != nil {
return fmt.Errorf("unable to save the JSON data to the config file: %w", err)
}
return nil
}
func configFile(configDir string) string {
return filepath.Join(utilities.CalculateConfigDir(configDir), configFileName)
}
func defaultConfig(configDir string) Config {
credentialsFilePath := defaultCredentialsConfigFile(configDir)
return Config{
CredentialsFile: credentialsFilePath,
CacheDirectory: "",
HTTP: HTTPConfig{
Timeout: 5,
MediaTimeout: 30,
},
LineWrapMaxWidth: 80,
Integrations: Integrations{
Browser: "",
Editor: "",
Pager: "",
ImageViewer: "",
VideoPlayer: "",
},
}
}

View file

@ -10,13 +10,12 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
)
const (
credentialsFileName = "credentials.json"
defaultCredentialsFileName = "credentials.json"
)
type CredentialsConfig struct {
@ -42,35 +41,29 @@ func (e CredentialsNotFoundError) Error() string {
// SaveCredentials saves the credentials into the credentials file within the specified configuration
// directory. If the directory is not specified then the default directory is used. If the directory
// is not present, it will be created.
func SaveCredentials(configDir, username string, credentials Credentials) (string, error) {
if err := utilities.EnsureDirectory(utilities.CalculateConfigDir(configDir)); err != nil {
func SaveCredentials(filePath, username string, credentials Credentials) (string, error) {
directory := filepath.Dir(filePath)
if err := utilities.EnsureDirectory(utilities.CalculateConfigDir(directory)); err != nil {
return "", fmt.Errorf("unable to ensure the configuration directory: %w", err)
}
var authConfig CredentialsConfig
filepath := credentialsConfigFile(configDir)
if _, err := os.Stat(filepath); err != nil {
if _, err := os.Stat(filePath); err != nil {
if !errors.Is(err, os.ErrNotExist) {
return "", fmt.Errorf("unknown error received when running stat on %s: %w", filepath, err)
return "", fmt.Errorf("unknown error received when running stat on %s: %w", filePath, err)
}
authConfig.Credentials = make(map[string]Credentials)
} else {
authConfig, err = NewCredentialsConfigFromFile(configDir)
authConfig, err = NewCredentialsConfigFromFile(filePath)
if err != nil {
return "", fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
}
}
instance := ""
if strings.HasPrefix(credentials.Instance, "https://") {
instance = strings.TrimPrefix(credentials.Instance, "https://")
} else if strings.HasPrefix(credentials.Instance, "http://") {
instance = strings.TrimPrefix(credentials.Instance, "http://")
}
instance := utilities.GetFQDN(credentials.Instance)
authenticationName := username + "@" + instance
@ -78,15 +71,15 @@ func SaveCredentials(configDir, username string, credentials Credentials) (strin
authConfig.Credentials[authenticationName] = credentials
if err := saveCredentialsConfigFile(authConfig, configDir); err != nil {
if err := saveCredentialsConfigFile(authConfig, filePath); err != nil {
return "", fmt.Errorf("unable to save the authentication configuration to file: %w", err)
}
return authenticationName, nil
}
func UpdateCurrentAccount(account string, configDir string) error {
credentialsConfig, err := NewCredentialsConfigFromFile(configDir)
func UpdateCurrentAccount(account string, filePath string) error {
credentialsConfig, err := NewCredentialsConfigFromFile(filePath)
if err != nil {
return fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
}
@ -97,19 +90,19 @@ func UpdateCurrentAccount(account string, configDir string) error {
credentialsConfig.CurrentAccount = account
if err := saveCredentialsConfigFile(credentialsConfig, configDir); err != nil {
if err := saveCredentialsConfigFile(credentialsConfig, filePath); err != nil {
return fmt.Errorf("unable to save the authentication configuration to file: %w", err)
}
return nil
}
func NewCredentialsConfigFromFile(configDir string) (CredentialsConfig, error) {
path := credentialsConfigFile(configDir)
file, err := os.Open(path)
// NewCredentialsConfigFromFile creates a new CredentialsConfig value from reading
// the credentials file.
func NewCredentialsConfigFromFile(filePath string) (CredentialsConfig, error) {
file, err := os.Open(filePath)
if err != nil {
return CredentialsConfig{}, fmt.Errorf("unable to open %s, %w", path, err)
return CredentialsConfig{}, fmt.Errorf("unable to open %s: %w", filePath, err)
}
defer file.Close()
@ -122,14 +115,11 @@ func NewCredentialsConfigFromFile(configDir string) (CredentialsConfig, error) {
return authConfig, nil
}
func saveCredentialsConfigFile(authConfig CredentialsConfig, configDir string) error {
path := credentialsConfigFile(configDir)
file, err := os.Create(path)
func saveCredentialsConfigFile(authConfig CredentialsConfig, filePath string) error {
file, err := os.Create(filePath)
if err != nil {
return fmt.Errorf("unable to open %s: %w", path, err)
return fmt.Errorf("unable to create the file at %s: %w", filePath, err)
}
defer file.Close()
encoder := json.NewEncoder(file)
@ -142,6 +132,6 @@ func saveCredentialsConfigFile(authConfig CredentialsConfig, configDir string) e
return nil
}
func credentialsConfigFile(configDir string) string {
return filepath.Join(utilities.CalculateConfigDir(configDir), credentialsFileName)
func defaultCredentialsConfigFile(configDir string) string {
return filepath.Join(utilities.CalculateConfigDir(configDir), defaultCredentialsFileName)
}

View file

@ -9,6 +9,7 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
@ -16,19 +17,19 @@ type AcceptOrRejectExecutor struct {
*flag.FlagSet
printer *printer.Printer
configDir string
config *config.Config
resourceType string
accountName string
command string
}
func NewAcceptOrRejectExecutor(enbasPrinter *printer.Printer, configDir, name, summary string) *AcceptOrRejectExecutor {
func NewAcceptOrRejectExecutor(enbasPrinter *printer.Printer, config *config.Config, name, summary string) *AcceptOrRejectExecutor {
acceptExe := AcceptOrRejectExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: enbasPrinter,
configDir: configDir,
command: name,
printer: enbasPrinter,
config: config,
command: name,
}
acceptExe.StringVar(&acceptExe.resourceType, flagType, "", "Specify the type of resource to accept or reject")
@ -49,7 +50,7 @@ func (a *AcceptOrRejectExecutor) Execute() error {
return UnsupportedTypeError{resourceType: a.resourceType}
}
gtsClient, err := client.NewClientFromConfig(a.configDir)
gtsClient, err := client.NewClientFromFile(a.config.CredentialsFile)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -58,7 +59,7 @@ func (a *AcceptOrRejectExecutor) Execute() error {
}
func (a *AcceptOrRejectExecutor) acceptOrRejectFollowRequest(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, a.accountName, a.configDir)
accountID, err := getAccountID(gtsClient, false, a.accountName, a.config.CredentialsFile)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}

View file

@ -12,7 +12,7 @@ import (
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
)
func getAccountID(gtsClient *client.Client, myAccount bool, accountName, configDir string) (string, error) {
func getAccountID(gtsClient *client.Client, myAccount bool, accountName, path string) (string, error) {
var (
accountID string
err error
@ -20,7 +20,7 @@ func getAccountID(gtsClient *client.Client, myAccount bool, accountName, configD
switch {
case myAccount:
accountID, err = getMyAccountID(gtsClient, configDir)
accountID, err = getMyAccountID(gtsClient, path)
if err != nil {
return "", fmt.Errorf("unable to get your account ID: %w", err)
}
@ -45,8 +45,8 @@ func getTheirAccountID(gtsClient *client.Client, accountURI string) (string, err
return account.ID, nil
}
func getMyAccountID(gtsClient *client.Client, configDir string) (string, error) {
account, err := getMyAccount(gtsClient, configDir)
func getMyAccountID(gtsClient *client.Client, path string) (string, error) {
account, err := getMyAccount(gtsClient, path)
if err != nil {
return "", fmt.Errorf("received an error while getting your account details: %w", err)
}
@ -54,8 +54,8 @@ func getMyAccountID(gtsClient *client.Client, configDir string) (string, error)
return account.ID, nil
}
func getMyAccount(gtsClient *client.Client, configDir string) (model.Account, error) {
authConfig, err := config.NewCredentialsConfigFromFile(configDir)
func getMyAccount(gtsClient *client.Client, path string) (model.Account, error) {
authConfig, err := config.NewCredentialsConfigFromFile(path)
if err != nil {
return model.Account{}, fmt.Errorf("unable to retrieve the authentication configuration: %w", err)
}

View file

@ -10,6 +10,7 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
@ -17,7 +18,7 @@ type AddExecutor struct {
*flag.FlagSet
printer *printer.Printer
configDir string
config *config.Config
resourceType string
toResourceType string
listID string
@ -28,14 +29,14 @@ type AddExecutor struct {
content string
}
func NewAddExecutor(printer *printer.Printer, configDir, name, summary string) *AddExecutor {
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,
configDir: configDir,
config: config,
accountNames: MultiStringFlagValue(emptyArr),
}
@ -71,7 +72,7 @@ func (a *AddExecutor) Execute() error {
return UnsupportedTypeError{resourceType: a.toResourceType}
}
gtsClient, err := client.NewClientFromConfig(a.configDir)
gtsClient, err := client.NewClientFromFile(a.config.CredentialsFile)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -154,7 +155,7 @@ func (a *AddExecutor) addNoteToAccount(gtsClient *client.Client) error {
return fmt.Errorf("unexpected number of accounts specified: want 1, got %d", len(a.accountNames))
}
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.configDir)
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.config.CredentialsFile)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}

View file

@ -9,6 +9,7 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
@ -16,19 +17,19 @@ type BlockOrUnblockExecutor struct {
*flag.FlagSet
printer *printer.Printer
configDir string
config *config.Config
resourceType string
accountName string
command string
}
func NewBlockOrUnblockExecutor(printer *printer.Printer, configDir, name, summary string) *BlockOrUnblockExecutor {
func NewBlockOrUnblockExecutor(printer *printer.Printer, config *config.Config, name, summary string) *BlockOrUnblockExecutor {
blockExe := BlockOrUnblockExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
command: name,
printer: printer,
config: config,
command: name,
}
blockExe.StringVar(&blockExe.resourceType, flagType, "", "Specify the type of resource to block or unblock")
@ -49,7 +50,7 @@ func (b *BlockOrUnblockExecutor) Execute() error {
return UnsupportedTypeError{resourceType: b.resourceType}
}
gtsClient, err := client.NewClientFromConfig(b.configDir)
gtsClient, err := client.NewClientFromFile(b.config.CredentialsFile)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -62,7 +63,7 @@ func (b *BlockOrUnblockExecutor) blockOrUnblockAccount(gtsClient *client.Client)
return FlagNotSetError{flagText: flagAccountName}
}
accountID, err := getAccountID(gtsClient, false, b.accountName, b.configDir)
accountID, err := getAccountID(gtsClient, false, b.accountName, b.config.CredentialsFile)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}

View file

@ -12,6 +12,7 @@ const (
CommandDelete string = "delete"
CommandEdit string = "edit"
CommandFollow string = "follow"
CommandInit string = "init"
CommandLogin string = "login"
CommandMute string = "mute"
CommandReject string = "reject"
@ -31,6 +32,7 @@ const (
commandDeleteSummary string = "Delete a specific resource"
commandEditSummary string = "Edit a specific resource"
commandFollowSummary string = "Follow a resource (e.g. an account)"
commandInitSummary string = "Create a new configuration file in the specified configuration directory"
commandLoginSummary string = "Login to an account on GoToSocial"
commandMuteSummary string = "Mute a resource (e.g. an account)"
commandRejectSummary string = "Reject a request (e.g. a follow request)"
@ -53,6 +55,7 @@ func CommandSummaryMap() map[string]string {
CommandDelete: commandDeleteSummary,
CommandEdit: commandEditSummary,
CommandFollow: commandFollowSummary,
CommandInit: commandInitSummary,
CommandLogin: commandLoginSummary,
CommandMute: commandMuteSummary,
CommandReject: commandRejectSummary,

View file

@ -10,6 +10,7 @@ import (
"strconv"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
@ -19,6 +20,7 @@ type CreateExecutor struct {
*flag.FlagSet
printer *printer.Printer
config *config.Config
addPoll bool
boostable bool
federated bool
@ -27,7 +29,6 @@ type CreateExecutor struct {
pollHidesVoteCounts bool
replyable bool
sensitive *bool
configDir string
content string
contentType string
fromFile string
@ -41,12 +42,12 @@ type CreateExecutor struct {
pollOptions MultiStringFlagValue
}
func NewCreateExecutor(printer *printer.Printer, configDir, name, summary string) *CreateExecutor {
func NewCreateExecutor(printer *printer.Printer, config *config.Config, name, summary string) *CreateExecutor {
createExe := CreateExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
printer: printer,
config: config,
}
createExe.BoolVar(&createExe.boostable, flagEnableReposts, true, "Specify if the status can be reposted/boosted by others")
@ -90,7 +91,7 @@ func (c *CreateExecutor) Execute() error {
return FlagNotSetError{flagText: flagType}
}
gtsClient, err := client.NewClientFromConfig(c.configDir)
gtsClient, err := client.NewClientFromFile(c.config.CredentialsFile)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}

View file

@ -9,6 +9,7 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
@ -16,17 +17,17 @@ type DeleteExecutor struct {
*flag.FlagSet
printer *printer.Printer
configDir string
config *config.Config
resourceType string
listID string
}
func NewDeleteExecutor(printer *printer.Printer, configDir, name, summary string) *DeleteExecutor {
func NewDeleteExecutor(printer *printer.Printer, config *config.Config, name, summary string) *DeleteExecutor {
deleteExe := DeleteExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
printer: printer,
config: config,
}
deleteExe.StringVar(&deleteExe.resourceType, flagType, "", "Specify the type of resource to delete")
@ -51,7 +52,7 @@ func (d *DeleteExecutor) Execute() error {
return UnsupportedTypeError{resourceType: d.resourceType}
}
gtsClient, err := client.NewClientFromConfig(d.configDir)
gtsClient, err := client.NewClientFromFile(d.config.CredentialsFile)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}

View file

@ -9,6 +9,7 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
@ -17,19 +18,19 @@ type EditExecutor struct {
*flag.FlagSet
printer *printer.Printer
configDir string
config *config.Config
resourceType string
listID string
listTitle string
listRepliesPolicy string
}
func NewEditExecutor(printer *printer.Printer, configDir, name, summary string) *EditExecutor {
func NewEditExecutor(printer *printer.Printer, config *config.Config, name, summary string) *EditExecutor {
editExe := EditExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
printer: printer,
config: config,
}
editExe.StringVar(&editExe.resourceType, flagType, "", "Specify the type of resource to update")
@ -56,7 +57,7 @@ func (e *EditExecutor) Execute() error {
return UnsupportedTypeError{resourceType: e.resourceType}
}
gtsClient, err := client.NewClientFromConfig(e.configDir)
gtsClient, err := client.NewClientFromFile(e.config.CredentialsFile)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}

View file

@ -102,3 +102,11 @@ type NotFollowingError struct {
func (e NotFollowingError) Error() string {
return "you are not following " + e.Account
}
type UnknownMediaAttachmentError struct {
AttachmentID string
}
func (e UnknownMediaAttachmentError) Error() string {
return "unknown media attachment '" + e.AttachmentID + "'"
}

View file

@ -9,6 +9,7 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
@ -16,7 +17,7 @@ type FollowOrUnfollowExecutor struct {
*flag.FlagSet
printer *printer.Printer
configDir string
config *config.Config
resourceType string
accountName string
showReposts bool
@ -24,13 +25,13 @@ type FollowOrUnfollowExecutor struct {
action string
}
func NewFollowOrUnfollowExecutor(printer *printer.Printer, configDir, name, summary string) *FollowOrUnfollowExecutor {
func NewFollowOrUnfollowExecutor(printer *printer.Printer, config *config.Config, name, summary string) *FollowOrUnfollowExecutor {
command := FollowOrUnfollowExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
action: name,
printer: printer,
config: config,
action: name,
}
command.StringVar(&command.resourceType, flagType, "", "Specify the type of resource to follow")
@ -53,7 +54,7 @@ func (f *FollowOrUnfollowExecutor) Execute() error {
return UnsupportedTypeError{resourceType: f.resourceType}
}
gtsClient, err := client.NewClientFromConfig(f.configDir)
gtsClient, err := client.NewClientFromFile(f.config.CredentialsFile)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -62,7 +63,7 @@ func (f *FollowOrUnfollowExecutor) Execute() error {
}
func (f *FollowOrUnfollowExecutor) followOrUnfollowAccount(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, f.accountName, f.configDir)
accountID, err := getAccountID(gtsClient, false, f.accountName, f.config.CredentialsFile)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}

61
internal/executor/init.go Normal file
View file

@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
//
// SPDX-License-Identifier: GPL-3.0-or-later
package executor
import (
"flag"
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
)
type InitExecutor struct {
*flag.FlagSet
printer *printer.Printer
configDir string
}
func NewInitExecutor(printer *printer.Printer, configDir, name, summary string) *InitExecutor {
initExe := InitExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
}
initExe.Usage = commandUsageFunc(name, summary, initExe.FlagSet)
return &initExe
}
func (i *InitExecutor) Execute() error {
if err := utilities.EnsureDirectory(i.configDir); err != nil {
return fmt.Errorf("unable to ensure that the configuration directory is present: %w", err)
}
i.printer.PrintSuccess("The configuration directory is present.")
fileExists, err := config.FileExists(i.configDir)
if err != nil {
return fmt.Errorf("unable to check if the config file exists: %w", err)
}
if fileExists {
i.printer.PrintInfo("The configuration file is already present in " + i.configDir + "\n")
return nil
}
if err := config.SaveDefaultConfigToFile(i.configDir); err != nil {
return fmt.Errorf("unable to create a new configuration file in %s: %w", i.configDir, err)
}
i.printer.PrintSuccess("Successfully created a new configuration file in " + i.configDir)
return nil
}

View file

@ -18,18 +18,18 @@ import (
type LoginExecutor struct {
*flag.FlagSet
printer *printer.Printer
configDir string
instance string
printer *printer.Printer
config *config.Config
instance string
}
func NewLoginExecutor(printer *printer.Printer, configDir, name, summary string) *LoginExecutor {
func NewLoginExecutor(printer *printer.Printer, config *config.Config, name, summary string) *LoginExecutor {
command := LoginExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
instance: "",
printer: printer,
config: config,
instance: "",
}
command.StringVar(&command.instance, flagInstance, "", "Specify the instance that you want to login to.")
@ -95,7 +95,7 @@ func (c *LoginExecutor) Execute() error {
return fmt.Errorf("unable to verify the credentials: %w", err)
}
loginName, err := config.SaveCredentials(c.configDir, account.Username, gtsClient.Authentication)
loginName, err := config.SaveCredentials(c.config.CredentialsFile, account.Username, gtsClient.Authentication)
if err != nil {
return fmt.Errorf("unable to save the authentication details: %w", err)
}

View file

@ -9,6 +9,7 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
@ -16,21 +17,21 @@ type MuteOrUnmuteExecutor struct {
*flag.FlagSet
printer *printer.Printer
config *config.Config
accountName string
configDir string
command string
resourceType string
muteDuration TimeDurationFlagValue
muteNotifications bool
}
func NewMuteOrUnmuteExecutor(printer *printer.Printer, configDir, name, summary string) *MuteOrUnmuteExecutor {
func NewMuteOrUnmuteExecutor(printer *printer.Printer, config *config.Config, name, summary string) *MuteOrUnmuteExecutor {
exe := MuteOrUnmuteExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
command: name,
printer: printer,
config: config,
command: name,
}
exe.StringVar(&exe.accountName, flagAccountName, "", "Specify the account name in full (username@domain)")
@ -53,7 +54,7 @@ func (m *MuteOrUnmuteExecutor) Execute() error {
return UnsupportedTypeError{resourceType: m.resourceType}
}
gtsClient, err := client.NewClientFromConfig(m.configDir)
gtsClient, err := client.NewClientFromFile(m.config.CredentialsFile)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -66,7 +67,7 @@ func (m *MuteOrUnmuteExecutor) muteOrUnmuteAccount(gtsClient *client.Client) err
return FlagNotSetError{flagText: flagAccountName}
}
accountID, err := getAccountID(gtsClient, false, m.accountName, m.configDir)
accountID, err := getAccountID(gtsClient, false, m.accountName, m.config.CredentialsFile)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}

View file

@ -9,6 +9,7 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
@ -16,7 +17,7 @@ type RemoveExecutor struct {
*flag.FlagSet
printer *printer.Printer
configDir string
config *config.Config
resourceType string
fromResourceType string
listID string
@ -24,14 +25,14 @@ type RemoveExecutor struct {
accountNames MultiStringFlagValue
}
func NewRemoveExecutor(printer *printer.Printer, configDir, name, summary string) *RemoveExecutor {
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,
configDir: configDir,
config: config,
accountNames: MultiStringFlagValue(emptyArr),
}
@ -63,7 +64,7 @@ func (r *RemoveExecutor) Execute() error {
return UnsupportedTypeError{resourceType: r.fromResourceType}
}
gtsClient, err := client.NewClientFromConfig(r.configDir)
gtsClient, err := client.NewClientFromFile(r.config.CredentialsFile)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -137,7 +138,7 @@ func (r *RemoveExecutor) removeNoteFromAccount(gtsClient *client.Client) error {
return fmt.Errorf("unexpected number of accounts specified: want 1, got %d", len(r.accountNames))
}
accountID, err := getAccountID(gtsClient, false, r.accountNames[0], r.configDir)
accountID, err := getAccountID(gtsClient, false, r.accountNames[0], r.config.CredentialsFile)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}

View file

@ -11,6 +11,7 @@ import (
"strings"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
@ -20,12 +21,11 @@ type ShowExecutor struct {
*flag.FlagSet
printer *printer.Printer
config *config.Config
myAccount bool
skipAccountRelationship bool
showUserPreferences bool
showInBrowser bool
configDir string
cacheRoot string
resourceType string
accountName string
statusID string
@ -34,21 +34,16 @@ type ShowExecutor struct {
tag string
pollID string
fromResourceType string
imageViewer string
videoPlayer string
limit int
attachmentIDs MultiStringFlagValue
}
func NewShowExecutor(printer *printer.Printer, configDir, cacheRoot, imageViewer, videoPlayer, name, summary string) *ShowExecutor {
func NewShowExecutor(printer *printer.Printer, config *config.Config, name, summary string) *ShowExecutor {
showExe := ShowExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
cacheRoot: cacheRoot,
imageViewer: imageViewer,
videoPlayer: videoPlayer,
printer: printer,
config: config,
}
showExe.BoolVar(&showExe.myAccount, flagMyAccount, false, "Set to true to lookup your account")
@ -100,7 +95,7 @@ func (s *ShowExecutor) Execute() error {
return UnsupportedTypeError{resourceType: s.resourceType}
}
gtsClient, err := client.NewClientFromConfig(s.configDir)
gtsClient, err := client.NewClientFromFile(s.config.CredentialsFile)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -126,7 +121,7 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
)
if s.myAccount {
account, err = getMyAccount(gtsClient, s.configDir)
account, err = getMyAccount(gtsClient, s.config.CredentialsFile)
if err != nil {
return fmt.Errorf("received an error while getting the account details: %w", err)
}
@ -288,7 +283,7 @@ func (s *ShowExecutor) showLists(gtsClient *client.Client) error {
}
func (s *ShowExecutor) showFollowers(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.configDir)
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.config.CredentialsFile)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}
@ -308,7 +303,7 @@ func (s *ShowExecutor) showFollowers(gtsClient *client.Client) error {
}
func (s *ShowExecutor) showFollowing(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.configDir)
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.config.CredentialsFile)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}
@ -471,7 +466,7 @@ func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
}
cacheDir := filepath.Join(
utilities.CalculateCacheDir(s.cacheRoot, utilities.GetFQDN(gtsClient.Authentication.Instance)),
utilities.CalculateCacheDir(s.config.CacheDirectory, utilities.GetFQDN(gtsClient.Authentication.Instance)),
"media",
)
@ -498,7 +493,7 @@ func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
for _, attachmentID := range s.attachmentIDs {
mediaObj, ok := attachmentsHashMap[attachmentID]
if !ok {
return fmt.Errorf("unknown media attachment: %s", attachmentID)
return UnknownMediaAttachmentError{AttachmentID: attachmentID}
}
split := strings.Split(mediaObj.url, "/")
@ -533,13 +528,13 @@ func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
}
if len(imageFiles) > 0 {
if err := utilities.OpenMedia(s.imageViewer, imageFiles); err != nil {
if err := utilities.OpenMedia(s.config.Integrations.ImageViewer, imageFiles); err != nil {
return fmt.Errorf("unable to open the image viewer: %w", err)
}
}
if len(videoFiles) > 0 {
if err := utilities.OpenMedia(s.videoPlayer, videoFiles); err != nil {
if err := utilities.OpenMedia(s.config.Integrations.VideoPlayer, videoFiles); err != nil {
return fmt.Errorf("unable to open the video player: %w", err)
}
}

View file

@ -15,17 +15,17 @@ import (
type SwitchExecutor struct {
*flag.FlagSet
configDir string
config *config.Config
toResourceType string
accountName string
printer *printer.Printer
}
func NewSwitchExecutor(printer *printer.Printer, configDir, name, summary string) *SwitchExecutor {
func NewSwitchExecutor(printer *printer.Printer, config *config.Config, name, summary string) *SwitchExecutor {
switchExe := SwitchExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
config: config,
}
switchExe.StringVar(&switchExe.toResourceType, flagTo, "", "The account to switch to")
@ -54,7 +54,7 @@ func (s *SwitchExecutor) switchToAccount() error {
return NoAccountSpecifiedError{}
}
if err := config.UpdateCurrentAccount(s.accountName, s.configDir); err != nil {
if err := config.UpdateCurrentAccount(s.accountName, s.config.CredentialsFile); err != nil {
return fmt.Errorf("unable to switch account to the account: %w", err)
}

View file

@ -6,7 +6,7 @@ package executor
import (
"flag"
"fmt"
"slices"
"strings"
)
@ -15,27 +15,41 @@ func commandUsageFunc(name, summary string, flagset *flag.FlagSet) func() {
return func() {
var builder strings.Builder
fmt.Fprintf(
&builder,
"SUMMARY:\n %s - %s\n\nUSAGE:\n enbas %s [flags]\n\nFLAGS:",
name,
summary,
name,
)
builder.WriteString("SUMMARY:")
builder.WriteString("\n " + name + " - " + summary)
builder.WriteString("\n\nUSAGE:")
builder.WriteString("\n enbas " + name)
flagMap := make(map[string]string)
flagset.VisitAll(func(f *flag.Flag) {
fmt.Fprintf(
&builder,
"\n --%s\n %s",
f.Name,
f.Usage,
)
flagMap[f.Name] = f.Usage
})
if len(flagMap) > 0 {
flags := make([]string, len(flagMap))
ind := 0
for f := range flagMap {
flags[ind] = f
ind++
}
slices.Sort(flags)
builder.WriteString(" [flags]")
builder.WriteString("\n\nFLAGS:")
for _, value := range flags {
builder.WriteString("\n --" + value)
builder.WriteString("\n " + flagMap[value])
}
}
builder.WriteString("\n")
w := flag.CommandLine.Output()
fmt.Fprint(w, builder.String())
_, _ = w.Write([]byte(builder.String()))
}
}

View file

@ -12,6 +12,7 @@ import (
type VersionExecutor struct {
*flag.FlagSet
printer *printer.Printer
showFullVersion bool
binaryVersion string
@ -21,7 +22,7 @@ type VersionExecutor struct {
}
func NewVersionExecutor(
enbasPrinter *printer.Printer,
printer *printer.Printer,
name,
summary,
binaryVersion,
@ -32,7 +33,7 @@ func NewVersionExecutor(
command := VersionExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: enbasPrinter,
printer: printer,
binaryVersion: binaryVersion,
buildTime: buildTime,
goVersion: goVersion,

View file

@ -15,16 +15,16 @@ import (
type WhoAmIExecutor struct {
*flag.FlagSet
printer *printer.Printer
configDir string
printer *printer.Printer
config *config.Config
}
func NewWhoAmIExecutor(printer *printer.Printer, configDir, name, summary string) *WhoAmIExecutor {
func NewWhoAmIExecutor(printer *printer.Printer, config *config.Config, name, summary string) *WhoAmIExecutor {
whoExe := WhoAmIExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
printer: printer,
config: config,
}
whoExe.Usage = commandUsageFunc(name, summary, whoExe.FlagSet)
@ -33,7 +33,7 @@ func NewWhoAmIExecutor(printer *printer.Printer, configDir, name, summary string
}
func (c *WhoAmIExecutor) Execute() error {
config, err := config.NewCredentialsConfigFromFile(c.configDir)
config, err := config.NewCredentialsConfigFromFile(c.config.CredentialsFile)
if err != nil {
return fmt.Errorf("unable to load the credential config: %w", err)
}

View file

@ -7,6 +7,6 @@ package internal
const (
ApplicationName = "enbas"
ApplicationWebsite = "https://codeflow.dananglin.me.uk/apollo/enbas"
RedirectUri = "urn:ietf:wg:oauth:2.0:oob"
RedirectURI = "urn:ietf:wg:oauth:2.0:oob"
UserAgent = "Enbas/0.0.0"
)

View file

@ -9,7 +9,7 @@ type Application struct {
ClientSecret string `json:"client_secret"`
ID string `json:"id"`
Name string `json:"name"`
RedirectUri string `json:"redirect_uri"`
RedirectURI string `json:"redirect_uri"`
VapidKey string `json:"vapid_key"`
Website string `json:"website"`
}

View file

@ -95,7 +95,7 @@ type InstanceV2Thumbnail struct {
ThumbnailDescription string `json:"thumbnail_description"`
ThumbnailType string `json:"thumbnail_type"`
URL string `json:"url"`
Versions InstanceV2ThumbnailVersions `json:"versions"`
Versions InstanceV2ThumbnailVersions `json:"versions"`
}
type InstanceV2ThumbnailVersions struct {

View file

@ -20,7 +20,7 @@ func CalculateConfigDir(configDir string) string {
configRoot, err := os.UserConfigDir()
if err != nil {
configRoot = "."
return filepath.Join(os.Getenv("HOME"), "."+internal.ApplicationName, "config")
}
return filepath.Join(configRoot, internal.ApplicationName)
@ -33,7 +33,7 @@ func CalculateCacheDir(cacheDir, instanceFQDN string) string {
cacheRoot, err := os.UserCacheDir()
if err != nil {
cacheRoot = "."
return filepath.Join(os.Getenv("HOME"), "."+internal.ApplicationName, "cache")
}
return filepath.Join(cacheRoot, internal.ApplicationName, instanceFQDN)