Initial Commit
This commit is contained in:
parent
7b35d0e081
commit
7fbf90a111
BIN
cmd/gotime-cui/gotime-cui
Executable file
BIN
cmd/gotime-cui/gotime-cui
Executable file
Binary file not shown.
38
cmd/gotime-cui/main.go
Normal file
38
cmd/gotime-cui/main.go
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"gogs.bullercodeworks.com/brian/gotime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var dir string
|
||||
/*
|
||||
err := termbox.Init()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer termbox.Close()
|
||||
*/
|
||||
|
||||
if len(os.Args) > 1 {
|
||||
dir = os.Args[1]
|
||||
}
|
||||
got := gotime.Create(dir)
|
||||
t := got.GetAllTimers()
|
||||
for i := range t {
|
||||
fmt.Println(t[i].ToJsonString())
|
||||
}
|
||||
fmt.Println("=== Start Timer ===")
|
||||
ts := gotime.CreateStartTimerTxns(&t[len(t)-1])
|
||||
for i := range ts {
|
||||
fmt.Println(ts[i].ToString())
|
||||
}
|
||||
fmt.Println("=== Stop Timer ===")
|
||||
ts = gotime.CreateStopTimerTxns(&t[len(t)-1])
|
||||
for i := range ts {
|
||||
fmt.Println(ts[i].ToString())
|
||||
}
|
||||
}
|
185
gotime.go
Normal file
185
gotime.go
Normal file
@ -0,0 +1,185 @@
|
||||
package gotime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type GoTime struct {
|
||||
Dir string
|
||||
timers []Timer
|
||||
files []string
|
||||
timeFormat string
|
||||
Tags []string
|
||||
}
|
||||
|
||||
// Create creates a new instance of GoTime
|
||||
// with the given data directory
|
||||
func Create(dir string) *GoTime {
|
||||
g := &GoTime{Dir: dir}
|
||||
g.timeFormat = "20060102T150405Z"
|
||||
|
||||
g.files = g.getTimerFiles()
|
||||
for _, f := range g.files {
|
||||
g.addTimersFromFile(f)
|
||||
}
|
||||
g.ResetIds()
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GoTime) ResetIds() {
|
||||
// Now set IDs
|
||||
id := 1
|
||||
for i := len(g.timers) - 1; i >= 0; i-- {
|
||||
g.timers[i].SetId(id)
|
||||
id++
|
||||
}
|
||||
}
|
||||
|
||||
// IsOn returns true if a timer is currently running
|
||||
func (g *GoTime) IsOn() bool {
|
||||
t := g.Status()
|
||||
if t.End.IsZero() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Status returns the most recent timer
|
||||
func (g *GoTime) Status() *Timer {
|
||||
if len(g.timers) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &g.timers[len(g.timers)-1]
|
||||
}
|
||||
|
||||
// IsRunning returns if the Status() is running
|
||||
func (g *GoTime) IsRunning() bool {
|
||||
return g.Status().IsRunning()
|
||||
}
|
||||
|
||||
func (g *GoTime) GetAllTimers() []Timer {
|
||||
return g.timers
|
||||
}
|
||||
|
||||
// getTimerFiles Returns a string slice of all of the data file names
|
||||
func (g *GoTime) getTimerFiles() []string {
|
||||
var ret []string
|
||||
// Timer files are all files in g.dir/data except undo.data
|
||||
files, _ := ioutil.ReadDir(g.Dir + "/data/")
|
||||
for _, f := range files {
|
||||
if f.Name() != "undo.data" {
|
||||
ret = append(ret, f.Name())
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// addTimersFromFile Adds all timer lines from g.Dir/data/f and adds a timer for it
|
||||
func (g *GoTime) addTimersFromFile(f string) error {
|
||||
content, err := ioutil.ReadFile(g.Dir + "/data/" + f)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
cntString := strings.TrimSpace(string(content))
|
||||
|
||||
lines := strings.Split(cntString, "\n")
|
||||
for i := range lines {
|
||||
if err = g.AddTimerFromString(lines[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// AddTimerFromString takes a string in the format of the lines from the data file
|
||||
// and builds a timer from it.
|
||||
func (g *GoTime) AddTimerFromString(st string) error {
|
||||
var err error
|
||||
t := new(Timer)
|
||||
flds := strings.Fields(st)
|
||||
if len(flds) > 1 && flds[0] == "inc" {
|
||||
// Start Time
|
||||
if len(flds) >= 2 {
|
||||
if t.Beg, err = time.Parse(g.timeFormat, flds[1]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// End Time
|
||||
if len(flds) >= 4 && flds[2] == "-" {
|
||||
if t.End, err = time.Parse(g.timeFormat, flds[3]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var inTags bool
|
||||
for i := range flds {
|
||||
if flds[i] == "#" {
|
||||
inTags = true
|
||||
continue
|
||||
}
|
||||
if inTags {
|
||||
tg := strings.Trim(flds[i], "\"")
|
||||
t.Tags = append(t.Tags, tg)
|
||||
g.AddTag(tg)
|
||||
}
|
||||
}
|
||||
if !t.Beg.IsZero() {
|
||||
g.timers = append(g.timers, *t)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// AddTag adds a tag to list of all used tags
|
||||
func (g *GoTime) AddTag(tg string) {
|
||||
if !g.HasTag(tg) {
|
||||
g.Tags = append(g.Tags, tg)
|
||||
}
|
||||
}
|
||||
|
||||
// HasTag returns if this tag is in our list
|
||||
func (g *GoTime) HasTag(tg string) bool {
|
||||
for i := range g.Tags {
|
||||
if g.Tags[i] == tg {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Start starts a new timer. If one is already active, it stops it first
|
||||
func (g *GoTime) StartTimer() *Timer {
|
||||
if g.IsRunning() {
|
||||
g.StopTimer()
|
||||
}
|
||||
t := new(Timer)
|
||||
t.Beg = time.Now()
|
||||
g.timers = append(g.timers, *t)
|
||||
// TODO: Add a line to the YYYY-MM.data file
|
||||
// TODO: Update the Undo File
|
||||
g.ResetIds()
|
||||
|
||||
return g.Status()
|
||||
}
|
||||
|
||||
// Stop stops the currently active timer
|
||||
func (g *GoTime) StopTimer() *Timer {
|
||||
if g.IsRunning() {
|
||||
g.Status().Stop()
|
||||
}
|
||||
// TODO: Add a stop time to the last line in the YYYY-MM.data file
|
||||
// TODO: Update the Undo File
|
||||
return g.Status()
|
||||
}
|
||||
|
||||
// AddTag adds a new tag to the most recent timer
|
||||
func (g *GoTime) AddTagToCurrentTimer(tg string) *Timer {
|
||||
g.Status().AddTag(tg)
|
||||
// TODO: Add the tag to the last line in the YYYY-MM.data file
|
||||
// TODO: Update the Undo File
|
||||
|
||||
return g.Status()
|
||||
}
|
123
timer.go
Normal file
123
timer.go
Normal file
@ -0,0 +1,123 @@
|
||||
package gotime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Timer struct {
|
||||
Id int
|
||||
Beg time.Time
|
||||
End time.Time
|
||||
Tags []string
|
||||
}
|
||||
|
||||
func (t *Timer) Start() {
|
||||
if t.Beg.IsZero() {
|
||||
t.Beg = time.Now()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Timer) Stop() {
|
||||
if t.End.IsZero() {
|
||||
t.End = time.Now()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Timer) SetId(i int) {
|
||||
t.Id = i
|
||||
}
|
||||
|
||||
func (t *Timer) SetStart(tm time.Time) error {
|
||||
if !t.End.IsZero() && !tm.Before(t.End) {
|
||||
return errors.New("Beginning time must be before End")
|
||||
}
|
||||
t.Beg = tm
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Timer) SetEnd(tm time.Time) error {
|
||||
if !tm.After(t.Beg) {
|
||||
return errors.New("End time must be after Beginning")
|
||||
}
|
||||
t.End = tm
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Timer) IsRunning() bool {
|
||||
return !t.Beg.IsZero() && t.End.IsZero()
|
||||
}
|
||||
|
||||
// AddTag adds the tag tg to this timer
|
||||
func (t *Timer) AddTag(tg string) {
|
||||
if !t.HasTag(tg) {
|
||||
t.Tags = append(t.Tags, tg)
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveTag removes the tag tg from this timer
|
||||
func (t *Timer) RemoveTag(tg string) {
|
||||
for i := 0; i < len(t.Tags); i++ {
|
||||
if t.Tags[i] == tg {
|
||||
t.Tags = append(t.Tags[:i], t.Tags[i+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HasTag returns if this timer has the tag
|
||||
func (t *Timer) HasTag(tg string) bool {
|
||||
for i := range t.Tags {
|
||||
if t.Tags[i] == tg {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *Timer) ToString() string {
|
||||
if t.Beg.IsZero() {
|
||||
return ""
|
||||
}
|
||||
timeFormat := "20060102T150405Z"
|
||||
|
||||
ret := "inc " + t.Beg.Format(timeFormat)
|
||||
if !t.End.IsZero() {
|
||||
ret += " - " + t.End.Format(timeFormat)
|
||||
}
|
||||
if len(t.Tags) > 0 {
|
||||
ret += " # "
|
||||
for i := range t.Tags {
|
||||
if strings.Contains(t.Tags[i], " ") {
|
||||
ret += "\"" + t.Tags[i] + "\""
|
||||
}
|
||||
ret += " "
|
||||
}
|
||||
ret = ret[:len(ret)-1]
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (t *Timer) ToJsonString() string {
|
||||
if t.Beg.IsZero() {
|
||||
return ""
|
||||
}
|
||||
timeFormat := "20060102T150405Z"
|
||||
|
||||
ret := "{\"start\":\"" + t.Beg.Format(timeFormat) + "\","
|
||||
if !t.End.IsZero() {
|
||||
ret += "\"end\":\"" + t.End.Format(timeFormat) + "\","
|
||||
}
|
||||
if len(t.Tags) > 0 {
|
||||
ret += "\"tags\":["
|
||||
for i := range t.Tags {
|
||||
ret += "\"" + t.Tags[i] + "\","
|
||||
}
|
||||
// Move trailing ',' to end
|
||||
ret = ret[:len(ret)-1] + "],"
|
||||
|
||||
}
|
||||
// Trim trailing ,
|
||||
ret = ret[:len(ret)-1] + "}"
|
||||
return ret
|
||||
}
|
73
transaction.go
Normal file
73
transaction.go
Normal file
@ -0,0 +1,73 @@
|
||||
package gotime
|
||||
|
||||
import "time"
|
||||
|
||||
type Transaction struct {
|
||||
tp string
|
||||
before *Timer
|
||||
after *Timer
|
||||
}
|
||||
|
||||
func CreateStartTimerTxns(tmr *Timer) []Transaction {
|
||||
t := CreateIntervalTxn()
|
||||
t.after = tmr
|
||||
return []Transaction{*t}
|
||||
}
|
||||
|
||||
func CreateStopTimerTxns(tmr *Timer) []Transaction {
|
||||
t1 := CreateIntervalTxn()
|
||||
t1.before = tmr
|
||||
t1.before.End = *new(time.Time)
|
||||
|
||||
t2 := CreateIntervalTxn()
|
||||
t2.after = tmr
|
||||
|
||||
return []Transaction{*t1, *t2}
|
||||
}
|
||||
|
||||
func CreateIntervalTxn() *Transaction {
|
||||
t := new(Transaction)
|
||||
t.tp = "interval"
|
||||
t.before = new(Timer)
|
||||
t.after = new(Timer)
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Transaction) SetBefore(tmr *Timer) {
|
||||
t.before = tmr
|
||||
}
|
||||
|
||||
func (t *Transaction) SetAfter(tmr *Timer) {
|
||||
t.after = tmr
|
||||
}
|
||||
|
||||
func (t *Transaction) ToString() string {
|
||||
ret := "txn:\n"
|
||||
ret += " type: " + t.tp + "\n"
|
||||
ret += " before: " + t.before.ToJsonString() + "\n"
|
||||
ret += " after: " + t.after.ToJsonString() + "\n"
|
||||
return ret
|
||||
}
|
||||
|
||||
/*
|
||||
* START Transaction
|
||||
|
||||
txn:
|
||||
type: interval
|
||||
before:
|
||||
after: {"start":"20170111T223025Z","tags":["bcw","bcw-gotime","work"]}
|
||||
|
||||
*
|
||||
*
|
||||
* STOP Transaction
|
||||
|
||||
txn:
|
||||
type: interval
|
||||
before: {"start":"20170111T201826Z","tags":["bcw","bcw-gotime","work"]}
|
||||
after:
|
||||
txn:
|
||||
type: interval
|
||||
before:
|
||||
after: {"start":"20170111T201826Z","end":"20170111T221747Z","tags":["bcw","bcw-gotime","work"]}
|
||||
|
||||
*/
|
Loading…
Reference in New Issue
Block a user