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.
This commit is contained in:
Matthias Beyer 2018-02-26 22:43:26 +01:00
parent f88884c321
commit c18c0bbbe4
3 changed files with 55 additions and 0 deletions

View File

@ -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" }

View File

@ -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;

View File

@ -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<Value>,
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<Write>,
stderr : Box<Write>,
stdin : Option<Stdin>,
}
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<Write> {
&self.resources.stdout
}
pub fn stderr(&self) -> &Box<Write> {
&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.