This library wraps the exec.Cmd
for readability and usability purposes. Some use cases I had when developing this:
- I want to execute a shell command from a Go application
- I want to get the output of the shell command to do some data transformations on it (eg. with the
aws
CLI command tool to list out infrastructure or withkubectl
to get a list of pods/deployments et cetera) - I want to be able to inject the user's current environment into the command
- I want the option to decide if the output to be printed to the default
stdout
orstderr
The purpose of this package is as an underlying library for a CLI tool that codifies contextual DevOps knowledge in an organisation. This means things like what commands should be run and in what order to achieve a certain desired outcome.
Since this can vary from organisation to organisation, it's usually not easy to pick up on the conventions and it's not useful to internalise this since different projects can have different conventions. Therefore, I write a CLI tooling around conventions, and this library helps with that.
To use this library, import it:
import "github.com/zephinzer/go-commander"
Create a new command via the NewCommand(...)
function:
func main() {
// ...
command := commander.NewCommand("ls").
AddParam("-al")
// ...
}
Finally, whenever you want, you can execute it:
// ...
output := command.Execute()
// ...
To get the output of the command, you can use the .Stderr
and .Stdout
properties of the output object:
// ...
// to get the stderr
fmt.Println(output.Stderr.String())
// to get the stdout
fmt.Println(output.Stdout.String())
// ...
It's usually useful to be able to inject environment variables into a custom command you wish to run. For example, if the user's AWS_PROFILE
is set to "production"
but you want it set to "staging"
, you can inject environment variables using the SetEnvironment
method. These will overwrite the global environment if the global environment is not disabled.
// ...
command := commander.NewCommand("aws").
SetEnvironment("AWS_PROFILE", "staging").
AddParam("sts")
AddParam("get-caller-identity")
// ...
By default, the current working directory is used. If you would like to run the command from a different directory, use the SetWorkingDirectory
method to set the path to the directory where you would like the command to run from
// ...
command := commander.NewCommand("ls").
SetWorkingDirectory("./tests")
// ...
For people who don't know what they're going to run, it can be useful to see the command they're running. This also gives you a better idea on how to debug things if things go wrong. To print the command as a string, you can use the GetAsString
method
// ...
command := commander.NewCommand("ls").
SetWorkingDirectory("./tests")
fmt.Println(command.GetAsString())
// ...
To print the stdout
/stderr
output as it comes in, you can use the EnableStdout
or EnableStderr
chainable methods
// ...
command := commander.NewCommand("ls").
SetWorkingDirectory("./tests").
EnableStdout(). // and/or
EnableStderr()
// ...
Occassionally it could be useful to stream the standard output/error to another buffer. To do this, you can use the SetStderr
or SetStdout
methods:
// ...
otherBuffer := bytes.NewBuffer(nil)
otherBufferWriter := bufio.NewWriter(otherBuffer)
command := commander.NewCommand("ls").
SetWorkingDirectory("./tests").
SetStderr(otherBufferWriter). // and/or
SetStdout(otherBufferWriter)
// ...
Sometimes it's useful to disable the global environment from polluting a command's environment. To do that, use the .DisableGlobalEnvironment
method.
// ...
command := commander.NewCommand("ls").
DisableGlobalEnvironment()
// ...
- Run
go mod tidy
orgo mod vendor
to bring in the dependencies - Run
go test ./...
to test this package - When pushed to Gitlab, this repository will trigger a pipeline to run tests, see the
./.gitlab-ci.yml
file for more information