mirror of
https://github.com/gotify/cli.git
synced 2024-01-28 15:20:39 +03:00
add watch command output (#20)
This commit is contained in:
29
README.md
29
README.md
@@ -12,6 +12,7 @@ Gotify-CLI is a command line client for pushing messages to [gotify/server][goti
|
|||||||
* initialization wizard
|
* initialization wizard
|
||||||
* piping support (`echo message | gotify push`)
|
* piping support (`echo message | gotify push`)
|
||||||
* simple to use
|
* simple to use
|
||||||
|
* watch and push script result changes (`gotify watch "curl http://example.com/api | jq '.data'"`)
|
||||||
|
|
||||||
## Alternatives
|
## Alternatives
|
||||||
|
|
||||||
@@ -61,28 +62,29 @@ $ gotify push "my message"
|
|||||||
$ echo my message | gotify push
|
$ echo my message | gotify push
|
||||||
$ gotify push < somefile
|
$ gotify push < somefile
|
||||||
$ gotify push -t "my title" -p 10 "my message"
|
$ gotify push -t "my title" -p 10 "my message"
|
||||||
|
$ gotify watch "curl http://example.com/api | jq '.data'"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Help
|
## Help
|
||||||
|
|
||||||
**Uses version `v1.2.0`**
|
**Uses version `v2.1.0`**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ gotify help
|
|
||||||
NAME:
|
NAME:
|
||||||
Gotify - The official Gotify-CLI
|
Gotify - The official Gotify-CLI
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
gotify [global options] command [command options] [arguments...]
|
cli [global options] command [command options] [arguments...]
|
||||||
|
|
||||||
VERSION:
|
VERSION:
|
||||||
1.2.0
|
2.1.0
|
||||||
|
|
||||||
COMMANDS:
|
COMMANDS:
|
||||||
init Initializes the Gotify-CLI
|
init Initializes the Gotify-CLI
|
||||||
version, v Shows the version
|
version, v Shows the version
|
||||||
config Shows the config
|
config Shows the config
|
||||||
push, p Pushes a message
|
push, p Pushes a message
|
||||||
|
watch watch the result of a command and pushes output difference
|
||||||
help, h Shows a list of commands or help for one command
|
help, h Shows a list of commands or help for one command
|
||||||
|
|
||||||
GLOBAL OPTIONS:
|
GLOBAL OPTIONS:
|
||||||
@@ -90,6 +92,25 @@ GLOBAL OPTIONS:
|
|||||||
--version, -v print the version
|
--version, -v print the version
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Watch help
|
||||||
|
|
||||||
|
```
|
||||||
|
NAME:
|
||||||
|
cli watch - watch the result of a command and pushes output difference
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
cli watch [command options] <cmd>
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
--interval value, -n value watch interval (sec) (default: 2)
|
||||||
|
--priority value, -p value Set the priority (default: 0)
|
||||||
|
--exec value, -x value Pass command to exec (default to "sh -c")
|
||||||
|
--title value, -t value Set the title (empty for command)
|
||||||
|
--token value Override the app token
|
||||||
|
--url value Override the Gotify URL
|
||||||
|
--output value, -o value Output verbosity (short|default|long) (default: "default")
|
||||||
|
```
|
||||||
|
|
||||||
### Push help
|
### Push help
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
1
cli.go
1
cli.go
@@ -29,6 +29,7 @@ func main() {
|
|||||||
command.Version(),
|
command.Version(),
|
||||||
command.Config(),
|
command.Config(),
|
||||||
command.Push(),
|
command.Push(),
|
||||||
|
command.Watch(),
|
||||||
}
|
}
|
||||||
err := app.Run(os.Args)
|
err := app.Run(os.Args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func Push() cli.Command {
|
func Push() cli.Command {
|
||||||
return cli.Command{
|
return cli.Command{
|
||||||
Name: "push",
|
Name: "push",
|
||||||
|
|||||||
148
command/watch.go
Normal file
148
command/watch.go
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gotify/cli/v2/config"
|
||||||
|
"github.com/gotify/cli/v2/utils"
|
||||||
|
"github.com/gotify/go-api-client/v2/models"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Watch() cli.Command {
|
||||||
|
return cli.Command{
|
||||||
|
Name: "watch",
|
||||||
|
Usage: "watch the result of a command and pushes output difference",
|
||||||
|
ArgsUsage: "<cmd>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
cli.Float64Flag{Name: "interval,n", Usage: "watch interval (sec)", Value: 2},
|
||||||
|
cli.IntFlag{Name: "priority,p", Usage: "Set the priority"},
|
||||||
|
cli.StringFlag{Name: "exec,x", Usage: "Pass command to exec", Value: "sh -c"},
|
||||||
|
cli.StringFlag{Name: "title,t", Usage: "Set the title (empty for command)"},
|
||||||
|
cli.StringFlag{Name: "token", Usage: "Override the app token"},
|
||||||
|
cli.StringFlag{Name: "url", Usage: "Override the Gotify URL"},
|
||||||
|
cli.StringFlag{Name: "output,o", Usage: "Output verbosity (short|default|long)", Value: "default"},
|
||||||
|
},
|
||||||
|
Action: doWatch,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doWatch(ctx *cli.Context) {
|
||||||
|
conf, confErr := config.ReadConfig(config.GetLocations())
|
||||||
|
|
||||||
|
cmdArgs := ctx.Args()
|
||||||
|
cmdStringNotation := strings.Join(cmdArgs, " ")
|
||||||
|
execArgs := strings.Split(ctx.String("exec"), " ")
|
||||||
|
cmdArgs = append(execArgs[1:], cmdStringNotation)
|
||||||
|
execCmd := execArgs[0]
|
||||||
|
|
||||||
|
outputMode := ctx.String("output")
|
||||||
|
if !(outputMode == "default" || outputMode == "long" || outputMode == "short") {
|
||||||
|
utils.Exit1With("output mode should be short|default|long")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
interval := ctx.Float64("interval")
|
||||||
|
priority := ctx.Int("priority")
|
||||||
|
title := ctx.String("title")
|
||||||
|
if title == "" {
|
||||||
|
title = cmdStringNotation
|
||||||
|
}
|
||||||
|
token := ctx.String("token")
|
||||||
|
if token == "" {
|
||||||
|
if confErr != nil {
|
||||||
|
utils.Exit1With("token is not configured, run 'gotify init'")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token = conf.Token
|
||||||
|
}
|
||||||
|
stringURL := ctx.String("url")
|
||||||
|
if stringURL == "" {
|
||||||
|
if confErr != nil {
|
||||||
|
utils.Exit1With("url is not configured, run 'gotify init'")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
stringURL = conf.URL
|
||||||
|
}
|
||||||
|
parsedURL, err := url.Parse(stringURL)
|
||||||
|
if err != nil {
|
||||||
|
utils.Exit1With("invalid url", stringURL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
watchInterval := time.Duration(interval*1000) * time.Millisecond
|
||||||
|
|
||||||
|
evalCmdOutput := func() (string, error) {
|
||||||
|
cmd := exec.Command(execCmd, cmdArgs...)
|
||||||
|
timeOut := time.After(watchInterval)
|
||||||
|
outputBuf := bytes.NewBuffer([]byte{})
|
||||||
|
cmd.Stdout = outputBuf
|
||||||
|
cmd.Stderr = outputBuf
|
||||||
|
err := cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("command failed to invoke: %v", err)
|
||||||
|
}
|
||||||
|
done := make(chan error)
|
||||||
|
go func() {
|
||||||
|
err := cmd.Wait()
|
||||||
|
if err != nil {
|
||||||
|
done <- fmt.Errorf("command failed to invoke: %v", err)
|
||||||
|
}
|
||||||
|
done <- nil
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case err := <-done:
|
||||||
|
return outputBuf.String(), err
|
||||||
|
case <-timeOut:
|
||||||
|
cmd.Process.Kill()
|
||||||
|
return outputBuf.String(), errors.New("command timed out")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastOutput, err := evalCmdOutput()
|
||||||
|
if err != nil {
|
||||||
|
utils.Exit1With("first run failed", err)
|
||||||
|
}
|
||||||
|
for range time.NewTicker(watchInterval).C {
|
||||||
|
output, err := evalCmdOutput()
|
||||||
|
if err != nil {
|
||||||
|
output += fmt.Sprintf("\n!== <%v> ==!", err)
|
||||||
|
}
|
||||||
|
if output != lastOutput {
|
||||||
|
msgData := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
|
switch outputMode {
|
||||||
|
case "long":
|
||||||
|
fmt.Fprintf(msgData, "command output for \"%s\" changed:\n\n", cmdStringNotation)
|
||||||
|
fmt.Fprintln(msgData, "== BEGIN OLD OUTPUT ==")
|
||||||
|
fmt.Fprint(msgData, lastOutput)
|
||||||
|
fmt.Fprintln(msgData, "== END OLD OUTPUT ==")
|
||||||
|
fmt.Fprintln(msgData, "== BEGIN NEW OUTPUT ==")
|
||||||
|
fmt.Fprint(msgData, output)
|
||||||
|
fmt.Fprintln(msgData, "== END NEW OUTPUT ==")
|
||||||
|
case "default":
|
||||||
|
fmt.Fprintf(msgData, "command output for \"%s\" changed:\n\n", cmdStringNotation)
|
||||||
|
fmt.Fprintln(msgData, "== BEGIN NEW OUTPUT ==")
|
||||||
|
fmt.Fprint(msgData, output)
|
||||||
|
fmt.Fprintln(msgData, "== END NEW OUTPUT ==")
|
||||||
|
case "short":
|
||||||
|
fmt.Fprintf(msgData, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
msgString := msgData.String()
|
||||||
|
fmt.Println(msgString)
|
||||||
|
pushMessage(parsedURL, token, models.MessageExternal{
|
||||||
|
Title: title,
|
||||||
|
Message: msgString,
|
||||||
|
Priority: priority,
|
||||||
|
}, true)
|
||||||
|
lastOutput = output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user