Skip to content

feat: add command output/error option #223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type Closer interface {
}

func Run(ctx context.Context, root *cmds.Command,
cmdline []string, stdin, stdout, stderr *os.File,
cmdline []string, stdin, stderr *os.File,
buildEnv cmds.MakeEnvironment, makeExecutor cmds.MakeExecutor) error {

printErr := func(err error) {
Expand All @@ -33,6 +33,21 @@ func Run(ctx context.Context, root *cmds.Command,

req, errParse := Parse(ctx, cmdline[1:], stdin, root)

var out *os.File
if outFile, _ := req.Options[cmds.OutputFile].(string); outFile != "" {
// FIXME: Consider exporting the extract file logic (used in `ipfs get`)
// and using it here (https://github.com/ipfs/tar-utils/blob/16821db/extractor.go#L277).
var err error
out, err = os.Create(outFile)
if err != nil {
printErr(err)
return err
}
// FIXME(BLOCKING): Where do we close the file? When the resp emitter closes?
} else {
out = os.Stdout
}

// Handle the timeout up front.
var cancel func()
if timeoutStr, ok := req.Options[cmds.TimeoutOpt]; ok {
Expand Down Expand Up @@ -72,7 +87,7 @@ func Run(ctx context.Context, root *cmds.Command,

// BEFORE handling the parse error, if we have enough information
// AND the user requested help, print it out and exit
err := HandleHelp(cmdline[0], req, stdout)
err := HandleHelp(cmdline[0], req, out)
if err == nil {
return nil
} else if err != ErrNoHelpRequested {
Expand All @@ -98,7 +113,7 @@ func Run(ctx context.Context, root *cmds.Command,
// - commands with no Run func are invoked directly.
// - the main command is invoked.
if req == nil || req.Command == nil || req.Command.Run == nil {
printHelp(false, stdout)
printHelp(false, out)
return nil
}

Expand Down Expand Up @@ -127,7 +142,7 @@ func Run(ctx context.Context, root *cmds.Command,
req.Options[cmds.EncLong] = cmds.JSON
}

re, err := NewResponseEmitter(stdout, stderr, req)
re, err := NewResponseEmitter(out, stderr, req)
if err != nil {
printErr(err)
return err
Expand Down
3 changes: 2 additions & 1 deletion cli/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ func TestRunWaits(t *testing.T) {
context.Background(),
root,
[]string{"test", "test"},
devnull, devnull, devnull,
// FIXME(BLOCKING): Redirect to devnull instead of stdout.
devnull, devnull,
func(ctx context.Context, req *cmds.Request) (cmds.Environment, error) {
return env{flag}, nil
},
Expand Down
2 changes: 2 additions & 0 deletions executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ func NewExecutor(root *Command) Executor {
}
}

// This is the *CLI* Executor (though is not in that package). The other one is
// the `client` HTTP Executor (defined in the HTTP package).
type executor struct {
root *Command
}
Expand Down
12 changes: 8 additions & 4 deletions opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ const (
OptLongHelp = "help"
DerefLong = "dereference-args"
StdinName = "stdin-name"
Hidden = "hidden"
HiddenShort = "H"
Ignore = "ignore"
IgnoreRules = "ignore-rules-path"
// FIXME(BLOCKING): Review names. (We may be able to use "output" once
// it's cleaned from subcommands.)
OutputFile = "command-output"
Hidden = "hidden"
HiddenShort = "H"
Ignore = "ignore"
IgnoreRules = "ignore-rules-path"
)

// options that are used by this package
Expand All @@ -25,6 +28,7 @@ var OptionStreamChannels = BoolOption(ChanOpt, "Stream channel output")
var OptionTimeout = StringOption(TimeoutOpt, "Set a global timeout on the command")
var OptionDerefArgs = BoolOption(DerefLong, "Symlinks supplied in arguments are dereferenced")
var OptionStdinName = StringOption(StdinName, "Assign a name if the file source is stdin.")
var OptionOutputFile = StringOption(OutputFile, "Filename to save the output in (by default it's redirected to stdout).")
var OptionHidden = BoolOption(Hidden, HiddenShort, "Include files that are hidden. Only takes effect on recursive add.")
var OptionIgnore = StringsOption(Ignore, "A rule (.gitignore-stype) defining which file(s) should be ignored (variadic, experimental)")
var OptionIgnoreRules = StringOption(IgnoreRules, "A path to a file with .gitignore-style ignore rules (experimental)")