-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcmdio.go
144 lines (117 loc) · 2.41 KB
/
cmdio.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package cmdio
import (
"io"
"os"
"os/exec"
"sync/atomic"
"syscall"
"github.com/l4go/task"
)
type CmdPipe struct {
cmd *exec.Cmd
pr io.ReadCloser
pw io.WriteCloser
cc task.Canceller
do_wait uint32
err error
}
func (self *CmdPipe) Read(p []byte) (int, error) {
return self.pr.Read(p)
}
func (self *CmdPipe) Write(p []byte) (int, error) {
return self.pw.Write(p)
}
func Exec(cc task.Canceller, cmd string, arg ...string) (*CmdPipe, error) {
self := &CmdPipe{
cmd: exec.CommandContext(cc.AsContext(), cmd, arg...),
cc: task.NewCancel(),
}
atomic.StoreUint32(&self.do_wait, 0)
var err error
var pr io.ReadCloser
var pw io.WriteCloser
pr, err = self.cmd.StdoutPipe()
if err != nil {
return nil, err
}
pw, err = self.cmd.StdinPipe()
if err != nil {
return nil, err
}
self.cmd.Stderr = os.Stderr
self.pr = pr
self.pw = pw
err = self.cmd.Start()
if err != nil {
return nil, err
}
return self, nil
}
func (self *CmdPipe) RecvWait() <-chan struct{} {
return self.cc.RecvCancel()
}
func (self *CmdPipe) Wait() error {
<-self.cc.RecvCancel()
return self.err
}
func (self *CmdPipe) Process() *os.Process {
return self.cmd.Process
}
func (self *CmdPipe) Signal(sig os.Signal) error {
return self.cmd.Process.Signal(sig)
}
func (self *CmdPipe) ReaderClose() error {
err := self.pr.Close()
once_wait := atomic.SwapUint32(&self.do_wait, 1)
if once_wait == 0 {
go func() {
self.err = self.cmd.Wait()
self.cc.Cancel()
}()
}
return err
}
func (self *CmdPipe) WriterClose() error {
return self.pw.Close()
}
func (self *CmdPipe) Close() error {
err := self.WriterClose()
self.ReaderClose()
self.cmd.Process.Kill()
return err
}
type StdPipe struct {
pr io.ReadCloser
pw io.WriteCloser
}
func StdDup() (*StdPipe, error) {
in, err := sys_dup(syscall.Stdin)
if err != nil {
return nil, err
}
out, err := sys_dup(syscall.Stdout)
if err != nil {
return nil, err
}
return &StdPipe{
pr: os.NewFile(uintptr(in), "dup stdin"),
pw: os.NewFile(uintptr(out), "dup stdout"),
}, nil
}
func (self *StdPipe) Read(p []byte) (int, error) {
return self.pr.Read(p)
}
func (self *StdPipe) Write(p []byte) (int, error) {
return self.pw.Write(p)
}
func (self *StdPipe) Close() error {
self.pw.Close()
self.pr.Close()
return nil
}
func (self *StdPipe) ReaderClose() error {
return self.pr.Close()
}
func (self *StdPipe) WriterClose() error {
return self.pw.Close()
}