mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-24 16:10:46 -06:00
ec85fb1960
This is part of a general effort to move all of Terraform's non-library package surface under internal in order to reinforce that these are for internal use within Terraform only. If you were previously importing packages under this prefix into an external codebase, you could pin to an earlier release tag as an interim solution until you've make a plan to achieve the same functionality some other way.
97 lines
2.2 KiB
Go
97 lines
2.2 KiB
Go
package remote
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"sync"
|
|
)
|
|
|
|
// Cmd represents a remote command being prepared or run.
|
|
type Cmd struct {
|
|
// Command is the command to run remotely. This is executed as if
|
|
// it were a shell command, so you are expected to do any shell escaping
|
|
// necessary.
|
|
Command string
|
|
|
|
// Stdin specifies the process's standard input. If Stdin is
|
|
// nil, the process reads from an empty bytes.Buffer.
|
|
Stdin io.Reader
|
|
|
|
// Stdout and Stderr represent the process's standard output and
|
|
// error.
|
|
//
|
|
// If either is nil, it will be set to ioutil.Discard.
|
|
Stdout io.Writer
|
|
Stderr io.Writer
|
|
|
|
// Once Wait returns, his will contain the exit code of the process.
|
|
exitStatus int
|
|
|
|
// Internal fields
|
|
exitCh chan struct{}
|
|
|
|
// err is used to store any error reported by the Communicator during
|
|
// execution.
|
|
err error
|
|
|
|
// This thing is a mutex, lock when making modifications concurrently
|
|
sync.Mutex
|
|
}
|
|
|
|
// Init must be called by the Communicator before executing the command.
|
|
func (c *Cmd) Init() {
|
|
c.Lock()
|
|
defer c.Unlock()
|
|
|
|
c.exitCh = make(chan struct{})
|
|
}
|
|
|
|
// SetExitStatus stores the exit status of the remote command as well as any
|
|
// communicator related error. SetExitStatus then unblocks any pending calls
|
|
// to Wait.
|
|
// This should only be called by communicators executing the remote.Cmd.
|
|
func (c *Cmd) SetExitStatus(status int, err error) {
|
|
c.Lock()
|
|
defer c.Unlock()
|
|
|
|
c.exitStatus = status
|
|
c.err = err
|
|
|
|
close(c.exitCh)
|
|
}
|
|
|
|
// Wait waits for the remote command to complete.
|
|
// Wait may return an error from the communicator, or an ExitError if the
|
|
// process exits with a non-zero exit status.
|
|
func (c *Cmd) Wait() error {
|
|
<-c.exitCh
|
|
|
|
c.Lock()
|
|
defer c.Unlock()
|
|
|
|
if c.err != nil || c.exitStatus != 0 {
|
|
return &ExitError{
|
|
Command: c.Command,
|
|
ExitStatus: c.exitStatus,
|
|
Err: c.err,
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ExitError is returned by Wait to indicate and error executing the remote
|
|
// command, or a non-zero exit status.
|
|
type ExitError struct {
|
|
Command string
|
|
ExitStatus int
|
|
Err error
|
|
}
|
|
|
|
func (e *ExitError) Error() string {
|
|
if e.Err != nil {
|
|
return fmt.Sprintf("error executing %q: %v", e.Command, e.Err)
|
|
}
|
|
return fmt.Sprintf("%q exit status: %d", e.Command, e.ExitStatus)
|
|
}
|