Skip to content
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

Allow more flexible configuration of the output steam (stdout vs. stderr) #1788

Closed
tzakharko opened this issue Apr 5, 2020 · 13 comments
Closed
Labels
A-help Area: documentation, including docs.rs, readme, examples, etc... C-enhancement Category: Raise on the bar on expectations S-wont-fix Status: Closed as there is no plan to fix this

Comments

@tzakharko
Copy link

Describe your use case

Some command line tools are used exclusively as components within larger configurations and their stdout might be piped into other tools. Clap is currently hard-coded in Error::use_stderr() to print certain messages (e.g. the help block) to stdout, which might lead to surprising behavior.

Describe the solution you'd like

It would be nice to have an option in configuring the behavior of Error:: use_stderr(). maybe a configuration option in App that would override the default behavior, e.g.:

App::new(...).
  ...
  .setting(AppSettings::PrintToStderr)
  .get_matches()

Alternatives, if applicable

I am currently intercepting all clap messages and printing them manually like this:

App::new(...).
  ...
 .get_matches_safe()
 .unwrap_or_else(|err| {
     eprintln!("{}", err.message);
     std::process::exit(1);
});

but it feels a bit hacky to me.

@pksunkara pksunkara added this to the 3.1 milestone Apr 5, 2020
@Dylan-DPC-zz
Copy link

@tzakharko hi thanks for the issue, would you be willing to send us a pr that makes this change? thanks

@tzakharko
Copy link
Author

@Dylan-DPC I am afraid I am neither familiar enough with the Clap codebase nor with Rust to figure out the best way of doing it at the moment. I suppose one would hav etc decouple the output settings from the Error struct, so it's probably not trivial.

I have opened the issue mainly because @pksunkara asked me to do so in a discussion thread. I understand this might be lower priority.

@Dylan-DPC-zz
Copy link

@tzakharko that's fine we will mentor you if needed. It's a good way to learn rust :D

@tzakharko
Copy link
Author

@Dylan-DPC fair enough :) I will have a look, but I won't be able to allocate any time for this short term. I will put it on my agenda and let's keep the issue open for now.

@CreepySkeleton CreepySkeleton added D: easy E-easy Call for participation: Experience needed to fix: Easy / not much labels Jun 30, 2020
@olson-sean-k
Copy link

I imagine this would be much trickier to implement, but how do folks feel about allowing arbitrary Write targets for this? Instead of naming bespoke outputs, users could instead provide an impl Write. This would still support selecting stdout or stderr via std::io::stdout and std::io::stderr, which both emit impl Write types.

I've been working on a CLI tool that incorporates paging by conditionally targeting a paging child process or the configured terminal. bat does something similar. AFAICT, it is not possible to use clap's generated help text, options, and subcommands with such a paging mechanism and the only alternative would be to define help options and subcommands manually and use App::print{_long}_help by hand. For example, you'll notice that both nym and bat automatically page their output except for help text, which is written to stdout by clap.

@epage epage added A-help Area: documentation, including docs.rs, readme, examples, etc... and removed C: settings labels Dec 8, 2021
@epage epage removed this from the 3.1 milestone Dec 8, 2021
@epage epage added C-enhancement Category: Raise on the bar on expectations and removed T: new setting labels Dec 8, 2021
@epage
Copy link
Member

epage commented Dec 9, 2021

@tzakharko I believe clap is only reporting --help and --version to stdout. Those are explicit user actions. What would be the use case of passing those flags but still programmatically processing the output so you don't want it on stdout?

