Created
January 24, 2024 18:58
-
-
Save irozgar/c2a0a8e6f16fdc6aa800d3edd4dd381f to your computer and use it in GitHub Desktop.
wlg
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"flag" | |
"fmt" | |
"io" | |
"log" | |
"os" | |
"path/filepath" | |
"time" | |
) | |
const appConfigHome = "wlg" | |
type Break struct { | |
StartTime time.Time | |
EndTime *time.Time | |
} | |
type Workday struct { | |
Date time.Time | |
StartTime time.Time | |
EndTime *time.Time | |
Breaks []Break | |
} | |
type AppData struct { | |
ActiveDay *Workday `json:"activeDay"` | |
Workdays []Workday `json:"workdays"` | |
} | |
func createBreak(startTime time.Time) Break { | |
return Break{StartTime: startTime} | |
} | |
func createWorkday(date time.Time, startTime time.Time) Workday { | |
return Workday{Date: date, StartTime: startTime} | |
} | |
func createAppData() AppData { | |
return AppData{Workdays: []Workday{}} | |
} | |
func loadAppData(a *AppData) error { | |
home, err := os.UserConfigDir() | |
if err != nil { | |
panic(err) | |
} | |
configFilepath := filepath.Join(home, appConfigHome, "config.json") | |
file, err := os.Open(configFilepath) | |
if err != nil { | |
return err | |
} | |
defer func(file *os.File) { | |
err := file.Close() | |
if err != nil { | |
panic(err) | |
} | |
}(file) | |
data, err := io.ReadAll(file) | |
if err != nil { | |
panic(err) | |
} | |
err = json.Unmarshal(data, &a) | |
if err != nil { | |
panic(err) | |
} | |
return nil | |
} | |
func (w *Workday) endWork(endTime time.Time) { | |
w.EndTime = &endTime | |
} | |
func (w *Workday) startBreak(startTime time.Time) { | |
lb := w.getLastBreak() | |
if lb != nil && lb.EndTime == nil { | |
panic("Last break is still active") | |
} | |
w.Breaks = append(w.Breaks, createBreak(startTime)) | |
} | |
func (w *Workday) endBreak(endTime time.Time) { | |
lb := w.getLastBreak() | |
if lb == nil || lb.EndTime != nil { | |
panic("No active break") | |
} | |
lb.endBreak(endTime) | |
} | |
func (w *Workday) getBreakTime() time.Duration { | |
total := time.Duration(0) | |
for _, b := range w.Breaks { | |
if b.EndTime == nil { | |
total += time.Now().Sub(b.StartTime) | |
} else { | |
total += b.EndTime.Sub(b.StartTime) | |
} | |
} | |
return total | |
} | |
func (w *Workday) getWorkTime() time.Duration { | |
if w.EndTime == nil { | |
return time.Now().Sub(w.StartTime) - w.getBreakTime() | |
} | |
return w.EndTime.Sub(w.StartTime) - w.getBreakTime() | |
} | |
func (w *Workday) getLastBreak() *Break { | |
if len(w.Breaks) == 0 { | |
return nil | |
} | |
return &w.Breaks[len(w.Breaks)-1] | |
} | |
func (w *Workday) getEstimatedEndTime() time.Time { | |
return w.StartTime.Add(8*time.Hour + w.getBreakTime()) | |
} | |
func (b *Break) endBreak(endTime time.Time) { | |
b.EndTime = &endTime | |
} | |
func (a *AppData) writeToFile() { | |
home, err := os.UserConfigDir() | |
if err != nil { | |
panic(err) | |
} | |
configHome := filepath.Join(home, appConfigHome) | |
err = os.MkdirAll(configHome, os.ModePerm) | |
if err != nil { | |
panic(err) | |
} | |
configFilepath := filepath.Join(configHome, "data.json") | |
file, err := os.Create(configFilepath) | |
if err != nil { | |
panic(err) | |
} | |
defer func(file *os.File) { | |
err := file.Close() | |
if err != nil { | |
panic(err) | |
} | |
}(file) | |
data, err := json.Marshal(a) | |
if err != nil { | |
panic(err) | |
} | |
log.Println(string(data)) | |
_, err = file.WriteString(string(data)) | |
if err != nil { | |
panic(err) | |
} | |
} | |
func formatDuration(d time.Duration) string { | |
total := int(d.Seconds()) | |
hours := total / 3600 | |
minutes := (total % 3600) / 60 | |
seconds := total % 60 | |
return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) | |
} | |
func defaultConfigPath() string { | |
home, err := os.UserConfigDir() | |
if err != nil { | |
panic(err) | |
} | |
return filepath.Join(home, appConfigHome, "config.json") | |
} | |
func main() { | |
flag.Usage = func() { | |
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s <command>\n", os.Args[0]) | |
fmt.Fprintf(flag.CommandLine.Output(), "Commands:\n") | |
fmt.Fprintf(flag.CommandLine.Output(), " day <subcommand>\n") | |
fmt.Fprintf(flag.CommandLine.Output(), " arrive\n") | |
fmt.Fprintf(flag.CommandLine.Output(), " leave\n") | |
fmt.Fprintf(flag.CommandLine.Output(), " check\n") | |
fmt.Fprintf(flag.CommandLine.Output(), " break\n") | |
fmt.Fprintf(flag.CommandLine.Output(), " back\n") | |
fmt.Fprintf(flag.CommandLine.Output(), "\n") | |
} | |
flag.Parse() | |
d := createAppData() | |
err := loadAppData(&d) | |
if err != nil && os.IsNotExist(err) { | |
d.writeToFile() | |
} else if err != nil { | |
panic(err) | |
} | |
if len(os.Args) < 3 { | |
flag.Usage() | |
os.Exit(1) | |
} | |
switch os.Args[1] { | |
case "day": | |
switch os.Args[2] { | |
case "arrive": | |
if d.ActiveDay != nil { | |
panic("Active workday already exists") | |
} | |
w := createWorkday(time.Now(), time.Now()) | |
d.ActiveDay = &w | |
d.writeToFile() | |
fmt.Println("Hello, your workday will end at " + w.StartTime.Add(8*time.Hour).Format("15:04:05")) | |
case "leave": | |
w := d.ActiveDay | |
if w == nil { | |
panic("No active workday") | |
} | |
w.endWork(time.Now()) | |
d.ActiveDay = nil | |
d.Workdays = append(d.Workdays, *w) | |
d.writeToFile() | |
fmt.Println("Goodbye, you worked " + formatDuration(w.EndTime.Sub(w.StartTime))) | |
case "check": | |
w := d.ActiveDay | |
if w == nil { | |
panic("No active workday") | |
} | |
fmt.Println("Worked time: " + formatDuration(w.getWorkTime())) | |
fmt.Println("Total Break time: " + formatDuration(w.getBreakTime())) | |
fmt.Println("End time: " + w.getEstimatedEndTime().Format("15:04:05")) | |
case "break": | |
w := d.ActiveDay | |
if w == nil { | |
panic("No active workday") | |
} | |
w.startBreak(time.Now()) | |
d.writeToFile() | |
case "back": | |
w := d.ActiveDay | |
if w == nil { | |
panic("No active workday") | |
} | |
w.endBreak(time.Now()) | |
d.writeToFile() | |
default: | |
flag.Usage() | |
os.Exit(1) | |
} | |
default: | |
flag.Usage() | |
os.Exit(1) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment