@@ -18,7 +18,7 @@ import (
18
18
"os/user"
19
19
"path/filepath"
20
20
"reflect"
21
- "runtime "
21
+ "regexp "
22
22
"sort"
23
23
"strconv"
24
24
"strings"
@@ -205,9 +205,17 @@ func (a *agent) runLoop(ctx context.Context) {
205
205
}
206
206
}
207
207
208
+ var (
209
+ isCmdExeRe = regexp .MustCompile (`^(cmd|cmd\.exe)$` )
210
+ )
211
+
208
212
func createMetadataCommand (ctx context.Context , script string ) (* exec.Cmd , error ) {
209
213
// This is largely copied from agentssh, but for some reason the command
210
- // generated there always returns exit status 1 in Windows.
214
+ // generated there always returns exit status 1 in Windows powershell.
215
+ //
216
+ // This function puts special PowerShell branching in place that fixes the issue,
217
+ // but I'm hesitant on porting it to agentssh before understanding exactly what's
218
+ // happening.
211
219
currentUser , err := user .Current ()
212
220
if err != nil {
213
221
return nil , xerrors .Errorf ("get current user: %w" , err )
@@ -218,31 +226,28 @@ func createMetadataCommand(ctx context.Context, script string) (*exec.Cmd, error
218
226
if err != nil {
219
227
return nil , xerrors .Errorf ("get user shell: %w" , err )
220
228
}
229
+ shellBase := filepath .Base (shell )
221
230
222
- var caller string
231
+ var args [] string
223
232
switch {
224
- case filepath .Base (shell ) == "pwsh.exe" :
225
- caller = "-Command"
226
- case runtime .GOOS == "windows" :
227
- caller = "/c"
233
+ case isCmdExeRe .MatchString (shellBase ):
234
+ args = append (args , "/c" )
228
235
default :
229
- caller = "-c"
236
+ // -c works for powershell and sh variants.
237
+ args = append (args , "-c" )
230
238
}
231
- // args := []string{caller, "Get-Process"}
232
- args := []string {"-NoProfile" , "-NonInteractive" }
233
- _ = caller
234
- return exec .CommandContext (ctx , "powershell" , args ... ), nil
239
+ args = append (args , script )
240
+ return exec .CommandContext (ctx , shell , args ... ), nil
235
241
}
236
242
237
243
func (* agent ) collectMetadata (ctx context.Context , md codersdk.WorkspaceAgentMetadataDescription ) * codersdk.WorkspaceAgentMetadataResult {
238
244
var out bytes.Buffer
239
245
result := & codersdk.WorkspaceAgentMetadataResult {
240
246
// CollectedAt is set here for testing purposes and overrode by
241
- // the server to the time the server received the result to protect
242
- // against clock skew.
247
+ // coderd to the time of server receipt to solve clock skew.
243
248
//
244
249
// In the future, the server may accept the timestamp from the agent
245
- // if it is certain the clocks are in sync .
250
+ // if it can guarantee the clocks are synchronized .
246
251
CollectedAt : time .Now (),
247
252
}
248
253
cmd , err := createMetadataCommand (ctx , md .Script )
@@ -251,19 +256,11 @@ func (*agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentMet
251
256
return result
252
257
}
253
258
254
- // execPath, err := exec.LookPath("cmd.exe")
255
- // if err != nil {
256
- // result.Error = fmt.Sprintf("look path: %+v", err)
257
- // return result
258
- // }
259
-
260
- // cmd = exec.CommandContext(ctx, execPath, "/c", "echo hello")
261
-
262
259
cmd .Stdout = & out
263
260
cmd .Stderr = & out
264
261
cmd .Stdin = io .LimitReader (nil , 0 )
265
262
266
- // We split up Start and Wait so that we can return a more useful error.
263
+ // We split up Start and Wait instead of calling Run so that we can return a more precise error.
267
264
err = cmd .Start ()
268
265
if err != nil {
269
266
result .Error = fmt .Sprintf ("start cmd: %+v" , err )
@@ -281,10 +278,8 @@ func (*agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentMet
281
278
out .Truncate (bufLimit )
282
279
}
283
280
284
- fmt .Printf ("ran %+v %+q: %v\n " , cmd .Path , cmd .Args , err )
285
-
286
281
if err != nil {
287
- result .Error = fmt .Sprintf ("run cmd: %+v" , err )
282
+ result .Error = fmt .Sprintf ("run cmd (shell %v) : %+v" , cmd . Path , err )
288
283
}
289
284
result .Value = out .String ()
290
285
return result
0 commit comments