2019-05-24 01:25:55 -07:00
|
|
|
use crate::common::*;
|
|
|
|
|
2020-01-07 18:05:48 -08:00
|
|
|
pub(crate) struct Env {
|
2020-03-05 21:44:20 -08:00
|
|
|
args: Vec<OsString>,
|
2020-03-07 19:23:20 -08:00
|
|
|
dir: PathBuf,
|
2020-03-15 03:22:33 -07:00
|
|
|
err: OutputStream,
|
|
|
|
out: OutputStream,
|
2019-05-24 01:25:55 -07:00
|
|
|
}
|
|
|
|
|
2020-01-07 18:05:48 -08:00
|
|
|
impl Env {
|
2020-01-04 18:58:42 -08:00
|
|
|
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),
|
|
|
|
};
|
|
|
|
|
2020-03-15 03:22:33 -07:00
|
|
|
let style = env::var_os("NO_COLOR").is_none()
|
|
|
|
&& env::var_os("TERM").as_deref() != Some(OsStr::new("dumb"));
|
2020-02-04 10:54:41 -08:00
|
|
|
|
2020-03-15 03:22:33 -07:00
|
|
|
let out_stream = OutputStream::stdout(style);
|
|
|
|
let err_stream = OutputStream::stderr(style);
|
2020-02-04 10:54:41 -08:00
|
|
|
|
2020-03-15 03:22:33 -07:00
|
|
|
Self::new(dir, env::args(), out_stream, err_stream)
|
2019-05-24 01:25:55 -07:00
|
|
|
}
|
|
|
|
|
2020-01-04 18:58:42 -08:00
|
|
|
pub(crate) fn run(&mut self) -> Result<(), Error> {
|
2020-01-15 23:37:12 -08:00
|
|
|
#[cfg(windows)]
|
|
|
|
ansi_term::enable_ansi_support().ok();
|
|
|
|
|
|
|
|
#[cfg(not(test))]
|
2020-02-14 00:12:49 -08:00
|
|
|
pretty_env_logger::init();
|
2020-01-15 23:37:12 -08:00
|
|
|
|
2020-03-06 22:50:04 -08:00
|
|
|
let args = Arguments::from_iter_safe(&self.args)?;
|
2020-01-15 23:37:12 -08:00
|
|
|
|
2020-03-15 03:22:33 -07:00
|
|
|
let use_color = args.options().use_color;
|
|
|
|
self.err.set_use_color(use_color);
|
|
|
|
self.out.set_use_color(use_color);
|
2020-01-15 23:37:12 -08:00
|
|
|
|
2020-03-06 22:50:04 -08:00
|
|
|
args.run(self)
|
2019-05-24 01:25:55 -07:00
|
|
|
}
|
|
|
|
|
2020-03-15 03:22:33 -07:00
|
|
|
pub(crate) fn new<S, I>(dir: PathBuf, args: I, out: OutputStream, err: OutputStream) -> Self
|
2019-05-24 01:25:55 -07:00
|
|
|
where
|
2020-03-05 21:44:20 -08:00
|
|
|
S: Into<OsString>,
|
2019-05-24 01:25:55 -07:00
|
|
|
I: IntoIterator<Item = S>,
|
|
|
|
{
|
2020-01-04 18:58:42 -08:00
|
|
|
Self {
|
|
|
|
args: args.into_iter().map(Into::into).collect(),
|
2020-03-07 19:23:20 -08:00
|
|
|
dir,
|
2020-03-15 03:22:33 -07:00
|
|
|
out,
|
|
|
|
err,
|
2019-05-24 01:25:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn status(&mut self) -> Result<(), i32> {
|
2020-01-14 00:52:27 -08:00
|
|
|
use structopt::clap::ErrorKind;
|
2020-01-15 23:37:12 -08:00
|
|
|
|
2019-05-24 01:25:55 -07:00
|
|
|
if let Err(error) = self.run() {
|
2020-01-14 00:52:27 -08:00
|
|
|
if let Error::Clap { source } = error {
|
2020-01-15 23:37:12 -08:00
|
|
|
if source.use_stderr() {
|
|
|
|
write!(&mut self.err, "{}", source).ok();
|
|
|
|
} else {
|
|
|
|
write!(&mut self.out, "{}", source).ok();
|
|
|
|
}
|
2020-01-14 00:52:27 -08:00
|
|
|
match source.kind {
|
|
|
|
ErrorKind::VersionDisplayed | ErrorKind::HelpDisplayed => Ok(()),
|
|
|
|
_ => Err(EXIT_FAILURE),
|
|
|
|
}
|
|
|
|
} else {
|
2020-03-15 03:22:33 -07:00
|
|
|
let style = self.err.style();
|
2020-01-15 23:37:12 -08:00
|
|
|
writeln!(
|
|
|
|
&mut self.err,
|
|
|
|
"{}{}: {}{}",
|
2020-03-15 03:22:33 -07:00
|
|
|
style.error().paint("error"),
|
|
|
|
style.message().prefix(),
|
2020-01-15 23:37:12 -08:00
|
|
|
error,
|
2020-03-15 03:22:33 -07:00
|
|
|
style.message().suffix(),
|
2020-01-15 23:37:12 -08:00
|
|
|
)
|
|
|
|
.ok();
|
2020-02-03 04:39:48 -08:00
|
|
|
|
|
|
|
if let Some(lint) = error.lint() {
|
|
|
|
writeln!(
|
|
|
|
&mut self.err,
|
|
|
|
"{}: This check can be disabled with `--allow {}`.",
|
2020-03-15 03:22:33 -07:00
|
|
|
style.message().paint("note"),
|
2020-02-03 04:39:48 -08:00
|
|
|
lint.name()
|
|
|
|
)
|
|
|
|
.ok();
|
|
|
|
}
|
|
|
|
|
2020-01-14 00:52:27 -08:00
|
|
|
Err(EXIT_FAILURE)
|
|
|
|
}
|
2019-05-24 01:25:55 -07:00
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-30 05:54:08 -08:00
|
|
|
pub(crate) fn dir(&self) -> &Path {
|
2020-03-07 19:23:20 -08:00
|
|
|
&self.dir
|
2020-01-30 05:54:08 -08:00
|
|
|
}
|
|
|
|
|
2019-05-24 01:25:55 -07:00
|
|
|
pub(crate) fn resolve(&self, path: impl AsRef<Path>) -> PathBuf {
|
2020-01-30 05:54:08 -08:00
|
|
|
self.dir().join(path).clean()
|
2019-05-24 01:25:55 -07:00
|
|
|
}
|
2020-02-04 10:54:41 -08:00
|
|
|
|
2020-03-15 03:22:33 -07:00
|
|
|
pub(crate) fn err(&self) -> &OutputStream {
|
|
|
|
&self.err
|
2020-02-04 10:54:41 -08:00
|
|
|
}
|
|
|
|
|
2020-03-15 03:22:33 -07:00
|
|
|
pub(crate) fn err_mut(&mut self) -> &mut OutputStream {
|
|
|
|
&mut self.err
|
2020-02-04 10:54:41 -08:00
|
|
|
}
|
2020-03-12 01:08:40 -07:00
|
|
|
|
2020-03-15 03:22:33 -07:00
|
|
|
pub(crate) fn out(&self) -> &OutputStream {
|
|
|
|
&self.out
|
2020-03-12 01:08:40 -07:00
|
|
|
}
|
2020-03-12 18:00:52 -07:00
|
|
|
|
2020-03-15 03:22:33 -07:00
|
|
|
pub(crate) fn out_mut(&mut self) -> &mut OutputStream {
|
|
|
|
&mut self.out
|
2020-03-12 18:00:52 -07:00
|
|
|
}
|
2019-05-24 01:25:55 -07:00
|
|
|
}
|
2020-01-14 00:52:27 -08:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn error_message_on_stdout() {
|
2020-03-05 21:44:20 -08:00
|
|
|
let mut env = test_env! {
|
|
|
|
args: [
|
2020-01-24 14:17:31 -08:00
|
|
|
"torrent",
|
|
|
|
"create",
|
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"udp:bar.com",
|
|
|
|
"--announce-tier",
|
|
|
|
"foo",
|
2020-03-05 21:44:20 -08:00
|
|
|
],
|
|
|
|
tree: {
|
|
|
|
foo: "",
|
|
|
|
}
|
|
|
|
};
|
2020-01-14 00:52:27 -08:00
|
|
|
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(), "");
|
|
|
|
}
|
|
|
|
}
|