Skip to content

Commit

Permalink
✨ Support command verbosity.
Browse files Browse the repository at this point in the history
Signed-off-by: Jeff Ortel <[email protected]>
  • Loading branch information
jortel committed Dec 7, 2023
1 parent 31d1afa commit c0a5dfc
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 38 deletions.
67 changes: 30 additions & 37 deletions command/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ package command
import (
"context"
"fmt"
"os/exec"
"strings"

hub "github.com/konveyor/tackle2-hub/addon"
"os/exec"
)

var (
Expand All @@ -20,10 +18,12 @@ var (
//
// Command execution.
type Command struct {
Options Options
Path string
Dir string
Output []byte
Verbosity int
Options Options
Path string
Dir string
Reporter Reporter
writer Writer
}

//
Expand All @@ -40,22 +40,26 @@ func (r *Command) Run() (err error) {
// The command and output are both reported in
// task Report.Activity.
func (r *Command) RunWith(ctx context.Context) (err error) {
addon.Activity(
"[CMD] Running: %s %s",
r.Path,
strings.Join(r.Options, " "))
r.writer.reporter = r.Reporter
r.Reporter.Run(r.Path, r.Options)
defer func() {
if err != nil {
r.Reporter.Error(r.Path, err, r.writer.buffer)
} else {
r.Reporter.Succeeded(r.Path)
}
}()
cmd := exec.CommandContext(ctx, r.Path, r.Options...)
cmd.Dir = r.Dir
r.Output, err = cmd.CombinedOutput()
if err != nil {
addon.Activity(
"[CMD] %s failed: %s.\n%s",
r.Path,
err.Error(),
string(r.Output))
cmd.Stdout = &r.writer
cmd.Stderr = &r.writer
err = cmd.Start()
if err == nil {
defer r.writer.Close()
} else {
addon.Activity("[CMD] succeeded.")
return
}
err = cmd.Wait()
return
}

Expand All @@ -64,41 +68,30 @@ func (r *Command) RunWith(ctx context.Context) (err error) {
// On error: The command (without arguments) and output are
// reported in task Report.Activity
func (r *Command) RunSilent() (err error) {
err = r.RunSilentWith(context.TODO())
r.Reporter.Verbosity = 0
err = r.RunWith(context.TODO())
return
}

//
// RunSilentWith executes the command with context.
// On error: The command (without arguments) and output are
// reported in task Report.Activity
func (r *Command) RunSilentWith(ctx context.Context) (err error) {
cmd := exec.CommandContext(ctx, r.Path, r.Options...)
cmd.Dir = r.Dir
r.Output, err = cmd.CombinedOutput()
if err != nil {
addon.Activity(
"[CMD] %s failed: %s.\n%s",
r.Path,
err.Error(),
string(r.Output))
}
return
// Output returns the command output.
func (r *Command) Output() (b []byte) {
return r.writer.buffer
}

//
// Options are CLI options.
type Options []string

//
// add
// Add option.
func (a *Options) Add(option string, s ...string) {
*a = append(*a, option)
*a = append(*a, s...)
}

//
// add
// Addf option.
func (a *Options) Addf(option string, x ...interface{}) {
*a = append(*a, fmt.Sprintf(option, x...))
}
79 changes: 79 additions & 0 deletions command/reporter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package command

import "strings"

const (
// Disabled reports: NOTHING.
Disabled = -2
// Error reports: error.
Error = -1
// Default reports: error, started, succeeded.
Default = 0
// LiveOutput reports: error, started, succeeded, output (live).
LiveOutput = 1
)

//
// Reporter activity reporter.
type Reporter struct {
Verbosity int
}

//
// Run reports command started in task Report.Activity.
func (r *Reporter) Run(path string, options Options) {
switch r.Verbosity {
case Disabled:
case Error:
case Default,
LiveOutput:
addon.Activity(
"[CMD] Running: %s %s",
path,
strings.Join(options, " "))
}
}

//
// Succeeded reports command succeeded in task Report.Activity.
func (r *Reporter) Succeeded(path string) {
switch r.Verbosity {
case Disabled:
case Error:
case Default,
LiveOutput:
addon.Activity("[CMD] %s succeeded.", path)
}
}

//
// Error reports command failed in task Report.Activity.
func (r *Reporter) Error(path string, err error, output []byte) {
switch r.Verbosity {
case Disabled:
case Error,
Default:
addon.Activity(
"[CMD] %s failed: %s.\n%s",
path,
err.Error(),
output)
case LiveOutput:
addon.Activity(
"[CMD] %s failed: %s.",
path,
err.Error())
}
}

//
// Output reports command output in task Report.Activity.
func (r *Reporter) Output(output string) {
switch r.Verbosity {
case Disabled:
case Error:
case Default:
case LiveOutput:
addon.Activity("> %s", output)
}
}
40 changes: 40 additions & 0 deletions command/writer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package command

import "strings"

//
// Writer records command output.
type Writer struct {
reporter Reporter
buffer []byte
index int
}

//
// Write command output.
// When verbosity > 0, output is reported in task Report.Activity.
func (w *Writer) Write(p []byte) (n int, err error) {
w.buffer = append(w.buffer, p...)
n = len(p)
batch := string(w.buffer[w.index:])
end := strings.LastIndex(batch, "\n")
if end != -1 {
output := batch[:end]
w.reporter.Output(output)
w.index += len(output)
w.index++
}
return
}

//
// Close the writer.
// When verbosity > 0, output is reported in task Report.Activity.
func (w *Writer) Close() {
batch := string(w.buffer[w.index:])
if len(batch) > 0 {
w.reporter.Output(batch)
w.index += len(batch)
w.index++
}
}
2 changes: 1 addition & 1 deletion ssh/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func (r *Agent) Add(id *api.Identity, host string) (err error) {
path)
return
}
_, err = f.Write(cmd.Output)
_, err = f.Write(cmd.Output())
if err != nil {
err = liberr.Wrap(
err,
Expand Down

0 comments on commit c0a5dfc

Please sign in to comment.