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

Support development of well-behaved CLI apps #21

Open
jonblack opened this issue Mar 20, 2018 · 21 comments
Open

Support development of well-behaved CLI apps #21

jonblack opened this issue Mar 20, 2018 · 21 comments
Labels
A-book Area: Documenting how to create CLIs C-tracking-issue Category: A tracking issue for an unstable feature

Comments

@jonblack
Copy link

jonblack commented Mar 20, 2018

CLI applications are expected to behave in a certain way. This is especially important when those applications are used in scripts.

I can always add more from the comments.

@epage
Copy link
Contributor

epage commented Mar 20, 2018

Someone else brought up consistency in command line flags. These resources might be useful

@BurntSushi
Copy link

Another to add to the list:

  • CLI tools should exit gracefully when a "broken pipe" error occurs.

@killercup
Copy link
Collaborator

killercup commented Mar 20, 2018

Thanks for opening this! One of the goals of this WG should be to have a best-pratice list like this including source code example in Rust :)

@uazu
Copy link

uazu commented Mar 20, 2018

Another suggestion:

  • It should be possible to enable a log-file friendly output mode where only permitted output is printable text, tab, LF (or CRLF for Windows) plus optionally ANSI colour escapes
  • It should be possible to disable use of ANSI colour escapes

The intention is to allow the log-files to be viewed sensibly in a pager or when converted to HTML in a browser.

@killercup
Copy link
Collaborator

More advanced/obscure:

  • If the tool is meant to be consumed by other tools (instead of/in addition to humans), provide specified, machine readable output (e.g., --message-formate=json which prints one JSON document per line and nothing else to stdout)

@lzybkr
Copy link

lzybkr commented Mar 20, 2018

@killercup - I think structured output will not be obscure in the future.

PowerShell has demonstrated the usefulness of structured output, but that usefulness quickly disappears stepping outside of PowerShell's cmdlets and scripts.

CLI tools are using language specific frameworks more and more which helps a lot with offering UI benefits like common command line parsing, generating command completions. I really hope structured output is one of these future benefits.

ripgrep --vimgrep is one immediate non-shell example where structured output is super useful, I envision a future where there are multiple shells other than PowerShell that would benefit from structured output as well.

@kbknapp
Copy link
Contributor

kbknapp commented Mar 21, 2018

I have the start of the "book" (I use that term loosely) I started which was meant to going over these exact points. CLI consistency is something I'm very interested in and would like to work on.

If I get some spare time, perhaps I can start this back up and open it up to the community for edits.

The book started as a clap reference, but the more I've thought about it I what I really want to do is sections that are more parser agnostic and goes over building command line applications and best practices such as the ones listed above.

