77 "os/exec"
88 "sync"
99
10+ "github.com/mattn/go-shellwords"
1011 "golang.org/x/sync/errgroup"
1112 "golang.org/x/sync/semaphore"
1213 "golang.org/x/sys/execabs"
@@ -109,18 +110,36 @@ func (proc *concurrentProcess) wait() {
109110// newCommandRunner creates new external command runner for given executable. The executable path
110111// is resolved in this function.
111112func (proc * concurrentProcess ) newCommandRunner (exe string , combineOutput bool ) (* externalCommand , error ) {
112- p , err := execabs .LookPath (exe )
113+ var args []string
114+ p , args , err := findExe (exe )
113115 if err != nil {
114116 return nil , err
115117 }
116118 cmd := & externalCommand {
117119 proc : proc ,
118120 exe : p ,
121+ args : args ,
119122 combineOutput : combineOutput ,
120123 }
121124 return cmd , nil
122125}
123126
127+ func findExe (exe string ) (string , []string , error ) {
128+ p , err := execabs .LookPath (exe )
129+ if err == nil {
130+ return p , nil , nil
131+ }
132+ // See if the command string contains args. As it is best effort, we do not
133+ // handle parse errors.
134+ if exeArgs , _ := shellwords .Parse (exe ); len (exeArgs ) > 0 {
135+ if p , err := execabs .LookPath (exeArgs [0 ]); err == nil {
136+ return p , exeArgs [1 :], nil
137+ }
138+ }
139+
140+ return "" , nil , err
141+ }
142+
124143// externalCommand is struct to run specific command concurrently with concurrentProcess bounding
125144// number of processes at the same time. This type manages fatal errors while running the command
126145// by using errgroup.Group. The wait() method must be called at the end for checking if some fatal
@@ -129,13 +148,20 @@ type externalCommand struct {
129148 proc * concurrentProcess
130149 eg errgroup.Group
131150 exe string
151+ args []string
132152 combineOutput bool
133153}
134154
135155// run runs the command with given arguments and stdin. The callback function is called after the
136156// process runs. First argument is stdout and the second argument is an error while running the
137157// process.
138158func (cmd * externalCommand ) run (args []string , stdin string , callback func ([]byte , error ) error ) {
159+ if len (cmd .args ) > 0 {
160+ var allArgs []string
161+ allArgs = append (allArgs , cmd .args ... )
162+ allArgs = append (allArgs , args ... )
163+ args = allArgs
164+ }
139165 exec := & cmdExecution {cmd .exe , args , stdin , cmd .combineOutput }
140166 cmd .proc .run (& cmd .eg , exec , callback )
141167}
0 commit comments