Merge pull request #61 from sboysel/feature/exec-on-event

Execute command on state change
This commit is contained in:
Kevin Schoon 2022-05-31 20:35:23 -05:00 committed by GitHub
commit e6aa45152c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 0 deletions

View File

@ -65,6 +65,33 @@ Example:
} }
``` ```
### Execute command on state change
Pomo will execute an arbitrary command specified in the array argument `onEvent`
when the state changes. The first element of this array should be the
executable to run while the remaining elements are space delimited arguments.
The new state will be exported as an environment variable `POMO_STATE` for this
command. Possible state values are `RUNNING`, `PAUSED`, `BREAKING`, or
`COMPLETE`.
For example, to trigger a terminal bell when a session completes, add the
following to `config.json`:
```json
...
"onEvent": ["/bin/sh", "/path/to/script/my_script.sh"],
...
```
where the contents of `my_script.sh` are
```bash
#!/bin/sh
if [ "$POMO_STATE" == "COMPLETE" ] ; then
echo -e '\a'
fi
```
See the `contrib` directory for user contributed scripts for use with `onEvent`.
## Integrations ## Integrations
By default pomo will setup a Unix socket and serve it's status there. By default pomo will setup a Unix socket and serve it's status there.

0
contrib/.gitkeep Normal file
View File

3
contrib/bell Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
echo -e '\e'

5
contrib/pomonag Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
if [ "$POMO_STATE" == "BREAKING" ] ; then
swaynag -m "It's time to take a break!"
fi

View File

@ -23,6 +23,7 @@ type Config struct {
DBPath string `json:"dbPath"` DBPath string `json:"dbPath"`
SocketPath string `json:"socketPath"` SocketPath string `json:"socketPath"`
IconPath string `json:"iconPath"` IconPath string `json:"iconPath"`
OnEvent []string `json:"onEvent"`
// Publish pushes updates to the configured // Publish pushes updates to the configured
// SocketPath rather than listening for requests // SocketPath rather than listening for requests
Publish bool `json:"publish"` Publish bool `json:"publish"`

View File

@ -2,6 +2,9 @@ package pomo
import ( import (
"database/sql" "database/sql"
"fmt"
"os"
"os/exec"
"sync" "sync"
"time" "time"
) )
@ -21,6 +24,7 @@ type TaskRunner struct {
notifier Notifier notifier Notifier
duration time.Duration duration time.Duration
mu sync.Mutex mu sync.Mutex
onEvent []string
} }
func NewMockedTaskRunner(task *Task, store *Store, notifier Notifier) (*TaskRunner, error) { func NewMockedTaskRunner(task *Task, store *Store, notifier Notifier) (*TaskRunner, error) {
@ -55,6 +59,7 @@ func NewTaskRunner(task *Task, config *Config) (*TaskRunner, error) {
toggle: make(chan bool), toggle: make(chan bool),
notifier: NewXnotifier(config.IconPath), notifier: NewXnotifier(config.IconPath),
duration: task.Duration, duration: task.Duration,
onEvent: config.OnEvent,
} }
return tr, nil return tr, nil
} }
@ -73,6 +78,34 @@ func (t *TaskRunner) TimePauseDuration() time.Duration {
func (t *TaskRunner) SetState(state State) { func (t *TaskRunner) SetState(state State) {
t.state = state t.state = state
// execute onEvent command if variable is set
if t.onEvent != nil {
go t.runOnEvent()
}
}
// execute script command specified by `onEvent` on state change
func (t *TaskRunner) runOnEvent() error {
var cmd *exec.Cmd
// parse command arguments
numArgs := len(t.onEvent)
app := t.onEvent[0]
if numArgs > 1 {
args := t.onEvent[1:(numArgs + 1)]
cmd = exec.Command(app, args...)
} else {
cmd = exec.Command(app)
}
// set state in command environment
cmd.Env = append(os.Environ(),
fmt.Sprintf("POMO_STATE=%s", t.state),
)
// run command
err := cmd.Run()
if err != nil {
return err
}
return nil
} }
func (t *TaskRunner) run() error { func (t *TaskRunner) run() error {