From b82ccf1882a470972e6842ed02436867727ac758 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Fri, 1 Oct 2021 21:42:26 -0700 Subject: [PATCH] Add `--base-directory` to `imdl torrent verify` type: added --- src/subcommand/torrent/verify.rs | 100 +++++++++++++++++++++++++++++-- src/test_env.rs | 8 +++ 2 files changed, 102 insertions(+), 6 deletions(-) diff --git a/src/subcommand/torrent/verify.rs b/src/subcommand/torrent/verify.rs index 59972c1..28cbcd2 100644 --- a/src/subcommand/torrent/verify.rs +++ b/src/subcommand/torrent/verify.rs @@ -16,7 +16,19 @@ const INPUT_FLAG: &str = "input-flag"; version_message(consts::VERSION_MESSAGE), about("Verify files against a .torrent file.") )] +#[cfg_attr(test, structopt(setting = AppSettings::ColorNever))] pub(crate) struct Verify { + #[structopt( + long = "base-directory", + short = "b", + value_name = "BASE-DIRECTORY", + conflicts_with = "content", + empty_values(false), + parse(from_os_str), + help = "Look for torrent content in `BASE-DIRECTORY`/`NAME`, where `NAME` is the `name` field \ + of the torrent info dictionary." + )] + base_directory: Option, #[structopt( long = "content", short = "c", @@ -24,7 +36,7 @@ pub(crate) struct Verify { empty_values(false), parse(from_os_str), help = "Verify torrent content at `PATH` against torrent metainfo. Defaults to `name` field \ - of torrent info dictionary." + of the torrent info dictionary." )] content: Option, #[structopt( @@ -64,13 +76,19 @@ impl Verify { let metainfo = Metainfo::from_input(&input)?; - let content = self.content.as_ref().map_or_else( - || match target { + let content = self + .content + .as_ref() + .cloned() + .or_else(|| { + self + .base_directory + .map(|base_directory| base_directory.join(&metainfo.info.name).lexiclean()) + }) + .unwrap_or_else(|| match target { InputTarget::Path(path) => path.join("..").join(&metainfo.info.name).lexiclean(), InputTarget::Stdin => PathBuf::from(&metainfo.info.name), - }, - PathBuf::clone, - ); + }); let progress_bar = if env.err().is_styled_term() && !options.quiet { let style = ProgressStyle::default_bar() @@ -137,6 +155,20 @@ mod tests { assert_matches!(env.run(), Err(Error::Clap { .. })); } + #[test] + fn base_directory_conflicts_with_content() { + let mut env = test_env! { + args: ["torrent", "verify", "foo.torrent", "--content", "foo", "--base-directory", "dir"], + tree: {}, + }; + assert_eq!( + env.run().unwrap_err().to_string(), + "error: The argument '--content ' cannot be used with '--base-directory \ + '\n\nUSAGE:\n imdl torrent verify --base-directory \ + --content \n\nFor more information try --help\n" + ); + } + #[test] fn pass() -> Result<()> { let mut create_env = test_env! { @@ -323,6 +355,62 @@ mod tests { Ok(()) } + #[test] + fn base_directory() -> Result<()> { + let mut create_env = test_env! { + args: [ + "torrent", + "create", + "--input", + "foo", + "--announce", + "https://bar", + ], + tree: { + foo: { + a: "abc", + d: "efg", + h: "ijk", + }, + }, + }; + + create_env.assert_ok(); + + create_env.create_dir("dir"); + + create_env.rename("foo", "dir/foo"); + + let torrent = create_env.resolve("foo.torrent")?; + let dir = create_env.resolve("dir")?; + + let mut verify_env = test_env! { + args: [ + "torrent", + "verify", + "--input", + &torrent, + "--base-directory", + &dir, + ], + tree: {}, + }; + + verify_env.assert_ok(); + + let want = format!( + "[1/2] \u{1F4BE} Loading metainfo from `{}`…\n[2/2] \u{1F9EE} Verifying pieces from \ + `{}`…\n\u{2728}\u{2728} Verification succeeded! \u{2728}\u{2728}\n", + torrent.display(), + dir.join("foo").display(), + ); + + assert_eq!(verify_env.err(), want); + assert_eq!(verify_env.out(), ""); + + Ok(()) + } + #[test] fn verify_stdin() -> Result<()> { let mut create_env = test_env! { diff --git a/src/test_env.rs b/src/test_env.rs index 26e1524..f108df1 100644 --- a/src/test_env.rs +++ b/src/test_env.rs @@ -77,6 +77,14 @@ impl TestEnv { fs::create_dir(self.env.resolve(path).unwrap()).unwrap(); } + pub(crate) fn rename(&self, from: impl AsRef, to: impl AsRef) { + fs::rename( + self.env.resolve(from).unwrap(), + self.env.resolve(to).unwrap(), + ) + .unwrap(); + } + pub(crate) fn read_to_string(&self, path: impl AsRef) -> String { fs::read_to_string(self.env.resolve(path).unwrap()).unwrap() }