-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmain.go
92 lines (79 loc) · 2.3 KB
/
main.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
package main
import (
"fmt"
"os"
"os/exec"
"regexp"
"strconv"
"time"
"github.com/Songmu/timeout"
"github.com/pborman/getopt"
)
func main() {
optKillAfter := getopt.StringLong("kill-after", 'k', "", "also send a KILL signal if COMMAND is still running. this long after the initial signal was sent")
optSig := getopt.StringLong("signal", 's', "", "specify the signal to be sent on timeout. IGNAL may be a name like 'HUP' or a number. see 'kill -l' for a list of signals")
optForeground := getopt.BoolLong("foreground", 0, "when not running timeout directly from a shell prompt, allow COMMAND to read from the TTY and get TTY signals. in this mode, children of COMMAND will not be timed out")
p := getopt.BoolLong("preserve-status", 0, "exit with the same status as COMMAND, even when the command times out")
opts := getopt.CommandLine
opts.Parse(os.Args)
rest := opts.Args()
if len(rest) < 2 {
opts.PrintUsage(os.Stderr)
os.Exit(1)
}
var err error
killAfter := float64(0)
if *optKillAfter != "" {
killAfter, err = parseDuration(*optKillAfter)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(125)
}
}
var sig os.Signal
if *optSig != "" {
sig, err = parseSignal(*optSig)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(125)
}
}
dur, err := parseDuration(rest[0])
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(125)
}
cmd := exec.Command(rest[1], rest[2:]...)
tio := &timeout.Timeout{
Duration: time.Duration(dur * float64(time.Second)),
Cmd: cmd,
Foreground: *optForeground,
KillAfter: time.Duration(killAfter * float64(time.Second)),
Signal: sig,
}
exit := tio.RunSimple(*p)
os.Exit(exit)
}
var durRe = regexp.MustCompile(`^([-0-9e.]+)([smhd])?$`)
func parseDuration(durStr string) (float64, error) {
matches := durRe.FindStringSubmatch(durStr)
if len(matches) == 0 {
return 0, fmt.Errorf("duration format invalid: %s", durStr)
}
base, err := strconv.ParseFloat(matches[1], 64)
if err != nil {
return 0, fmt.Errorf("invalid time interval `%s`", durStr)
}
switch matches[2] {
case "", "s":
return base, nil
case "m":
return base * 60, nil
case "h":
return base * 60 * 60, nil
case "d":
return base * 60 * 60 * 24, nil
default:
return 0, fmt.Errorf("invalid time interval `%s`", durStr)
}
}