From c18c0bbbe455119c935510bd6fb65292e97950b1 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 26 Feb 2018 22:43:26 +0100 Subject: [PATCH] Provide stdin/out/err resources via Runtime object This way we can control whether "out" output goes to stdout or stderr without the user of the functionality knowing. This is useful for later when we use libimagrt to automatically read and write the store from and to stdout/in depending on whether we are talking to a TTY or a pipe. --- lib/core/libimagrt/Cargo.toml | 1 + lib/core/libimagrt/src/lib.rs | 1 + lib/core/libimagrt/src/runtime.rs | 53 +++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/lib/core/libimagrt/Cargo.toml b/lib/core/libimagrt/Cargo.toml index e8a569ba..11e38d5f 100644 --- a/lib/core/libimagrt/Cargo.toml +++ b/lib/core/libimagrt/Cargo.toml @@ -29,6 +29,7 @@ is-match = "0.1" toml-query = "0.6" error-chain = "0.11" handlebars = "0.29.0" +atty = "0.2" libimagstore = { version = "0.7.0", path = "../../../lib/core/libimagstore" } libimagerror = { version = "0.7.0", path = "../../../lib/core/libimagerror" } diff --git a/lib/core/libimagrt/src/lib.rs b/lib/core/libimagrt/src/lib.rs index b6c6e735..8895f39d 100644 --- a/lib/core/libimagrt/src/lib.rs +++ b/lib/core/libimagrt/src/lib.rs @@ -47,6 +47,7 @@ extern crate clap; extern crate toml; extern crate toml_query; #[macro_use] extern crate is_match; +extern crate atty; extern crate libimagstore; extern crate libimagutil; diff --git a/lib/core/libimagrt/src/runtime.rs b/lib/core/libimagrt/src/runtime.rs index e1f8fa8a..dbbfbb51 100644 --- a/lib/core/libimagrt/src/runtime.rs +++ b/lib/core/libimagrt/src/runtime.rs @@ -21,6 +21,9 @@ use std::path::PathBuf; use std::process::Command; use std::env; use std::process::exit; +use std::io::Stdin; +use std::io::Write; +use std::fmt::Debug; pub use clap::App; use toml::Value; @@ -47,6 +50,43 @@ pub struct Runtime<'a> { configuration: Option, cli_matches: ArgMatches<'a>, store: Store, + resources: Resources, +} + +/// Resources for standard output, error output and input stream +/// +/// These resources are set depending whether stdin/stdout are TTYs or not, but they are always +/// provided. +struct Resources { + stdout : Box, + stderr : Box, + stdin : Option, +} + +impl Debug for Resources { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + write!(f, "Resources(...)") + } +} + +/// Builds a Resource object +/// +/// If stdout is not a TTY, the Resources::stdout will actually point to stderr +/// If stdin is not a TTY, it will be None +fn aquire_resources() -> Resources { + Resources { + stdout: if ::atty::is(::atty::Stream::Stdout) { + Box::new(::std::io::stdout()) + } else { + Box::new(::std::io::stderr()) + }, + stderr: Box::new(::std::io::stderr()), + stdin: if ::atty::is(::atty::Stream::Stdin) { + Some(::std::io::stdin()) + } else { + None + }, + } } impl<'a> Runtime<'a> { @@ -150,6 +190,7 @@ impl<'a> Runtime<'a> { configuration: config, rtp: rtp, store: store, + resources: aquire_resources(), } }) .chain_err(|| RuntimeErrorKind::Instantiate) @@ -438,6 +479,18 @@ impl<'a> Runtime<'a> { .or(env::var("EDITOR").ok()) .map(Command::new) } + + pub fn stdout(&self) -> &Box { + &self.resources.stdout + } + + pub fn stderr(&self) -> &Box { + &self.resources.stderr + } + + pub fn stdin(&self) -> Option<&Stdin> { + self.resources.stdin.as_ref() + } } /// Exported for the `imag` command, you probably do not want to use that.