Allow setting working directory for exec.Run

Fixes #536

Closes #537
https://github.com/cuelang/cue/pull/537

GitOrigin-RevId: 5bb80f0ec131e8d1c9cdbe9abdb37429bb1f8359
Change-Id: I4d93e6930c82ea29454b3c53c898b60d70155be6
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9922
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/testdata/script/cmd_dir.txt b/cmd/cue/cmd/testdata/script/cmd_dir.txt
new file mode 100644
index 0000000..5cf6501
--- /dev/null
+++ b/cmd/cue/cmd/testdata/script/cmd_dir.txt
@@ -0,0 +1,28 @@
+cue cmd ls
+cmp stdout expect-stdout
+
+-- expect-stdout --
+a.txt
+b.txt
+
+-- ls-work-dir/a.txt --
+-- ls-work-dir/b.txt --
+
+-- ls_tool.cue --
+package ls
+
+command: ls: {
+    ls: {
+		kind:   "exec"
+		cmd:    "ls"
+		dir:    "ls-work-dir"
+		stdout: string
+	}
+
+	task: display: {
+		kind: "print"
+		text: ls.stdout
+	}
+}
+
+-- cue.mod --
diff --git a/pkg/tool/exec/doc.go b/pkg/tool/exec/doc.go
index d7cb622..ef4e88a 100644
--- a/pkg/tool/exec/doc.go
+++ b/pkg/tool/exec/doc.go
@@ -11,6 +11,10 @@
 //     	// cmd is the command to run.
 //     	cmd: string | [string, ...string]
 //
+//     	// dir specifies the working directory of the command.
+//     	// The default is the current working directory.
+//     	dir?: string
+//
 //     	// env defines the environment variables to use for this system.
 //     	// If the value is a list, the entries mus be of the form key=value,
 //     	// where the last value takes precendence in the case of multiple
diff --git a/pkg/tool/exec/exec.cue b/pkg/tool/exec/exec.cue
index cd9d797..94054bd 100644
--- a/pkg/tool/exec/exec.cue
+++ b/pkg/tool/exec/exec.cue
@@ -21,6 +21,10 @@
 	// cmd is the command to run.
 	cmd: string | [string, ...string]
 
+	// dir specifies the working directory of the command.
+	// The default is the current working directory.
+	dir?: string
+
 	// env defines the environment variables to use for this system.
 	// If the value is a list, the entries mus be of the form key=value,
 	// where the last value takes precendence in the case of multiple
diff --git a/pkg/tool/exec/exec.go b/pkg/tool/exec/exec.go
index 1cec194..2145f14 100644
--- a/pkg/tool/exec/exec.go
+++ b/pkg/tool/exec/exec.go
@@ -137,6 +137,8 @@
 
 	cmd := exec.CommandContext(ctx.Context, bin, args...)
 
+	cmd.Dir, _ = ctx.Obj.Lookup("dir").String()
+
 	env := ctx.Obj.Lookup("env")
 
 	// List case.
diff --git a/pkg/tool/exec/pkg.go b/pkg/tool/exec/pkg.go
index 74d3b7e..7150b0c 100644
--- a/pkg/tool/exec/pkg.go
+++ b/pkg/tool/exec/pkg.go
@@ -20,8 +20,9 @@
 	Native: []*internal.Builtin{},
 	CUE: `{
 	Run: {
-		$id: *"tool/exec.Run" | "exec"
-		cmd: string | [string, ...string]
+		$id:  *"tool/exec.Run" | "exec"
+		cmd:  string | [string, ...string]
+		dir?: string
 		env: {
 			[string]: string | [...=~"="]
 		}