Commit
+51 -0 +/-3 browse
1 | diff --git a/README.md b/README.md |
2 | index 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 |
34 | index 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 |
46 | index 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 |