@olson-sean-k some quick thoughts on this

  • We wouldn't be able to detect coloring support. Thats ok, the user can do it and tell us what coloring to do (we would only be able to support ansi coloring)
  • It'd be a bit annoying to pass the lifetimes everywhere if its part of the builder. We're trying to reduce our lifetimes (Lifetimes of App, Arg, ArgGroup: removing or relaxing #1041 )

@epage epage added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed P4: nice to have E-easy Call for participation: Experience needed to fix: Easy / not much labels Dec 9, 2021
@epage
Copy link
Member

epage commented Jan 11, 2022

I am leaning towards rejecting this until we have a use case that explains why output going to stdout for explicit user interactions is interfering with an applications behavior (especially since there are cases where people want their -V to be parseable).

This isn't to make a statement of whether we want this or not but because we are specifically looking at finding ways to trim the API of clap which also raises the bar for changes that expand the API.

@epage epage closed this as completed Jan 11, 2022
@epage epage added S-wont-fix Status: Closed as there is no plan to fix this and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 11, 2022
@TheOnlyMrCat
Copy link

An example use case is if a command is leveraging shell hooks to cd when certain subcommands are used. The shell hook is only capable of capturing stdout, due to limitations of the shell language, but the program otherwise tries to behave like a normal shell command with subcommands and flags.

@epage
Copy link
Member

epage commented Jan 13, 2022

I've not dealt with shell hooks to cd. Could you elaborate more on the relationhip between the command and the hook and how a call to --help or --version wouldn't be processed correctly?

@TheOnlyMrCat
Copy link

The shell hook is the main interface to the program, so the user would be expected to run prog --help.
The shell hook passes all arguments through to the program and captures the contents of stdout. (There is no way to swap stdout and stderr).

The automatic --help and --version flags print to stdout, which is incorrectly interpreted as a directory to attempt to change to, and as a result are not shown to the user in the intended way.

function prog() {
    result="$(prog_bin $@)" # Run `prog_bin` with the supplied arguments, capturing stdout but leaving stderr to the tty
    [[ -n $result ]] && cd $result # If anything was printed to stdout, `cd` to it.
}

@tzakharko
Copy link
Author

@epage Sorry for replying late and thanks for following this through. I have to be quite honest that I do not remember what was the actual problem that made me open this issue, it was two years ago and couldn't find any relevant notes. I think it had to do with the fact that some outputs did not pipe correctly when uses as part of a complex unix command sequence, but we are not currently using these tools so I guess that's all I can say.

At any rate, I would be fine with this being closed, as it is not a critical issue for us at the moment. But I gather from the comments that some other folks are running into real-world issues, so maybe they will have a better motivating example.

@olson-sean-k
Copy link

It seems that version 4.0 of clap is on the horizon, so I wanted to bump this again in hopes that some of the dust has settled since this issue was first opened.

I am leaning towards rejecting this until we have a use case that explains why output going to stdout for explicit user interactions is interfering with an applications behavior

I believe the use case described in my previous comment has precedent and falls into this category. It is not possible to (comprehensively) implement cli --pager=target if clap cannot be configured to write to (more) arbitrary targets. Redirecting standard I/O streams does not completely solve I/O routing for a CLI application.

We wouldn't be able to detect coloring support. ... the user can do it and tell us what coloring to do

I feel that clap should probably allow users to configure styled (colored) output in all cases. Arbitrary outputs could interact with the styling APIs, with something like a RenderTarget that provides styling information as well as the impl Write target.

Regarding styling, perhaps detection and styles could be feature gated. When the styling feature is enabled, RenderTarget::default could try to detect styling support and use it where available while simply disabling it when the feature is not enabled. In both of these cases the default impl Write target could be std::io::stdout.

Any thoughts on something like this post-4.0? Thanks for taking a look!

@epage
Copy link
Member

epage commented Sep 22, 2022

I believe the use case described in #1788 (comment) has precedent and falls into this category. It is not possible to (comprehensively) implement cli --pager=target if clap cannot be configured to write to (more) arbitrary targets. Redirecting standard I/O streams does not completely solve I/O routing for a CLI application.

Requiring clap to take on lifetimes again to pass around the streams would be a no-go.

For you printing everything yourself, my hope is that with the new styling API I plan to focus on for 4.x, we'll be able to provide you a render_help function that returns a type that will output ANSI escape codes (currently, we only allow access to output stripped of escape codes)

Regarding styling, perhaps detection and styles could be feature gated.

Any thoughts on something like this post-4.0? Thanks for taking a look!

My priority is going to be on the issues currently targeting 4.x. People are free to come up with a design for additional APIs but the further from my priorities, the less attention it will get. There will also be a high bar for impact on all users.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-help Area: documentation, including docs.rs, readme, examples, etc... C-enhancement Category: Raise on the bar on expectations S-wont-fix Status: Closed as there is no plan to fix this
Projects
None yet
Development

No branches or pull requests

7 participants