Author: Sam Boysel [sboysel@gmail.com]
Hash: 3d3a2bc152388ee8cefbf88b754822549e0ab63a
Timestamp: Tue, 31 May 2022 06:20:58 +0000 (2 years ago)

+51 -0 +/-3 browse
execute command on state change
1diff --git a/README.md b/README.md
2index 5aa4e3e..f5a216e 100644
3--- a/README.md
4+++ b/README.md
5 @@ -65,6 +65,27 @@ Example:
6 }
7 ```
8
9+ ### Execute command on state change
10+
11+ Pomo will execute the command specified in the array argument `onEvent` when the
12+ state changes. The new state will be exported as an environment variable
13+ `POMO_STATE` for this command. For example, to trigger a terminal bell when a
14+ session complete, add the following to `config.json`
15+ ```
16+ ...
17+ "onEvent": ["/bin/sh", "/path/to/script/my_script.sh"]
18+ ...
19+ ```
20+ where the contents of `my_script.sh` are
21+ ```
22+ #!/bin/sh
23+
24+ if [ "$POMO_STATE" == "COMPLETE" ] ; then
25+ echo -e '\a'
26+ fi
27+ ```
28+ Possible state values are `RUNNING`, `PAUSED`, `BREAKING`, or `COMPLETE`.
29+
30 ## Integrations
31
32 By default pomo will setup a Unix socket and serve it's status there.
33 diff --git a/pkg/internal/config.go b/pkg/internal/config.go
34index d4ecf3c..85033f8 100644
35--- a/pkg/internal/config.go
36+++ b/pkg/internal/config.go
37 @@ -23,6 +23,7 @@ type Config struct {
38 DBPath string `json:"dbPath"`
39 SocketPath string `json:"socketPath"`
40 IconPath string `json:"iconPath"`
41+ OnEvent []string `json:"onEvent"`
42 // Publish pushes updates to the configured
43 // SocketPath rather than listening for requests
44 Publish bool `json:"publish"`
45 diff --git a/pkg/internal/runner.go b/pkg/internal/runner.go
46index 58a0039..9a83fef 100644
47--- a/pkg/internal/runner.go
48+++ b/pkg/internal/runner.go
49 @@ -2,6 +2,9 @@ package pomo
50
51 import (
52 "database/sql"
53+ "fmt"
54+ "os"
55+ "os/exec"
56 "sync"
57 "time"
58 )
59 @@ -21,6 +24,7 @@ type TaskRunner struct {
60 notifier Notifier
61 duration time.Duration
62 mu sync.Mutex
63+ onEvent []string
64 }
65
66 func NewMockedTaskRunner(task *Task, store *Store, notifier Notifier) (*TaskRunner, error) {
67 @@ -55,6 +59,7 @@ func NewTaskRunner(task *Task, config *Config) (*TaskRunner, error) {
68 toggle: make(chan bool),
69 notifier: NewXnotifier(config.IconPath),
70 duration: task.Duration,
71+ onEvent: config.OnEvent,
72 }
73 return tr, nil
74 }
75 @@ -75,6 +80,20 @@ func (t *TaskRunner) SetState(state State) {
76 t.state = state
77 }
78
79+ // execute script command specified by `onEvent` on state change
80+ func (t *TaskRunner) OnEvent() error {
81+ app, args := t.onEvent[0], t.onEvent[1:len(t.onEvent)]
82+ cmd := exec.Command(app, args...)
83+ cmd.Env = append(os.Environ(),
84+ fmt.Sprintf("POMO_STATE=%s", t.state),
85+ )
86+ err := cmd.Run()
87+ if err != nil {
88+ return err
89+ }
90+ return nil
91+ }
92+
93 func (t *TaskRunner) run() error {
94 for t.count < t.nPomodoros {
95 // Create a new pomodoro where we
96 @@ -85,6 +104,8 @@ func (t *TaskRunner) run() error {
97 pomodoro.Start = time.Now()
98 // Set state to RUNNIN
99 t.SetState(RUNNING)
100+ // Execute onEvent command
101+ t.OnEvent()
102 // Create a new timer
103 timer := time.NewTimer(t.duration)
104 // Record our started time
105 @@ -104,6 +125,8 @@ func (t *TaskRunner) run() error {
106 remaining := t.TimeRemaining()
107 // Change state to PAUSED
108 t.SetState(PAUSED)
109+ // Execute onEvent command
110+ t.OnEvent()
111 // Wait for the user to press [p]
112 <-t.pause
113 // Resume the timer with previous
114 @@ -114,6 +137,8 @@ func (t *TaskRunner) run() error {
115 t.duration = remaining
116 // Restore state to RUNNING
117 t.SetState(RUNNING)
118+ // Execute onEvent command
119+ t.OnEvent()
120 goto loop
121 }
122 pomodoro.End = time.Now()
123 @@ -128,6 +153,8 @@ func (t *TaskRunner) run() error {
124 break
125 }
126 t.SetState(BREAKING)
127+ // Execute onEvent command
128+ t.OnEvent()
129 t.notifier.Notify("Pomo", "It is time to take a break!")
130 // Reset the duration incase it
131 // was paused.
132 @@ -138,6 +165,8 @@ func (t *TaskRunner) run() error {
133 }
134 t.notifier.Notify("Pomo", "Pomo session has completed!")
135 t.SetState(COMPLETE)
136+ // Execute onEvent command
137+ t.OnEvent()
138 return nil
139 }
140