Ultimately I'd like the book to be broken up into three parts:

  • Command Line Guidelines/UX (Not necessarily Rust specific)
  • Building command line applications in Rust (would focus on Rust centric work, so some parts are specific idiosyncrasy of Rust (println! panicing on a broken pipe, error handling, etc.)
  • Using clap (more friendly than the API docs, and more of a reference)

@jonblack
Copy link
Author

@kbknapp I like the proposed layout for the book and would love to help out. A lot of what's being proposed I suspect will end up in the first section since they are guidelines. I also think some of these behaviors are optional (e.g. structured output) while others should be politely enforced (e.g. exit status, graceful exit, ansi colors) with a crate or two.

@jonblack
Copy link
Author

I found the following quotes about the UNIX philosophy which I think outline our cause, too:

Many UNIX programs do quite trivial things in isolation, but, combined with other programs, become general and useful tools. - Brian Kernighan, 1984

This is the UNIX philosophy: write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface. - Doug McIllroy, 1978

@jonblack
Copy link
Author

jonblack commented Mar 21, 2018

I copied the following items from the here: https://www.slideshare.net/bigfishdesign/well-behaved-unix:

  • Correctly handle signals (SIGHUP, SIGINT, SIGCHLD)
  • Respect hard/soft resource limits (e.g. max open files)

@kalefranz
Copy link

I’m a rust n00b, coming from python. So could be a non-issue for rust, but w.r.t. signal handling... a tricky part seems to be correctly passing those signals to subprocesses. Basically making sure users ultimately get the expected behavior from a sent signal even if the primary process has happened to fork a subprocess or three.

@XAMPPRocky
Copy link

For some of items mentioned at the top could a utility be built that lints against binaries in general? For example you give it a list of commands, ones that should succeed & fail and check against the status code, read the —help format check that each short option has a long option equivalent, etc.

@Screwtapello
Copy link

For more potential suggestions about "well-behaved CLI apps", you could look at the GNU Coding Standards. Highlights include:

  • Error messages from compilers should look like this: sourcefile:lineno: message [...] Error messages from other noninteractive programs should look like this: program:sourcefile:lineno: message when there is an appropriate source file, or like this: program: message when there is no relevant source file.
  • Please don’t make the behavior of a utility depend on the name used to invoke it. It is useful sometimes to make a link to a utility with a different name, and that should not change what it does.
  • Likewise, please don’t make the behavior of a command-line program depend on the type of output device it gets as standard output or standard input. Device independence is an important principle of the system’s design; do not compromise it merely to save someone from typing an option now and then.
  • It is usually a good idea for file names given as ordinary arguments to be input files only; any output files would be specified using options (preferably -o or --output).
  • Near the end of the --help options output please place lines giving the email address for bug reports [and] the package’s home page
  • A big long list of long-option names you can choose from, to make it more likely that users will guess the right options for your program

There's a bunch of other guidance too, some of it more or less specific to GNU projects and/or C projects.

I can't find an equivalent document for OpenBSD or FreeBSD, except that style(9) mentions "Usage statements should look like the manual page's SYNOPSIS."

@luser
Copy link

luser commented Mar 21, 2018

Likewise, please don’t make the behavior of a command-line program depend on the type of output device it gets as standard output or standard input. Device independence is an important principle of the system’s design; do not compromise it merely to save someone from typing an option now and then.

As a counterpoint, I do think detecting a terminal for automatic color output is sensible and widely adopted.

I don't love the GNU standards, but there are certainly some good things in there. Supporting --help and --version has become widely accepted, for example.

@epage
Copy link
Contributor

epage commented Mar 21, 2018

Should we include any guidance on line endings?

With cobalt, we had some tests failing when developers were using autocrlf because of some odd behaviors. in cobalt cobalt was inconsistent on line endings e.g. if you used markdown, then the line endings would be normalized. We ended up just giving up and calling normalize_line_endings on everything.

@Screwtapello
Copy link

As a counterpoint, I do think detecting a terminal for automatic color output is sensible and widely adopted.

Yeah, at this point I'd be surprised and a little annoyed if a program didn't turn off colour output when piped to another command.

I think that particular guideline is aimed at tools like ripgrep that produce output in a different syntax, not just uncoloured, when the output is a terminal. I remember trying to write a shell-script to do something useful with ripgrep output once; I ran ripgrep once to see what the output looked like, I wrote my script to manage that output, then I piped ripgrep's output into my script and everything fell apart. I certainly understand why ripgrep does that (it tries to produce more machine-readable output when it thinks it's talking to a machine), but I'd probably rather it print the same format but log a warning to stderr like "You seem to be piping ripgrep output to another program; you can use the --vimgrep option to produce output that's easier to parse, or --quiet to silence this hint".

Should we include any guidance on line endings?

You mean in program output, or what line-endings programs should support in input files?

@epage
Copy link
Contributor

epage commented Mar 21, 2018

You mean in program output, or what line-endings programs should support in input files?

The one that I was thinking of was output but probably good to document input as well.

@uazu
Copy link

uazu commented Mar 21, 2018

Yeah, at this point I'd be surprised and a little annoyed if a program didn't turn off colour output when piped to another command.

But then again 'less' can handle colour output (with -R), so I'd want an option to turn it back on again for piping to less. With ripgrep I have a wrapper script which sets it all up as I want it.

@tomwhoiscontrary
Copy link

On signals, can i suggest handling SIGWINCH? You can get that when the user resizes the terminal you're running in. The right behaviour might be to do nothing, or to redraw if it's a curses-style interface. It's almost certainly not to crash, which is something i have seen!

@uazu
Copy link

uazu commented Jun 8, 2018

When SIGWINCH is used, wouldn't it normally be handled by the curses-like layer? That's how I've coded it in the past. So normal app code wouldn't need to touch it. It is something specific to library code in just a few places. Anyway, perhaps you could add a note to #27.

@XAMPPRocky
Copy link

While curses/TUI's aren't covered by the WG I would like to see some way of having responsive cli output for humans as currently to be the most compatible you have to print at 80 columns. For example if you're printing a table it'd be nice to be set a minimum and maximum column width with shortening or line breaking a column. Also on SIGWINCH specifically it'd be nice for loading bars to be respond to terminal width changes than break completely on any width change.

@killercup killercup mentioned this issue Jul 24, 2018
@settings settings bot removed the tracking issue label Aug 23, 2022
@epage epage added A-book Area: Documenting how to create CLIs C-tracking-issue Category: A tracking issue for an unstable feature labels Aug 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-book Area: Documenting how to create CLIs C-tracking-issue Category: A tracking issue for an unstable feature
Projects
None yet
Development

No branches or pull requests