checkpoint: add configuration
This commit is contained in:
parent
632a620180
commit
f451ed22c3
6 changed files with 138 additions and 35 deletions
|
@ -10,6 +10,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/executor"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/executor"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
@ -30,21 +31,10 @@ func main() {
|
||||||
func run() error {
|
func run() error {
|
||||||
var (
|
var (
|
||||||
configDir string
|
configDir string
|
||||||
cacheDir string
|
|
||||||
pager string
|
|
||||||
imageViewer string
|
|
||||||
videoPlayer string
|
|
||||||
maxTerminalWidth int
|
|
||||||
noColor *bool
|
noColor *bool
|
||||||
)
|
)
|
||||||
|
|
||||||
flag.StringVar(&configDir, "config-dir", "", "Specify your config directory")
|
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 {
|
flag.BoolFunc("no-color", "Disable ANSI colour output when displaying text on screen", func(value string) error {
|
||||||
boolVal, err := strconv.ParseBool(value)
|
boolVal, err := strconv.ParseBool(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -80,7 +70,15 @@ func run() error {
|
||||||
command := flag.Arg(0)
|
command := flag.Arg(0)
|
||||||
args := flag.Args()[1:]
|
args := flag.Args()[1:]
|
||||||
|
|
||||||
printer := printer.NewPrinter(*noColor, pager, maxTerminalWidth)
|
config, err := config.NewConfigFromFile(configDir)
|
||||||
|
if err != nil {
|
||||||
|
printer := printer.NewPrinter(*noColor, "", 80)
|
||||||
|
printer.PrintFailure("unable to load the configuration: " + err.Error() + ".")
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
printer := printer.NewPrinter(*noColor, config.Integrations.Pager, config.LineWrapMaxWidth)
|
||||||
|
|
||||||
executorMap := map[string]executor.Executor{
|
executorMap := map[string]executor.Executor{
|
||||||
executor.CommandAccept: executor.NewAcceptOrRejectExecutor(
|
executor.CommandAccept: executor.NewAcceptOrRejectExecutor(
|
||||||
|
@ -175,10 +173,8 @@ func run() error {
|
||||||
),
|
),
|
||||||
executor.CommandShow: executor.NewShowExecutor(
|
executor.CommandShow: executor.NewShowExecutor(
|
||||||
printer,
|
printer,
|
||||||
|
&config,
|
||||||
configDir,
|
configDir,
|
||||||
cacheDir,
|
|
||||||
imageViewer,
|
|
||||||
videoPlayer,
|
|
||||||
executor.CommandShow,
|
executor.CommandShow,
|
||||||
executor.CommandSummaryLookup(executor.CommandShow),
|
executor.CommandSummaryLookup(executor.CommandShow),
|
||||||
),
|
),
|
||||||
|
|
103
internal/config/config.go
Normal file
103
internal/config/config.go
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
configFileName = "config.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
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)
|
||||||
|
|
||||||
|
fileExists, err := utilities.FileExists(path)
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, fmt.Errorf("unable to check if the config file exists: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fileExists {
|
||||||
|
if err := saveDefaultConfigToFile(path); err != nil {
|
||||||
|
return Config{}, fmt.Errorf("unable to save the default config to file: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, 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 Config{}, fmt.Errorf("unable to decode the JSON data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func configFile(configDir string) string {
|
||||||
|
return filepath.Join(utilities.CalculateConfigDir(configDir), configFileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveDefaultConfigToFile(path string) error {
|
||||||
|
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()
|
||||||
|
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 defaultConfig() Config {
|
||||||
|
return Config{
|
||||||
|
CacheDirectory: "",
|
||||||
|
HTTP: HTTPConfig{
|
||||||
|
Timeout: 5,
|
||||||
|
MediaTimeout: 30,
|
||||||
|
},
|
||||||
|
LineWrapMaxWidth: 80,
|
||||||
|
Integrations: Integrations{
|
||||||
|
Browser: "",
|
||||||
|
Editor: "",
|
||||||
|
Pager: "",
|
||||||
|
ImageViewer: "",
|
||||||
|
VideoPlayer: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -109,7 +109,7 @@ func NewCredentialsConfigFromFile(configDir string) (CredentialsConfig, error) {
|
||||||
|
|
||||||
file, err := os.Open(path)
|
file, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return CredentialsConfig{}, fmt.Errorf("unable to open %s, %w", path, err)
|
return CredentialsConfig{}, fmt.Errorf("unable to open %s: %w", path, err)
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
|
@ -127,9 +127,8 @@ func saveCredentialsConfigFile(authConfig CredentialsConfig, configDir string) e
|
||||||
|
|
||||||
file, err := os.Create(path)
|
file, err := os.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to open %s: %w", path, err)
|
return fmt.Errorf("unable to create the file at %s: %w", path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
encoder := json.NewEncoder(file)
|
encoder := json.NewEncoder(file)
|
||||||
|
|
|
@ -102,3 +102,11 @@ type NotFollowingError struct {
|
||||||
func (e NotFollowingError) Error() string {
|
func (e NotFollowingError) Error() string {
|
||||||
return "you are not following " + e.Account
|
return "you are not following " + e.Account
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UnknownMediaAttachmentError struct {
|
||||||
|
AttachmentID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e UnknownMediaAttachmentError) Error() string {
|
||||||
|
return "unknown media attachment '" + e.AttachmentID + "'"
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"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/model"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
|
@ -20,12 +21,12 @@ type ShowExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
|
config *config.Config
|
||||||
myAccount bool
|
myAccount bool
|
||||||
skipAccountRelationship bool
|
skipAccountRelationship bool
|
||||||
showUserPreferences bool
|
showUserPreferences bool
|
||||||
showInBrowser bool
|
showInBrowser bool
|
||||||
configDir string
|
configDir string
|
||||||
cacheRoot string
|
|
||||||
resourceType string
|
resourceType string
|
||||||
accountName string
|
accountName string
|
||||||
statusID string
|
statusID string
|
||||||
|
@ -34,21 +35,17 @@ type ShowExecutor struct {
|
||||||
tag string
|
tag string
|
||||||
pollID string
|
pollID string
|
||||||
fromResourceType string
|
fromResourceType string
|
||||||
imageViewer string
|
|
||||||
videoPlayer string
|
|
||||||
limit int
|
limit int
|
||||||
attachmentIDs MultiStringFlagValue
|
attachmentIDs MultiStringFlagValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewShowExecutor(printer *printer.Printer, configDir, cacheRoot, imageViewer, videoPlayer, name, summary string) *ShowExecutor {
|
func NewShowExecutor(printer *printer.Printer, config *config.Config, configDir, name, summary string) *ShowExecutor {
|
||||||
showExe := ShowExecutor{
|
showExe := ShowExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: printer,
|
printer: printer,
|
||||||
|
config: config,
|
||||||
configDir: configDir,
|
configDir: configDir,
|
||||||
cacheRoot: cacheRoot,
|
|
||||||
imageViewer: imageViewer,
|
|
||||||
videoPlayer: videoPlayer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showExe.BoolVar(&showExe.myAccount, flagMyAccount, false, "Set to true to lookup your account")
|
showExe.BoolVar(&showExe.myAccount, flagMyAccount, false, "Set to true to lookup your account")
|
||||||
|
@ -471,7 +468,7 @@ func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheDir := filepath.Join(
|
cacheDir := filepath.Join(
|
||||||
utilities.CalculateCacheDir(s.cacheRoot, utilities.GetFQDN(gtsClient.Authentication.Instance)),
|
utilities.CalculateCacheDir(s.config.CacheDirectory, utilities.GetFQDN(gtsClient.Authentication.Instance)),
|
||||||
"media",
|
"media",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -498,7 +495,7 @@ func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
|
||||||
for _, attachmentID := range s.attachmentIDs {
|
for _, attachmentID := range s.attachmentIDs {
|
||||||
mediaObj, ok := attachmentsHashMap[attachmentID]
|
mediaObj, ok := attachmentsHashMap[attachmentID]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unknown media attachment: %s", attachmentID)
|
return UnknownMediaAttachmentError{AttachmentID: attachmentID}
|
||||||
}
|
}
|
||||||
|
|
||||||
split := strings.Split(mediaObj.url, "/")
|
split := strings.Split(mediaObj.url, "/")
|
||||||
|
@ -533,13 +530,13 @@ func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(imageFiles) > 0 {
|
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)
|
return fmt.Errorf("unable to open the image viewer: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(videoFiles) > 0 {
|
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)
|
return fmt.Errorf("unable to open the video player: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ func CalculateConfigDir(configDir string) string {
|
||||||
|
|
||||||
configRoot, err := os.UserConfigDir()
|
configRoot, err := os.UserConfigDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
configRoot = "."
|
return filepath.Join(os.Getenv("HOME"), "."+internal.ApplicationName, "config")
|
||||||
}
|
}
|
||||||
|
|
||||||
return filepath.Join(configRoot, internal.ApplicationName)
|
return filepath.Join(configRoot, internal.ApplicationName)
|
||||||
|
@ -33,7 +33,7 @@ func CalculateCacheDir(cacheDir, instanceFQDN string) string {
|
||||||
|
|
||||||
cacheRoot, err := os.UserCacheDir()
|
cacheRoot, err := os.UserCacheDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cacheRoot = "."
|
return filepath.Join(os.Getenv("HOME"), "."+internal.ApplicationName, "cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
return filepath.Join(cacheRoot, internal.ApplicationName, instanceFQDN)
|
return filepath.Join(cacheRoot, internal.ApplicationName, instanceFQDN)
|
||||||
|
|
Loading…
Reference in a new issue