@ -1,2 +1,25 @@ |
|||||
# wtt |
# wtt |
||||
Work Time Tracker - console time tracking app |
Work Time Tracker - console time tracking app |
||||
|
|
||||
|
|
||||
|
### Use |
||||
|
Create new project |
||||
|
``` |
||||
|
./wtt new ProjectName |
||||
|
``` |
||||
|
|
||||
|
|
||||
|
Start working on a project |
||||
|
``` |
||||
|
./wtt start ProjectName |
||||
|
``` |
||||
|
|
||||
|
Stop working on the current project |
||||
|
``` |
||||
|
./wtt stop |
||||
|
``` |
||||
|
|
||||
|
List projects |
||||
|
``` |
||||
|
./wtt list |
||||
|
``` |
@ -0,0 +1,9 @@ |
|||||
|
package main |
||||
|
|
||||
|
import "log" |
||||
|
|
||||
|
func check(err error) { |
||||
|
if err != nil { |
||||
|
log.Println(err) |
||||
|
} |
||||
|
} |
@ -0,0 +1,97 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"log" |
||||
|
"os" |
||||
|
"os/user" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/fatih/color" |
||||
|
) |
||||
|
|
||||
|
var directoryPath string |
||||
|
var filePath string |
||||
|
|
||||
|
func main() { |
||||
|
usr, err := user.Current() |
||||
|
if err != nil { |
||||
|
log.Fatal(err) |
||||
|
} |
||||
|
directoryPath = usr.HomeDir + "/.wtt" |
||||
|
filePath = directoryPath + "/work.json" |
||||
|
readProjects() |
||||
|
|
||||
|
//get the command line parameters
|
||||
|
if len(os.Args) > 1 { |
||||
|
switch os.Args[1] { |
||||
|
case "new": |
||||
|
//create project os.Args[2]
|
||||
|
if len(os.Args) > 2 { |
||||
|
projectName := os.Args[2] |
||||
|
color.Green("creating new project: " + projectName) |
||||
|
err := newProject(projectName) |
||||
|
if err != nil { |
||||
|
break |
||||
|
} |
||||
|
saveWork() |
||||
|
} else { |
||||
|
color.Red("No project name specified") |
||||
|
} |
||||
|
break |
||||
|
case "list": |
||||
|
//list projects
|
||||
|
listProjects() |
||||
|
break |
||||
|
case "start": |
||||
|
//check if already there is any project started
|
||||
|
if work.CurrentProjectName != "" { |
||||
|
color.Red("Can not start project, already project " + work.CurrentProjectName + " running") |
||||
|
break |
||||
|
} |
||||
|
//start project os.Args[2]
|
||||
|
if len(os.Args) > 2 { |
||||
|
projectName := os.Args[2] |
||||
|
i := getProjectIByName(projectName) |
||||
|
if i < 0 { |
||||
|
color.Red("Project name: " + projectName + ", no exists") |
||||
|
break |
||||
|
} |
||||
|
var newStreak Streak |
||||
|
newStreak.Start = time.Now() |
||||
|
work.Projects[i].Streaks = append(work.Projects[i].Streaks, newStreak) |
||||
|
work.CurrentProjectName = projectName |
||||
|
saveWork() |
||||
|
fmt.Println("starting to work in project " + work.Projects[i].Name) |
||||
|
} |
||||
|
break |
||||
|
case "stop": |
||||
|
if work.CurrentProjectName == "" { |
||||
|
color.Red("no project started to stop") |
||||
|
break |
||||
|
} |
||||
|
i := getProjectIByName(work.CurrentProjectName) |
||||
|
if i < 0 { |
||||
|
color.Red("Project name: " + work.CurrentProjectName + ", no exists") |
||||
|
break |
||||
|
} |
||||
|
j := len(work.Projects[i].Streaks) - 1 |
||||
|
work.Projects[i].Streaks[j].End = time.Now() |
||||
|
work.Projects[i].Streaks[j].Duration = time.Now().Sub(work.Projects[i].Streaks[j].Start) |
||||
|
work.CurrentProjectName = "" |
||||
|
saveWork() |
||||
|
fmt.Print("Worked ") |
||||
|
fmt.Print(work.Projects[i].Streaks[j].Duration) |
||||
|
fmt.Println(" in the project " + work.Projects[i].Name) |
||||
|
|
||||
|
//stop project os.Args[2]
|
||||
|
break |
||||
|
default: |
||||
|
color.Red("no option selected") |
||||
|
os.Exit(1) |
||||
|
} |
||||
|
} else { |
||||
|
color.Red("no option selected") |
||||
|
os.Exit(1) |
||||
|
} |
||||
|
} |
@ -0,0 +1,98 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"encoding/json" |
||||
|
"errors" |
||||
|
"fmt" |
||||
|
"io/ioutil" |
||||
|
"os" |
||||
|
"strconv" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/fatih/color" |
||||
|
) |
||||
|
|
||||
|
type Project struct { |
||||
|
Name string `json:"name"` |
||||
|
Streaks []Streak `json:"streaks"` |
||||
|
} |
||||
|
type Streak struct { |
||||
|
Start time.Time `json:"start"` |
||||
|
End time.Time `json:"end"` |
||||
|
Duration time.Duration `json:"duration"` |
||||
|
Description string `json:"description"` |
||||
|
} |
||||
|
type Work struct { |
||||
|
Projects []Project `json:"projects"` |
||||
|
CurrentProjectName string `json:"currentProjectName"` |
||||
|
} |
||||
|
|
||||
|
var work Work |
||||
|
|
||||
|
func readProjects() { |
||||
|
file, err := ioutil.ReadFile(filePath) |
||||
|
if err != nil { |
||||
|
//file not exists, create directory and file
|
||||
|
color.Yellow(directoryPath + " not exists, creating directory") |
||||
|
_ = os.Mkdir(directoryPath, os.ModePerm) |
||||
|
saveWork() |
||||
|
} |
||||
|
content := string(file) |
||||
|
json.Unmarshal([]byte(content), &work) |
||||
|
} |
||||
|
|
||||
|
func saveWork() { |
||||
|
|
||||
|
jsonProjects, err := json.Marshal(work) |
||||
|
check(err) |
||||
|
err = ioutil.WriteFile(filePath, jsonProjects, 0644) |
||||
|
check(err) |
||||
|
} |
||||
|
func getProjectIByName(name string) int { |
||||
|
for i, project := range work.Projects { |
||||
|
if project.Name == name { |
||||
|
return i |
||||
|
} |
||||
|
} |
||||
|
return -1 |
||||
|
} |
||||
|
func projectExist(name string) bool { |
||||
|
for _, project := range work.Projects { |
||||
|
if project.Name == name { |
||||
|
return true |
||||
|
} |
||||
|
} |
||||
|
return false |
||||
|
} |
||||
|
func newProject(name string) error { |
||||
|
//first, check if the project name is not taken yet
|
||||
|
if projectExist(name) { |
||||
|
color.Red("Project name: " + name + ", already exists") |
||||
|
return errors.New("project name already exist") |
||||
|
} |
||||
|
var newProject Project |
||||
|
newProject.Name = name |
||||
|
work.Projects = append(work.Projects, newProject) |
||||
|
return nil |
||||
|
} |
||||
|
func listProjects() { |
||||
|
fmt.Println("") |
||||
|
fmt.Println("") |
||||
|
fmt.Println("Listing projects") |
||||
|
fmt.Println("") |
||||
|
for k, project := range work.Projects { |
||||
|
fmt.Println("project " + strconv.Itoa(k)) |
||||
|
fmt.Print("name: ") |
||||
|
color.Blue(project.Name) |
||||
|
for k2, streak := range project.Streaks { |
||||
|
fmt.Println(" streak: " + strconv.Itoa(k2)) |
||||
|
fmt.Print(" Start:") |
||||
|
fmt.Println(streak.Start) |
||||
|
fmt.Print(" End:") |
||||
|
fmt.Println(streak.End) |
||||
|
fmt.Print(" Duration:") |
||||
|
fmt.Println(streak.Duration) |
||||
|
} |
||||
|
fmt.Println("") |
||||
|
} |
||||
|
} |