Content-Length: 576371 | pFad | http://github.com/go-cmd/cmd/commit/bb29a473728d0935abd87c4969bbbbca328ef557

61 Rework Cmd.Options as Options.SetCmd · go-cmd/cmd@bb29a47 · GitHub
Skip to content

Commit bb29a47

Browse files
Rework Cmd.Options as Options.SetCmd
1 parent 6480229 commit bb29a47

File tree

3 files changed

+96
-19
lines changed

3 files changed

+96
-19
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# go-cmd/cmd Changelog
22

3+
## v1.4
4+
5+
### v1.4.0
6+
7+
* Added `Options.SetCmd` based on PR #53 #54 by @wenerme
8+
39
## v1.3
410

511
### v1.3.1 (2021-10-13)

cmd.go

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,37 @@ import (
5353
"time"
5454
)
5555

56-
// Apply ExecCmdOption before process start, used for customize SysProcAttr.
57-
type ExecCmdOption func(cmd *exec.Cmd)
58-
5956
// Cmd represents an external command, similar to the Go built-in os/exec.Cmd.
6057
// A Cmd cannot be reused after calling Start. Exported fields are read-only and
6158
// should not be modified, except Env which can be set before calling Start.
6259
// To create a new Cmd, call NewCmd or NewCmdOptions.
6360
type Cmd struct {
64-
Name string
65-
Args []string
66-
Env []string
67-
Dir string
68-
Options []ExecCmdOption
69-
Stdout chan string // streaming STDOUT if enabled, else nil (see Options)
70-
Stderr chan string // streaming STDERR if enabled, else nil (see Options)
61+
// Name of binary (command) to run. This is the only required value.
62+
// No path expansion is done.
63+
// Used to set underlying os/exec.Cmd.Path.
64+
Name string
65+
66+
// Commands line arguments passed to the command.
67+
// Args are optional.
68+
// Used to set underlying os/exec.Cmd.Args.
69+
Args []string
70+
71+
// Environment variables set before running the command.
72+
// Env is optional.
73+
Env []string
74+
75+
// Current working directory from which to run the command.
76+
// Dir is optional; default is current working directory
77+
// of calling process.
78+
// Used to set underlying os/exec.Cmd.Dir.
79+
Dir string
80+
81+
// Stdout sets streaming STDOUT if enabled, else nil (see Options).
82+
Stdout chan string
83+
84+
// Stderr sets streaming STDERR if enabled, else nil (see Options).
85+
Stderr chan string
86+
7187
*sync.Mutex
7288
started bool // cmd.Start called, no error
7389
stopped bool // Stop called
@@ -81,9 +97,11 @@ type Cmd struct {
8197
status Status
8298
statusChan chan Status // nil until Start() called
8399
doneChan chan struct{} // closed when done running
100+
setCmdFuncs []func(cmd *exec.Cmd)
84101
}
85102

86103
var (
104+
// ErrNotStarted is returned by Stop if called before Start or StartWithStdin.
87105
ErrNotStarted = errors.New("command not running")
88106
)
89107

@@ -134,14 +152,20 @@ type Options struct {
134152
// faster and more efficient than polling Cmd.Status. The caller must read both
135153
// streaming channels, else lines are dropped silently.
136154
Streaming bool
155+
156+
// SetCmd is a list of callbacks to customize the underlying os/exec.Cmd.
157+
// For example, use it to set SysProcAttr. All callbacks are called once,
158+
// just before running the command.
159+
SetCmd []func(cmd *exec.Cmd)
137160
}
138161

139162
// NewCmdOptions creates a new Cmd with options. The command is not started
140163
// until Start is called.
141164
func NewCmdOptions(options Options, name string, args ...string) *Cmd {
142165
c := &Cmd{
143-
Name: name,
144-
Args: args,
166+
Name: name,
167+
Args: args,
168+
// --
145169
Mutex: &sync.Mutex{},
146170
status: Status{
147171
Cmd: name,
@@ -167,6 +191,16 @@ func NewCmdOptions(options Options, name string, args ...string) *Cmd {
167191
c.stderrStream = NewOutputStream(c.Stderr)
168192
}
169193

194+
if len(options.SetCmd) > 0 {
195+
c.setCmdFuncs = []func(cmd *exec.Cmd){}
196+
for _, f := range options.SetCmd {
197+
if f == nil {
198+
continue
199+
}
200+
c.setCmdFuncs = append(c.setCmdFuncs, f)
201+
}
202+
}
203+
170204
return c
171205
}
172206

@@ -185,7 +219,14 @@ func (c *Cmd) Clone() *Cmd {
185219
)
186220
clone.Dir = c.Dir
187221
clone.Env = c.Env
188-
clone.Options = c.Options
222+
223+
if len(c.setCmdFuncs) > 0 {
224+
clone.setCmdFuncs = make([]func(cmd *exec.Cmd), len(c.setCmdFuncs))
225+
for i := range c.setCmdFuncs {
226+
clone.setCmdFuncs[i] = c.setCmdFuncs[i]
227+
}
228+
}
229+
189230
return clone
190231
}
191232

@@ -374,7 +415,9 @@ func (c *Cmd) run(in io.Reader) {
374415
// is nil, use the current process' environment.
375416
cmd.Env = c.Env
376417
cmd.Dir = c.Dir
377-
for _, f := range c.Options {
418+
419+
// Run all optional commands to customize underlying os/exe.Cmd.
420+
for _, f := range c.setCmdFuncs {
378421
f(cmd)
379422
}
380423

cmd_test.go

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,14 +1128,42 @@ func TestStdinOk(t *testing.T) {
11281128
}
11291129
}
11301130

1131-
func TestExecCCmdOptions(t *testing.T) {
1132-
p := cmd.NewCmd("/bin/ls")
1131+
func TestOptionsSetCmd(t *testing.T) {
11331132
handled := false
1134-
p.Options = append(p.Options, func(cmd *exec.Cmd) {
1135-
handled = true
1136-
})
1133+
p := cmd.NewCmdOptions(
1134+
cmd.Options{
1135+
SetCmd: []func(cmd *exec.Cmd){
1136+
func(cmd *exec.Cmd) { handled = true },
1137+
},
1138+
},
1139+
"/bin/ls",
1140+
)
1141+
<-p.Start()
1142+
if !handled {
1143+
t.Error("exec cmd option not applied")
1144+
}
1145+
1146+
// nil funcs should be ignored, not cause a panic
1147+
handled = false
1148+
p = cmd.NewCmdOptions(
1149+
cmd.Options{
1150+
SetCmd: []func(cmd *exec.Cmd){
1151+
nil,
1152+
func(cmd *exec.Cmd) { handled = true },
1153+
},
1154+
},
1155+
"/bin/ls",
1156+
)
11371157
<-p.Start()
11381158
if !handled {
11391159
t.Error("exec cmd option not applied")
11401160
}
1161+
1162+
// Cloning should copy the funcs
1163+
handled = false
1164+
p2 := p.Clone()
1165+
<-p2.Start()
1166+
if !handled {
1167+
t.Error("exec cmd option not applied")
1168+
}
11411169
}

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/go-cmd/cmd/commit/bb29a473728d0935abd87c4969bbbbca328ef557

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy