Skip to content

Commit 0b88314

Browse files
Add initial http and daemon support. Add nocache flag
1 parent 78917b2 commit 0b88314

File tree

8 files changed

+365
-146
lines changed

8 files changed

+365
-146
lines changed

go.mod

+7-9
Original file line numberDiff line numberDiff line change
@@ -17,43 +17,41 @@ require (
1717
github.com/sirupsen/logrus v1.9.3
1818
github.com/spf13/cobra v1.8.0
1919
github.com/stretchr/testify v1.8.4
20-
golang.org/x/sync v0.5.0
20+
golang.org/x/sync v0.6.0
2121
golang.org/x/term v0.16.0
2222
)
2323

2424
require (
2525
github.com/acorn-io/baaah v0.0.0-20240119160309-2a58ee757bbd // indirect
2626
github.com/bombsimon/logrusr/v4 v4.0.0 // indirect
2727
github.com/davecgh/go-spew v1.1.1 // indirect
28-
github.com/fatih/color v1.15.0 // indirect
28+
github.com/fatih/color v1.16.0 // indirect
2929
github.com/go-logr/logr v1.4.1 // indirect
3030
github.com/google/go-cmp v0.6.0 // indirect
3131
github.com/google/go-containerregistry v0.16.1 // indirect
3232
github.com/gorilla/websocket v1.5.0 // indirect
3333
github.com/hexops/gotextdiff v1.0.3 // indirect
3434
github.com/hexops/valast v1.4.3 // indirect
3535
github.com/inconshreveable/mousetrap v1.1.0 // indirect
36-
github.com/kr/pretty v0.3.1 // indirect
3736
github.com/mattn/go-colorable v0.1.13 // indirect
38-
github.com/mattn/go-isatty v0.0.17 // indirect
37+
github.com/mattn/go-isatty v0.0.20 // indirect
3938
github.com/mattn/go-runewidth v0.0.9 // indirect
4039
github.com/nightlyone/lockfile v1.0.0 // indirect
4140
github.com/olekukonko/tablewriter v0.0.5 // indirect
4241
github.com/onsi/ginkgo/v2 v2.13.0 // indirect
4342
github.com/onsi/gomega v1.29.0 // indirect
4443
github.com/pmezard/go-difflib v1.0.0 // indirect
45-
github.com/rogpeppe/go-internal v1.11.0 // indirect
4644
github.com/samber/lo v1.38.1 // indirect
4745
github.com/samber/slog-logrus v1.0.0 // indirect
4846
github.com/spf13/pflag v1.0.5 // indirect
4947
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
5048
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect
51-
golang.org/x/mod v0.14.0 // indirect
52-
golang.org/x/net v0.19.0 // indirect
49+
golang.org/x/mod v0.15.0 // indirect
50+
golang.org/x/net v0.20.0 // indirect
5351
golang.org/x/sys v0.16.0 // indirect
54-
golang.org/x/tools v0.16.0 // indirect
52+
golang.org/x/tools v0.17.0 // indirect
5553
gopkg.in/yaml.v3 v3.0.1 // indirect
5654
k8s.io/klog/v2 v2.110.1 // indirect
57-
mvdan.cc/gofumpt v0.4.0 // indirect
55+
mvdan.cc/gofumpt v0.6.0 // indirect
5856
sigs.k8s.io/controller-runtime v0.16.3 // indirect
5957
)

go.sum

+19-16
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
1414
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
1515
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1616
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
17-
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
18-
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
19-
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
17+
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
18+
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
2019
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
20+
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
21+
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
2122
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
2223
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
2324
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -66,8 +67,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
6667
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
6768
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
6869
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
69-
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
70-
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
70+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
71+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
7172
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
7273
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
7374
github.com/nightlyone/lockfile v1.0.0 h1:RHep2cFKK4PonZJDdEl4GmkabuhbsRMgk/k3uAmxBiA=
@@ -85,8 +86,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
8586
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
8687
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
8788
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
88-
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
89-
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
89+
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
90+
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
9091
github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo=
9192
github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
9293
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -113,20 +114,20 @@ golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcH
113114
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
114115
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
115116
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
116-
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
117-
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
117+
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
118+
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
118119
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
119120
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
120121
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
121122
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
122-
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
123-
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
123+
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
124+
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
124125
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
125126
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
126127
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
127128
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
128-
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
129-
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
129+
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
130+
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
130131
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
131132
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
132133
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -140,6 +141,7 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
140141
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
141142
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
142143
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
144+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
143145
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
144146
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
145147
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -157,8 +159,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
157159
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
158160
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
159161
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
160-
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
161-
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
162+
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
163+
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
162164
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
163165
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
164166
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -171,7 +173,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
171173
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
172174
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
173175
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
174-
mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
175176
mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
177+
mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo=
178+
mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA=
176179
sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4=
177180
sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0=

