mirror of
https://github.com/thegeeklab/wp-plugin-go.git
synced 2024-11-21 04:00:40 +00:00
refactor: rework plugin cmd (#82)
BREAKING CHANGE: `types.Cmd` was moved to `exec.Cmd` and the `Private` field from the struct was removed. The filed `Trace` is now a bool field instead of a bool pointer, and the helper method `SetTrace` was also removed. BREAKING CHANGE: The method `trace.Cmd` was removed, please use the `Trace` field of `exec.Cmd`.
This commit is contained in:
parent
e2bc944f1f
commit
6be7f2b898
58
exec/command.go
Normal file
58
exec/command.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package exec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/sys/execabs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cmd represents a command to be executed, with options to control its behavior.
|
||||||
|
// The Cmd struct embeds the standard library's exec.Cmd, adding additional fields
|
||||||
|
// to control the command's output and tracing.
|
||||||
|
type Cmd struct {
|
||||||
|
*exec.Cmd
|
||||||
|
Trace bool // Print composed command before execution.
|
||||||
|
TraceWriter io.Writer // Where to write the trace output.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run runs the command and waits for it to complete.
|
||||||
|
// If there is an error starting the command, it is returned.
|
||||||
|
// Otherwise, the command is waited for and its exit status is returned.
|
||||||
|
func (c *Cmd) Run() error {
|
||||||
|
if c.Trace {
|
||||||
|
fmt.Fprintf(c.TraceWriter, "+ %s\n", strings.Join(c.Args, " "))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command creates a new Cmd struct with the given name and arguments. It looks up the
|
||||||
|
// absolute path of the executable using execabs.LookPath, and sets up the Cmd with
|
||||||
|
// the necessary environment and output streams. The Cmd is configured to trace
|
||||||
|
// the command execution by setting Trace to true and TraceWriter to os.Stdout.
|
||||||
|
func Command(name string, arg ...string) (*Cmd, error) {
|
||||||
|
abs, err := execabs.LookPath(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not find executable %q: %w", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := &Cmd{
|
||||||
|
Cmd: execabs.Command(abs, arg...),
|
||||||
|
Trace: true,
|
||||||
|
TraceWriter: os.Stdout,
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
|
||||||
|
return cmd, nil
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package types
|
package exec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -20,7 +20,7 @@ func TestCmdRun(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "trace enabled",
|
name: "trace enabled",
|
||||||
cmd: &Cmd{
|
cmd: &Cmd{
|
||||||
Trace: boolPtr(true),
|
Trace: true,
|
||||||
Cmd: &exec.Cmd{
|
Cmd: &exec.Cmd{
|
||||||
Path: "/usr/bin/echo",
|
Path: "/usr/bin/echo",
|
||||||
Args: []string{"echo", "hello"},
|
Args: []string{"echo", "hello"},
|
||||||
@ -30,19 +30,20 @@ func TestCmdRun(t *testing.T) {
|
|||||||
wantStdout: "hello\n",
|
wantStdout: "hello\n",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "private output",
|
name: "trace disabled",
|
||||||
cmd: &Cmd{
|
cmd: &Cmd{
|
||||||
Private: true,
|
Trace: false,
|
||||||
Cmd: &exec.Cmd{
|
Cmd: &exec.Cmd{
|
||||||
Path: "/usr/bin/echo",
|
Path: "/usr/bin/echo",
|
||||||
Args: []string{"echo", "hello"},
|
Args: []string{"echo", "hello"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantTrace: "+ echo hello\n",
|
wantStdout: "hello\n",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "custom env",
|
name: "custom env",
|
||||||
cmd: &Cmd{
|
cmd: &Cmd{
|
||||||
|
Trace: true,
|
||||||
Cmd: &exec.Cmd{
|
Cmd: &exec.Cmd{
|
||||||
Path: "/bin/sh",
|
Path: "/bin/sh",
|
||||||
Args: []string{"sh", "-c", "echo $TEST"},
|
Args: []string{"sh", "-c", "echo $TEST"},
|
||||||
@ -52,21 +53,10 @@ func TestCmdRun(t *testing.T) {
|
|||||||
wantTrace: "+ sh -c echo $TEST\n",
|
wantTrace: "+ sh -c echo $TEST\n",
|
||||||
wantStdout: "1\n",
|
wantStdout: "1\n",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "custom stdout",
|
|
||||||
cmd: &Cmd{
|
|
||||||
Cmd: &exec.Cmd{
|
|
||||||
Path: "/bin/sh",
|
|
||||||
Args: []string{"sh", "-c", "echo hello"},
|
|
||||||
Stdout: new(bytes.Buffer),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantTrace: "+ sh -c echo hello\n",
|
|
||||||
wantStdout: "hello\n",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "custom stderr",
|
name: "custom stderr",
|
||||||
cmd: &Cmd{
|
cmd: &Cmd{
|
||||||
|
Trace: true,
|
||||||
Cmd: &exec.Cmd{
|
Cmd: &exec.Cmd{
|
||||||
Path: "/bin/sh",
|
Path: "/bin/sh",
|
||||||
Args: []string{"sh", "-c", "echo error >&2"},
|
Args: []string{"sh", "-c", "echo error >&2"},
|
||||||
@ -76,6 +66,16 @@ func TestCmdRun(t *testing.T) {
|
|||||||
wantTrace: "+ sh -c echo error >&2\n",
|
wantTrace: "+ sh -c echo error >&2\n",
|
||||||
wantStderr: "error\n",
|
wantStderr: "error\n",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "error",
|
||||||
|
cmd: &Cmd{
|
||||||
|
Trace: true,
|
||||||
|
Cmd: &exec.Cmd{
|
||||||
|
Path: "/invalid/path",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@ -101,42 +101,3 @@ func TestCmdRun(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCmdSetTrace(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
cmd *Cmd
|
|
||||||
trace bool
|
|
||||||
expected *bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "set trace to true",
|
|
||||||
cmd: &Cmd{},
|
|
||||||
trace: true,
|
|
||||||
expected: boolPtr(true),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "set trace to false",
|
|
||||||
cmd: &Cmd{},
|
|
||||||
trace: false,
|
|
||||||
expected: boolPtr(false),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "overwrite existing trace value",
|
|
||||||
cmd: &Cmd{Trace: boolPtr(true)},
|
|
||||||
trace: false,
|
|
||||||
expected: boolPtr(false),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
tt.cmd.SetTrace(tt.trace)
|
|
||||||
assert.Equal(t, tt.expected, tt.cmd.Trace)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func boolPtr(b bool) *bool {
|
|
||||||
return &b
|
|
||||||
}
|
|
@ -12,9 +12,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http/httptrace"
|
"net/http/httptrace"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
@ -120,8 +117,3 @@ func HTTP(ctx context.Context) context.Context {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cmd prints the executed command to stdout.
|
|
||||||
func Cmd(cmd *exec.Cmd) {
|
|
||||||
fmt.Fprintf(os.Stdout, "+ %s\n", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/sys/execabs"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Cmd represents a command to be executed. It extends the execabs.Cmd struct
|
|
||||||
// and adds fields for controlling the command's execution, such as whether
|
|
||||||
// it should be executed in private mode (with output discarded) and whether
|
|
||||||
// its execution should be traced.
|
|
||||||
type Cmd struct {
|
|
||||||
*execabs.Cmd
|
|
||||||
Private bool
|
|
||||||
Trace *bool
|
|
||||||
TraceWriter io.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run executes the command and waits for it to complete.
|
|
||||||
// If the Trace field is nil, it is set to true.
|
|
||||||
// The Env, Stdout, and Stderr fields are set to their default values if they are nil.
|
|
||||||
// If the Private field is true, the Stdout field is set to io.Discard.
|
|
||||||
// If the Trace field is true, the command line is printed to Stdout.
|
|
||||||
func (c *Cmd) Run() error {
|
|
||||||
if c.Trace == nil {
|
|
||||||
c.SetTrace(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Env == nil {
|
|
||||||
c.Env = os.Environ()
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Stdout == nil {
|
|
||||||
c.Stdout = os.Stdout
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Stderr == nil {
|
|
||||||
c.Stderr = os.Stderr
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Private {
|
|
||||||
c.Stdout = io.Discard
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.TraceWriter == nil {
|
|
||||||
c.TraceWriter = os.Stdout
|
|
||||||
}
|
|
||||||
|
|
||||||
if *c.Trace {
|
|
||||||
fmt.Fprintf(c.TraceWriter, "+ %s\n", strings.Join(c.Args, " "))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.Start(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTrace sets the Trace field of the Cmd to the provided boolean value.
|
|
||||||
func (c *Cmd) SetTrace(trace bool) {
|
|
||||||
c.Trace = &trace
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user