Clean up task editor and time editor

This commit is contained in:
Martin Pander
2026-02-17 20:57:21 +01:00
parent 6e60698526
commit 1a9fd9b4b0
10 changed files with 141 additions and 115 deletions

View File

@@ -4,6 +4,7 @@ package timewarrior
import (
"bytes"
"context"
"encoding/json"
"fmt"
"log/slog"
@@ -44,11 +45,12 @@ type TimeSquire struct {
configLocation string
defaultArgs []string
config *TWConfig
ctx context.Context
mutex sync.Mutex
}
func NewTimeSquire(configLocation string) *TimeSquire {
func NewTimeSquire(ctx context.Context, configLocation string) *TimeSquire {
if _, err := exec.LookPath(twBinary); err != nil {
slog.Error("Timewarrior not found")
return nil
@@ -57,6 +59,7 @@ func NewTimeSquire(configLocation string) *TimeSquire {
ts := &TimeSquire{
configLocation: configLocation,
defaultArgs: []string{},
ctx: ctx,
mutex: sync.Mutex{},
}
ts.config = ts.extractConfig()
@@ -75,11 +78,11 @@ func (ts *TimeSquire) GetTags() []string {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"tags"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"tags"}...)...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting tags:", err)
slog.Error("Failed getting tags", "error", err)
return nil
}
@@ -150,17 +153,20 @@ func (ts *TimeSquire) getIntervalsUnlocked(filter ...string) Intervals {
args = append(args, filter...)
}
cmd := exec.Command(twBinary, args...)
cmd := exec.CommandContext(ts.ctx, twBinary, args...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting intervals:", err)
if ts.ctx.Err() == context.Canceled {
return nil
}
slog.Error("Failed getting intervals", "error", err)
return nil
}
intervals := make(Intervals, 0)
err = json.Unmarshal(output, &intervals)
if err != nil {
slog.Error("Failed unmarshalling intervals:", err)
slog.Error("Failed unmarshalling intervals", "error", err)
return nil
}
@@ -194,9 +200,9 @@ func (ts *TimeSquire) StartTracking(tags []string) error {
args := append(ts.defaultArgs, "start")
args = append(args, tags...)
cmd := exec.Command(twBinary, args...)
cmd := exec.CommandContext(ts.ctx, twBinary, args...)
if err := cmd.Run(); err != nil {
slog.Error("Failed starting tracking:", err)
slog.Error("Failed starting tracking", "error", err)
return err
}
@@ -207,9 +213,9 @@ func (ts *TimeSquire) StopTracking() error {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, "stop")...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, "stop")...)
if err := cmd.Run(); err != nil {
slog.Error("Failed stopping tracking:", err)
slog.Error("Failed stopping tracking", "error", err)
return err
}
@@ -220,9 +226,9 @@ func (ts *TimeSquire) ContinueTracking() error {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, "continue")...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, "continue")...)
if err := cmd.Run(); err != nil {
slog.Error("Failed continuing tracking:", err)
slog.Error("Failed continuing tracking", "error", err)
return err
}
@@ -233,9 +239,9 @@ func (ts *TimeSquire) ContinueInterval(id int) error {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"continue", fmt.Sprintf("@%d", id)}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"continue", fmt.Sprintf("@%d", id)}...)...)
if err := cmd.Run(); err != nil {
slog.Error("Failed continuing interval:", err)
slog.Error("Failed continuing interval", "error", err)
return err
}
@@ -246,9 +252,9 @@ func (ts *TimeSquire) CancelTracking() error {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, "cancel")...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, "cancel")...)
if err := cmd.Run(); err != nil {
slog.Error("Failed canceling tracking:", err)
slog.Error("Failed canceling tracking", "error", err)
return err
}
@@ -259,9 +265,9 @@ func (ts *TimeSquire) DeleteInterval(id int) error {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"delete", fmt.Sprintf("@%d", id)}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"delete", fmt.Sprintf("@%d", id)}...)...)
if err := cmd.Run(); err != nil {
slog.Error("Failed deleting interval:", err)
slog.Error("Failed deleting interval", "error", err)
return err
}
@@ -272,9 +278,9 @@ func (ts *TimeSquire) FillInterval(id int) error {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"fill", fmt.Sprintf("@%d", id)}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"fill", fmt.Sprintf("@%d", id)}...)...)
if err := cmd.Run(); err != nil {
slog.Error("Failed filling interval:", err)
slog.Error("Failed filling interval", "error", err)
return err
}
@@ -287,9 +293,9 @@ func (ts *TimeSquire) JoinInterval(id int) error {
// Join the current interval with the previous one
// The previous interval has id+1 (since intervals are ordered newest first)
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"join", fmt.Sprintf("@%d", id+1), fmt.Sprintf("@%d", id)}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"join", fmt.Sprintf("@%d", id+1), fmt.Sprintf("@%d", id)}...)...)
if err := cmd.Run(); err != nil {
slog.Error("Failed joining interval:", err)
slog.Error("Failed joining interval", "error", err)
return err
}
@@ -303,7 +309,7 @@ func (ts *TimeSquire) ModifyInterval(interval *Interval, adjust bool) error {
// Export the modified interval
intervals, err := json.Marshal(Intervals{interval})
if err != nil {
slog.Error("Failed marshalling interval:", err)
slog.Error("Failed marshalling interval", "error", err)
return err
}
@@ -314,11 +320,11 @@ func (ts *TimeSquire) ModifyInterval(interval *Interval, adjust bool) error {
}
// Import the modified interval
cmd := exec.Command(twBinary, args...)
cmd := exec.CommandContext(ts.ctx, twBinary, args...)
cmd.Stdin = bytes.NewBuffer(intervals)
out, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed modifying interval:", err, string(out))
slog.Error("Failed modifying interval", "error", err, "output", string(out))
return err
}
@@ -334,10 +340,10 @@ func (ts *TimeSquire) GetSummary(filter ...string) string {
args = append(args, filter...)
}
cmd := exec.Command(twBinary, args...)
cmd := exec.CommandContext(ts.ctx, twBinary, args...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting summary:", err)
slog.Error("Failed getting summary", "error", err)
return ""
}
@@ -348,7 +354,7 @@ func (ts *TimeSquire) GetActive() *Interval {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"get", "dom.active"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"get", "dom.active"}...)...)
output, err := cmd.CombinedOutput()
if err != nil || string(output) == "0\n" {
return nil
@@ -369,18 +375,18 @@ func (ts *TimeSquire) Undo() {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"undo"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"undo"}...)...)
err := cmd.Run()
if err != nil {
slog.Error("Failed undoing:", err)
slog.Error("Failed undoing", "error", err)
}
}
func (ts *TimeSquire) extractConfig() *TWConfig {
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"show"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"show"}...)...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting config:", err)
slog.Error("Failed getting config", "error", err)
return nil
}