-
Notifications
You must be signed in to change notification settings - Fork 0
/
recorder.go
97 lines (74 loc) · 1.87 KB
/
recorder.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
package recmd
import (
"fmt"
"io"
"os"
"os/exec"
"os/signal"
"syscall"
"github.com/scaxyz/recmd/timedpipe"
)
type Recorder struct{}
// NewRecorder creates a new Recorder.
//
// It takes no parameters and returns a pointer to a Recorder.
func NewRecorder() *Recorder {
return &Recorder{}
}
// Record records a command and returns a Record object with the command's output and error.
//
// cmdStr: the command to be executed.
// Returns a pointer to the Record object and an error.
func (r *Recorder) Record(cmdStr string, input io.Reader, args ...string) (Record, error) {
if cmdStr == "" {
return nil, fmt.Errorf("empty command")
}
cmd := exec.Command(cmdStr, args...)
record, err := r.RecordCmd(cmd, input)
if err != nil {
return nil, err
}
return record, nil
}
func (*Recorder) RecordCmd(cmd *exec.Cmd, input io.Reader) (Record, error) {
if cmd == nil {
return nil, fmt.Errorf("empty command")
}
errP := timedpipe.New(timedpipe.WithOutput(os.Stderr), timedpipe.StartNow())
outP := timedpipe.New(timedpipe.WithOutput(os.Stdout), timedpipe.StartNow())
inP := timedpipe.New(timedpipe.WithInput(input), timedpipe.StartNow())
cmd.Stderr = errP
cmd.Stdout = outP
if input != nil {
cmd.Stdin = inP
}
record := &ByteRecord{
Cmd: cmd.String(),
Out: outP.GetWriteData(),
In: inP.GetReadData(),
Err: errP.GetWriteData(),
JsonFormat: FormatBase64,
}
stopChan := make(chan os.Signal, 2)
signal.Notify(stopChan, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
doneChan := make(chan error)
go func() {
err := cmd.Run()
doneChan <- err
}()
var err error
select {
case interrupt := <-stopChan:
cmd.Process.Signal(interrupt)
case err = <-doneChan:
break
}
record.ExitC = cmd.ProcessState.ExitCode()
if _, ok := err.(*exec.ExitError); ok {
err = nil
}
if err != nil {
return nil, err
}
return record, nil
}