-
-
Notifications
You must be signed in to change notification settings - Fork 19
/
cmd_chronic.go
99 lines (80 loc) · 2.29 KB
/
cmd_chronic.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package main
import (
"bytes"
"fmt"
"os/exec"
"syscall"
"github.com/skx/subcommands"
)
// Structure for our options and state.
type chronicCommand struct {
// We embed the NoFlags option, because we accept no command-line flags.
subcommands.NoFlags
}
// Info returns the name of this subcommand.
func (c *chronicCommand) Info() (string, string) {
return "chronic", `Run a command quietly, if it succeeds.
Details:
The chronic command allows you to execute a program, and hide the output
if the command succeeds.
The ideal use-case is for wrapping cronjobs, where you don't care about the
output unless the execution fails.
Example:
Compare the output of these two commands:
$ sysbox chronic ls
$
$ sysbox chronic ls /missing/dir
ls: cannot access '/missing/file': No such file or directory
`
}
// RunCommand is a helper to run a command, returning output and the exit-code.
func (c *chronicCommand) RunCommand(command []string) (stdout string, stderr string, exitCode int) {
var outbuf, errbuf bytes.Buffer
cmd := exec.Command(command[0], command[1:]...)
cmd.Stdout = &outbuf
cmd.Stderr = &errbuf
err := cmd.Run()
stdout = outbuf.String()
stderr = errbuf.String()
if err != nil {
// try to get the exit code
if exitError, ok := err.(*exec.ExitError); ok {
ws := exitError.Sys().(syscall.WaitStatus)
exitCode = ws.ExitStatus()
} else {
// This will happen (in OSX) if `name` is not
// available in $PATH, in this situation, exit
// code could not be get, and stderr will be
// empty string very likely, so we use the default
// fail code, and format err to string and set to stderr
exitCode = 1
if stderr == "" {
stderr = err.Error()
}
}
} else {
// success, exitCode should be 0 if go is ok
ws := cmd.ProcessState.Sys().(syscall.WaitStatus)
exitCode = ws.ExitStatus()
}
return stdout, stderr, exitCode
}
// Execute is invoked if the user specifies `chronic` as the subcommand.
func (c *chronicCommand) Execute(args []string) int {
if len(args) <= 0 {
fmt.Printf("Usage: chronic command to execute ..\n")
return 1
}
stdout, stderr, exit := c.RunCommand(args)
if exit == 0 {
return 0
}
fmt.Printf("%q exited with status code %d\n", args, exit)
if len(stdout) > 0 {
fmt.Println(stdout)
}
if len(stderr) > 0 {
fmt.Println(stderr)
}
return exit
}