intermodal/src/env.rs

182 lines
3.9 KiB
Rust
Raw Normal View History

2019-05-24 01:25:55 -07:00
use crate::common::*;
pub(crate) struct Env {
args: Vec<OsString>,
2019-05-24 01:25:55 -07:00
dir: Box<dyn AsRef<Path>>,
pub(crate) err: Box<dyn Write>,
pub(crate) out: Box<dyn Write>,
err_style: Style,
out_style: Style,
out_is_term: bool,
2019-05-24 01:25:55 -07:00
}
impl Env {
pub(crate) fn main() -> Self {
2019-05-24 01:25:55 -07:00
let dir = match env::current_dir() {
Ok(dir) => dir,
Err(error) => panic!("Failed to get current directory: {}", error),
};
let no_color = env::var_os("NO_COLOR").is_some()
|| env::var_os("TERM").as_deref() == Some(OsStr::new("dumb"));
let err_style = if no_color || !atty::is(atty::Stream::Stderr) {
Style::inactive()
} else {
Style::active()
};
let out_style = if no_color || !atty::is(atty::Stream::Stdout) {
Style::inactive()
} else {
Style::active()
};
let out_is_term = atty::is(atty::Stream::Stdout);
Self::new(
dir,
io::stdout(),
out_style,
out_is_term,
io::stderr(),
err_style,
env::args(),
)
2019-05-24 01:25:55 -07:00
}
pub(crate) fn run(&mut self) -> Result<(), Error> {
#[cfg(windows)]
ansi_term::enable_ansi_support().ok();
#[cfg(not(test))]
pretty_env_logger::init();
let args = Arguments::from_iter_safe(&self.args)?;
match args.options().use_color {
UseColor::Always => self.err_style = Style::active(),
UseColor::Auto => {}
UseColor::Never => self.err_style = Style::inactive(),
}
args.run(self)
2019-05-24 01:25:55 -07:00
}
pub(crate) fn new<D, O, E, S, I>(
dir: D,
out: O,
out_style: Style,
out_is_term: bool,
err: E,
err_style: Style,
args: I,
) -> Self
2019-05-24 01:25:55 -07:00
where
D: AsRef<Path> + 'static,
O: Write + 'static,
2019-05-24 01:25:55 -07:00
E: Write + 'static,
S: Into<OsString>,
2019-05-24 01:25:55 -07:00
I: IntoIterator<Item = S>,
{
Self {
args: args.into_iter().map(Into::into).collect(),
2019-05-24 01:25:55 -07:00
dir: Box::new(dir),
err: Box::new(err),
out: Box::new(out),
out_style,
out_is_term,
err_style,
2019-05-24 01:25:55 -07:00
}
}
pub(crate) fn status(&mut self) -> Result<(), i32> {
use structopt::clap::ErrorKind;
2019-05-24 01:25:55 -07:00
if let Err(error) = self.run() {
if let Error::Clap { source } = error {
if source.use_stderr() {
write!(&mut self.err, "{}", source).ok();
} else {
write!(&mut self.out, "{}", source).ok();
}
match source.kind {
ErrorKind::VersionDisplayed | ErrorKind::HelpDisplayed => Ok(()),
_ => Err(EXIT_FAILURE),
}
} else {
writeln!(
&mut self.err,
"{}{}: {}{}",
self.err_style.error().paint("error"),
self.err_style.message().prefix(),
error,
self.err_style.message().suffix(),
)
.ok();
if let Some(lint) = error.lint() {
writeln!(
&mut self.err,
"{}: This check can be disabled with `--allow {}`.",
self.err_style.message().paint("note"),
lint.name()
)
.ok();
}
Err(EXIT_FAILURE)
}
2019-05-24 01:25:55 -07:00
} else {
Ok(())
}
}
pub(crate) fn dir(&self) -> &Path {
self.dir.as_ref().as_ref()
}
2019-05-24 01:25:55 -07:00
pub(crate) fn resolve(&self, path: impl AsRef<Path>) -> PathBuf {
self.dir().join(path).clean()
2019-05-24 01:25:55 -07:00
}
pub(crate) fn out_is_term(&self) -> bool {
self.out_is_term
}
pub(crate) fn out_style(&self) -> Style {
self.out_style
}
2019-05-24 01:25:55 -07:00
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn error_message_on_stdout() {
let mut env = test_env! {
args: [
"torrent",
"create",
"--input",
"foo",
"--announce",
"udp:bar.com",
"--announce-tier",
"foo",
],
tree: {
foo: "",
}
};
env.status().ok();
let err = env.err();
if !err.starts_with("error: Failed to parse announce URL:") {
panic!("Unexpected standard error output: {}", err);
}
assert_eq!(env.out(), "");
}
}