pkg/engine/cmd.go

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package engine
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"fmt"
8+
"os"
9+
"os/exec"
10+
"strings"
11+
"sync/atomic"
12+
13+
"github.com/google/shlex"
14+
"github.com/gptscript-ai/gptscript/pkg/openai"
15+
"github.com/gptscript-ai/gptscript/pkg/types"
16+
"github.com/gptscript-ai/gptscript/pkg/version"
17+
)
18+
19+
func (e *Engine) runCommand(ctx context.Context, tool types.Tool, input string) (cmdOut string, cmdErr error) {
20+
id := fmt.Sprint(atomic.AddInt64(&completionID, 1))
21+
22+
defer func() {
23+
e.Progress <- openai.Status{
24+
CompletionID: id,
25+
Response: map[string]any{
26+
"output": cmdOut,
27+
"err": cmdErr,
28+
},
29+
}
30+
}()
31+
32+
if tool.BuiltinFunc != nil {
33+
e.Progress <- openai.Status{
34+
CompletionID: id,
35+
Request: map[string]any{
36+
"command": []string{tool.ID},
37+
"input": input,
38+
},
39+
}
40+
return tool.BuiltinFunc(ctx, e.Env, input)
41+
}
42+
43+
cmd, close, err := e.newCommand(ctx, nil, tool.Instructions, input)
44+
if err != nil {
45+
return "", err
46+
}
47+
defer close()
48+
49+
e.Progress <- openai.Status{
50+
CompletionID: id,
51+
Request: map[string]any{
52+
"command": cmd.Args,
53+
"input": input,
54+
},
55+
}
56+
57+
output := &bytes.Buffer{}
58+
cmd.Stdin = strings.NewReader(input)
59+
cmd.Stderr = os.Stderr
60+
cmd.Stdout = output
61+
62+
if err := cmd.Run(); err != nil {
63+
_, _ = os.Stderr.Write(output.Bytes())
64+
log.Errorf("failed to run tool [%s] cmd %v: %v", tool.Name, cmd.Args, err)
65+
return "", err
66+
}
67+
68+
return output.String(), nil
69+
}
70+
71+
func (e *Engine) newCommand(ctx context.Context, extraEnv []string, instructions, input string) (*exec.Cmd, func(), error) {
72+
env := append(e.Env[:], extraEnv...)
73+
data := map[string]any{}
74+
75+
dec := json.NewDecoder(bytes.NewReader([]byte(input)))
76+
dec.UseNumber()
77+
78+
envMap := map[string]string{}
79+
for _, env := range env {
80+
key, value, ok := strings.Cut(env, "=")
81+
key, ok = strings.CutPrefix(key, "GPTSCRIPT_VAR_")
82+
if !ok {
83+
continue
84+
}
85+
envMap[key] = value
86+
}
87+
88+
if err := json.Unmarshal([]byte(input), &data); err == nil {
89+
for k, v := range data {
90+
envName := strings.ToUpper(strings.ReplaceAll(k, "-", "_"))
91+
switch val := v.(type) {
92+
case string:
93+
envMap[envName] = val
94+
env = append(env, envName+"="+val)
95+
envMap[k] = val
96+
env = append(env, k+"="+val)
97+
case json.Number:
98+
envMap[envName] = string(val)
99+
env = append(env, envName+"="+string(val))
100+
envMap[k] = string(val)
101+
env = append(env, k+"="+string(val))
102+
case bool:
103+
envMap[envName] = fmt.Sprint(val)
104+
env = append(env, envName+"="+fmt.Sprint(val))
105+
envMap[k] = fmt.Sprint(val)
106+
env = append(env, k+"="+fmt.Sprint(val))
107+
default:
108+
data, err := json.Marshal(val)
109+
if err == nil {
110+
envMap[envName] = string(data)
111+
env = append(env, envName+"="+string(data))
112+
envMap[k] = string(data)
113+
env = append(env, k+"="+string(data))
114+
}
115+
}
116+
}
117+
}
118+
119+
interpreter, rest, _ := strings.Cut(instructions, "\n")
120+
interpreter = strings.TrimSpace(interpreter)[2:]
121+
122+
interpreter = os.Expand(interpreter, func(s string) string {
123+
return envMap[s]
124+
})
125+
126+
args, err := shlex.Split(interpreter)
127+
if err != nil {
128+
return nil, nil, err
129+
}
130+
131+
var (
132+
cmdArgs = args[1:]
133+
close func()
134+
)
135+
136+
if strings.TrimSpace(rest) != "" {
137+
f, err := os.CreateTemp("", version.ProgramName)
138+
if err != nil {
139+
return nil, nil, err
140+
}
141+
close = func() {
142+
os.Remove(f.Name())
143+
}
144+
145+
_, err = f.Write([]byte(rest))
146+
_ = f.Close()
147+
if err != nil {
148+
close()
149+
return nil, nil, err
150+
}
151+
cmdArgs = append(cmdArgs, f.Name())
152+
}
153+
154+
cmd := exec.CommandContext(ctx, args[0], cmdArgs...)
155+
cmd.Env = env
156+
return cmd, close, nil
157+
}

0 commit comments

Comments
 (0)