feat: add possibility to track time in timewarrior as well
Some checks failed
Go CI Pipeline / ci (push) Has been cancelled
Some checks failed
Go CI Pipeline / ci (push) Has been cancelled
This commit is contained in:
parent
127018b565
commit
c0a83b5892
4 changed files with 44 additions and 15 deletions
12
app.go
12
app.go
|
|
@ -42,8 +42,8 @@ func (a *App) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) connect() (*SSHConnection, error) { // Rückgabetyp geändert
|
func (a *App) connect(withoutTimew bool) (*SSHConnection, error) { // Rückgabetyp geändert
|
||||||
if err := a.timeStore.StartTracking(TagWork); err != nil {
|
if err := a.timeStore.StartTracking(TagWork, withoutTimew); err != nil {
|
||||||
slog.Warn(fmt.Sprintf("Failed to start time tracking for '%s': %v", TagWork, err))
|
slog.Warn(fmt.Sprintf("Failed to start time tracking for '%s': %v", TagWork, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,20 +189,20 @@ func (a *App) makeChoice() {
|
||||||
|
|
||||||
switch choice {
|
switch choice {
|
||||||
case "start work":
|
case "start work":
|
||||||
a.connect()
|
a.connect(withoutTimew)
|
||||||
case "stop work":
|
case "stop work":
|
||||||
if err := a.timeStore.StopTracking(); err != nil {
|
if err := a.timeStore.StopTracking(withoutTimew); err != nil {
|
||||||
slog.Error(fmt.Sprintf("Failed to stop time tracking: %v", err))
|
slog.Error(fmt.Sprintf("Failed to stop time tracking: %v", err))
|
||||||
}
|
}
|
||||||
if err := a.killForwardings(); err != nil {
|
if err := a.killForwardings(); err != nil {
|
||||||
slog.Warn(fmt.Sprintf("Could not kill all forwardings: %v", err))
|
slog.Warn(fmt.Sprintf("Could not kill all forwardings: %v", err))
|
||||||
}
|
}
|
||||||
case "start break":
|
case "start break":
|
||||||
if err := a.timeStore.StartTracking(TagBreak); err != nil {
|
if err := a.timeStore.StartTracking(TagBreak, withoutTimew); err != nil {
|
||||||
slog.Error(fmt.Sprintf("Failed to start break tracking: %v", err))
|
slog.Error(fmt.Sprintf("Failed to start break tracking: %v", err))
|
||||||
}
|
}
|
||||||
case "stop break":
|
case "stop break":
|
||||||
if err := a.timeStore.StartTracking(TagWork); err != nil {
|
if err := a.timeStore.StartTracking(TagWork, withoutTimew); err != nil {
|
||||||
slog.Error(fmt.Sprintf("Failed to stop break (start work): %v", err))
|
slog.Error(fmt.Sprintf("Failed to stop break (start work): %v", err))
|
||||||
}
|
}
|
||||||
case "show day summary":
|
case "show day summary":
|
||||||
|
|
|
||||||
19
cmd.go
19
cmd.go
|
|
@ -12,6 +12,8 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var withoutTimew bool
|
||||||
|
|
||||||
func (a *App) setupCommands() *cobra.Command {
|
func (a *App) setupCommands() *cobra.Command {
|
||||||
rootCmd := &cobra.Command{
|
rootCmd := &cobra.Command{
|
||||||
Use: "workctl",
|
Use: "workctl",
|
||||||
|
|
@ -44,7 +46,7 @@ Use --background (-b) to keep tunnels running in the background without auto-con
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
fmt.Println("Starting workday procedures...")
|
fmt.Println("Starting workday procedures...")
|
||||||
|
|
||||||
sshCon, err := a.connect()
|
sshCon, err := a.connect(withoutTimew)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("ERROR: Failed to start connections: %v\n", err)
|
fmt.Printf("ERROR: Failed to start connections: %v\n", err)
|
||||||
return fmt.Errorf("connection setup failed: %w", err)
|
return fmt.Errorf("connection setup failed: %w", err)
|
||||||
|
|
@ -71,7 +73,7 @@ Use --background (-b) to keep tunnels running in the background without auto-con
|
||||||
|
|
||||||
fmt.Println("\nINFO: Received interrupt signal. Shutting down background process...")
|
fmt.Println("\nINFO: Received interrupt signal. Shutting down background process...")
|
||||||
slog.Info("Received signal, cleanup via defer sshCon.Close() will run.")
|
slog.Info("Received signal, cleanup via defer sshCon.Close() will run.")
|
||||||
if err := a.timeStore.StopTracking(); err != nil {
|
if err := a.timeStore.StopTracking(withoutTimew); err != nil {
|
||||||
slog.Warn(fmt.Sprintf("Failed to stop time tracking: %v", err))
|
slog.Warn(fmt.Sprintf("Failed to stop time tracking: %v", err))
|
||||||
} else {
|
} else {
|
||||||
slog.Info("Time tracking stopped.")
|
slog.Info("Time tracking stopped.")
|
||||||
|
|
@ -84,7 +86,7 @@ Use --background (-b) to keep tunnels running in the background without auto-con
|
||||||
|
|
||||||
fmt.Println("Workstation SSH session finished.")
|
fmt.Println("Workstation SSH session finished.")
|
||||||
slog.Info("Foreground session ended, cleanup via defer sshCon.Close() will run.")
|
slog.Info("Foreground session ended, cleanup via defer sshCon.Close() will run.")
|
||||||
if err := a.timeStore.StopTracking(); err != nil {
|
if err := a.timeStore.StopTracking(withoutTimew); err != nil {
|
||||||
slog.Warn(fmt.Sprintf("Failed to stop time tracking: %v", err))
|
slog.Warn(fmt.Sprintf("Failed to stop time tracking: %v", err))
|
||||||
} else {
|
} else {
|
||||||
slog.Info("Time tracking stopped.")
|
slog.Info("Time tracking stopped.")
|
||||||
|
|
@ -96,18 +98,19 @@ Use --background (-b) to keep tunnels running in the background without auto-con
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().BoolVarP(&a.flags.StartInBackground, "background", "b", false, "Run tunnels in the background instead of connecting immediately")
|
cmd.Flags().BoolVarP(&a.flags.StartInBackground, "background", "b", false, "Run tunnels in the background instead of connecting immediately")
|
||||||
|
cmd.Flags().BoolVarP(&withoutTimew, "timew", "t", false, "Set this flag if you dont want to use Timewarrior Timestorage as well")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) stopCommand() *cobra.Command {
|
func (a *App) stopCommand() *cobra.Command {
|
||||||
return &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "stop",
|
Use: "stop",
|
||||||
Short: "Stop work: Stop time tracking, kill tunnels",
|
Short: "Stop work: Stop time tracking, kill tunnels",
|
||||||
Long: "Stops the current time tracking entry and attempts to kill active SSH tunnels.",
|
Long: "Stops the current time tracking entry and attempts to kill active SSH tunnels.",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
fmt.Println("Stopping workday procedures...")
|
fmt.Println("Stopping workday procedures...")
|
||||||
if err := a.timeStore.StopTracking(); err != nil {
|
if err := a.timeStore.StopTracking(withoutTimew); err != nil {
|
||||||
slog.Error(fmt.Sprintf("Failed to stop time tracking: %v", err))
|
slog.Error(fmt.Sprintf("Failed to stop time tracking: %v", err))
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Time tracking stopped.")
|
fmt.Println("Time tracking stopped.")
|
||||||
|
|
@ -122,6 +125,8 @@ func (a *App) stopCommand() *cobra.Command {
|
||||||
fmt.Println("Workday stop procedures finished.")
|
fmt.Println("Workday stop procedures finished.")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
cmd.Flags().BoolVarP(&withoutTimew, "timew", "t", false, "Set this flag if you dont want to use Timewarrior Timestorage as well")
|
||||||
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) trackCommand() *cobra.Command {
|
func (a *App) trackCommand() *cobra.Command {
|
||||||
|
|
@ -159,7 +164,7 @@ This also stops any currently running timer.`,
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Attempting to start tracking interval '%s'...\n", tag)
|
fmt.Printf("Attempting to start tracking interval '%s'...\n", tag)
|
||||||
if err := a.timeStore.StartTracking(tag); err != nil {
|
if err := a.timeStore.StartTracking(tag, withoutTimew); err != nil {
|
||||||
slog.Error(fmt.Sprintf("Failed to start tracking '%s': %v", tag, err))
|
slog.Error(fmt.Sprintf("Failed to start tracking '%s': %v", tag, err))
|
||||||
return fmt.Errorf("could not start tracking '%s': %w", tag, err)
|
return fmt.Errorf("could not start tracking '%s': %w", tag, err)
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +178,7 @@ This also stops any currently running timer.`,
|
||||||
Short: "Start tracking 'break'",
|
Short: "Start tracking 'break'",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
fmt.Println("Starting break...")
|
fmt.Println("Starting break...")
|
||||||
if err := a.timeStore.StartTracking(TagBreak); err != nil {
|
if err := a.timeStore.StartTracking(TagBreak, withoutTimew); err != nil {
|
||||||
slog.Error(fmt.Sprintf("Failed to start break tracking: %v", err))
|
slog.Error(fmt.Sprintf("Failed to start break tracking: %v", err))
|
||||||
return fmt.Errorf("could not start break: %w", err)
|
return fmt.Errorf("could not start break: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
helpers.go
Normal file
18
helpers.go
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func runCommand(name string, args ...string) {
|
||||||
|
cmd := exec.Command(name, args...)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Command execution error", "command", name, "args", args, "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
10
store.go
10
store.go
|
|
@ -113,7 +113,7 @@ func (ts *TimeStore) stopCurrentEntry(now time.Time) (bool, error) {
|
||||||
return rowsAffected > 0, nil
|
return rowsAffected > 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TimeStore) StartTracking(tag string) error {
|
func (ts *TimeStore) StartTracking(tag string, withoutTimew bool) error {
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
return fmt.Errorf("cannot start tracking with an empty tag")
|
return fmt.Errorf("cannot start tracking with an empty tag")
|
||||||
}
|
}
|
||||||
|
|
@ -126,6 +126,9 @@ func (ts *TimeStore) StartTracking(tag string) error {
|
||||||
if stopped {
|
if stopped {
|
||||||
slog.Info("Stopped previous time entry.")
|
slog.Info("Stopped previous time entry.")
|
||||||
}
|
}
|
||||||
|
if !withoutTimew {
|
||||||
|
runCommand("timew", "start", "work")
|
||||||
|
}
|
||||||
|
|
||||||
query := `INSERT INTO time_entries (tag, start_time, end_time) VALUES (?, ?, NULL);`
|
query := `INSERT INTO time_entries (tag, start_time, end_time) VALUES (?, ?, NULL);`
|
||||||
_, err = ts.db.Exec(query, tag, now)
|
_, err = ts.db.Exec(query, tag, now)
|
||||||
|
|
@ -136,12 +139,15 @@ func (ts *TimeStore) StartTracking(tag string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TimeStore) StopTracking() error {
|
func (ts *TimeStore) StopTracking(withoutTimew bool) error {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
stopped, err := ts.stopCurrentEntry(now)
|
stopped, err := ts.stopCurrentEntry(now)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if !withoutTimew {
|
||||||
|
runCommand("timew", "stop", "work")
|
||||||
|
}
|
||||||
if stopped {
|
if stopped {
|
||||||
slog.Info(fmt.Sprintf("Stopped tracking at %s", now.Format(time.RFC3339)))
|
slog.Info(fmt.Sprintf("Stopped tracking at %s", now.Format(time.RFC3339)))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue