-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathexec.go
More file actions
101 lines (89 loc) · 1.84 KB
/
exec.go
File metadata and controls
101 lines (89 loc) · 1.84 KB
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
100
101
package exec
import (
"bytes"
"errors"
"fmt"
"github.com/shxsun/beelog"
"io/ioutil"
"math/rand"
"os/exec"
"strings"
"time"
)
var ErrInvalid = errors.New("error invalid")
var ErrTimeout = errors.New("error timeout")
var defaultEnvName = "TIMEOUT_EXEC_ID"
type Cmd struct {
Timeout time.Duration
UniqID string
IsClean bool
*exec.Cmd
}
func init() {
beelog.SetLevel(beelog.LevelWarning)
//beelog.SetLevel(beelog.LevelTrace)
}
// create a new instance
func Command(name string, args ...string) *Cmd {
cmd := &Cmd{}
cmd.Cmd = exec.Command(name, args...)
return cmd
}
func (c *Cmd) WaitTimeout(timeout time.Duration) error {
done := make(chan error)
go func() {
done <- c.Wait()
}()
select {
case <-time.After(timeout):
return ErrTimeout
case err := <-done:
return err
}
}
// run command and wait until program exits or timeout
func (c *Cmd) Run() (err error) {
beelog.Info("start run:", c.Args)
// set env flag
if c.IsClean {
if c.UniqID == "" {
c.UniqID = fmt.Sprintf("%d:%d", time.Now().UnixNano(), rand.Int())
}
c.Env = append(c.Env, defaultEnvName+"="+c.UniqID)
}
// start program
if err = c.Start(); err != nil {
return
}
if c.Timeout > time.Duration(0) {
err = c.WaitTimeout(c.Timeout)
} else {
err = c.Wait()
}
if c.IsClean {
c.KillAll()
return
} else if err == ErrTimeout {
c.Process.Kill()
}
return
}
// Output runs the command and returns its standard output.
func (c *Cmd) Output() ([]byte, error) {
if c.Stdout != nil {
return nil, errors.New("exec: Stdout already set")
}
var b bytes.Buffer
c.Stdout = &b
err := c.Run()
return b.Bytes(), err
}
// get spectified pid of environ
func procEnv(pid int) ([]string, error) {
data, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/environ", pid))
if err != nil {
return nil, err
}
envs := strings.Split(string(data), "\x00")
return envs, nil
}