Esempio n. 1
0
func newCmd(sh *Shell, vars map[string]string, name string, args ...string) (*Cmd, error) {
	// Mimics https://golang.org/src/os/exec/exec.go Command.
	if filepath.Base(name) == name {
		lp, err := lookpath.Look(sh.Vars, name)
		if err != nil {
			return nil, fmt.Errorf("gosh: failed to locate executable: %s", name)
		}
		name = lp
	}
	return newCmdInternal(sh, vars, name, args)
}
Esempio n. 2
0
// execute executes the binary pointed to by the given path using the given
// arguments and options. If the wait flag is set, the function waits for the
// completion of the binary and the timeout value can optionally specify for
// how long should the function wait before timing out.
func (e *executor) execute(wait bool, timeout time.Duration, opts opts, path string, args ...string) (*exec.Cmd, error) {
	e.increaseIndent()
	defer e.decreaseIndent()

	// Check if <path> identifies a binary in the PATH environment
	// variable of the opts.Env.
	if binary, err := lookpath.Look(opts.env, path); err == nil {
		// If so, make sure to execute this binary. This step
		// enables us to "shadow" binaries included in the
		// PATH environment variable of the host OS (which
		// would be otherwise used to lookup <path>).
		//
		// This mechanism is used instead of modifying the
		// PATH environment variable of the host OS as the
		// latter is not thread-safe.
		path = binary
	}
	command := exec.Command(path, args...)
	command.Dir = opts.dir
	command.Stdin = opts.stdin
	command.Stdout = opts.stdout
	command.Stderr = opts.stderr
	command.Env = envvar.MapToSlice(opts.env)
	if out := e.verboseStdout(opts); out != ioutil.Discard {
		args := []string{}
		for _, arg := range command.Args {
			// Quote any arguments that contain '"', ''', '|', or ' '.
			if strings.IndexAny(arg, "\"' |") != -1 {
				args = append(args, strconv.Quote(arg))
			} else {
				args = append(args, arg)
			}
		}
		e.printf(out, strings.Replace(strings.Join(args, " "), "%", "%%", -1))
	}

	var err error
	switch {
	case !wait:
		err = command.Start()
		e.printf(e.verboseStdout(opts), okOrFailed(err))

	case timeout == 0:
		err = command.Run()
		e.printf(e.verboseStdout(opts), okOrFailed(err))
	default:
		err = e.timedCommand(timeout, opts, command)
		// Verbose output handled in timedCommand.
	}
	return command, err
}
Esempio n. 3
0
func TestLook(t *testing.T) {
	tmpDir, cleanup := initTmpDir(t)
	defer cleanup()
	dirA, dirB := mkdir(t, tmpDir, "a"), mkdir(t, tmpDir, "b")
	aFoo, aBar := mkfile(t, dirA, "foo", 0755), mkfile(t, dirA, "bar", 0755)
	bBar, bBaz := mkfile(t, dirB, "bar", 0755), mkfile(t, dirB, "baz", 0755)
	aExe, bExe := mkfile(t, dirA, "exe", 0644), mkfile(t, dirB, "exe", 0755)
	tests := []struct {
		Env  map[string]string
		Name string
		Want string
	}{
		{nil, "", ""},
		{nil, "foo", ""},
		{pathEnv(dirA), "foo", aFoo},
		{pathEnv(dirA), "bar", aBar},
		{pathEnv(dirA), "baz", ""},
		{pathEnv(dirB), "foo", ""},
		{pathEnv(dirB), "bar", bBar},
		{pathEnv(dirB), "baz", bBaz},
		{pathEnv(dirA, dirB), "foo", aFoo},
		{pathEnv(dirA, dirB), "bar", aBar},
		{pathEnv(dirA, dirB), "baz", bBaz},
		// Make sure we find bExe, since aExe isn't executable.
		{pathEnv(dirA, dirB), "exe", bExe},
		// Absolute name lookups.
		{nil, dirA, ""},
		{nil, dirB, ""},
		{nil, aFoo, aFoo},
		{nil, aBar, aBar},
		{nil, bBar, bBar},
		{nil, bBaz, bBaz},
		{nil, aExe, ""},
		{nil, bExe, bExe},
	}
	for _, test := range tests {
		hdr := fmt.Sprintf("env=%v name=%v", test.Env, test.Name)
		look, err := lookpath.Look(test.Env, test.Name)
		if got, want := look, test.Want; got != want {
			t.Errorf("%s got %v, want %v", hdr, got, want)
		}
		if (look == "") == (err == nil) {
			t.Errorf("%s got mismatched look=%v err=%v", hdr, look, err)
		}
		if err != nil && !isNotFoundError(err, test.Name) {
			t.Errorf("%s got wrong error %v", hdr, err)
		}
	}
}