veyron/lib/modules: introduce sh.StartExternalCommand
This CL splits up the shell.Start function into shell.Start and
shell.StartExternalCommand. This allows users (such as the e2e tests) to
run commands that have not been pre-registered. The shell will not
attempt to run these commands in the envelope.
Change-Id: I920b6172e6750aa3e6de4c031d5dd5e3fef95936
diff --git a/lib/modules/shell.go b/lib/modules/shell.go
index c80aae7..c6cd898 100644
--- a/lib/modules/shell.go
+++ b/lib/modules/shell.go
@@ -37,6 +37,7 @@
package modules
import (
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -213,6 +214,14 @@
return registry.help(command)
}
+func (sh *Shell) StartExternalCommand(env []string, args ...string) (Handle, error) {
+ if len(args) == 0 {
+ return nil, errors.New("no arguments specified to StartExternalCommand")
+ }
+ c := newExecHandleForExternalCommand(args[0])
+ return sh.startCommand(c, env, args...)
+}
+
// Start starts the specified command, it returns a Handle which can be
// used for interacting with that command.
//
@@ -236,6 +245,26 @@
// Commands must have already been registered using RegisterFunction
// or RegisterChild.
func (sh *Shell) Start(name string, env []string, args ...string) (Handle, error) {
+ cmd := registry.getCommand(name)
+ if cmd == nil {
+ return nil, fmt.Errorf("%s: not registered", name)
+ }
+ expanded := append([]string{name}, sh.expand(args...)...)
+ c := cmd.factory()
+ h, err := sh.startCommand(c, env, expanded...)
+ if err != nil {
+ // If the error is a timeout, then h can be used to recover
+ // any output from the process.
+ return h, err
+ }
+
+ if err := h.WaitForReady(sh.waitTimeout); err != nil {
+ return h, err
+ }
+ return h, nil
+}
+
+func (sh *Shell) startCommand(c command, env []string, args ...string) (Handle, error) {
cenv, err := sh.setupCommandEnv(env)
if err != nil {
return nil, err
@@ -244,16 +273,10 @@
if err != nil {
return nil, err
}
- cmd := registry.getCommand(name)
- if cmd == nil {
- return nil, fmt.Errorf("%s: not registered", name)
- }
- expanded := append([]string{name}, sh.expand(args...)...)
- h, err := cmd.factory().start(sh, p, cenv, expanded...)
+
+ h, err := c.start(sh, p, cenv, args...)
if err != nil {
- // If the error is a timeout, then h can be used to recover
- // any output from the process.
- return h, err
+ return nil, err
}
sh.mu.Lock()
sh.handles[h] = struct{}{}
@@ -459,6 +482,11 @@
// Pid returns the pid of the process running the command
Pid() int
+
+ // WaitForReady waits until the child process signals to us that it is
+ // ready. If this does not occur within the given timeout duration, a
+ // timeout error is returned.
+ WaitForReady(timeout time.Duration) error
}
// command is used to abstract the implementations of inprocess and subprocess