diff --git a/CHANGELOG.md b/CHANGELOG.md index 30e3b58..19ef977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [0.0.4] - 2024-05-08 + +- ✨ Add -p flag to config to print config path + +## [0.0.3] - 2024-03-11 + +- ✨ Add JSON formatter +- 💥 Breaking change: renamed output.stdout.config value formatter to format + ## [0.0.2] - 2024-03-09 - ✨ Use plain formatter to output entry from drop diff --git a/README.md b/README.md index 24eae91..8b4aa0c 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ Each separate output has its own set of configuration. So, replace `which-one` w *This section may change in the near future. We're considering supporting multiple formats.* -- `formatter`: Which formatter to use when outputting data. This value is used by `my-log drop` to output the new entry. +- `format`: Which formatter to use when outputting data. This value is also used by `my-log drop` to output the new entry. ### `[formatters]` @@ -144,7 +144,7 @@ Some formatters may have custom configuration. + [ ] filter to specific logs + [ ] stdout - [x] plain text - - [ ] JSON + - [x] JSON - [ ] YAML - [ ] Other formats? Submit an issue! + [ ] file output diff --git a/cmd/config.go b/cmd/config.go index dc28dd7..1407796 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -32,6 +32,11 @@ var configCmd = &cobra.Command{ //Long: ``, SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) (err error) { + print, _ := cmd.Flags().GetBool("print") + if print { + fmt.Fprintln(cmd.OutOrStdout(), config.ConfigPath) + return nil + } force, _ := cmd.Flags().GetBool("force") if !force { _, err = os.Stat(config.ConfigPath) @@ -60,4 +65,5 @@ func init() { rootCmd.AddCommand(configCmd) configCmd.Flags().BoolP("force", "f", false, "Force overwrite") + configCmd.Flags().BoolP("print", "p", false, "Print path only") } diff --git a/cmd/drop.go b/cmd/drop.go index a268d20..d74917e 100644 --- a/cmd/drop.go +++ b/cmd/drop.go @@ -42,17 +42,17 @@ var dropCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) error { log := args[0] title := args[1] - ms := models.Metas{} + ms := &models.Metas{} if len(j.RawMessage) > 8 { - err := json.Unmarshal([]byte(j.RawMessage), &ms) + err := json.Unmarshal([]byte(j.RawMessage), ms) if err != nil { return err } } for k, v := range fields { - ms = append(ms, models.Meta{k, tools.ParseString(v)}) + ms.AppendTo(k, tools.ParseString(v)) } - e := models.Entry{title, d.t, ms} + e := models.Entry{title, d.t, *ms} l := models.Log{log, []models.Entry{e}} err := files.Append(l) if err != nil { @@ -67,7 +67,10 @@ var dropCmd = &cobra.Command{ if err != nil { return err } - fmt.Fprintf(cmd.OutOrStdout(), "%s\n", out) + if len(out) > 0 && out[len(out)-1] != 10 { + out = append(out, 10) + } + fmt.Fprintf(cmd.OutOrStdout(), "%s", out) return nil }, diff --git a/cmd/root.go b/cmd/root.go index 7e7bbbd..44de5f0 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -50,7 +50,7 @@ func init() { // will be global for your application. rootCmd.PersistentFlags().StringVarP(&config.ConfigPath, "config", "c", config.ConfigPath, "config file") - rootCmd.PersistentFlags().StringToStringVarP(&config.Overrides, "config-value", "v", config.Overrides, "Override config values. Use dot syntax to specify key. E.g. -v output.stdout.config.formatter=json") + rootCmd.PersistentFlags().StringToStringVarP(&config.Overrides, "config-value", "v", config.Overrides, "Override config values. Use dot syntax to specify key. E.g. -v output.stdout.config.format=json") // Cobra also supports local flags, which will only run // when this action is called directly. diff --git a/config/default.go b/config/default.go index 76ef8d2..8f93873 100644 --- a/config/default.go +++ b/config/default.go @@ -28,7 +28,7 @@ dotFolder = true enabled = true [output.stdout.config] # Formatter to use when outputting to stdout -formatter = "plain" +format = "plain" [formatters] diff --git a/config/load_test.go b/config/load_test.go index 51e024e..eab7c94 100644 --- a/config/load_test.go +++ b/config/load_test.go @@ -70,14 +70,14 @@ func TestStdoutMissing(t *testing.T) { } func TestStdoutLoad(t *testing.T) { - os.Setenv("LOG_STDOUT_FORMATTER", "json") - defer os.Unsetenv("LOG_STDOUT_FORMATTER") + os.Setenv("LOG_STDOUT_FORMAT", "json") + defer os.Unsetenv("LOG_STDOUT_FORMAT") os.Setenv("LOG_STDOUT_ENABLED", "true") defer os.Unsetenv("LOG_STDOUT_ENABLED") c, _ := Load() std, en := c.Outputs.Stdout() assert.True(t, en) - assert.Equal(t, "json", std.Formatter) + assert.Equal(t, "json", std.Format) } func TestFormatJson(t *testing.T) { diff --git a/config/types.go b/config/types.go index a950a80..58fb2c4 100644 --- a/config/types.go +++ b/config/types.go @@ -21,7 +21,7 @@ type Output struct { } type Stdout struct { - Formatter string `env:"LOG_STDOUT_FORMATTER" mapstructure:"formatter"` + Format string `env:"LOG_STDOUT_FORMAT" mapstructure:"format"` } type stdoutEnabled struct { diff --git a/formatters/new.go b/formatters/new.go index 37d8a96..bade49b 100644 --- a/formatters/new.go +++ b/formatters/new.go @@ -11,6 +11,7 @@ type formatMaker func(config.Formatters) (Formatter, error) var formatterMap = map[string]formatMaker{ "plain": newPlain, "json": newJson, + "zero": newNull, } func Preferred() (f Formatter, err error) { @@ -19,8 +20,7 @@ func Preferred() (f Formatter, err error) { return } std, _ := conf.Outputs.Stdout() - kind := std.Formatter - return New(kind) + return New(std.Format) } func New(kind string) (f Formatter, err error) { diff --git a/formatters/new_test.go b/formatters/new_test.go index c6d5e56..ed56be3 100644 --- a/formatters/new_test.go +++ b/formatters/new_test.go @@ -10,7 +10,7 @@ import ( ) func TestKinds(t *testing.T) { - assert.ElementsMatch(t, []string{"plain", "json"}, Kinds()) + assert.ElementsMatch(t, []string{"plain", "json", "zero"}, Kinds()) } func TestNewUnsupported(t *testing.T) { diff --git a/formatters/null.go b/formatters/null.go new file mode 100644 index 0000000..4dd1775 --- /dev/null +++ b/formatters/null.go @@ -0,0 +1,32 @@ +package formatters + +import ( + "codeberg.org/danjones000/my-log/config" + "codeberg.org/danjones000/my-log/models" +) + +func newNull(ff config.Formatters) (Formatter, error) { + return &Null{}, nil +} + +type Null struct{} + +func (n *Null) Name() string { + return "zero" +} + +func (n *Null) Meta(m models.Meta) (o []byte, err error) { + return +} + +func (n *Null) Entry(e models.Entry) (o []byte, err error) { + return +} + +func (n *Null) Log(l models.Log) (o []byte, err error) { + return +} + +func (n *Null) Logs(logs []models.Log) (out []byte, err error) { + return +} diff --git a/formatters/null_test.go b/formatters/null_test.go new file mode 100644 index 0000000..f7c26c1 --- /dev/null +++ b/formatters/null_test.go @@ -0,0 +1,45 @@ +package formatters + +import ( + "testing" + "time" + + "codeberg.org/danjones000/my-log/models" + "github.com/stretchr/testify/assert" +) + +var empty []byte + +func TestNullName(t *testing.T) { + f, err := New("zero") + assert.NoError(t, err) + assert.Equal(t, "zero", f.Name()) +} + +func TestNullMeta(t *testing.T) { + f, _ := New("zero") + o, err := f.Meta(models.Meta{"foo", 42}) + assert.NoError(t, err) + assert.Equal(t, empty, o) +} + +func TestNullEntry(t *testing.T) { + f, _ := New("zero") + o, err := f.Entry(models.Entry{"title", time.Now(), models.Metas{}}) + assert.NoError(t, err) + assert.Equal(t, empty, o) +} + +func TestNullLog(t *testing.T) { + f, _ := New("zero") + o, err := f.Log(models.Log{"jim", []models.Entry{{"title", time.Now(), models.Metas{}}}}) + assert.NoError(t, err) + assert.Equal(t, empty, o) +} + +func TestNullLogs(t *testing.T) { + f, _ := New("zero") + o, err := f.Logs([]models.Log{{"jim", []models.Entry{{"title", time.Now(), models.Metas{}}}}}) + assert.NoError(t, err) + assert.Equal(t, empty, o) +} diff --git a/models/entry.go b/models/entry.go index bca992c..2a11fd2 100644 --- a/models/entry.go +++ b/models/entry.go @@ -186,7 +186,7 @@ func (e Entry) MarshalJSON() ([]byte, error) { out := map[string]any{} out["title"] = e.Title out["date"] = e.Date.Format(time.RFC3339) - for k, v := range e.Fields.toMap() { + for k, v := range e.Fields.Map() { out[k] = v } return json.Marshal(out) diff --git a/models/meta_test.go b/models/meta_test.go index 3f623d0..2d4cea8 100644 --- a/models/meta_test.go +++ b/models/meta_test.go @@ -13,6 +13,8 @@ import ( // Type assertions var _ encoding.TextMarshaler = Meta{} var _ encoding.TextUnmarshaler = new(Meta) +var _ json.Marshaler = Metas{} +var _ json.Unmarshaler = new(Metas) var skipMarshalTest = errors.New("skip marshal") @@ -125,3 +127,17 @@ func TestMetasJsonError(t *testing.T) { assert.Error(t, err) assert.Len(t, ms, 0) } + +func TestMetasAppend(t *testing.T) { + ms := Metas{} + ms = ms.Append("foo", 42) + assert.Len(t, ms, 1) + assert.Equal(t, Meta{"foo", 42}, ms[0]) +} + +func TestMetasAppendTo(t *testing.T) { + ms := &Metas{} + ms.AppendTo("foo", 42) + assert.Len(t, *ms, 1) + assert.Equal(t, Meta{"foo", 42}, (*ms)[0]) +} diff --git a/models/metas.go b/models/metas.go index 7a2602f..4db9d46 100644 --- a/models/metas.go +++ b/models/metas.go @@ -1,21 +1,15 @@ package models import ( - //"bufio" - //"bytes" "encoding/json" - //"fmt" - //"errors" - //"regexp" - //"strings" - //"sync" "time" - //"codeberg.org/danjones000/my-log/tools" ) +// A slice of Meta type Metas []Meta -func (ms Metas) toMap() map[string]any { +// Returns a single map containing all the Meta. Is useful when encoding to JSON +func (ms Metas) Map() map[string]any { out := map[string]any{} for _, f := range ms { if _, found := out[f.Key]; found || f.Key == "title" || f.Key == "date" { @@ -42,12 +36,14 @@ func (ms Metas) toMap() map[string]any { return out } +// Implements json.Marshaler func (ms Metas) MarshalJSON() ([]byte, error) { - return json.Marshal(ms.toMap()) + return json.Marshal(ms.Map()) } +// Implements json.Unmarshaler func (ms *Metas) UnmarshalJSON(in []byte) error { - old := (*ms).toMap() + old := (*ms).Map() out := map[string]any{} err := json.Unmarshal(in, &out) if err != nil { @@ -62,3 +58,14 @@ func (ms *Metas) UnmarshalJSON(in []byte) error { *ms = ret return nil } + +// Returns a new Metas with a new Meta appended +func (ms Metas) Append(k string, v any) Metas { + return append(ms, Meta{k, v}) +} + +// Appends a new Meta to this Metas +func (ms *Metas) AppendTo(k string, v any) { + n := (*ms).Append(k, v) + *ms = n +}