MCPcopy Index your code
hub / github.com/coder/coder / sendCommand

Method sendCommand

agent/reconnectingpty/screen.go:338–408  ·  view source on GitHub ↗

sendCommand runs a screen command against a running screen session. If the command fails with an error matching anything in successErrors it will be considered a success state (for example "no session" when quitting and the session is already dead). The command will be retried until successful, th

(ctx context.Context, command string, successErrors []string)

Source from the content-addressed store, hash-verified

336// canceled context's error as-is while a timed-out context returns together
337// with the last error from the command.
338func (rpty *screenReconnectingPTY) sendCommand(ctx context.Context, command string, successErrors []string) error {
339 ctx, cancel := context.WithTimeout(ctx, attachTimeout)
340 defer cancel()
341
342 var lastErr error
343 run := func() (bool, error) {
344 var stdout bytes.Buffer
345 //nolint:gosec
346 cmd := rpty.execer.CommandContext(ctx, "screen",
347 // -x targets an attached session.
348 "-x", rpty.id,
349 // -c is the flag for the config file.
350 "-c", rpty.configFile,
351 // -X runs a command in the matching session.
352 "-X", command,
353 )
354 cmd.Env = withTerminalEnv(rpty.command.Env)
355 cmd.Dir = rpty.command.Dir
356 cmd.Stdout = &stdout
357 err := cmd.Run()
358 if err == nil {
359 return true, nil
360 }
361
362 stdoutStr := stdout.String()
363 for _, se := range successErrors {
364 if strings.Contains(stdoutStr, se) {
365 return true, nil
366 }
367 }
368
369 // Things like "exit status 1" are imprecise so include stdout as it may
370 // contain more information ("no screen session found" for example).
371 if !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) {
372 lastErr = xerrors.Errorf("`screen -x %s -X %s`: %w: %s", rpty.id, command, err, stdoutStr)
373 }
374
375 return false, nil
376 }
377
378 // Run immediately.
379 done, err := run()
380 if err != nil {
381 return err
382 }
383 if done {
384 return nil
385 }
386
387 // Then run on an interval.
388 ticker := time.NewTicker(250 * time.Millisecond)
389 defer ticker.Stop()
390
391 for {
392 select {
393 case <-ctx.Done():
394 if errors.Is(ctx.Err(), context.Canceled) {
395 return ctx.Err()

Callers 2

lifecycleMethod · 0.95
doAttachMethod · 0.95

Calls 11

withTerminalEnvFunction · 0.85
ErrMethod · 0.80
CommandContextMethod · 0.65
RunMethod · 0.65
StopMethod · 0.65
runFunction · 0.50
StringMethod · 0.45
ContainsMethod · 0.45
IsMethod · 0.45
ErrorfMethod · 0.45
DoneMethod · 0.45

Tested by

no test coverage detected