From 49663d5d086b9f7d8e52195566a8c518ba650963 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Thu, 15 Feb 2018 07:41:18 -0600 Subject: [PATCH] Remove commands from library --- .gitignore | 3 + cmd/gime-export/main.go | 287 -------------------- cmd/gime/.gitignore | 2 - cmd/gime/README.md | 4 - cmd/gime/helpers.go | 251 ------------------ cmd/gime/main.go | 495 ----------------------------------- cmd/gime/timer_operations.go | 169 ------------ model_timeentry.go | 16 +- timeentry.go | 8 +- 9 files changed, 19 insertions(+), 1216 deletions(-) delete mode 100644 cmd/gime-export/main.go delete mode 100644 cmd/gime/.gitignore delete mode 100644 cmd/gime/README.md delete mode 100644 cmd/gime/helpers.go delete mode 100644 cmd/gime/main.go delete mode 100644 cmd/gime/timer_operations.go diff --git a/.gitignore b/.gitignore index d3beee5..f9b152c 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ _testmain.go *.test *.prof +# Gomobile files +gime-sources.jar +gime.aar diff --git a/cmd/gime-export/main.go b/cmd/gime-export/main.go deleted file mode 100644 index a93f46b..0000000 --- a/cmd/gime-export/main.go +++ /dev/null @@ -1,287 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "os" - "strings" - "time" - - "git.bullercodeworks.com/brian/gime" - userConfig "github.com/br0xen/user-config" -) - -const ( - AppName = "gime" - AppVersion = 1 - DefDBName = "gime.db" - DefArchDBName = "gimearch.db" -) - -var validOperations map[string][]string -var opFuncs map[string]func([]string) int -var timeEntries *gime.TimeEntryCollection -var gdb *gime.GimeDB -var cfg *userConfig.Config - -var fuzzyFormats []string - -func main() { - var ret int - initialize() - var parms []string - - if len(os.Args) > 1 { - parms = os.Args[1:] - parms[0] = matchParameter(parms[0]) - } else { - // If no parameters were passed, 'help' - parms = append(parms, "help") - } - - if fn, ok := opFuncs[parms[0]]; ok { - ret = fn(parms[1:]) - } else { - fmt.Println("Unknown command") - ret = 1 - } - os.Exit(ret) -} - -func loadRecentTimeEntries() { - timeEntries = gdb.LoadTimeEntryCollection(gime.TypeRecent) -} - -func cmdPrintHelp(args []string) int { - //if len(args) == 0 { - fmt.Println("gime-export - An export utility for the gime application\n") - fmt.Println("Usage: gime-export [format] [[start date/time]-[end date/time]] [tags...]") - for _, v := range validOperations { - for vi := range v { - fmt.Println(" ", v[vi]) - } - fmt.Println("") - } - //} - return 0 -} - -func cmdPrintFHGTimesheet(args []string) int { - loadRecentTimeEntries() - - var beg, end time.Time - searchTags := []string{} - - for _, opt := range args { - var tmpBeg, tmpEnd time.Time - - // Do our best to figure out what timers the user wants to list - var err error - if strings.Contains(opt, "-") { - pts := strings.Split(opt, "-") - if len(pts[0]) > 0 { - // This should be the starting date - tmpBeg, err = parseFuzzyTime(pts[0]) - if err != nil { - // We couldn't parse it as a time, - // Probably this is just a tag - searchTags = append(searchTags, opt) - continue - } - } - if len(pts[1]) > 0 { - // This should be the ending date - tmpEnd, err = parseFuzzyTime(pts[1]) - if err != nil { - searchTags = append(searchTags, opt) - continue - } - } - } else { - // Tag filters - searchTags = append(searchTags, opt) - } - if !tmpBeg.IsZero() || !tmpEnd.IsZero() { - beg, end = tmpBeg, tmpEnd - } - } - if end.IsZero() { - end = time.Now() - } - - timeSpanFilter := func(t *gime.TimeEntry) bool { - return t.GetStart().After(beg) && t.GetEnd().Before(end) - } - tagFilter := func(t *gime.TimeEntry) bool { - for i := range searchTags { - if !t.HasTag(searchTags[i]) { - return false - } - } - return true - } - - compoundFilter := func(t *gime.TimeEntry) bool { - // Otherwise we want to filter timespan and tags - return timeSpanFilter(t) && tagFilter(t) - } - - ttl := fmt.Sprintf("%s - %s", beg.Format("2006/01/02"), end.Format("2006/01/02")) - if len(searchTags) > 0 { - ttl = fmt.Sprint(ttl, " ", searchTags) - } - fmt.Println(ttl) - - timerCollection := filterTimerCollection(timeEntries, compoundFilter) - - dayTimes := make(map[string]float64) - for i := beg; i.Before(end); i = i.Add(time.Hour * 24) { - dayTimes[i.Format("2006/01/02")] = 0 - } - - for i := timerCollection.Length() - 1; i >= 0; i-- { - wrkTimer := timerCollection.Get(i) - dur := wrkTimer.GetEnd().Sub(wrkTimer.GetStart()).Round(time.Minute * 15) - dayTimes[wrkTimer.GetStart().Format("2006/01/02")] += (dur.Minutes() / 60) - } - - out := [2]string{"", ""} - for i := beg; i.Before(end); i = i.Add(time.Hour * 24) { - dayString := i.Format("2006/01/02") - out[0] += fmt.Sprint(dayString, ",") - out[1] += fmt.Sprint(dayTimes[dayString], ",") - } - fmt.Println(out[0][:len(out[0])-1]) - fmt.Println(out[1][:len(out[1])-1]) - - return 0 -} - -func initialize() { - var err error - validOperations = make(map[string][]string) - opFuncs = make(map[string]func([]string) int) - - opFuncs["help"] = cmdPrintHelp - validOperations["help"] = []string{ - "help - Prints this", - } - - opFuncs["fhgts"] = cmdPrintFHGTimesheet - validOperations["fhgts"] = []string{ - "fhgts [duration] [tags] - Output entries in Flint Hills Group timesheet format", - " (csv, daily totals, decimal format, 1/4 hour rounding)", - } - - // Load the Config - cfg, err = userConfig.NewConfig(AppName) - if err != nil { - fmt.Println(err.Error()) - fmt.Println("Creating new config") - cfg.Save() - } - // If dbdir isn't set, set it to the config directory - if cfg.Get("dbdir") == "" { - cfg.Set("dbdir", cfg.GetConfigPath()+"/") - } - // If dbname isn't set, set it to the default database filename - if cfg.Get("dbname") == "" { - cfg.Set("dbname", DefDBName) - } - // If dbarchivename isn't set, set it to the default archive database filename - if cfg.Get("dbarchname") == "" { - cfg.Set("dbarchname", DefArchDBName) - } - if gdb, err = gime.LoadDatabase(cfg.Get("dbdir"), cfg.Get("dbname"), cfg.Get("dbarchname")); err != nil { - fmt.Println("Error loading the database") - os.Exit(1) - } - - fuzzyFormats = []string{ - "1504", - "15:04", // Kitchen, 24hr - time.Kitchen, - time.RFC3339, - "2006-01-02T15:04:05", // RFC3339 without timezone - "2006-01-02T15:04", // RFC3339 without seconds or timezone - time.Stamp, - "02 Jan 06 15:04:05", // RFC822 with second - time.RFC822, - "01/02/2006 15:04", // U.S. Format - "01/02/2006 15:04:05", // U.S. Format with seconds - "01/02/06 15:04", // U.S. Format, short year - "01/02/06 15:04:05", // U.S. Format, short year, with seconds - "2006-01-02", - "2006-01-02 15:04", - "2006-01-02 15:04:05", - "20060102", - "20060102 15:04", - "20060102 15:04:05", - "20060102 1504", - "20060102 150405", - "20060102T15:04", - "20060102T15:04:05", - "20060102T1504", - "20060102T150405", - } -} - -func matchParameter(in string) string { - var chkParms []string - for k := range validOperations { - chkParms = append(chkParms, k) - } - var nextParms []string - for i := range in { - for _, p := range chkParms { - if p[i] == in[i] { - nextParms = append(nextParms, p) - } - } - // If we get here and there is only one parameter left, return it - chkParms = nextParms - if len(nextParms) == 1 { - break - } - // Otherwise, loop - nextParms = []string{} - } - if len(chkParms) == 0 { - return "" - } - return chkParms[0] -} - -func parseFuzzyTime(t string) (time.Time, error) { - var ret time.Time - var err error - for i := range fuzzyFormats { - ret, err = time.Parse(fuzzyFormats[i], t) - if err == nil { - // Make sure it's in the local timezone - tz := time.Now().Format("Z07:00") - t = ret.Format("2006-01-02T15:04:05") + tz - if ret, err = time.Parse(time.RFC3339, t); err != nil { - return ret, err - } - // Check for zero on year/mo/day - if ret.Year() == 0 && ret.Month() == time.January && ret.Day() == 1 { - ret = ret.AddDate(time.Now().Year(), int(time.Now().Month())-1, time.Now().Day()-1) - } - return ret, nil - } - } - return time.Time{}, errors.New("Unable to parse time: " + t) -} - -// filterTimerCollection takes a collection and a function that it runs every entry through -// If the function returns true for the entry, it adds it to a new collection to be returned -func filterTimerCollection(c *gime.TimeEntryCollection, fn func(t *gime.TimeEntry) bool) *gime.TimeEntryCollection { - ret := new(gime.TimeEntryCollection) - for i := 0; i < c.Length(); i++ { - if fn(c.Get(i)) { - ret.Push(c.Get(i)) - } - } - return ret -} diff --git a/cmd/gime/.gitignore b/cmd/gime/.gitignore deleted file mode 100644 index 1fdcae5..0000000 --- a/cmd/gime/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -gime -*.db diff --git a/cmd/gime/README.md b/cmd/gime/README.md deleted file mode 100644 index 327f2eb..0000000 --- a/cmd/gime/README.md +++ /dev/null @@ -1,4 +0,0 @@ -gime -==== - -This folder contains the cli application for gime diff --git a/cmd/gime/helpers.go b/cmd/gime/helpers.go deleted file mode 100644 index 606209e..0000000 --- a/cmd/gime/helpers.go +++ /dev/null @@ -1,251 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "strconv" - "time" - - "git.bullercodeworks.com/brian/gime" -) - -// filterTimerCollection takes a collection and a function that it runs every entry through -// If the function returns true for the entry, it adds it to a new collection to be returned -func filterTimerCollection(c *gime.TimeEntryCollection, fn func(t *gime.TimeEntry) bool) *gime.TimeEntryCollection { - ret := new(gime.TimeEntryCollection) - for i := 0; i < c.Length(); i++ { - if fn(c.Get(i)) { - ret.Push(c.Get(i)) - } - } - return ret -} - -func TimerCollectionToString(c *gime.TimeEntryCollection) string { - var ret string - for i := 0; i < c.Length(); i++ { - ret += TimerToString(c.Get(i)) - if i < c.Length()-1 { - ret += "\n" - } - } - return ret -} - -// TimerToString takes a TimeEntry and gives a nicely formatted string -func TimerToString(t *gime.TimeEntry) string { - var ret string - var end string - if t.StartsToday() { - ret = t.GetStart().Format("15:04 - ") - end = "**:**" - } else { - ret = t.GetStart().Format("2006/01/02 15:04:05 - ") - end = "**:**:**" - } - if !t.GetEnd().IsZero() { - if t.EndsToday() { - end = t.GetEnd().Format("15:04") - } else { - end = t.GetEnd().Format("2006/01/02 15:04:05") - } - } - ret += end - tags := t.GetTags() - if tags.Length() > 0 { - ret += " [ " - for i := 0; i < tags.Length(); i++ { - ret += tags.Get(i) + " " - } - ret += "]" - } - return ret -} - -func InferTimerDetailString(t *gime.TimeEntry) string { - diffEnd := time.Now() - if !t.GetEnd().IsZero() { - diffEnd = t.GetEnd() - } - if int(diffEnd.Sub(t.GetStart())) >= (int(time.Hour) * diffEnd.Hour()) { - return TimerDetailToLongString(t) - } - return TimerDetailToString(t) -} - -func TimerDetailToString(t *gime.TimeEntry) string { - ret := t.GetStart().Format("15:04") - if t.GetEnd().IsZero() { - ret += " (" + padLeft(sinceToString(t.GetStart()), len("00h 00m 00s")) + ") " - } else { - ret += " (" + padLeft(diffToString(t.GetStart(), t.GetEnd()), len("00h 00m 00s")) + ") " - } - if t.GetTags().Length() > 0 { - ret += " [ " - for j := 0; j < t.GetTags().Length(); j++ { - ret += t.GetTags().Get(j) - if j < t.GetTags().Length()-1 { - ret += ", " - } - } - ret += " ] " - } - return ret -} - -// ...ToLongString includes year/month/day -func TimerDetailToLongString(t *gime.TimeEntry) string { - ret := t.GetStart().Format(time.Stamp) - if t.GetEnd().IsZero() { - ret += " (" + padLeft(sinceToString(t.GetStart()), len("0000y 00m 00d 00h 00m 00s")) + ") " - } else { - ret += " (" + padLeft(diffToString(t.GetStart(), t.GetEnd()), len("0000y 00m 00d 00h 00m 00s")) + ") " - } - if t.GetTags().Length() > 0 { - ret += " [ " - for j := 0; j < t.GetTags().Length(); j++ { - ret += t.GetTags().Get(j) - if j < t.GetTags().Length()-1 { - ret += ", " - } - } - ret += " ] " - } - return ret -} - -// findTimerById takes a timer id and returns the TimeEntry and the type string -// of the entry corresponding to that id -// It searches TypeCurrent -> TypeRecent -> TypeArchive -func findTimerById(tmrId int) (*gime.TimeEntry, int, error) { - // Find the timer for this tmrId - var prevNum, numLoaded int - for i := range gdb.AllTypes { - timeCollection := gdb.LoadTimeEntryCollection(gdb.AllTypes[i]) - numLoaded += timeCollection.Length() - if numLoaded > tmrId { - // This is the set that it's in, the index we need is tmrId - prevNum - return timeCollection.Get(tmrId - prevNum), gdb.AllTypes[i], nil - } - prevNum = numLoaded - } - return nil, gime.TypeAll, errors.New("Unable to find timer with id: " + strconv.Itoa(tmrId)) -} - -func parseFuzzyTime(t string) (time.Time, error) { - var ret time.Time - var err error - for i := range fuzzyFormats { - ret, err = time.Parse(fuzzyFormats[i], t) - if err == nil { - // Make sure it's in the local timezone - tz := time.Now().Format("Z07:00") - t = ret.Format("2006-01-02T15:04:05") + tz - if ret, err = time.Parse(time.RFC3339, t); err != nil { - return ret, err - } - // Check for zero on year/mo/day - if ret.Year() == 0 && ret.Month() == time.January && ret.Day() == 1 { - ret = ret.AddDate(time.Now().Year(), int(time.Now().Month())-1, time.Now().Day()-1) - } - return ret, nil - } - } - return time.Time{}, errors.New("Unable to parse time: " + t) -} - -func sinceToString(tm time.Time) string { - return diffToString(tm, time.Now()) -} - -func diffToString(tm1, tm2 time.Time) string { - ret := "" - yr, mo, dy, hr, mn, sc := diff(tm1, tm2) - higher := false - - if yr > 0 { - ret += fmt.Sprintf("%4dy ", yr) - higher = true - } - if mo > 0 || higher { - ret += fmt.Sprintf("%2dm ", mo) - higher = true - } - if dy > 0 || higher { - ret += fmt.Sprintf("%2dd ", dy) - higher = true - } - if hr > 0 || higher { - ret += fmt.Sprintf("%2dh ", hr) - higher = true - } - if mn > 0 || higher { - ret += fmt.Sprintf("%2dm ", mn) - higher = true - } - if sc > 0 || higher { - ret += fmt.Sprintf("%2ds", sc) - } - return ret -} - -func padRight(st string, l int) string { - for len(st) < l { - st = st + " " - } - return st -} - -func padLeft(st string, l int) string { - for len(st) < l { - st = " " + st - } - return st -} - -func diff(a, b time.Time) (year, month, day, hour, min, sec int) { - if a.Location() != b.Location() { - b = b.In(a.Location()) - } - if a.After(b) { - a, b = b, a - } - y1, M1, d1 := a.Date() - y2, M2, d2 := b.Date() - - h1, m1, s1 := a.Clock() - h2, m2, s2 := b.Clock() - - year = int(y2 - y1) - month = int(M2 - M1) - day = int(d2 - d1) - hour = int(h2 - h1) - min = int(m2 - m1) - sec = int(s2 - s1) - - // Normalize negative values - if sec < 0 { - sec += 60 - min-- - } - if min < 0 { - min += 60 - hour-- - } - if hour < 0 { - hour += 24 - day-- - } - if day < 0 { - // days in month: - t := time.Date(y1, M1, 32, 0, 0, 0, 0, time.UTC) - day += 32 - t.Day() - month-- - } - if month < 0 { - month += 12 - year-- - } - - return -} diff --git a/cmd/gime/main.go b/cmd/gime/main.go deleted file mode 100644 index bc3fb20..0000000 --- a/cmd/gime/main.go +++ /dev/null @@ -1,495 +0,0 @@ -package main - -import ( - "fmt" - "os" - "sort" - "strings" - "time" - - "git.bullercodeworks.com/brian/gime" - userConfig "github.com/br0xen/user-config" -) - -const ( - AppName = "gime" - AppVersion = 1 - DefDBName = "gime.db" - DefArchDBName = "gimearch.db" -) - -var validOperations map[string][]string -var opFuncs map[string]func([]string) int -var timeEntries *gime.TimeEntryCollection -var gdb *gime.GimeDB -var cfg *userConfig.Config - -var fuzzyFormats []string - -func main() { - var ret int - initialize() - var parms []string - - if len(os.Args) > 1 { - parms = os.Args[1:] - parms[0] = matchParameter(parms[0]) - } else { - // If no parameters were passed, just print the status - parms = append(parms, "status") - } - - if fn, ok := opFuncs[parms[0]]; ok { - ret = fn(parms[1:]) - } else { - fmt.Println("Unknown command") - ret = 1 - } - os.Exit(ret) -} - -func loadActiveTimeEntries() { - timeEntries = gdb.LoadTimeEntryCollection(gime.TypeCurrent) -} - -func loadActiveAndRecentTimeEntries() { - timeEntries = gdb.LoadTimeEntryCollection(gime.TypeNoArchive) -} - -func getMostRecentTimeEntry() (*gime.TimeEntry, error) { - return gdb.GetLatestTimeEntry() -} - -func cmdDoArchive(args []string) int { - if len(args) == 0 { - fmt.Println("Nothing to do") - return 1 - } - bef, err := parseFuzzyTime(args[0]) - if err != nil { - fmt.Println("Error parsing time") - return 1 - } - ret := 0 - fmt.Print("Archive all timers before ", bef) - loadActiveAndRecentTimeEntries() - for i := 0; i < timeEntries.Length(); i++ { - tst := timeEntries.Get(i) - if tst.GetEnd().Before(bef) { - fmt.Print(".") - if err = gdb.ArchiveTimeEntry(tst.GetUUID()); err != nil { - fmt.Print("Error archiving entry (", tst.GetUUID(), ")", err.Error()) - ret = 1 - } - } - } - fmt.Println("Done") - return ret -} - -func cmdDoConfig(args []string) int { - if len(args) == 0 { - fmt.Println("Invalid configuration options passed") - return 1 - } - - for _, opt := range args { - if !strings.Contains(opt, "=") { - // Single word triggers - switch opt { - case "reset": - fmt.Println("Resetting Configuration...") - cfg.Set("dbdir", cfg.GetConfigPath()+"/") - cfg.Set("dbname", DefDBName) - cfg.Set("dbarchname", DefArchDBName) - case "list": - fmt.Println("Current " + AppName + " config") - for _, v := range cfg.GetKeyList() { - fmt.Println(" " + v + ": " + cfg.Get(v)) - } - case "dbpath": - fmt.Println(cfg.Get("dbdir") + cfg.Get("dbname")) - } - } else { - // Key=Value options - pts := strings.Split(opt, "=") - if len(pts) == 2 { - switch pts[0] { - case "dbdir": - val := pts[1] - if val[len(val)-1] != '/' { - val = val + "/" - } - cfg.Set("dbdir", val) - case "dbname": - cfg.Set("dbname", pts[1]) - case "dbarchname": - cfg.Set("dbarchname", pts[1]) - } - } - } - } - return 0 -} - -func cmdPrintDetail(args []string) int { - fmt.Println("Not implemented yet.") - return 1 -} - -func cmdPrintHelp(args []string) int { - if len(args) == 0 { - fmt.Println("gime - A simple timekeeping application\n") - fmt.Println("Usage: gime [@timerID] [operation] [tags...]") - for _, v := range validOperations { - for vi := range v { - fmt.Println(" ", v[vi]) - } - fmt.Println("") - } - } else { - switch args[0] { - case "formats": - fmt.Println("Supported date/time formats:") - for i := range fuzzyFormats { - fmt.Println(" ", fuzzyFormats[i]) - } - } - fmt.Println("") - } - return 0 -} - -func cmdPrintList(args []string) int { - loadActiveAndRecentTimeEntries() - - useDefaultFilter := true - - var beg, end time.Time - searchTags := []string{} - - for _, opt := range args { - var tmpBeg, tmpEnd time.Time - - // Do our best to figure out what timers the user wants to list - var err error - if strings.Contains(opt, "-") { - useDefaultFilter = false - pts := strings.Split(opt, "-") - if len(pts[0]) > 0 { - // This should be the starting date - tmpBeg, err = parseFuzzyTime(pts[0]) - if err != nil { - // We couldn't parse it as a time, - // Probably this is just a tag - searchTags = append(searchTags, opt) - continue - } - } - if len(pts[1]) > 0 { - // This should be the ending date - tmpEnd, err = parseFuzzyTime(pts[1]) - if err != nil { - searchTags = append(searchTags, opt) - continue - } - } - } else { - // Tag filters - searchTags = append(searchTags, opt) - } - if !tmpBeg.IsZero() || !tmpEnd.IsZero() { - beg, end = tmpBeg, tmpEnd - } - } - if end.IsZero() { - end = time.Now() - } - - // By default, list all entries ending today or still running - defaultFilter := func(t *gime.TimeEntry) bool { - return t.EndsToday() || t.IsRunning() - } - - timeSpanFilter := func(t *gime.TimeEntry) bool { - return t.GetStart().After(beg) && t.GetEnd().Before(end) - } - tagFilter := func(t *gime.TimeEntry) bool { - for i := range searchTags { - if !t.HasTag(searchTags[i]) { - return false - } - } - return true - } - - compoundFilter := func(t *gime.TimeEntry) bool { - // If we didn't get any other filter specifications, just use the default - if useDefaultFilter { - return defaultFilter(t) - } - // Otherwise we want to filter timespan and tags - return timeSpanFilter(t) && tagFilter(t) - } - - fmt.Println(time.Now().Format("2006/01/02")) - str := TimerCollectionToString(filterTimerCollection(timeEntries, compoundFilter)) - str = " " + strings.Replace(str, "\n", "\n ", -1) - fmt.Println(str) - return 0 -} - -func cmdListTags(args []string) int { - loadActiveAndRecentTimeEntries() - var allTags []string - for i := 0; i < timeEntries.Length(); i++ { - tc := timeEntries.Get(i).GetTags() - for j := 0; j < tc.Length(); j++ { - tg := tc.Get(j) - var found bool - for tst := range allTags { - if allTags[tst] == tg { - found = true - break - } - } - if !found { - allTags = append(allTags, tg) - } - } - } - - sort.Sort(sort.StringSlice(allTags)) - for i := range allTags { - fmt.Println(allTags[i]) - } - return 0 -} - -func cmdPrintStatus(args []string) int { - loadActiveTimeEntries() - curr := time.Now() - fmt.Println("Current Time:", curr.Format(time.Stamp)) - if timeEntries.Length() == 0 { - fmt.Println("No timer running") - } else { - fmt.Print("Active Timers (", timeEntries.Length(), ")\n") - // Find the longest start time & longest duration - short := true - for i := 0; i < timeEntries.Length(); i++ { - v := timeEntries.Get(i) - if v.GetStart().Day() != curr.Day() { - short = false - break - } - } - - for i := 0; i < timeEntries.Length(); i++ { - v := timeEntries.Get(i) - if short { - fmt.Printf(" @%d %s\n", i, TimerDetailToString(v)) - } else { - fmt.Printf(" @%d %s\n", i, TimerDetailToLongString(v)) - } - } - } - return 0 -} - -func cmdDoFuzzyParse(args []string) int { - if len(args) == 0 { - return 1 - } - var t time.Time - var err error - if t, err = parseFuzzyTime(args[0]); err != nil { - fmt.Println(err.Error()) - return 1 - } - fmt.Println(t.Format(time.RFC3339)) - return 0 -} - -func initialize() { - var err error - validOperations = make(map[string][]string) - opFuncs = make(map[string]func([]string) int) - - opFuncs["cont"] = cmdContinueTimer - validOperations["cont"] = []string{ - "cont [time] - Continue the last stopped timer", - } - - opFuncs["config"] = cmdDoConfig - validOperations["config"] = []string{ - "config [command] - Perform configuration", - " list - List current configuration", - " reset - Reset current configuration", - " Configuration Options:", - " dbdir=[database directory]", - " dbname=[database filename]", - " dbarchname=[archive database filename]", - } - - opFuncs["detail"] = cmdPrintDetail - validOperations["detail"] = []string{ - "detail @id - Print details about a timer", - } - - opFuncs["delete"] = cmdDeleteTimer - validOperations["delete"] = []string{ - "delete @id - Delete a timer", - } - - opFuncs["end"] = cmdStopTimer - validOperations["end"] = []string{ - "end - The same as stop", - } - - opFuncs["help"] = cmdPrintHelp - validOperations["help"] = []string{ - "help - Print this", - } - - opFuncs["list"] = cmdPrintList - validOperations["list"] = []string{ - "list [duration] [+tags] - List time entries", - " valid values of [duration] include:", - " day - List all entries for the current day", - " week - List all entries for the current week", - " month - List all entries for the current month", - " year - List all entries for the current year", - " To list entries by tag, preceed the tags with a +", - } - - opFuncs["ls"] = cmdPrintList - validOperations["ls"] = []string{ - "ls [duration] [+tags] - The same as list", - } - - opFuncs["remove"] = cmdDeleteTimer - validOperations["remove"] = []string{ - "remove @id - See 'delete'", - } - - opFuncs["status"] = cmdPrintStatus - validOperations["status"] = []string{ - "status - Print the status of all active timers", - } - - opFuncs["start"] = cmdStartTimer - validOperations["start"] = []string{ - "start [time] [tags ...] - Start a timer with the given tags (space separated)", - " If the first sub-argument given looks like a time,", - " the timer will be started then (past or future).", - " If a timer is already running it'll be stopped", - } - - opFuncs["stop"] = cmdStopTimer - validOperations["stop"] = []string{ - "stop [time] - Stops the current timer", - " If the first sub-argument given looks like a time,", - " the timer will be stopped then (past or future).", - } - - opFuncs["switch"] = cmdSwitchTimer - validOperations["switch"] = []string{ - "switch [tags ...] - Stop all currently running timers and start a new", - " one with the given tags", - } - - opFuncs["archive"] = cmdDoArchive - validOperations["archive"] = []string{ - "archive [date] - Archive all entries older than the given date", - } - - opFuncs["fuzzyparse"] = cmdDoFuzzyParse - validOperations["fuzzyparse"] = []string{ - "fuzzyparse - Parse the next argument as a date/time and print", - " the RFC3339 result. (Basically for testing)", - } - - opFuncs["tags"] = cmdListTags - validOperations["tags"] = []string{ - "tags - List all tags that have been used in non-archived", - " time entries", - } - - // Load the Config - cfg, err = userConfig.NewConfig(AppName) - if err != nil { - fmt.Println(err.Error()) - fmt.Println("Creating new config") - cfg.Save() - } - // If dbdir isn't set, set it to the config directory - if cfg.Get("dbdir") == "" { - cfg.Set("dbdir", cfg.GetConfigPath()+"/") - } - // If dbname isn't set, set it to the default database filename - if cfg.Get("dbname") == "" { - cfg.Set("dbname", DefDBName) - } - // If dbarchivename isn't set, set it to the default archive database filename - if cfg.Get("dbarchname") == "" { - cfg.Set("dbarchname", DefArchDBName) - } - if gdb, err = gime.LoadDatabase(cfg.Get("dbdir"), cfg.Get("dbname"), cfg.Get("dbarchname")); err != nil { - fmt.Println("Error loading the database") - os.Exit(1) - } - - fuzzyFormats = []string{ - "1504", - "15:04", // Kitchen, 24hr - time.Kitchen, - time.RFC3339, - "2006-01-02T15:04:05", // RFC3339 without timezone - "2006-01-02T15:04", // RFC3339 without seconds or timezone - time.Stamp, - "02 Jan 06 15:04:05", // RFC822 with second - time.RFC822, - "01/02/2006 15:04", // U.S. Format - "01/02/2006 15:04:05", // U.S. Format with seconds - "01/02/06 15:04", // U.S. Format, short year - "01/02/06 15:04:05", // U.S. Format, short year, with seconds - "2006-01-02", - "2006-01-02 15:04", - "2006-01-02 15:04:05", - "20060102", - "20060102 15:04", - "20060102 15:04:05", - "20060102 1504", - "20060102 150405", - "20060102T15:04", - "20060102T15:04:05", - "20060102T1504", - "20060102T150405", - } -} - -func matchParameter(in string) string { - var chkParms []string - for k := range validOperations { - chkParms = append(chkParms, k) - } - var nextParms []string - for i := range in { - for _, p := range chkParms { - if p[i] == in[i] { - nextParms = append(nextParms, p) - } - } - // If we get here and there is only one parameter left, return it - chkParms = nextParms - if len(nextParms) == 1 { - break - } - // Otherwise, loop - nextParms = []string{} - } - if len(chkParms) == 0 { - return "" - } - return chkParms[0] -} diff --git a/cmd/gime/timer_operations.go b/cmd/gime/timer_operations.go deleted file mode 100644 index 60b119c..0000000 --- a/cmd/gime/timer_operations.go +++ /dev/null @@ -1,169 +0,0 @@ -package main - -import ( - "fmt" - "strconv" - "time" - - "git.bullercodeworks.com/brian/gime" -) - -func cmdContinueTimer(args []string) int { - // Get the last running timer and start a new one with the same tags - te, err := getMostRecentTimeEntry() - if err != nil { - fmt.Println(err.Error()) - return 1 - } - tagColl := te.GetTags() - var tags []string - for i := 0; i < tagColl.Length(); i++ { - tags = append(tags, tagColl.Get(i)) - } - args = append(args, tags...) - return cmdStartTimer(args) -} - -// switchTimer performs a stop on any currently running timers -// and starts a new timer with the given arguments -func cmdSwitchTimer(args []string) int { - loadActiveTimeEntries() - tm := time.Now() - if timeEntries.Length() > 0 { - fmt.Println("Stopped Timers:") - } - for i := 0; i < timeEntries.Length(); i++ { - tmr := timeEntries.Get(i) - tmr.SetEnd(tm) - if err := gdb.UpdateTimeEntry(tmr); err != nil { - fmt.Println(err.Error()) - return 1 - } - fmt.Println(" " + TimerToString(tmr)) - } - fmt.Println("Started Timer:") - return cmdStartTimer(args) -} - -// cmdStartTimer takes a list of arguments and returns the return code -// to be passed along to os.Exit -func cmdStartTimer(args []string) int { - var err error - var tm time.Time - tagStart := 0 - if len(args) > 0 { - // Check if the first argument looks like a date/time - tm, err = parseFuzzyTime(args[0]) - } - - if len(args) == 0 || err != nil { - // Just start it now - tm = time.Now() - } else { - tagStart = 1 - } - var entry *gime.TimeEntry - - var timerArgs []string - if tagStart < len(args) { - timerArgs = args[tagStart:] - } - tc := new(gime.TagCollection) - for i := range timerArgs { - tc.Push(timerArgs[i]) - } - if entry, err = gime.CreateTimeEntry(tm, time.Time{}, tc); err != nil { - fmt.Println(err) - return 1 - } - if err = gdb.SaveTimeEntry(entry); err != nil { - fmt.Println(err) - return 1 - } - fmt.Println(" " + TimerToString(entry)) - return 0 -} - -// cmdStopTimer takes parameters that describe which times to stop -func cmdStopTimer(args []string) int { - // args[0] should either be a timer id (starting with '@') or 'all' - var err error - tm := time.Now() - actTimers := gdb.LoadTimeEntryCollection(gime.TypeCurrent) - var tmr *gime.TimeEntry - stopId := "@0" // By default, stop the first timer - for i := range args { - if args[i] == "all" || args[i][0] == '@' { - stopId = args[i] - continue - } - tmpTm, err := parseFuzzyTime(args[i]) - if err == nil { - // We found a time - tm = tmpTm - continue - } - } - if stopId != "all" { - // Find the timer that we're stopping - timerId, err := strconv.Atoi(stopId[1:]) - if err != nil { - fmt.Println("Error parsing timer id:", err.Error()) - return 1 - } - tmr, _, err = findTimerById(timerId) - if err != nil { - fmt.Println(err.Error()) - return 1 - } - } - - stopTimer := func(tmr *gime.TimeEntry, at time.Time) int { - tmr.SetEnd(at) - if err = gdb.UpdateTimeEntry(tmr); err != nil { - fmt.Println(err.Error()) - return 1 - } - fmt.Println("Stopped:", InferTimerDetailString(tmr)) - return 0 - } - if stopId == "all" { - var ret int - for i := 0; i < actTimers.Length(); i++ { - ret += stopTimer(actTimers.Get(i), tm) - } - if ret > 0 { - return 1 // One or more stop operations failed - } - return 0 - } - // Just stop the one timer - return stopTimer(tmr, tm) -} - -// cmdDeleteTimer takes parameters that describe the timers to be deleted. -func cmdDeleteTimer(args []string) int { - var err error - if len(args) < 1 || args[0][0] != '@' { - fmt.Println("Couldn't determine which timer(s) to delete") - return 1 - } - - // We've got a timer id to delete - timerId, err := strconv.Atoi(args[0][1:]) - if err != nil { - fmt.Println("Error parsing timer id: " + err.Error()) - return 1 - } - tmr, tp, err := findTimerById(timerId) - if err != nil { - fmt.Println(err.Error()) - return 1 - } - if gdb.RemoveTimeEntry(tmr.GetUUID()) != nil { - fmt.Println("Error removing entry " + gime.TypeToString(tp) + "." + tmr.GetUUID()) - return 1 - } - fmt.Println("Deleted Time Entry: " + TimerToString(tmr)) - return 0 -} diff --git a/model_timeentry.go b/model_timeentry.go index a1b12af..ae46874 100644 --- a/model_timeentry.go +++ b/model_timeentry.go @@ -30,10 +30,10 @@ func (gdb *GimeDB) GetLatestTimeEntry() (*TimeEntry, error) { return ret, err } -// FindTimeEntryByUUID searches all entries +// findTimeEntryAndTypeByUUID searches all entries // for the time entry with the given uuid, return the TimeEntry, the type, and/or and error // Types are searched TypeCurrent -> TypeRecent -> TypeArchive -func (gdb *GimeDB) FindTimeEntryByUUID(uuid string) (*TimeEntry, int, error) { +func (gdb *GimeDB) findTimeEntryAndTypeByUUID(uuid string) (*TimeEntry, int, error) { for i := range gdb.AllTypes { timeCollection := gdb.LoadTimeEntryCollection(gdb.AllTypes[i]) for j := 0; j < timeCollection.Length(); j++ { @@ -45,6 +45,14 @@ func (gdb *GimeDB) FindTimeEntryByUUID(uuid string) (*TimeEntry, int, error) { return nil, TypeAll, errors.New("Unable to find time entry with uuid " + uuid) } +// FindTimeEntryByUUID searches all entries +// for the time entry with the given uuid, return the TimeEntry, the type, and/or and error +// Types are searched TypeCurrent -> TypeRecent -> TypeArchive +func (gdb *GimeDB) FindTimeEntryByUUID(uuid string) (*TimeEntry, error) { + te, _, err := gdb.findTimeEntryAndTypeByUUID(uuid) + return te, err +} + // SaveTimeEntry creates a time entry in the database // If TimeEntry.end is zero, then it puts it in TypeCurrent func (gdb *GimeDB) SaveTimeEntry(te *TimeEntry) error { @@ -81,7 +89,7 @@ func (gdb *GimeDB) SaveTimeEntryType(tp int, te *TimeEntry) error { // ArchiveTimeEntry takes a time from TypeRecent and moves it to TypeArchive func (gdb *GimeDB) ArchiveTimeEntry(uuid string) error { - archTime, tp, err := gdb.FindTimeEntryByUUID(uuid) + archTime, tp, err := gdb.findTimeEntryAndTypeByUUID(uuid) if tp != TypeRecent { return errors.New("Couldn't find timer to archive in the 'Recent' bucket") } @@ -106,7 +114,7 @@ func (gdb *GimeDB) UpdateTimeEntry(te *TimeEntry) error { // RemoveTimeEntry removes a time entry with the given uuid from the database func (gdb *GimeDB) RemoveTimeEntry(uuid string) error { - fndEntry, tp, err := gdb.FindTimeEntryByUUID(uuid) + fndEntry, tp, err := gdb.findTimeEntryAndTypeByUUID(uuid) if err != nil { return errors.New("Unable to find time entry with uuid " + uuid) } diff --git a/timeentry.go b/timeentry.go index 0685b5a..8adff57 100644 --- a/timeentry.go +++ b/timeentry.go @@ -106,15 +106,15 @@ func (t *TimeEntry) Equals(tst *TimeEntry) bool { // StartsToday returns if the timer's start time is today func (t *TimeEntry) StartsToday() bool { currTime := time.Now() - dur := currTime.Hour()*int(time.Hour) + currTime.Minute()*int(time.Minute) - return int(time.Since(t.GetStart())) < dur + dur := int64(currTime.Hour())*int64(time.Hour) + int64(currTime.Minute())*int64(time.Minute) + return int64(time.Since(t.GetStart())) < dur } // StartsToday returns if the timer's end time is today func (t *TimeEntry) EndsToday() bool { currTime := time.Now() - dur := currTime.Hour()*int(time.Hour) + currTime.Minute()*int(time.Minute) - return int(time.Since(t.GetEnd())) < dur + dur := int64(currTime.Hour())*int64(time.Hour) + int64(currTime.Minute())*int64(time.Minute) + return int64(time.Since(t.GetEnd())) < dur } // IsRunning returns if the timer is still running