-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: Add ability to enable/disable color * feat: Redesign command package api * chore: Clean up fatal tests * feat: Completely redesign spinner package api * feat: Redesign and refactor file api * chore: Remove unused dependencies * chore: Fix lint errors * feat: Add ability for spinner to write debug messages * feat: Spinner is now an io.Writer, remove debug writer and Debugf * feat: Add UpdateMessage method to Spinner * feat: Ellipses counts as part of max message length for spinner * chore: Add additional docs
- Loading branch information
Showing
14 changed files
with
1,167 additions
and
271 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,15 @@ | ||
# goutils | ||
|
||
[](https://pkg.go.dev/github.com/TouchBistro/goutils) | ||
|
||
A collection of useful go utilities. See [the docs](https://pkg.go.dev/github.com/TouchBistro/goutils) for more information. | ||
|
||
## Installation | ||
|
||
``` | ||
go get github.com/TouchBistro/goutils | ||
``` | ||
|
||
## License | ||
|
||
MIT © TouchBistro, see [LICENSE](LICENSE) for details. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,87 @@ | ||
package color | ||
package color_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/TouchBistro/goutils/color" | ||
) | ||
|
||
func TestColors(t *testing.T) { | ||
noColor = false | ||
|
||
color.SetEnabled(true) | ||
tests := []struct { | ||
name string | ||
colorFn func(string) string | ||
input string | ||
expected string | ||
name string | ||
colorFn func(string) string | ||
input string | ||
want string | ||
}{ | ||
{ | ||
"Red() test", | ||
Red, | ||
color.Red, | ||
"foo bar", | ||
"\x1b[31mfoo bar\x1b[39m", | ||
}, | ||
{ | ||
"Green() test", | ||
Green, | ||
color.Green, | ||
"foo bar", | ||
"\x1b[32mfoo bar\x1b[39m", | ||
}, | ||
{ | ||
"Yellow() test", | ||
Yellow, | ||
color.Yellow, | ||
"foo bar", | ||
"\x1b[33mfoo bar\x1b[39m", | ||
}, | ||
{ | ||
"Blue() test", | ||
Blue, | ||
color.Blue, | ||
"foo bar", | ||
"\x1b[34mfoo bar\x1b[39m", | ||
}, | ||
{ | ||
"Magenta() test", | ||
Magenta, | ||
color.Magenta, | ||
"foo bar", | ||
"\x1b[35mfoo bar\x1b[39m", | ||
}, | ||
{ | ||
"Cyan() test", | ||
Cyan, | ||
color.Cyan, | ||
"foo bar", | ||
"\x1b[36mfoo bar\x1b[39m", | ||
}, | ||
{ | ||
"White() test", | ||
White, | ||
color.White, | ||
"foo bar", | ||
"\x1b[37mfoo bar\x1b[39m", | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
received := tt.colorFn(tt.input) | ||
assert.Equal(t, tt.expected, received) | ||
got := tt.colorFn(tt.input) | ||
if got != tt.want { | ||
t.Errorf("got %s, want %s", got, tt.want) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestStripReset(t *testing.T) { | ||
noColor = false | ||
|
||
received := Red("foo \x1b[39mbar") | ||
assert.Equal(t, "\x1b[31mfoo bar\x1b[39m", received) | ||
color.SetEnabled(true) | ||
got := color.Red("foo \x1b[39mbar") | ||
want := "\x1b[31mfoo bar\x1b[39m" | ||
if got != want { | ||
t.Errorf("got %s, want %s", got, want) | ||
} | ||
} | ||
|
||
func TestNoColor(t *testing.T) { | ||
noColor = true | ||
|
||
received := Red("foo bar") | ||
assert.Equal(t, "foo bar", received) | ||
func TestColorDisabled(t *testing.T) { | ||
color.SetEnabled(false) | ||
got := color.Red("foo bar") | ||
want := "foo bar" | ||
if got != want { | ||
t.Errorf("got %s, want %s", got, want) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,113 @@ | ||
// Package command provides functionality for working with programs the host OS. | ||
// It provides a high level API over os/exec for running commands, which is | ||
// easier to use for common cases. | ||
package command | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"os/exec" | ||
"strings" | ||
|
||
"github.com/pkg/errors" | ||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
func IsCommandAvailable(command string) bool { | ||
// IsAvailable checks if command is available on the system. This is done by | ||
// checking if command exists within the user's PATH. | ||
func IsAvailable(command string) bool { | ||
_, err := exec.LookPath(command) | ||
if err != nil { | ||
log.WithFields(log.Fields{"error": err.Error(), "command": command}).Debug("Error looking up command.") | ||
return false | ||
return err == nil | ||
} | ||
|
||
// Command manages the configuration of a command | ||
// that will be run in a child process. | ||
type Command struct { | ||
stdin io.Reader | ||
stdout io.Writer | ||
stderr io.Writer | ||
env map[string]string | ||
dir string | ||
} | ||
|
||
// New creates a command instance from the given options. | ||
func New(opts ...Option) *Command { | ||
c := &Command{} | ||
for _, opt := range opts { | ||
opt(c) | ||
} | ||
return true | ||
return c | ||
} | ||
|
||
func Exec(cmdName string, args []string, id string, opts ...func(*exec.Cmd)) error { | ||
cmd := exec.Command(cmdName, args...) | ||
// Option is a function that takes a command and applies | ||
// a configuration to it. | ||
type Option func(*Command) | ||
|
||
stdout := log.WithFields(log.Fields{ | ||
"id": id, | ||
}).WriterLevel(log.DebugLevel) | ||
defer stdout.Close() | ||
// WithStdin sets the reader the the command's stdin should read from. | ||
func WithStdin(stdin io.Reader) Option { | ||
return func(c *Command) { | ||
c.stdin = stdin | ||
} | ||
} | ||
|
||
stderr := log.WithFields(log.Fields{ | ||
"id": id, | ||
}).WriterLevel(log.DebugLevel) | ||
defer stderr.Close() | ||
// WithStdout sets the writer that the command's stdout | ||
// should be written to. | ||
func WithStdout(stdout io.Writer) Option { | ||
return func(c *Command) { | ||
c.stdout = stdout | ||
} | ||
} | ||
|
||
cmd.Stdout = stdout | ||
cmd.Stderr = stderr | ||
// WithStderr sets the writer that the command's stderr | ||
// should be written to. | ||
func WithStderr(stderr io.Writer) Option { | ||
return func(c *Command) { | ||
c.stderr = stderr | ||
} | ||
} | ||
|
||
for _, opt := range opts { | ||
opt(cmd) | ||
// WithEnv sets the environment variables for the process | ||
// the command will be run in. | ||
func WithEnv(env map[string]string) Option { | ||
return func(c *Command) { | ||
c.env = env | ||
} | ||
} | ||
|
||
err := cmd.Run() | ||
if err != nil { | ||
argsStr := strings.Join(args, " ") | ||
return errors.Wrapf(err, "Exec failed to run %s %s", cmdName, argsStr) | ||
// WithDir sets the directory the command should be run in. | ||
func WithDir(dir string) Option { | ||
return func(c *Command) { | ||
c.dir = dir | ||
} | ||
} | ||
|
||
// Exec executes the named program with the given arguments. | ||
func (c *Command) Exec(name string, args ...string) error { | ||
cmd := exec.Command(name, args...) | ||
if c.stdin != nil { | ||
cmd.Stdin = c.stdin | ||
} | ||
if c.stdout != nil { | ||
cmd.Stdout = c.stdout | ||
} | ||
if c.stderr != nil { | ||
cmd.Stderr = c.stderr | ||
} | ||
if c.env != nil { | ||
for k, v := range c.env { | ||
cmd.Env = append(cmd.Env, k+"="+v) | ||
} | ||
} | ||
if c.dir != "" { | ||
cmd.Dir = c.dir | ||
} | ||
|
||
if err := cmd.Run(); err != nil { | ||
argsStr := strings.Join(args, " ") | ||
return fmt.Errorf("command: failed to run '%s %s': %w", name, argsStr, err) | ||
} | ||
return nil | ||
} | ||
|
||
// Exec executes the named program with the given arguments. | ||
// This is a shorthand for when the default command options wish to be used. | ||
func Exec(name string, args ...string) error { | ||
return New().Exec(name, args...) | ||
} |
Oops, something went wrong.