Initial Commit
This commit is contained in:
		
							
								
								
									
										
											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"]} | ||||
|  | ||||
| */ | ||||
		Reference in New Issue
	
	Block a user