Skip to content

Commit 1cf9852

Browse files
authored
cmd/testscript: add support to pass through env vars with -e (#54)
1 parent 2ea7272 commit 1cf9852

File tree

5 files changed

+302
-13
lines changed

5 files changed

+302
-13
lines changed

cmd/testscript/help.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ The testscript command runs github.com/rogpeppe/go-internal/testscript scripts
1414
in a fresh temporary work directory tree.
1515
1616
Usage:
17-
testscript [-v] files...
17+
testscript [-v] [-e VAR]... files...
1818
1919
The testscript command is designed to make it easy to create self-contained
2020
reproductions of command sequences.
@@ -31,6 +31,11 @@ proxy server. See the documentation for
3131
github.com/rogpeppe/go-internal/goproxytest for details on the format of these
3232
files/directories.
3333
34+
Environment variables can be passed through to each script with the -e flag,
35+
where VAR is the name of the variable. Variables override testscript-defined
36+
values, with the exception of WORK which cannot be overridden. The -e flag can
37+
appear multiple times to specify multiple variables.
38+
3439
Examples
3540
========
3641

cmd/testscript/main.go

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ const (
2828
goModProxyDir = ".gomodproxy"
2929
)
3030

31+
type envVarsFlag struct {
32+
vals []string
33+
}
34+
35+
func (e *envVarsFlag) String() string {
36+
return fmt.Sprintf("%v", e.vals)
37+
}
38+
39+
func (e *envVarsFlag) Set(v string) error {
40+
e.vals = append(e.vals, v)
41+
return nil
42+
}
43+
3144
func main() {
3245
os.Exit(main1())
3346
}
@@ -49,8 +62,10 @@ func mainerr() (retErr error) {
4962
fs.Usage = func() {
5063
mainUsage(os.Stderr)
5164
}
65+
var envVars envVarsFlag
5266
fWork := fs.Bool("work", false, "print temporary work directory and do not remove when done")
5367
fVerbose := fs.Bool("v", false, "run tests verbosely")
68+
fs.Var(&envVars, "e", "pass through environment variable to script (can appear multiple times)")
5469
if err := fs.Parse(os.Args[1:]); err != nil {
5570
return err
5671
}
@@ -77,7 +92,7 @@ func mainerr() (retErr error) {
7792
if err := os.Mkdir(runDir, 0777); err != nil {
7893
return fmt.Errorf("failed to create a run directory within %v for %v: %v", td, fileName, err)
7994
}
80-
if err := run(runDir, fileName, *fVerbose); err != nil {
95+
if err := run(runDir, fileName, *fVerbose, envVars.vals); err != nil {
8196
return err
8297
}
8398
}
@@ -127,7 +142,7 @@ func (r runner) Verbose() bool {
127142
return r.verbose
128143
}
129144

130-
func run(runDir, fileName string, verbose bool) error {
145+
func run(runDir, fileName string, verbose bool, envVars []string) error {
131146
var ar *txtar.Archive
132147
var err error
133148

@@ -184,26 +199,44 @@ func run(runDir, fileName string, verbose bool) error {
184199
}
185200
}
186201

187-
if len(gomodProxy.Files) > 0 {
188-
srv, err := goproxytest.NewServer(mods, "")
189-
if err != nil {
190-
return fmt.Errorf("cannot start proxy for %v: %v", fileName, err)
191-
}
192-
defer srv.Close()
193-
202+
addSetup := func(f func(env *testscript.Env) error) {
194203
origSetup := p.Setup
195-
196204
p.Setup = func(env *testscript.Env) error {
197205
if origSetup != nil {
198206
if err := origSetup(env); err != nil {
199207
return err
200208
}
201209
}
210+
return f(env)
211+
}
212+
}
213+
214+
if len(gomodProxy.Files) > 0 {
215+
srv, err := goproxytest.NewServer(mods, "")
216+
if err != nil {
217+
return fmt.Errorf("cannot start proxy for %v: %v", fileName, err)
218+
}
219+
defer srv.Close()
220+
221+
addSetup(func(env *testscript.Env) error {
202222
// Add GOPROXY after calling the original setup
203223
// so that it overrides any GOPROXY set there.
204224
env.Vars = append(env.Vars, "GOPROXY="+srv.URL)
205225
return nil
206-
}
226+
})
227+
}
228+
229+
if len(envVars) > 0 {
230+
addSetup(func(env *testscript.Env) error {
231+
for _, v := range envVars {
232+
if v == "WORK" {
233+
// cannot override WORK
234+
continue
235+
}
236+
env.Vars = append(env.Vars, v+"="+os.Getenv(v))
237+
}
238+
return nil
239+
})
207240
}
208241

209242
r := runner{

cmd/testscript/main_test.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ import (
1010
"os"
1111
"os/exec"
1212
"path/filepath"
13+
"runtime"
1314
"strings"
1415
"testing"
1516

1617
"github.com/rogpeppe/go-internal/gotooltest"
18+
"github.com/rogpeppe/go-internal/internal/os/execpath"
1719
"github.com/rogpeppe/go-internal/testscript"
1820
)
1921

@@ -24,6 +26,10 @@ func TestMain(m *testing.M) {
2426
}
2527

2628
func TestScripts(t *testing.T) {
29+
if _, err := exec.LookPath("go"); err != nil {
30+
t.Fatalf("need go in PATH for these tests")
31+
}
32+
2733
var stderr bytes.Buffer
2834
cmd := exec.Command("go", "env", "GOMOD")
2935
cmd.Stderr = &stderr
@@ -46,7 +52,9 @@ func TestScripts(t *testing.T) {
4652
return nil
4753
},
4854
Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){
49-
"unquote": unquote,
55+
"unquote": unquote,
56+
"dropgofrompath": dropgofrompath,
57+
"setfilegoproxy": setfilegoproxy,
5058
},
5159
}
5260
if err := gotooltest.Setup(&p); err != nil {
@@ -69,3 +77,36 @@ func unquote(ts *testscript.TestScript, neg bool, args []string) {
6977
ts.Check(err)
7078
}
7179
}
80+
81+
func dropgofrompath(ts *testscript.TestScript, neg bool, args []string) {
82+
if neg {
83+
ts.Fatalf("unsupported: ! dropgofrompath")
84+
}
85+
var newPath []string
86+
for _, d := range filepath.SplitList(ts.Getenv("PATH")) {
87+
getenv := func(k string) string {
88+
if k == "PATH" {
89+
return d
90+
}
91+
return ts.Getenv(k)
92+
}
93+
if _, err := execpath.Look("go", getenv); err != nil {
94+
newPath = append(newPath, d)
95+
}
96+
}
97+
ts.Setenv("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
98+
}
99+
100+
func setfilegoproxy(ts *testscript.TestScript, neg bool, args []string) {
101+
if neg {
102+
ts.Fatalf("unsupported: ! setfilegoproxy")
103+
}
104+
path := args[0]
105+
path = filepath.ToSlash(path)
106+
// probably sufficient to just handle spaces
107+
path = strings.Replace(path, " ", "%20", -1)
108+
if runtime.GOOS == "windows" {
109+
path = "/" + path
110+
}
111+
ts.Setenv("GOPROXY", "file://"+path)
112+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Test passing environment variables to scripts with no go command on PATH
2+
#
3+
# This is the counterpart to env_var_with_go.txt
4+
5+
unquote noproxy.txt
6+
unquote withproxy.txt
7+
dropgofrompath
8+
9+
env BANANA=banana
10+
env GOPATH=$WORK/ourgopath
11+
12+
env GOPROXY=
13+
14+
# no GOPROXY, no pass-through, no proxy
15+
testscript -v noproxy.txt
16+
stdout ^BANANA=$
17+
stdout ^GOPATH=$
18+
stdout ^GOPROXY=$
19+
! stderr .+
20+
21+
# no GOPROXY, no pass-through, with proxy
22+
testscript -v withproxy.txt
23+
stdout ^BANANA=$
24+
stdout ^GOPATH=$
25+
stdout ^GOPROXY=http://.*/mod$
26+
! stderr .+
27+
28+
# no GOPROXY, with pass-through, no proxy
29+
testscript -v -e BANANA -e GOPATH -e GOPROXY noproxy.txt
30+
stdout ^BANANA=banana$
31+
stdout ^GOPATH=${WORK@R}[/\\]ourgopath$
32+
stdout ^GOPROXY=$
33+
! stderr .+
34+
35+
# no GOPROXY, with pass-through, with proxy
36+
testscript -v -e BANANA -e GOPATH -e GOPROXY withproxy.txt
37+
stdout ^BANANA=banana$
38+
stdout ^GOPATH=${WORK@R}[/\\]ourgopath$
39+
stdout ^GOPROXY=$
40+
! stderr .+
41+
42+
setfilegoproxy $WORK/proxy
43+
44+
# with GOPROXY, no pass-through, no proxy
45+
testscript -v noproxy.txt
46+
stdout ^BANANA=$
47+
stdout ^GOPATH=$
48+
stdout ^GOPROXY=$
49+
! stderr .+
50+
51+
# with GOPROXY, no pass-through, with proxy
52+
testscript -v withproxy.txt
53+
stdout ^BANANA=$
54+
stdout ^GOPATH=$
55+
stdout ^GOPROXY=http://.*/mod$
56+
! stderr .+
57+
58+
# with GOPROXY, with pass-through, no proxy
59+
testscript -v -e BANANA -e GOPATH -e GOPROXY noproxy.txt
60+
stdout ^BANANA=banana$
61+
stdout ^GOPATH=${WORK@R}[/\\]ourgopath$
62+
stdout ^GOPROXY=$GOPROXY$
63+
! stderr .+
64+
65+
# with GOPROXY, with pass-through, with proxy
66+
testscript -v -e BANANA -e GOPATH -e GOPROXY withproxy.txt
67+
stdout ^BANANA=banana$
68+
stdout ^GOPATH=${WORK@R}[/\\]ourgopath$
69+
stdout ^GOPROXY=$GOPROXY$
70+
! stderr .+
71+
72+
-- noproxy.txt --
73+
>env BANANA
74+
>env GOPATH
75+
>env GOPROXY
76+
77+
-- withproxy.txt --
78+
>env BANANA
79+
>env GOPATH
80+
>env GOPROXY
81+
82+
>-- .gomodproxy/fruit.com_v1.0.0/.mod --
83+
>module fruit.com
84+
>
85+
>-- .gomodproxy/fruit.com_v1.0.0/.info --
86+
>{"Version":"v1.0.0","Time":"2018-10-22T18:45:39Z"}
87+
>
88+
>-- .gomodproxy/fruit.com_v1.0.0/go.mod --
89+
>module fruit.com
90+
>
91+
>-- .gomodproxy/fruit.com_v1.0.0/fruit/fruit.go --
92+
>package fruit
93+
>
94+
>const Apple = "apple"
95+
>-- .gomodproxy/fruit.com_v1.0.0/coretest/coretest.go --
96+
>// package coretest becomes a candidate for the missing
97+
>// core import in main above
98+
>package coretest
99+
>
100+
>const Mandarin = "mandarin"

0 commit comments

Comments
 (0)