mirror of https://github.com/coder/coder.git
61 lines
1.6 KiB
Go
61 lines
1.6 KiB
Go
package pty
|
|
|
|
import (
|
|
"context"
|
|
"os/exec"
|
|
)
|
|
|
|
// StartOption represents a configuration option passed to Start.
|
|
type StartOption func(*startOptions)
|
|
|
|
type startOptions struct {
|
|
ptyOpts []Option
|
|
}
|
|
|
|
// WithPTYOption applies the given options to the underlying PTY.
|
|
func WithPTYOption(opts ...Option) StartOption {
|
|
return func(o *startOptions) {
|
|
o.ptyOpts = append(o.ptyOpts, opts...)
|
|
}
|
|
}
|
|
|
|
// Cmd is a drop-in replacement for exec.Cmd with most of the same API, but
|
|
// it exposes the context.Context to our PTY code so that we can still kill the
|
|
// process when the Context expires. This is required because on Windows, we don't
|
|
// start the command using the `exec` library, so we have to manage the context
|
|
// ourselves.
|
|
type Cmd struct {
|
|
Context context.Context
|
|
Path string
|
|
Args []string
|
|
Env []string
|
|
Dir string
|
|
}
|
|
|
|
func CommandContext(ctx context.Context, name string, arg ...string) *Cmd {
|
|
return &Cmd{
|
|
Context: ctx,
|
|
Path: name,
|
|
Args: append([]string{name}, arg...),
|
|
Env: make([]string, 0),
|
|
}
|
|
}
|
|
|
|
func Command(name string, arg ...string) *Cmd {
|
|
return CommandContext(context.Background(), name, arg...)
|
|
}
|
|
|
|
func (c *Cmd) AsExec() *exec.Cmd {
|
|
//nolint: gosec
|
|
execCmd := exec.CommandContext(c.Context, c.Path, c.Args[1:]...)
|
|
execCmd.Dir = c.Dir
|
|
execCmd.Env = c.Env
|
|
return execCmd
|
|
}
|
|
|
|
// Start the command in a TTY. The calling code must not use cmd after passing it to the PTY, and
|
|
// instead rely on the returned Process to manage the command/process.
|
|
func Start(cmd *Cmd, opt ...StartOption) (PTYCmd, Process, error) {
|
|
return startPty(cmd, opt...)
|
|
}
|