Author: Kevin Schoon [kevinschoon@gmail.com]
Committer: GitHub [noreply@github.com] Wed, 01 Jun 2022 01:35:23 +0000
Hash: e6aa45152c8e13f66deda4fa80a5112b6088c4ef
Timestamp: Wed, 01 Jun 2022 01:35:23 +0000 (2 years ago)

+69 -0 +/-6 browse
Merge pull request #61 from sboysel/feature/exec-on-event
Merge pull request #61 from sboysel/feature/exec-on-event

Execute command on state change
1diff --git a/README.md b/README.md
2index 5aa4e3e..e1ea9fc 100644
3--- a/README.md
4+++ b/README.md
5 @@ -65,6 +65,33 @@ Example:
6 }
7 ```
8
9+ ### Execute command on state change
10+
11+ Pomo will execute an arbitrary command specified in the array argument `onEvent`
12+ when the state changes. The first element of this array should be the
13+ executable to run while the remaining elements are space delimited arguments.
14+ The new state will be exported as an environment variable `POMO_STATE` for this
15+ command. Possible state values are `RUNNING`, `PAUSED`, `BREAKING`, or
16+ `COMPLETE`.
17+
18+ For example, to trigger a terminal bell when a session completes, add the
19+ following to `config.json`:
20+ ```json
21+ ...
22+ "onEvent": ["/bin/sh", "/path/to/script/my_script.sh"],
23+ ...
24+ ```
25+ where the contents of `my_script.sh` are
26+ ```bash
27+ #!/bin/sh
28+
29+ if [ "$POMO_STATE" == "COMPLETE" ] ; then
30+ echo -e '\a'
31+ fi
32+ ```
33+
34+ See the `contrib` directory for user contributed scripts for use with `onEvent`.
35+
36 ## Integrations
37
38 By default pomo will setup a Unix socket and serve it's status there.
39 diff --git a/contrib/.gitkeep b/contrib/.gitkeep
40new file mode 100644
41index 0000000..e69de29
42--- /dev/null
43+++ b/contrib/.gitkeep
44 diff --git a/contrib/bell b/contrib/bell
45new file mode 100755
46index 0000000..b4c6e8f
47--- /dev/null
48+++ b/contrib/bell
49 @@ -0,0 +1,3 @@
50+ #!/bin/sh
51+
52+ echo -e '\e'
53 diff --git a/contrib/pomonag b/contrib/pomonag
54new file mode 100755
55index 0000000..4259c6e
56--- /dev/null
57+++ b/contrib/pomonag
58 @@ -0,0 +1,5 @@
59+ #!/bin/sh
60+
61+ if [ "$POMO_STATE" == "BREAKING" ] ; then
62+ swaynag -m "It's time to take a break!"
63+ fi
64 diff --git a/pkg/internal/config.go b/pkg/internal/config.go
65index d4ecf3c..85033f8 100644
66--- a/pkg/internal/config.go
67+++ b/pkg/internal/config.go
68 @@ -23,6 +23,7 @@ type Config struct {
69 DBPath string `json:"dbPath"`
70 SocketPath string `json:"socketPath"`
71 IconPath string `json:"iconPath"`
72+ OnEvent []string `json:"onEvent"`
73 // Publish pushes updates to the configured
74 // SocketPath rather than listening for requests
75 Publish bool `json:"publish"`
76 diff --git a/pkg/internal/runner.go b/pkg/internal/runner.go
77index 58a0039..46a802c 100644
78--- a/pkg/internal/runner.go
79+++ b/pkg/internal/runner.go
80 @@ -2,6 +2,9 @@ package pomo
81
82 import (
83 "database/sql"
84+ "fmt"
85+ "os"
86+ "os/exec"
87 "sync"
88 "time"
89 )
90 @@ -21,6 +24,7 @@ type TaskRunner struct {
91 notifier Notifier
92 duration time.Duration
93 mu sync.Mutex
94+ onEvent []string
95 }
96
97 func NewMockedTaskRunner(task *Task, store *Store, notifier Notifier) (*TaskRunner, error) {
98 @@ -55,6 +59,7 @@ func NewTaskRunner(task *Task, config *Config) (*TaskRunner, error) {
99 toggle: make(chan bool),
100 notifier: NewXnotifier(config.IconPath),
101 duration: task.Duration,
102+ onEvent: config.OnEvent,
103 }
104 return tr, nil
105 }
106 @@ -73,6 +78,34 @@ func (t *TaskRunner) TimePauseDuration() time.Duration {
107
108 func (t *TaskRunner) SetState(state State) {
109 t.state = state
110+ // execute onEvent command if variable is set
111+ if t.onEvent != nil {
112+ go t.runOnEvent()
113+ }
114+ }
115+
116+ // execute script command specified by `onEvent` on state change
117+ func (t *TaskRunner) runOnEvent() error {
118+ var cmd *exec.Cmd
119+ // parse command arguments
120+ numArgs := len(t.onEvent)
121+ app := t.onEvent[0]
122+ if numArgs > 1 {
123+ args := t.onEvent[1:(numArgs + 1)]
124+ cmd = exec.Command(app, args...)
125+ } else {
126+ cmd = exec.Command(app)
127+ }
128+ // set state in command environment
129+ cmd.Env = append(os.Environ(),
130+ fmt.Sprintf("POMO_STATE=%s", t.state),
131+ )
132+ // run command
133+ err := cmd.Run()
134+ if err != nil {
135+ return err
136+ }
137+ return nil
138 }
139
140 func (t *TaskRunner) run() error {