Exec executes a given command in the container of given type without allocating a pty Returns ComposeCmd results of stdout, stderr, err If Nocapture arg is true, stdout/stderr will be empty and output directly to stdout/stderr
(opts *ExecOpts)
| 2468 | // Returns ComposeCmd results of stdout, stderr, err |
| 2469 | // If Nocapture arg is true, stdout/stderr will be empty and output directly to stdout/stderr |
| 2470 | func (app *DdevApp) Exec(opts *ExecOpts) (string, string, error) { |
| 2471 | _ = app.DockerEnv() |
| 2472 | |
| 2473 | defer util.TimeTrackC(fmt.Sprintf("app.Exec %v", opts))() |
| 2474 | |
| 2475 | if opts.Cmd == "" && len(opts.RawCmd) == 0 { |
| 2476 | return "", "", fmt.Errorf("no command provided") |
| 2477 | } |
| 2478 | |
| 2479 | if opts.Service == "" { |
| 2480 | opts.Service = "web" |
| 2481 | } |
| 2482 | |
| 2483 | state, err := dockerutil.GetContainerStateByName(fmt.Sprintf("ddev-%s-%s", app.Name, opts.Service)) |
| 2484 | if err != nil || state != "running" { |
| 2485 | switch state { |
| 2486 | case "doesnotexist": |
| 2487 | return "", "", fmt.Errorf("service %s does not exist in project %s (state=%s)", opts.Service, app.Name, state) |
| 2488 | case "exited": |
| 2489 | return "", "", fmt.Errorf("service %s has exited; state=%s", opts.Service, state) |
| 2490 | default: |
| 2491 | return "", "", fmt.Errorf("service %s is not currently running in project %s (state=%s), use `ddev logs -s %s` to see what happened to it", opts.Service, app.Name, state, opts.Service) |
| 2492 | } |
| 2493 | } |
| 2494 | |
| 2495 | err = app.ProcessHooks("pre-exec") |
| 2496 | if err != nil { |
| 2497 | return "", "", fmt.Errorf("failed to process pre-exec hooks: %v", err) |
| 2498 | } |
| 2499 | |
| 2500 | baseComposeExecCmd := []string{"exec"} |
| 2501 | if opts.Dir != "" { |
| 2502 | baseComposeExecCmd = append(baseComposeExecCmd, "-w", opts.Dir) |
| 2503 | } |
| 2504 | |
| 2505 | if !isatty.IsTerminal(os.Stdin.Fd()) || !opts.Tty { |
| 2506 | baseComposeExecCmd = append(baseComposeExecCmd, "-T") |
| 2507 | } |
| 2508 | |
| 2509 | if opts.Detach { |
| 2510 | baseComposeExecCmd = append(baseComposeExecCmd, "--detach") |
| 2511 | } |
| 2512 | |
| 2513 | if opts.User != "" { |
| 2514 | baseComposeExecCmd = append(baseComposeExecCmd, "-u", opts.User) |
| 2515 | } |
| 2516 | |
| 2517 | if len(opts.Env) > 0 { |
| 2518 | for _, envVar := range opts.Env { |
| 2519 | baseComposeExecCmd = append(baseComposeExecCmd, "-e", envVar) |
| 2520 | } |
| 2521 | } |
| 2522 | |
| 2523 | baseComposeExecCmd = append(baseComposeExecCmd, opts.Service) |
| 2524 | |
| 2525 | // Cases to handle |
| 2526 | // - Free form, all unquoted. Like `ls -l -a` |
| 2527 | // - Quoted to delay pipes and other features to container, like `"ls -l -a | grep junk"` |