From 21b3de5ef29f3adeefa57237fdcf9a92876eb5b0 Mon Sep 17 00:00:00 2001 From: Albert Wolszon Date: Fri, 20 Jan 2023 11:59:18 +0100 Subject: [PATCH 1/3] Add new logger --- cmd/poe.go | 35 ++++++++++++++++++++++++-------- cmd/poe2arb.go | 21 ++++++++++++++++--- cmd/version.go | 4 +++- go.mod | 1 + go.sum | 4 ++-- log/logger.go | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 9 +++++++-- 7 files changed, 113 insertions(+), 16 deletions(-) create mode 100644 log/logger.go diff --git a/cmd/poe.go b/cmd/poe.go index de5fbcf..c455656 100644 --- a/cmd/poe.go +++ b/cmd/poe.go @@ -9,6 +9,7 @@ import ( "github.com/leancodepl/poe2arb/converter" "github.com/leancodepl/poe2arb/flutter" + "github.com/leancodepl/poe2arb/log" "github.com/leancodepl/poe2arb/poeditor" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -18,7 +19,9 @@ var poeCmd = &cobra.Command{ Use: "poe", Short: "Exports POEditor terms and converts them to ARB. " + "Must be run from the Flutter project root directory or its subdirectory.", - RunE: runPoe, + SilenceErrors: true, + SilenceUsage: true, + RunE: runPoe, } const ( @@ -36,23 +39,32 @@ func init() { } func runPoe(cmd *cobra.Command, args []string) error { + log := GetLogger(cmd) + + logSub := log.Info("loading options").Sub() + sel, err := getOptionsSelector(cmd) if err != nil { + logSub.Error("failed " + err.Error()) return err } options, err := sel.SelectOptions() if err != nil { + logSub.Error("failed: " + err.Error()) return err } - poeCmd, err := NewPoeCommand(options) + poeCmd, err := NewPoeCommand(options, log) if err != nil { + logSub.Error(err.Error()) return err } + log.Info("fetching project languages") langs, err := poeCmd.GetExportLanguages() if err != nil { + logSub.Error(err.Error()) return err } @@ -70,7 +82,7 @@ func runPoe(cmd *cobra.Command, args []string) error { } } - fmt.Println("\nDone!") + log.Success("done") return nil } @@ -110,9 +122,10 @@ func getFlutterConfig() (*flutter.FlutterConfig, error) { type poeCommand struct { options *poeOptions client *poeditor.Client + log *log.Logger } -func NewPoeCommand(options *poeOptions) (*poeCommand, error) { +func NewPoeCommand(options *poeOptions, log *log.Logger) (*poeCommand, error) { if errs := validatePoeOptions(options); len(errs) > 0 { msg := "" for _, err := range errs { @@ -126,6 +139,7 @@ func NewPoeCommand(options *poeOptions) (*poeCommand, error) { return &poeCommand{ options: options, client: client, + log: log, }, nil } @@ -144,7 +158,6 @@ func validatePoeOptions(options *poeOptions) []error { } func (c *poeCommand) GetExportLanguages() ([]poeditor.Language, error) { - fmt.Println("Fetching project languages...") langs, err := c.client.GetProjectLanguages(c.options.ProjectID) if err != nil { return nil, err @@ -186,8 +199,9 @@ func (c *poeCommand) GetExportLanguages() ([]poeditor.Language, error) { func (c *poeCommand) EnsureOutputDirectory() error { dir := c.options.OutputDir if _, err := os.Stat(dir); os.IsNotExist(err) { - fmt.Printf("Creating directory %s...\n", dir) + logSub := c.log.Info("creating directory %s", dir).Sub() if err := os.MkdirAll(dir, os.ModePerm); err != nil { + logSub.Error("failed: " + err.Error()) return err } } @@ -196,7 +210,7 @@ func (c *poeCommand) EnsureOutputDirectory() error { } func (c *poeCommand) ExportLanguage(lang poeditor.Language, template, requireResourceAttributes bool) error { - fmt.Printf("Fetching JSON export for %s (%s)...\n", lang.Name, lang.Code) + logSub := c.log.Info("fetching JSON export for %s (%s)", lang.Name, lang.Code).Sub() url, err := c.client.GetExportURL(c.options.ProjectID, lang.Code) if err != nil { return err @@ -204,23 +218,28 @@ func (c *poeCommand) ExportLanguage(lang poeditor.Language, template, requireRes resp, err := http.Get(url) if err != nil { + logSub.Error("making HTTP request failed: " + err.Error()) return errors.Wrap(err, "making HTTP request for export") } filePath := path.Join(c.options.OutputDir, fmt.Sprintf("%s%s.arb", c.options.ARBPrefix, lang.Code)) file, err := os.Create(filePath) if err != nil { + logSub.Error("creating file failed: " + err.Error()) return errors.Wrap(err, "creating ARB file") } defer file.Close() + convertLogSub := logSub.Info("converting JSON to ARB").Sub() + conv := converter.NewConverter(resp.Body, lang.Code, template, requireResourceAttributes) err = conv.Convert(file) if err != nil { + convertLogSub.Error(err.Error()) return err } - fmt.Printf("Success converting JSON to ARB for %s (%s).\n", lang.Name, lang.Code) + logSub.Success("saved to %s", filePath) return nil } diff --git a/cmd/poe2arb.go b/cmd/poe2arb.go index d760f7f..e7a8b4d 100644 --- a/cmd/poe2arb.go +++ b/cmd/poe2arb.go @@ -1,17 +1,32 @@ // Package cmd provides command-line interface commands. package cmd -import "github.com/spf13/cobra" +import ( + "context" + + "github.com/leancodepl/poe2arb/log" + "github.com/spf13/cobra" +) var rootCmd = &cobra.Command{ Use: "poe2arb", Short: "POEditor JSON to Flutter ARB converter", } -func Execute() { +type ctxKey int + +const loggerKey = ctxKey(1) + +func Execute(logger *log.Logger) { rootCmd.AddCommand(convertCmd) rootCmd.AddCommand(poeCmd) rootCmd.AddCommand(versionCmd) - rootCmd.Execute() + ctx := context.WithValue(context.Background(), loggerKey, logger) + + rootCmd.ExecuteContext(ctx) +} + +func GetLogger(cmd *cobra.Command) *log.Logger { + return cmd.Context().Value(loggerKey).(*log.Logger) } diff --git a/cmd/version.go b/cmd/version.go index 22e772d..3538a2a 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -18,7 +18,9 @@ var versionCmd = &cobra.Command{ } func runVersion(cmd *cobra.Command, args []string) error { - cmd.Printf("poe2arb version %s, commit %s, built at %s\n", Version, Commit, BuiltDate) + log := GetLogger(cmd) + + log.Info("poe2arb version %s, commit %s, built at %s", Version, Commit, BuiltDate) return nil } diff --git a/go.mod b/go.mod index 2feb34e..42e77e8 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/leancodepl/poe2arb go 1.19 require ( + github.com/TwiN/go-color v1.4.0 github.com/caarlos0/env/v6 v6.10.1 github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.6.1 diff --git a/go.sum b/go.sum index db321d6..8316137 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/TwiN/go-color v1.4.0 h1:fNbOwOrvup5oj934UragnW0B1WKaAkkB85q19Y7h4ng= +github.com/TwiN/go-color v1.4.0/go.mod h1:0QTVEPlu+AoCyTrho7bXbVkrCkVpdQr7YF7PYWEtSxM= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= @@ -40,8 +42,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/wk8/go-ordered-map/v2 v2.1.0 h1:irLJKNi0WMmX6f4MQC7urUX5pE8Ab5dOtM2orbaeEjU= -github.com/wk8/go-ordered-map/v2 v2.1.0/go.mod h1:ny62VR4ZctzfAJyvdkBYE1DmSHfsuLsj6AGsxni6wWQ= github.com/wk8/go-ordered-map/v2 v2.1.1 h1:y13jts8SahUV/CChdundKh4kAR/1+Y4qYE+rI3Br7cY= github.com/wk8/go-ordered-map/v2 v2.1.1/go.mod h1:ny62VR4ZctzfAJyvdkBYE1DmSHfsuLsj6AGsxni6wWQ= golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= diff --git a/log/logger.go b/log/logger.go new file mode 100644 index 0000000..1294a0d --- /dev/null +++ b/log/logger.go @@ -0,0 +1,55 @@ +// Package log provides beautiful logger for the console interface. +package log + +import ( + "fmt" + "io" + "os" + "strings" + + clr "github.com/TwiN/go-color" +) + +type Logger struct { + writer io.Writer + depth int +} + +func NewStdout() *Logger { + return &Logger{ + writer: os.Stdout, + depth: 0, + } +} + +func (l *Logger) Info(msg string, params ...any) *Logger { + l.log(clr.Blue, msg, params...) + + return l +} + +func (l *Logger) Success(msg string, params ...any) *Logger { + l.log(clr.Green, msg, params...) + + return l +} + +func (l *Logger) Error(msg string, params ...any) *Logger { + l.log(clr.Red, msg, params...) + + return l +} + +func (l *Logger) log(color, msg string, params ...any) { + str := strings.Repeat(" ", l.depth) + str += color + " • " + clr.Reset + fmt.Sprintf(msg, params...) + "\n" + + fmt.Fprint(l.writer, str) +} + +func (l *Logger) Sub() *Logger { + return &Logger{ + writer: l.writer, + depth: l.depth + 1, + } +} diff --git a/main.go b/main.go index 881808d..8367da4 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,12 @@ package main -import "github.com/leancodepl/poe2arb/cmd" +import ( + "github.com/leancodepl/poe2arb/cmd" + "github.com/leancodepl/poe2arb/log" +) func main() { - cmd.Execute() + logger := log.NewStdout() + + cmd.Execute(logger) } From 213d79bc84fa5bb37309a47c7bfef6988d03f59a Mon Sep 17 00:00:00 2001 From: Albert Wolszon Date: Fri, 20 Jan 2023 13:19:24 +0100 Subject: [PATCH 2/3] Add tests for logger --- log/logger.go | 5 ++-- log/logger_test.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++ main.go | 4 +++- 3 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 log/logger_test.go diff --git a/log/logger.go b/log/logger.go index 1294a0d..03493fb 100644 --- a/log/logger.go +++ b/log/logger.go @@ -4,7 +4,6 @@ package log import ( "fmt" "io" - "os" "strings" clr "github.com/TwiN/go-color" @@ -15,9 +14,9 @@ type Logger struct { depth int } -func NewStdout() *Logger { +func New(writer io.Writer) *Logger { return &Logger{ - writer: os.Stdout, + writer: writer, depth: 0, } } diff --git a/log/logger_test.go b/log/logger_test.go new file mode 100644 index 0000000..38d998c --- /dev/null +++ b/log/logger_test.go @@ -0,0 +1,60 @@ +package log_test + +import ( + "bytes" + "testing" + + "github.com/leancodepl/poe2arb/log" + "github.com/stretchr/testify/assert" +) + +const ( + blue = "\x1b[34m" + green = "\x1b[32m" + red = "\x1b[31m" + reset = "\x1b[0m" +) + +func TestLoggerInfo(t *testing.T) { + var buf bytes.Buffer + + l := log.New(&buf) + + l.Info("Hello, %s!", "world") + + assert.Equal(t, blue+" • "+reset+"Hello, world!\n", buf.String()) +} + +func TestLoggerSuccess(t *testing.T) { + var buf bytes.Buffer + + l := log.New(&buf) + + l.Success("Hello, %s!", "world") + + assert.Equal(t, green+" • "+reset+"Hello, world!\n", buf.String()) +} + +func TestLoggerError(t *testing.T) { + var buf bytes.Buffer + + l := log.New(&buf) + + l.Error("Hello, %s!", "world") + + assert.Equal(t, red+" • "+reset+"Hello, world!\n", buf.String()) +} + +func TestLoggerSub(t *testing.T) { + var buf bytes.Buffer + + l := log.New(&buf) + + sub := l.Sub() + sub.Info("test") + + subSub := sub.Sub() + subSub.Info("test2") + + assert.Equal(t, " "+blue+" • "+reset+"test\n "+blue+" • "+reset+"test2\n", buf.String()) +} diff --git a/main.go b/main.go index 8367da4..b64c87b 100644 --- a/main.go +++ b/main.go @@ -1,12 +1,14 @@ package main import ( + "os" + "github.com/leancodepl/poe2arb/cmd" "github.com/leancodepl/poe2arb/log" ) func main() { - logger := log.NewStdout() + logger := log.New(os.Stdout) cmd.Execute(logger) } From add8a3db6b1514f6e97e5fe004778e5811f35afa Mon Sep 17 00:00:00 2001 From: Albert Wolszon Date: Fri, 20 Jan 2023 13:25:37 +0100 Subject: [PATCH 3/3] Make GetLogger private --- cmd/poe.go | 2 +- cmd/poe2arb.go | 2 +- cmd/version.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/poe.go b/cmd/poe.go index c455656..8372672 100644 --- a/cmd/poe.go +++ b/cmd/poe.go @@ -39,7 +39,7 @@ func init() { } func runPoe(cmd *cobra.Command, args []string) error { - log := GetLogger(cmd) + log := getLogger(cmd) logSub := log.Info("loading options").Sub() diff --git a/cmd/poe2arb.go b/cmd/poe2arb.go index e7a8b4d..ac5d860 100644 --- a/cmd/poe2arb.go +++ b/cmd/poe2arb.go @@ -27,6 +27,6 @@ func Execute(logger *log.Logger) { rootCmd.ExecuteContext(ctx) } -func GetLogger(cmd *cobra.Command) *log.Logger { +func getLogger(cmd *cobra.Command) *log.Logger { return cmd.Context().Value(loggerKey).(*log.Logger) } diff --git a/cmd/version.go b/cmd/version.go index 3538a2a..e65764b 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -18,7 +18,7 @@ var versionCmd = &cobra.Command{ } func runVersion(cmd *cobra.Command, args []string) error { - log := GetLogger(cmd) + log := getLogger(cmd) log.Info("poe2arb version %s, commit %s, built at %s", Version, Commit, BuiltDate)