From ce0bd9298addfbb9f167ddd06bd2c781eb3de8c0 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sat, 10 Mar 2018 15:35:05 +0100 Subject: [PATCH] Implement pipe magic in libimagrt When we merged the changes in libimagrt so that it automatically detects whether stdin/stdout is a TTY and provides the user with stderr in case stdout is not a TTY, we forgot that things like imag foo | grep bar becomes impossible with that, because imag detects that stdout is not a tty and automatically uses stderr for output. But in this case, we don't want that. The output has to be stdout in this case. With this change, we have a flag in the runtime ("--pipe-magic" or "-P", globally available) which turns on "pipe magic". The expected behaviour is the following, if "-P" is passed: * If stdout is a TTY, we print to stdout * If stdout is not a TTY, we print to stderr * If stdin is not a TTY, we do not provide it If "-P" is not passed, we allow the user of libimagrt to use stdin for interactive stuff (the interactive stuff is not yet implemented). Signed-off-by: Matthias Beyer --- lib/core/libimagrt/src/runtime.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/core/libimagrt/src/runtime.rs b/lib/core/libimagrt/src/runtime.rs index aec26192..8f18f75a 100644 --- a/lib/core/libimagrt/src/runtime.rs +++ b/lib/core/libimagrt/src/runtime.rs @@ -49,6 +49,7 @@ pub struct Runtime<'a> { configuration: Option, cli_matches: ArgMatches<'a>, store: Store, + use_pipe_magic: bool, stdin_is_tty: bool, stdout_is_tty: bool, } @@ -148,12 +149,15 @@ impl<'a> Runtime<'a> { Store::new(storepath, &config) }; + let pipe_magic = matches.is_present(Runtime::pipe_magic_name()); + store_result.map(|store| { Runtime { cli_matches: matches, configuration: config, rtp: rtp, store: store, + use_pipe_magic: pipe_magic, stdout_is_tty: ::atty::is(::atty::Stream::Stdout), stdin_is_tty: ::atty::is(::atty::Stream::Stdin), } @@ -249,6 +253,13 @@ impl<'a> Runtime<'a> { .takes_value(true) .value_name("LOGDESTS")) + .arg(Arg::with_name(Runtime::pipe_magic_name()) + .long(Runtime::pipe_magic_name()) + .short("P") + .help("Use pipe-detection. With this flag, imag expects a JSON store on STDIN if stdin is not a TTY and prints the store to STDOUT if it is not a TTY.") + .required(false) + .takes_value(false)) + } /// Get the argument names of the Runtime which are available @@ -338,6 +349,11 @@ impl<'a> Runtime<'a> { "logging-destinations" } + /// Get the argument name for pipe magic + pub fn pipe_magic_name() -> &'static str { + "pipe-magic" + } + /// Initialize the internal logger fn init_logger(matches: &ArgMatches, config: Option<&Value>) { use log::set_max_level; @@ -446,10 +462,10 @@ impl<'a> Runtime<'a> { } pub fn stdout(&self) -> OutputProxy { - if self.stdout_is_tty { - OutputProxy::Out(::std::io::stdout()) - } else { + if self.use_pipe_magic && !self.stdout_is_tty { OutputProxy::Err(::std::io::stderr()) + } else { + OutputProxy::Out(::std::io::stdout()) } } @@ -458,10 +474,10 @@ impl<'a> Runtime<'a> { } pub fn stdin(&self) -> Option { - if self.stdin_is_tty { - Some(::std::io::stdin()) - } else { + if self.use_pipe_magic && !self.stdin_is_tty { None + } else { + Some(::std::io::stdin()) } } }