Skip to content

Commit

Permalink
Add commands for file manipulation
Browse files Browse the repository at this point in the history
* Fix pass-through of input arguments

* Naming

* Error on negative index

* Setup `track` command

* Migrate from `ioutil` to `io`

* Improve help text

* Make reconciler predicate-based

* Return resulting record and customise “not found” error

* Unify date options and add shortcuts

* Naming

* Add `start` command

* Add comments, naming

* Make reconciler object-oriented

* Restructure code

* Add `stop` command

* Improve error messages

* Make time configurable

* Help text

* Add command for adding new record

* Keep templates hidden

* Add should total

* Unhide manipulation commands

* Make written file contents testable

* Fix position when inserting block
  • Loading branch information
jotaen committed Mar 14, 2021
1 parent d33793e commit a1b176d
Show file tree
Hide file tree
Showing 41 changed files with 950 additions and 312 deletions.
4 changes: 2 additions & 2 deletions run
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ format() {
cli() {
# When passing in a file, remember to prepend `../`
cd src
go run app/cli/main/*.go $@
go run app/cli/main/*.go "$@"
}

# MAIN
task=$1
shift 1
$task $@
$task "$@"
22 changes: 0 additions & 22 deletions src/app/cli/append.go

This file was deleted.

47 changes: 47 additions & 0 deletions src/app/cli/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package cli

import (
. "klog"
"klog/app"
"klog/app/cli/lib"
"klog/parser"
"klog/parser/parsing"
)

type Create struct {
Template string `name:"template" hidden help:"The name of the template to instantiate"`
ShouldTotal Duration `name:"should" help:"A should total property"`
lib.AtDateArgs
lib.OutputFileArgs
}

func (opt *Create) Run(ctx app.Context) error {
date := opt.AtDate(ctx.Now())
lines, err := func() ([]parsing.Text, error) {
if opt.Template != "" {
return ctx.InstantiateTemplate(opt.Template)
}
headline := opt.AtDate(ctx.Now()).ToString()
if opt.ShouldTotal != nil {
headline += " (" + opt.ShouldTotal.ToString() + "!)"
}
return []parsing.Text{
{headline, 0},
}, nil
}()
if err != nil {
return err
}
return reconcile(
opt.OutputFileArgs,
ctx,
func(pr *parser.ParseResult) (*parser.Reconciler, error) {
return parser.NewBlockReconciler(pr, func(r1 Record, r2 Record) bool {
return date.IsAfterOrEqual(r1.Date()) && r2.Date().IsAfterOrEqual(date)
})
},
func(r *parser.Reconciler) (Record, string, error) {
return r.AddBlock(lines)
},
)
}
54 changes: 54 additions & 0 deletions src/app/cli/create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package cli

import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"klog"
"klog/app/cli/lib"
"testing"
)

func TestCreate(t *testing.T) {
state, err := NewTestingContext()._SetRecords(`
1920-02-01
4h33m
1920-02-02
9:00-12:00
`)._SetNow(1920, 2, 3, 15, 24)._Run((&Create{}).Run)
require.Nil(t, err)
assert.Equal(t, `
1920-02-01
4h33m
1920-02-02
9:00-12:00
1920-02-03
`, state.writtenFileContents)
}

func TestCreateWithValues(t *testing.T) {
state, err := NewTestingContext()._SetRecords(`
1975-12-31
1h
2h
1976-01-01
1h
`)._Run((&Create{
AtDateArgs: lib.AtDateArgs{Date: klog.Ɀ_Date_(1976, 1, 2)},
ShouldTotal: klog.NewDuration(5, 55),
}).Run)
require.Nil(t, err)
assert.Equal(t, `
1975-12-31
1h
2h
1976-01-01
1h
1976-01-02 (5h55m!)
`, state.writtenFileContents)
}
2 changes: 1 addition & 1 deletion src/app/cli/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Json struct {
}

func (opt *Json) Run(ctx app.Context) error {
records, err := ctx.RetrieveRecords(opt.File...)
records, err := ctx.ReadInputs(opt.File...)
if err != nil {
parserErrs, isParserErr := err.(parsing.Errors)
if isParserErr {
Expand Down
46 changes: 45 additions & 1 deletion src/app/cli/lib/common_args.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package lib

import (
. "klog"
"klog/app"
"klog/service"
gotime "time"
)
Expand All @@ -10,7 +11,50 @@ type InputFilesArgs struct {
File []string `arg optional type:"existingfile" name:"file" help:".klg source file(s) (if empty the bookmark is used)"`
}

type DiffArg struct {
type OutputFileArgs struct {
File string `arg optional type:"existingfile" name:"file" help:".klg source file (if empty the bookmark is used)"`
}

func (args *OutputFileArgs) OutputFile(ctx app.Context) (string, error) {
if args.File != "" {
return args.File, nil
}
b, err := ctx.Bookmark()
if err != nil {
return "", nil
}
return b.Path, nil
}

type AtDateArgs struct {
Today bool `name:"today" help:"Use today’s date (default)"`
Yesterday bool `name:"yesterday" help:"Use yesterday’s date"`
Date Date `name:"date" short:"d" help:"The date of the record"`
}

func (args *AtDateArgs) AtDate(now gotime.Time) Date {
if args.Date != nil {
return args.Date
}
today := NewDateFromTime(now)
if args.Yesterday {
return today.PlusDays(-1)
}
return today
}

type AtTimeArgs struct {
Time Time `name:"time" short:"t" help:"Specify the time (defaults to now)"`
}

func (args *AtTimeArgs) AtTime(now gotime.Time) Time {
if args.Time != nil {
return args.Time
}
return NewTimeFromTime(now)
}

type DiffArgs struct {
Diff bool `name:"diff" short:"d" help:"Show difference between actual and should total time"`
}

Expand Down
38 changes: 38 additions & 0 deletions src/app/cli/main/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"klog"
"klog/app/cli/lib"
"reflect"
"strings"
)

func dateDecoder() kong.MapperFunc {
Expand All @@ -26,6 +27,43 @@ func dateDecoder() kong.MapperFunc {
}
}

func timeDecoder() kong.MapperFunc {
return func(ctx *kong.DecodeContext, target reflect.Value) error {
var value string
if err := ctx.Scan.PopValueInto("time", &value); err != nil {
return err
}
if value == "" {
return errors.New("Please provide a valid time")
}
t, err := klog.NewTimeFromString(value)
if err != nil {
return errors.New("`" + value + "` is not a valid time")
}
target.Set(reflect.ValueOf(t))
return nil
}
}

func durationDecoder() kong.MapperFunc {
return func(ctx *kong.DecodeContext, target reflect.Value) error {
var value string
if err := ctx.Scan.PopValueInto("duration", &value); err != nil {
return err
}
if value == "" {
return errors.New("Please provide a valid duration")
}
value = strings.TrimSuffix(value, "!")
d, err := klog.NewDurationFromString(value)
if err != nil {
return errors.New("`" + value + "` is not a valid duration")
}
target.Set(reflect.ValueOf(d))
return nil
}
}

func periodDecoder() kong.MapperFunc {
return func(ctx *kong.DecodeContext, target reflect.Value) error {
var value string
Expand Down
8 changes: 7 additions & 1 deletion src/app/cli/main/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@ package main
import . "klog/app/cli"

type cli struct {
// Evaluate
Print Print `cmd group:"Evaluate" help:"Pretty-print records"`
Total Total `cmd group:"Evaluate" help:"Evaluate the total time"`
Report Report `cmd group:"Evaluate" help:"Print a calendar report summarising all days"`
Tags Tags `cmd group:"Evaluate" help:"Print total times aggregated by tags"`
Now Now `cmd group:"Evaluate" help:"Evaluate today’s record (including potential open ranges)"`

Append Append `cmd group:"Manipulate" hidden help:"Appends a new record to a file (based on templates)"`
// Manipulate
Track Track `cmd group:"Manipulate" help:"Add a new entry to a record"`
Start Start `cmd group:"Manipulate" aliases:"in" help:"Start open time range"`
Stop Stop `cmd group:"Manipulate" aliases:"out" help:"Close open time range"`
Create Create `cmd group:"Manipulate" help:"Creates a new record"`

// Misc
Bookmark Bookmark `cmd group:"Misc" help:"Default file that klog reads from"`
Json Json `cmd group:"Misc" help:"Convert records to JSON"`
Widget Widget `cmd group:"Misc" help:"Start menu bar widget (MacOS only)"`
Expand Down
8 changes: 8 additions & 0 deletions src/app/cli/main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ func main() {
datePrototype, _ := klog.NewDate(1, 1, 1)
return kong.TypeMapper(reflect.TypeOf(&datePrototype).Elem(), dateDecoder())
}(),
func() kong.Option {
timePrototype, _ := klog.NewTime(0, 0)
return kong.TypeMapper(reflect.TypeOf(&timePrototype).Elem(), timeDecoder())
}(),
func() kong.Option {
durationPrototype := klog.NewDuration(0, 0)
return kong.TypeMapper(reflect.TypeOf(&durationPrototype).Elem(), durationDecoder())
}(),
func() kong.Option {
period := lib.Period{}
return kong.TypeMapper(reflect.TypeOf(&period).Elem(), periodDecoder())
Expand Down
4 changes: 2 additions & 2 deletions src/app/cli/now.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
)

type Now struct {
lib.DiffArg
lib.DiffArgs
Follow bool `name:"follow" short:"f" help:"Keep shell open and follow changes"`
lib.WarnArgs
lib.InputFilesArgs
Expand All @@ -30,7 +30,7 @@ func (opt *Now) Run(ctx app.Context) error {

func handle(opt *Now, ctx app.Context) error {
now := ctx.Now()
records, err := ctx.RetrieveRecords(opt.File...)
records, err := ctx.ReadInputs(opt.File...)
if err != nil {
return err
}
Expand Down
18 changes: 9 additions & 9 deletions src/app/cli/now_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ import (
)

func TestSkipsWhenThereAreNoRecords(t *testing.T) {
out, err := NewTestingContext()._SetRecords(``)._Run((&Now{}).Run)
state, err := NewTestingContext()._SetRecords(``)._Run((&Now{}).Run)
require.Nil(t, err)
assert.Equal(t, "\nNo record found for today\n", out)
assert.Equal(t, "\nNo record found for today\n", state.printBuffer)
}

func TestSkipsWhenThereAreNoRecentRecords(t *testing.T) {
out, err := NewTestingContext()._SetNow(1999, 3, 14, 0, 0)._SetRecords(`
state, err := NewTestingContext()._SetNow(1999, 3, 14, 0, 0)._SetRecords(`
1999-03-12
4h
`)._Run((&Now{}).Run)
require.Nil(t, err)
assert.Equal(t, "\nNo record found for today\n", out)
assert.Equal(t, "\nNo record found for today\n", state.printBuffer)
}

func TestPrintsTodaysEvalutaion(t *testing.T) {
out, err := NewTestingContext()._SetNow(1999, 3, 14, 15, 0)._SetRecords(`
state, err := NewTestingContext()._SetNow(1999, 3, 14, 15, 0)._SetRecords(`
1999-03-13
12h5m
Expand All @@ -38,23 +38,23 @@ func TestPrintsTodaysEvalutaion(t *testing.T) {
assert.Equal(t, `
Today Overall
Total 5h45m 17h50m
`, out)
`, state.printBuffer)
}

func TestPrintsEvalutaionWithDiff(t *testing.T) {
out, err := NewTestingContext()._SetNow(1999, 3, 14, 3, 13)._SetRecords(`
state, err := NewTestingContext()._SetNow(1999, 3, 14, 3, 13)._SetRecords(`
1999-03-12 (3h10m!)
2h50m
1999-03-13 (6h!)
23:38 - ?
`)._Run((&Now{DiffArg: lib.DiffArg{Diff: true}}).Run)
`)._Run((&Now{DiffArgs: lib.DiffArgs{Diff: true}}).Run)
require.Nil(t, err)
assert.Equal(t, `
Yesterday Overall
Total 3h35m 6h25m
Should 6h! 9h10m!
Diff -2h25m -2h45m
E.T.A. 5:38 5:58
`, out)
`, state.printBuffer)
}
2 changes: 1 addition & 1 deletion src/app/cli/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type Print struct {
}

func (opt *Print) Run(ctx app.Context) error {
records, err := ctx.RetrieveRecords(opt.File...)
records, err := ctx.ReadInputs(opt.File...)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit a1b176d

Please sign in to comment.