~ghost08/wt

59b0066d76e81272ccd83d6d4eb198a6081381b5 — Vladimír Magyar 2 years ago 0ee8845
Add merge command
5 files changed, 101 insertions(+), 31 deletions(-)

M entries.go
M go.mod
M go.sum
M main.go
A merge.go
M entries.go => entries.go +13 -0
@@ 18,6 18,19 @@ type Entry struct {
	End         time.Time
}

//Compare returns -1 if f is before e
//0 if f overlaps e
//1 if f is after e
func (e Entry) Compare(f Entry) int {
	if f.Start.Before(e.Start) && f.End.Before(e.Start) {
		return -1
	}
	if f.Start.After(e.Start) && f.End.After(e.Start) {
		return 1
	}
	return 0
}

func (e Entry) String() string {
	return fmt.Sprintf(
		"{Project:%s, Description:'%s', Start: %s, End: %s}",

M go.mod => go.mod +1 -1
@@ 19,5 19,5 @@ require (
	github.com/posener/script v1.1.5 // indirect
	github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
	github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
	golang.org/x/sys v0.0.0-20210603125802-9665404d3644 // indirect
	golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 // indirect
)

M go.sum => go.sum +2 -0
@@ 53,6 53,8 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644 h1:CA1DEQ4NdKphKeL70tvsWNdT5oFh1lOjihRcEDROi0I=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 h1:C+AwYEtBp/VQwoLntUmQ/yx3MS9vmZaKNdw5eOpoQe8=
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.5-0.20201125200606-c27b9fd57aec/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

M main.go => main.go +23 -30
@@ 38,10 38,13 @@ var CLI struct {
		To          []string `required help:"specify the primary recipients of the emails generated"`
		From        string   `required help:"specify the sender of the emails" env:"SENDMAIL_FROM"`
	} `cmd help:"sends the report by email"`
	DataFile           string `optional short:"d" help:"path to the wt data file (default:$HOME/.local/wt.data)" predictor:"file"`
	Merge struct {
		Path string `arg required type:"path" help:"path to a data file to merge with the default wt data file"`
	} `cmd help:"merge an external wt data file"`
	DataFile           string `optional short:"d" help:"path to the wt data file (default:$HOME/.local/wt.data)" type:"path"`
	InstallCompletions struct {
		Uninstall bool
	} `cmd:"" help:"install shell completions"`
	} `cmd help:"install shell completions"`
}

func main() {


@@ 74,6 77,9 @@ func main() {
					"from":          predict.Something,
				},
			},
			"merge": {
				Args: predict.Files("*"),
			},
		},
		Flags: map[string]complete.Predictor{
			"data-file": predict.Files("*"),


@@ 90,40 96,29 @@ func main() {
		kong.UsageOnError(),
	)

	var err error
	switch ctx.Command() {
	case "start <project> <description>":
		if err := start(); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}
		err = start()
	case "end":
		if err := end(); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}
		end()
	case "report", "report <month>":
		if err := report(); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}
		err = report()
	case "send-report", "send-report <month>":
		if err := sendreport(); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}
		err = sendreport()
	case "status":
		if err := status(); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}
		err = status()
	case "merge <path>":
		err = merge()
	case "install-completions":
		if err := install.Install("wt"); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}
		err = install.Install("wt")
	default:
		log.Fatal(ctx.Command())
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
}

func loadEntries() (Entries, error) {


@@ 187,10 182,7 @@ func start() error {
	},
		es...,
	)
	if err := saveEntries(es); err != nil {
		return err
	}
	return nil
	return saveEntries(es)
}

func end() error {


@@ 215,6 207,7 @@ func end() error {
	if err := saveEntries(es); err != nil {
		return err
	}
	//TODO prettier print
	fmt.Printf("Ending entry %s", last)
	return nil
}

A merge.go => merge.go +62 -0
@@ 0,0 1,62 @@
package main

import (
	"fmt"
	"os"
	"sort"

	"github.com/gookit/color"
)

func merge() error {
	f, err := os.Open(CLI.Merge.Path)
	if err != nil {
		return err
	}
	defer f.Close()
	newEntries, err := Parse(f)
	if err != nil {
		return err
	}

	es, err := loadEntries()
	if err != nil {
		return fmt.Errorf("loading entries: %w", err)
	}

	fmt.Println()
	for _, e := range newEntries {
		i := sort.Search(len(es), func(i int) bool {
			x := es[i].Compare(e)
			return x == 1 || x == 0
		})
		if i < len(es) && es[i].Compare(e) == 0 {
			// e overlaps at es[i]
			return fmt.Errorf(
				"Entry %s %s %s-%s overlaps existing entry in default data file: %s %s %s-%s",
				e.Project,
				e.Description,
				e.Start.Format("2006-01-02 15:04:05"),
				e.End.Format("2006-01-02 15:04:05"),
				es[i].Project,
				es[i].Description,
				es[i].Start.Format("2006-01-02 15:04:05"),
				es[i].End.Format("2006-01-02 15:04:05"),
			)
		} else {
			// e is not present in es,
			// but i is the index where it would be inserted.
			fmt.Printf(
				"    %s\n    %s\t\t%s\n\t\t\t%s-%s\n",
				color.Style{color.FgLightWhite, color.OpBold}.Render("inserting entry:"),
				color.FgCyan.Render(e.Project),
				color.FgLightWhite.Render(e.Description),
				color.FgMagenta.Sprint(e.Start.Format("15:04:05")),
				color.FgMagenta.Sprint(e.End.Format("15:04:05")),
			)
			es = append(es[:i], append([]Entry{e}, es[i:]...)...)
		}
	}

	return saveEntries(es)
}