Skip to content

Commit 36aefe2

Browse files
Nils WireklintNils Wireklint
authored andcommitted
Share Command Creator for Windows
1 parent d1a4a14 commit 36aefe2

File tree

3 files changed

+37
-92
lines changed

3 files changed

+37
-92
lines changed

pkg/runner/local_runner.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ package runner
33
import (
44
"context"
55
"errors"
6+
"math"
67
"os"
78
"os/exec"
89
"path/filepath"
910
"strings"
11+
"syscall"
1012

1113
"github.com/buildbarn/bb-remote-execution/pkg/proto/runner"
1214
"github.com/buildbarn/bb-storage/pkg/filesystem"
@@ -91,6 +93,37 @@ func (r *localRunner) openLog(logPath string) (filesystem.FileAppender, error) {
9193
// on whether the action needs to be run in a chroot() or not.
9294
type CommandCreator func(ctx context.Context, arguments []string, inputRootDirectory *path.Builder, workingDirectoryParser path.Parser, pathVariable string) (*exec.Cmd, error)
9395

96+
// NewPlainCommandCreator returns a CommandCreator for cases where we don't
97+
// need to chroot into the input root directory.
98+
func NewPlainCommandCreator(sysProcAttr *syscall.SysProcAttr) CommandCreator {
99+
return func(ctx context.Context, arguments []string, inputRootDirectory *path.Builder, workingDirectoryParser path.Parser, pathVariable string) (*exec.Cmd, error) {
100+
workingDirectory, scopeWalker := inputRootDirectory.Join(path.VoidScopeWalker)
101+
if err := path.Resolve(workingDirectoryParser, scopeWalker); err != nil {
102+
return nil, util.StatusWrap(err, "Failed to resolve working directory")
103+
}
104+
workingDirectoryStr, err := path.GetLocalString(workingDirectory)
105+
if err != nil {
106+
return nil, util.StatusWrap(err, "Failed to create local representation of working directory")
107+
}
108+
executablePath, err := lookupExecutable(workingDirectory, pathVariable, arguments[0])
109+
if err != nil {
110+
return nil, err
111+
}
112+
113+
// exec.CommandContext() has some smartness to call
114+
// exec.LookPath() under the hood, which we don't want.
115+
// Call it with a placeholder path, followed by setting
116+
// cmd.Path and cmd.Args manually. This ensures that our
117+
// own values remain respected.
118+
cmd := exec.CommandContext(ctx, "/nonexistent")
119+
cmd.Args = arguments
120+
cmd.Dir = workingDirectoryStr
121+
cmd.Path = executablePath
122+
cmd.SysProcAttr = sysProcAttr
123+
return cmd, nil
124+
}
125+
}
126+
94127
// NewLocalRunner returns a Runner capable of running commands on the
95128
// local system directly.
96129
func NewLocalRunner(buildDirectory filesystem.Directory, buildDirectoryPath *path.Builder, commandCreator CommandCreator, setTmpdirEnvironmentVariable bool) runner.RunnerServer {
@@ -225,7 +258,9 @@ func getExecutablePath(baseDirectory *path.Builder, searchPathStr, argv0 string)
225258
// This operates on platform native paths, or unix-style slash paths.
226259
// The latter are customarily sent by Bazel in multiplatform builds.
227260
func lookupExecutable(workingDirectory *path.Builder, pathVariable, argv0 string) (string, error) {
228-
if strings.ContainsRune(argv0, os.PathSeparator) {
261+
if strings.ContainsFunc(argv0, func(r rune) bool {
262+
return r <= math.MaxUint8 && os.IsPathSeparator(uint8(r))
263+
}) {
229264
// No PATH processing needs to be performed.
230265
return argv0, nil
231266
}

pkg/runner/local_runner_unix.go

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,37 +18,6 @@ import (
1818
"google.golang.org/protobuf/types/known/durationpb"
1919
)
2020

21-
// NewPlainCommandCreator returns a CommandCreator for cases where we don't
22-
// need to chroot into the input root directory.
23-
func NewPlainCommandCreator(sysProcAttr *syscall.SysProcAttr) CommandCreator {
24-
return func(ctx context.Context, arguments []string, inputRootDirectory *path.Builder, workingDirectoryParser path.Parser, pathVariable string) (*exec.Cmd, error) {
25-
workingDirectory, scopeWalker := inputRootDirectory.Join(path.VoidScopeWalker)
26-
if err := path.Resolve(workingDirectoryParser, scopeWalker); err != nil {
27-
return nil, util.StatusWrap(err, "Failed to resolve working directory")
28-
}
29-
workingDirectoryStr, err := path.GetLocalString(workingDirectory)
30-
if err != nil {
31-
return nil, util.StatusWrap(err, "Failed to create local representation of working directory")
32-
}
33-
executablePath, err := lookupExecutable(workingDirectory, pathVariable, arguments[0])
34-
if err != nil {
35-
return nil, err
36-
}
37-
38-
// exec.CommandContext() has some smartness to call
39-
// exec.LookPath() under the hood, which we don't want.
40-
// Call it with a placeholder path, followed by setting
41-
// cmd.Path and cmd.Args manually. This ensures that our
42-
// own values remain respected.
43-
cmd := exec.CommandContext(ctx, "/nonexistent")
44-
cmd.Args = arguments
45-
cmd.Dir = workingDirectoryStr
46-
cmd.Path = executablePath
47-
cmd.SysProcAttr = sysProcAttr
48-
return cmd, nil
49-
}
50-
}
51-
5221
// NewChrootedCommandCreator returns a CommandCreator for cases where we
5322
// need to chroot into the input root directory.
5423
func NewChrootedCommandCreator(sysProcAttr *syscall.SysProcAttr) (CommandCreator, error) {

pkg/runner/local_runner_windows.go

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,81 +4,22 @@
44
package runner
55

66
import (
7-
"context"
87
"os"
98
"os/exec"
10-
"path/filepath"
119
"syscall"
1210

1311
"github.com/buildbarn/bb-remote-execution/pkg/proto/resourceusage"
14-
"github.com/buildbarn/bb-storage/pkg/filesystem/path"
15-
"github.com/buildbarn/bb-storage/pkg/util"
1612

1713
"golang.org/x/sys/windows"
1814
"google.golang.org/grpc/codes"
1915
"google.golang.org/grpc/status"
2016
"google.golang.org/protobuf/types/known/durationpb"
2117
)
2218

23-
// NewPlainCommandCreator returns a CommandCreator for cases where we don't
24-
// need to chroot into the input root directory.
25-
func NewPlainCommandCreator(sysProcAttr *syscall.SysProcAttr) CommandCreator {
26-
return func(ctx context.Context, arguments []string, inputRootDirectory *path.Builder, workingDirectoryParser path.Parser, pathVariable string) (*exec.Cmd, error) {
27-
// TODO: This may not work correctly if the action sets
28-
// the PATH environment variable explicitly.
29-
//
30-
// exec.CommandContext() has some smartness to call
31-
// exec.LookPath() under the hood, which we don't want.
32-
// Call it with a placeholder path, followed by setting
33-
// cmd.Path and cmd.Args manually. This ensures that our
34-
// own values remain respected.
35-
argv0 := arguments[0]
36-
37-
pathBuilder, scopeWalker := path.EmptyBuilder.Join(path.VoidScopeWalker)
38-
if err := path.Resolve(path.NewLocalParser(argv0), scopeWalker); err != nil {
39-
return nil, err
40-
}
41-
argv0, err := pathBuilder.GetWindowsString()
42-
if err != nil {
43-
return nil, err
44-
}
45-
46-
arguments[0] = "\\nonexistent-place-back-later"
47-
cmd := exec.CommandContext(ctx, arguments[0], arguments[1:]...)
48-
cmd.SysProcAttr = sysProcAttr
49-
50-
// Set the working relative to be relative to the input
51-
// root directory.
52-
workingDirectory, scopeWalker := inputRootDirectory.Join(path.VoidScopeWalker)
53-
if err := path.Resolve(workingDirectoryParser, scopeWalker); err != nil {
54-
return nil, util.StatusWrap(err, "Failed to resolve working directory")
55-
}
56-
workingDirectoryStr, err := path.GetLocalString(workingDirectory)
57-
if err != nil {
58-
return nil, util.StatusWrap(err, "Failed to create local representation of working directory")
59-
}
60-
cmd.Dir = workingDirectoryStr
61-
62-
executablePath, err := lookupExecutable(workingDirectory, pathVariable, argv0)
63-
if err != nil {
64-
return nil, err
65-
}
66-
67-
// Must use backslashes to execute relative paths
68-
executablePath = filepath.FromSlash(executablePath)
69-
arguments[0] = executablePath
70-
71-
cmd.Args = arguments
72-
cmd.Path = executablePath
73-
cmd.SysProcAttr = sysProcAttr
74-
return cmd, nil
75-
}
76-
}
77-
7819
// NewChrootedCommandCreator gives an error on Windows, as chroot is not
7920
// supported on the platform.
8021
func NewChrootedCommandCreator(sysProcAttr *syscall.SysProcAttr) (CommandCreator, error) {
81-
return nil, status.Error(codes.InvalidArgument, "Chroot not supported on Windows")
22+
return nil, status.Error(codes.InvalidArgument, "Chroot is not supported on Windows")
8223
}
8324

8425
var temporaryDirectoryEnvironmentVariablePrefixes = [...]string{"TMP=", "TEMP="}

0 commit comments

Comments
 (0)