Compare commits
	
		
			No commits in common. "ea3b22fcccc7aecaf28f8005478a1ad957332a30" and "2346c30fec91633444accb83837a132379e0ea00" have entirely different histories.
		
	
	
		
			ea3b22fccc
			...
			2346c30fec
		
	
		
							
								
								
									
										13
									
								
								.github/workflows/build.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								.github/workflows/build.yaml
									
									
									
									
										vendored
									
									
								
							| @ -39,7 +39,7 @@ jobs: | ||||
|     runs-on: ${{matrix.os}} | ||||
| 
 | ||||
|     env: | ||||
|       RUSTFLAGS: --deny warnings | ||||
|       RUSTFLAGS: "-D warnings" | ||||
| 
 | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
| @ -63,9 +63,14 @@ jobs: | ||||
|           target | ||||
|         key: cargo-${{ env.CACHE_KEY }}-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} | ||||
| 
 | ||||
|     - name: Install Rust Toolchain Components | ||||
|       run: | | ||||
|         rustup component add clippy rustfmt | ||||
|     - name: Install Stable | ||||
|       uses: actions-rs/toolchain@v1 | ||||
|       with: | ||||
|         toolchain: stable | ||||
|         target: ${{matrix.target}} | ||||
|         profile: minimal | ||||
|         components: clippy, rustfmt | ||||
|         override: true | ||||
| 
 | ||||
|     - name: Info | ||||
|       run: | | ||||
|  | ||||
							
								
								
									
										649
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										649
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										17
									
								
								bin/package
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								bin/package
									
									
									
									
									
								
							| @ -26,13 +26,16 @@ case $os in | ||||
|     ;; | ||||
| esac | ||||
| 
 | ||||
| RUSTFLAGS='--deny warnings --codegen target-feature=+crt-static' \ | ||||
|   cargo build --bin $bin --target $target --release | ||||
| executable=target/$target/release/$bin | ||||
| 
 | ||||
| if [[ $os == windows-2016 ]]; then | ||||
|   executable=$executable.exe | ||||
| fi | ||||
| case $os in | ||||
|   ubuntu-latest | macos-latest) | ||||
|     cargo rustc --bin $bin --target $target --release | ||||
|     executable=target/$target/release/$bin | ||||
|     ;; | ||||
|   windows-latest) | ||||
|     cargo rustc --bin $bin --target $target --release -- -C target-feature="+crt-static" | ||||
|     executable=target/$target/release/$bin.exe | ||||
|     ;; | ||||
| esac | ||||
| 
 | ||||
| echo "Building completions..." | ||||
| cargo run --package gen -- --bin $executable completion-scripts | ||||
|  | ||||
| @ -1 +0,0 @@ | ||||
| 1.51.0 | ||||
| @ -7,9 +7,9 @@ const TI: u64 = GI << 10; | ||||
| const PI: u64 = TI << 10; | ||||
| const EI: u64 = PI << 10; | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Copy, Clone, PartialOrd, Ord, Eq, Serialize, Deserialize, Default)] | ||||
| #[serde(transparent)] | ||||
| pub struct Bytes(pub(crate) u64); | ||||
| #[derive(Debug, PartialEq, Copy, Clone, PartialOrd, Ord, Eq, Serialize, Deserialize, Default)] | ||||
| pub(crate) struct Bytes(pub(crate) u64); | ||||
| 
 | ||||
| impl Bytes { | ||||
|   pub(crate) fn kib() -> Self { | ||||
| @ -89,7 +89,7 @@ impl FromStr for Bytes { | ||||
|       _ => { | ||||
|         return Err(Error::ByteSuffix { | ||||
|           text: text.to_owned(), | ||||
|           suffix: suffix.clone(), | ||||
|           suffix: suffix.to_owned(), | ||||
|         }) | ||||
|       } | ||||
|     }; | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| pub struct Env { | ||||
| pub(crate) struct Env { | ||||
|   args: Vec<OsString>, | ||||
|   dir: PathBuf, | ||||
|   input: Box<dyn InputStream>, | ||||
| @ -41,7 +41,7 @@ impl Env { | ||||
|         .and_then(|width| width.parse::<usize>().ok()); | ||||
| 
 | ||||
|       if let Some(width) = width { | ||||
|         app = app.set_term_width(width); | ||||
|         app = app.set_term_width(width) | ||||
|       } | ||||
| 
 | ||||
|       app | ||||
|  | ||||
| @ -2,7 +2,7 @@ use crate::common::*; | ||||
| 
 | ||||
| #[derive(Debug, Snafu)] | ||||
| #[snafu(visibility(pub(crate)))] | ||||
| pub enum Error { | ||||
| pub(crate) enum Error { | ||||
|   #[snafu(display("Failed to parse announce URL: {}", source))] | ||||
|   AnnounceUrlParse { source: url::ParseError }, | ||||
|   #[snafu(display("Failed to parse byte count `{}`: {}", text, source))] | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| #[derive(Deserialize, Serialize, Debug, PartialEq, Clone, Ord, PartialOrd, Eq)] | ||||
| #[serde(transparent)] | ||||
| #[derive(Deserialize, Serialize, Debug, PartialEq, Clone, Ord, PartialOrd, Eq)] | ||||
| pub(crate) struct FilePath { | ||||
|   components: Vec<String>, | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Clone)] | ||||
| pub struct HostPort { | ||||
| pub(crate) struct HostPort { | ||||
|   host: Host, | ||||
|   port: u16, | ||||
| } | ||||
|  | ||||
| @ -2,7 +2,7 @@ use crate::common::*; | ||||
| 
 | ||||
| #[derive(Debug, Snafu)] | ||||
| #[snafu(visibility(pub(crate)))] | ||||
| pub enum HostPortParseError { | ||||
| pub(crate) enum HostPortParseError { | ||||
|   #[snafu(display("Failed to parse host `{}`: {}", text, source))] | ||||
|   Host { | ||||
|     text: String, | ||||
|  | ||||
							
								
								
									
										12
									
								
								src/info.rs
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/info.rs
									
									
									
									
									
								
							| @ -1,22 +1,22 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| #[derive(Deserialize, Serialize, Debug, PartialEq, Clone)] | ||||
| pub struct Info { | ||||
| pub(crate) struct Info { | ||||
|   #[serde(
 | ||||
|     skip_serializing_if = "Option::is_none", | ||||
|     default, | ||||
|     with = "unwrap_or_skip" | ||||
|   )] | ||||
|   pub private: Option<bool>, | ||||
|   pub(crate) private: Option<bool>, | ||||
|   #[serde(rename = "piece length")] | ||||
|   pub piece_length: Bytes, | ||||
|   pub name: String, | ||||
|   pub(crate) piece_length: Bytes, | ||||
|   pub(crate) name: String, | ||||
|   #[serde(
 | ||||
|     skip_serializing_if = "Option::is_none", | ||||
|     default, | ||||
|     with = "unwrap_or_skip" | ||||
|   )] | ||||
|   pub source: Option<String>, | ||||
|   pub(crate) source: Option<String>, | ||||
|   pub(crate) pieces: PieceList, | ||||
|   #[serde(flatten)] | ||||
|   pub(crate) mode: Mode, | ||||
| @ -26,7 +26,7 @@ pub struct Info { | ||||
|     with = "unwrap_or_skip", | ||||
|     rename = "update-url" | ||||
|   )] | ||||
|   pub update_url: Option<Url>, | ||||
|   pub(crate) update_url: Option<Url>, | ||||
| } | ||||
| 
 | ||||
| impl Info { | ||||
|  | ||||
| @ -1,12 +1,12 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||||
| pub struct Infohash { | ||||
|   pub inner: Sha1Digest, | ||||
| pub(crate) struct Infohash { | ||||
|   inner: Sha1Digest, | ||||
| } | ||||
| 
 | ||||
| impl Infohash { | ||||
|   pub fn from_input(input: &Input) -> Result<Infohash, Error> { | ||||
|   pub(crate) fn from_input(input: &Input) -> Result<Infohash, Error> { | ||||
|     let value = Value::from_bencode(input.data()).map_err(|error| Error::MetainfoDecode { | ||||
|       input: input.source().clone(), | ||||
|       error, | ||||
| @ -43,7 +43,7 @@ impl Infohash { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   pub fn from_bencoded_info_dict(info: &[u8]) -> Infohash { | ||||
|   pub(crate) fn from_bencoded_info_dict(info: &[u8]) -> Infohash { | ||||
|     Infohash { | ||||
|       inner: Sha1Digest::from_data(info), | ||||
|     } | ||||
|  | ||||
| @ -1,20 +1,20 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| pub struct Input { | ||||
| pub(crate) struct Input { | ||||
|   source: InputTarget, | ||||
|   data: Vec<u8>, | ||||
| } | ||||
| 
 | ||||
| impl Input { | ||||
|   pub fn new(source: InputTarget, data: Vec<u8>) -> Input { | ||||
|   pub(crate) fn new(source: InputTarget, data: Vec<u8>) -> Input { | ||||
|     Self { source, data } | ||||
|   } | ||||
| 
 | ||||
|   pub fn data(&self) -> &[u8] { | ||||
|   pub(crate) fn data(&self) -> &[u8] { | ||||
|     &self.data | ||||
|   } | ||||
| 
 | ||||
|   pub fn source(&self) -> &InputTarget { | ||||
|   pub(crate) fn source(&self) -> &InputTarget { | ||||
|     &self.source | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -1,13 +1,13 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| #[derive(PartialEq, Debug, Clone)] | ||||
| pub enum InputTarget { | ||||
| pub(crate) enum InputTarget { | ||||
|   Path(PathBuf), | ||||
|   Stdin, | ||||
| } | ||||
| 
 | ||||
| impl InputTarget { | ||||
|   pub fn try_from_os_str(text: &OsStr) -> Result<Self, OsString> { | ||||
|   pub(crate) fn try_from_os_str(text: &OsStr) -> Result<Self, OsString> { | ||||
|     text | ||||
|       .try_into() | ||||
|       .map_err(|err: Error| OsString::from(err.to_string())) | ||||
|  | ||||
							
								
								
									
										126
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								src/lib.rs
									
									
									
									
									
								
							| @ -41,85 +41,85 @@ | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| #[macro_use] | ||||
| pub mod assert_matches; | ||||
| mod assert_matches; | ||||
| 
 | ||||
| #[macro_use] | ||||
| pub mod errln; | ||||
| mod errln; | ||||
| 
 | ||||
| #[macro_use] | ||||
| pub mod err; | ||||
| mod err; | ||||
| 
 | ||||
| #[macro_use] | ||||
| pub mod out; | ||||
| mod out; | ||||
| 
 | ||||
| #[macro_use] | ||||
| pub mod outln; | ||||
| mod outln; | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| #[macro_use] | ||||
| pub mod test_env; | ||||
| mod test_env; | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| pub mod test_env_builder; | ||||
| mod test_env_builder; | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| pub mod capture; | ||||
| mod capture; | ||||
| 
 | ||||
| pub mod arguments; | ||||
| pub mod bytes; | ||||
| pub mod common; | ||||
| pub mod consts; | ||||
| pub mod env; | ||||
| pub mod error; | ||||
| pub mod file_error; | ||||
| pub mod file_info; | ||||
| pub mod file_path; | ||||
| pub mod file_status; | ||||
| pub mod files; | ||||
| pub mod hasher; | ||||
| pub mod host_port; | ||||
| pub mod host_port_parse_error; | ||||
| pub mod info; | ||||
| pub mod infohash; | ||||
| pub mod input; | ||||
| pub mod input_stream; | ||||
| pub mod input_target; | ||||
| pub mod into_u64; | ||||
| pub mod into_usize; | ||||
| pub mod invariant; | ||||
| pub mod lint; | ||||
| pub mod linter; | ||||
| pub mod magnet_link; | ||||
| pub mod magnet_link_parse_error; | ||||
| pub mod md5_digest; | ||||
| pub mod metainfo; | ||||
| pub mod metainfo_error; | ||||
| pub mod mode; | ||||
| pub mod options; | ||||
| pub mod output_stream; | ||||
| pub mod output_target; | ||||
| pub mod piece_length_picker; | ||||
| pub mod piece_list; | ||||
| pub mod platform; | ||||
| pub mod platform_interface; | ||||
| pub mod print; | ||||
| pub mod reckoner; | ||||
| pub mod run; | ||||
| pub mod sha1_digest; | ||||
| pub mod shell; | ||||
| pub mod sort_key; | ||||
| pub mod sort_order; | ||||
| pub mod sort_spec; | ||||
| pub mod status; | ||||
| pub mod step; | ||||
| pub mod style; | ||||
| pub mod subcommand; | ||||
| pub mod table; | ||||
| pub mod torrent_summary; | ||||
| pub mod use_color; | ||||
| pub mod verifier; | ||||
| pub mod walker; | ||||
| pub mod xor_args; | ||||
| mod arguments; | ||||
| mod bytes; | ||||
| mod common; | ||||
| mod consts; | ||||
| mod env; | ||||
| mod error; | ||||
| mod file_error; | ||||
| mod file_info; | ||||
| mod file_path; | ||||
| mod file_status; | ||||
| mod files; | ||||
| mod hasher; | ||||
| mod host_port; | ||||
| mod host_port_parse_error; | ||||
| mod info; | ||||
| mod infohash; | ||||
| mod input; | ||||
| mod input_stream; | ||||
| mod input_target; | ||||
| mod into_u64; | ||||
| mod into_usize; | ||||
| mod invariant; | ||||
| mod lint; | ||||
| mod linter; | ||||
| mod magnet_link; | ||||
| mod magnet_link_parse_error; | ||||
| mod md5_digest; | ||||
| mod metainfo; | ||||
| mod metainfo_error; | ||||
| mod mode; | ||||
| mod options; | ||||
| mod output_stream; | ||||
| mod output_target; | ||||
| mod piece_length_picker; | ||||
| mod piece_list; | ||||
| mod platform; | ||||
| mod platform_interface; | ||||
| mod print; | ||||
| mod reckoner; | ||||
| mod run; | ||||
| mod sha1_digest; | ||||
| mod shell; | ||||
| mod sort_key; | ||||
| mod sort_order; | ||||
| mod sort_spec; | ||||
| mod status; | ||||
| mod step; | ||||
| mod style; | ||||
| mod subcommand; | ||||
| mod table; | ||||
| mod torrent_summary; | ||||
| mod use_color; | ||||
| mod verifier; | ||||
| mod walker; | ||||
| mod xor_args; | ||||
| 
 | ||||
| #[cfg(feature = "bench")] | ||||
| pub mod bench; | ||||
|  | ||||
| @ -12,7 +12,7 @@ impl Linter { | ||||
|   } | ||||
| 
 | ||||
|   pub(crate) fn allow(&mut self, allowed: impl IntoIterator<Item = Lint>) { | ||||
|     self.allowed.extend(allowed); | ||||
|     self.allowed.extend(allowed) | ||||
|   } | ||||
| 
 | ||||
|   pub(crate) fn is_allowed(&self, lint: Lint) -> bool { | ||||
|  | ||||
| @ -1,17 +1,17 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| #[derive(Debug, PartialEq)] | ||||
| pub struct MagnetLink { | ||||
|   pub infohash: Infohash, | ||||
|   pub name: Option<String>, | ||||
|   pub peers: Vec<HostPort>, | ||||
|   pub trackers: Vec<Url>, | ||||
|   pub indices: BTreeSet<u64>, | ||||
| pub(crate) struct MagnetLink { | ||||
|   infohash: Infohash, | ||||
|   name: Option<String>, | ||||
|   peers: Vec<HostPort>, | ||||
|   trackers: Vec<Url>, | ||||
|   indices: BTreeSet<u64>, | ||||
| } | ||||
| 
 | ||||
| impl MagnetLink { | ||||
|   /// See `Info::infohash_lossy` for details on when this function is lossy.
 | ||||
|   pub fn from_metainfo_lossy(metainfo: &Metainfo) -> Result<MagnetLink> { | ||||
|   pub(crate) fn from_metainfo_lossy(metainfo: &Metainfo) -> Result<MagnetLink> { | ||||
|     let mut link = Self::with_infohash(metainfo.infohash_lossy()?); | ||||
| 
 | ||||
|     link.set_name(metainfo.info.name.clone()); | ||||
| @ -23,7 +23,7 @@ impl MagnetLink { | ||||
|     Ok(link) | ||||
|   } | ||||
| 
 | ||||
|   pub fn with_infohash(infohash: Infohash) -> Self { | ||||
|   pub(crate) fn with_infohash(infohash: Infohash) -> Self { | ||||
|     MagnetLink { | ||||
|       infohash, | ||||
|       name: None, | ||||
| @ -34,23 +34,23 @@ impl MagnetLink { | ||||
|   } | ||||
| 
 | ||||
|   #[allow(dead_code)] | ||||
|   pub fn set_name(&mut self, name: impl Into<String>) { | ||||
|   pub(crate) fn set_name(&mut self, name: impl Into<String>) { | ||||
|     self.name = Some(name.into()); | ||||
|   } | ||||
| 
 | ||||
|   pub fn add_peer(&mut self, peer: HostPort) { | ||||
|   pub(crate) fn add_peer(&mut self, peer: HostPort) { | ||||
|     self.peers.push(peer); | ||||
|   } | ||||
| 
 | ||||
|   pub fn add_tracker(&mut self, tracker: Url) { | ||||
|   pub(crate) fn add_tracker(&mut self, tracker: Url) { | ||||
|     self.trackers.push(tracker); | ||||
|   } | ||||
| 
 | ||||
|   pub fn add_index(&mut self, index: u64) { | ||||
|   pub(crate) fn add_index(&mut self, index: u64) { | ||||
|     self.indices.insert(index); | ||||
|   } | ||||
| 
 | ||||
|   pub fn to_url(&self) -> Url { | ||||
|   pub(crate) fn to_url(&self) -> Url { | ||||
|     let mut url = Url::parse("magnet:").invariant_unwrap("`magnet:` is valid URL"); | ||||
| 
 | ||||
|     let mut query = format!("xt=urn:btih:{}", self.infohash); | ||||
| @ -85,7 +85,7 @@ impl MagnetLink { | ||||
|     url | ||||
|   } | ||||
| 
 | ||||
|   pub fn parse(text: &str) -> Result<Self, MagnetLinkParseError> { | ||||
|   fn parse(text: &str) -> Result<Self, MagnetLinkParseError> { | ||||
|     let url = Url::parse(&text).context(magnet_link_parse_error::Url)?; | ||||
| 
 | ||||
|     if url.scheme() != "magnet" { | ||||
|  | ||||
| @ -2,7 +2,7 @@ use crate::common::*; | ||||
| 
 | ||||
| #[derive(Debug, Snafu)] | ||||
| #[snafu(visibility(pub(crate)))] | ||||
| pub enum MagnetLinkParseError { | ||||
| pub(crate) enum MagnetLinkParseError { | ||||
|   #[snafu(display("Failed to parse hex string `{}`: {}", text, source))] | ||||
|   HexParse { | ||||
|     text: String, | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| #[derive(Deserialize, Serialize, Debug, Eq, PartialEq, Copy, Clone)] | ||||
| #[serde(transparent)] | ||||
| #[derive(Deserialize, Serialize, Debug, Eq, PartialEq, Copy, Clone)] | ||||
| pub(crate) struct Md5Digest { | ||||
|   #[serde(with = "SerHex::<serde_hex::Strict>")] | ||||
|   bytes: [u8; 16], | ||||
|  | ||||
| @ -1,68 +1,68 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| #[derive(Deserialize, Serialize, Debug, PartialEq, Clone)] | ||||
| pub struct Metainfo { | ||||
| pub(crate) struct Metainfo { | ||||
|   #[serde(
 | ||||
|     skip_serializing_if = "Option::is_none", | ||||
|     default, | ||||
|     with = "unwrap_or_skip" | ||||
|   )] | ||||
|   pub announce: Option<String>, | ||||
|   pub(crate) announce: Option<String>, | ||||
|   #[serde(
 | ||||
|     rename = "announce-list", | ||||
|     skip_serializing_if = "Option::is_none", | ||||
|     default, | ||||
|     with = "unwrap_or_skip" | ||||
|   )] | ||||
|   pub announce_list: Option<Vec<Vec<String>>>, | ||||
|   pub(crate) announce_list: Option<Vec<Vec<String>>>, | ||||
|   #[serde(
 | ||||
|     skip_serializing_if = "Option::is_none", | ||||
|     default, | ||||
|     with = "unwrap_or_skip" | ||||
|   )] | ||||
|   pub comment: Option<String>, | ||||
|   pub(crate) comment: Option<String>, | ||||
|   #[serde(
 | ||||
|     rename = "created by", | ||||
|     skip_serializing_if = "Option::is_none", | ||||
|     default, | ||||
|     with = "unwrap_or_skip" | ||||
|   )] | ||||
|   pub created_by: Option<String>, | ||||
|   pub(crate) created_by: Option<String>, | ||||
|   #[serde(
 | ||||
|     rename = "creation date", | ||||
|     skip_serializing_if = "Option::is_none", | ||||
|     default, | ||||
|     with = "unwrap_or_skip" | ||||
|   )] | ||||
|   pub creation_date: Option<u64>, | ||||
|   pub(crate) creation_date: Option<u64>, | ||||
|   #[serde(
 | ||||
|     skip_serializing_if = "Option::is_none", | ||||
|     default, | ||||
|     with = "unwrap_or_skip" | ||||
|   )] | ||||
|   pub encoding: Option<String>, | ||||
|   pub info: Info, | ||||
|   pub(crate) encoding: Option<String>, | ||||
|   pub(crate) info: Info, | ||||
|   #[serde(
 | ||||
|     skip_serializing_if = "Option::is_none", | ||||
|     default, | ||||
|     with = "unwrap_or_skip" | ||||
|   )] | ||||
|   pub nodes: Option<Vec<HostPort>>, | ||||
|   pub(crate) nodes: Option<Vec<HostPort>>, | ||||
| } | ||||
| 
 | ||||
| impl Metainfo { | ||||
|   pub fn from_input(input: &Input) -> Result<Metainfo> { | ||||
|   pub(crate) fn from_input(input: &Input) -> Result<Metainfo> { | ||||
|     Self::deserialize(input.source(), input.data()) | ||||
|   } | ||||
| 
 | ||||
|   pub fn deserialize(source: &InputTarget, data: &[u8]) -> Result<Metainfo, Error> { | ||||
|   pub(crate) fn deserialize(source: &InputTarget, data: &[u8]) -> Result<Metainfo, Error> { | ||||
|     let metainfo = bendy::serde::de::from_bytes(&data).context(error::MetainfoDeserialize { | ||||
|       input: source.clone(), | ||||
|     })?; | ||||
|     Ok(metainfo) | ||||
|   } | ||||
| 
 | ||||
|   pub fn serialize(&self) -> Result<Vec<u8>, Error> { | ||||
|   pub(crate) fn serialize(&self) -> Result<Vec<u8>, Error> { | ||||
|     bendy::serde::ser::to_bytes(&self).context(error::MetainfoSerialize) | ||||
|   } | ||||
| 
 | ||||
| @ -99,7 +99,7 @@ impl Metainfo { | ||||
|     self.info.content_size() | ||||
|   } | ||||
| 
 | ||||
|   pub fn trackers<'a>(&'a self) -> impl Iterator<Item = Result<Url>> + 'a { | ||||
|   pub(crate) fn trackers<'a>(&'a self) -> impl Iterator<Item = Result<Url>> + 'a { | ||||
|     let mut seen = HashSet::new(); | ||||
|     iter::once(&self.announce) | ||||
|       .flatten() | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone)] | ||||
| pub enum MetainfoError { | ||||
| pub(crate) enum MetainfoError { | ||||
|   Type, | ||||
|   InfoMissing, | ||||
|   InfoType, | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| #[derive(Deserialize, Serialize, Debug, PartialEq, Clone)] | ||||
| #[serde(untagged)] | ||||
| #[derive(Deserialize, Serialize, Debug, PartialEq, Clone)] | ||||
| pub(crate) enum Mode { | ||||
|   Single { | ||||
|     length: Bytes, | ||||
|  | ||||
| @ -1,10 +1,10 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| pub(crate) struct OutputStream { | ||||
|   active: bool, | ||||
|   stream: Box<dyn Write>, | ||||
|   style: bool, | ||||
|   term: bool, | ||||
|   active: bool, | ||||
| } | ||||
| 
 | ||||
| impl OutputStream { | ||||
|  | ||||
| @ -1,22 +1,22 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||||
| pub struct Sha1Digest { | ||||
|   pub bytes: [u8; Self::LENGTH], | ||||
| pub(crate) struct Sha1Digest { | ||||
|   bytes: [u8; Self::LENGTH], | ||||
| } | ||||
| 
 | ||||
| impl Sha1Digest { | ||||
|   pub const LENGTH: usize = 20; | ||||
|   pub(crate) const LENGTH: usize = 20; | ||||
| 
 | ||||
|   pub fn from_bytes(bytes: [u8; Self::LENGTH]) -> Self { | ||||
|   pub(crate) fn from_bytes(bytes: [u8; Self::LENGTH]) -> Self { | ||||
|     Sha1Digest { bytes } | ||||
|   } | ||||
| 
 | ||||
|   pub fn bytes(self) -> [u8; Self::LENGTH] { | ||||
|   pub(crate) fn bytes(self) -> [u8; Self::LENGTH] { | ||||
|     self.bytes | ||||
|   } | ||||
| 
 | ||||
|   pub fn from_data(data: impl AsRef<[u8]>) -> Self { | ||||
|   pub(crate) fn from_data(data: impl AsRef<[u8]>) -> Self { | ||||
|     Sha1::from(data).digest().into() | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -4,7 +4,7 @@ use structopt::clap; | ||||
| 
 | ||||
| #[derive(Copy, Clone, EnumVariantNames, IntoStaticStr, EnumString, EnumIter, Debug)] | ||||
| #[strum(serialize_all = "kebab-case")] | ||||
| pub enum Shell { | ||||
| pub(crate) enum Shell { | ||||
|   Zsh, | ||||
|   Bash, | ||||
|   Fish, | ||||
| @ -62,6 +62,6 @@ mod tests { | ||||
| 
 | ||||
|   #[test] | ||||
|   fn variants() { | ||||
|     assert_eq!(Shell::VARIANTS, clap::Shell::variants()); | ||||
|     assert_eq!(Shell::VARIANTS, clap::Shell::variants()) | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -338,7 +338,9 @@ impl Create { | ||||
| 
 | ||||
|     if let OutputTarget::Path(path) = &output { | ||||
|       if !self.force && path.exists() { | ||||
|         return Err(Error::OutputExists { path: path.clone() }); | ||||
|         return Err(Error::OutputExists { | ||||
|           path: path.to_owned(), | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
| @ -1149,7 +1151,7 @@ mod tests { | ||||
|         length: Bytes(3), | ||||
|         md5sum: None, | ||||
|       } | ||||
|     ); | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   #[test] | ||||
| @ -1180,7 +1182,7 @@ mod tests { | ||||
|         length: Bytes(4), | ||||
|         md5sum: None, | ||||
|       } | ||||
|     ); | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   #[test] | ||||
| @ -1211,7 +1213,7 @@ mod tests { | ||||
|         length: Bytes(4), | ||||
|         md5sum: None, | ||||
|       } | ||||
|     ); | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   #[test] | ||||
| @ -1256,7 +1258,7 @@ mod tests { | ||||
|           }, | ||||
|         ], | ||||
|       } | ||||
|     ); | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   #[test] | ||||
| @ -1283,7 +1285,7 @@ mod tests { | ||||
|         length: Bytes(3), | ||||
|         md5sum: None, | ||||
|       } | ||||
|     ); | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   #[test] | ||||
| @ -1317,7 +1319,7 @@ mod tests { | ||||
|         length: Bytes(3), | ||||
|         md5sum: None, | ||||
|       } | ||||
|     ); | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   #[test] | ||||
| @ -1344,7 +1346,7 @@ mod tests { | ||||
|         length: Bytes(0), | ||||
|         md5sum: None, | ||||
|       } | ||||
|     ); | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   #[test] | ||||
| @ -1365,7 +1367,7 @@ mod tests { | ||||
|     env.assert_ok(); | ||||
|     let metainfo = env.load_metainfo("foo.torrent"); | ||||
|     assert_eq!(metainfo.info.pieces.count(), 0); | ||||
|     assert_eq!(metainfo.info.mode, Mode::Multiple { files: Vec::new() }); | ||||
|     assert_eq!(metainfo.info.mode, Mode::Multiple { files: Vec::new() }) | ||||
|   } | ||||
| 
 | ||||
|   #[test] | ||||
|  | ||||
| @ -16,19 +16,7 @@ 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<PathBuf>, | ||||
|   #[structopt(
 | ||||
|     long = "content", | ||||
|     short = "c", | ||||
| @ -36,7 +24,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 the torrent info dictionary." | ||||
|             of torrent info dictionary." | ||||
|   )] | ||||
|   content: Option<PathBuf>, | ||||
|   #[structopt(
 | ||||
| @ -76,19 +64,13 @@ impl Verify { | ||||
| 
 | ||||
|     let metainfo = Metainfo::from_input(&input)?; | ||||
| 
 | ||||
|     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 { | ||||
|     let content = self.content.as_ref().map_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() | ||||
| @ -155,20 +137,6 @@ 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 <PATH>' cannot be used with '--base-directory \ | ||||
|        <BASE-DIRECTORY>'\n\nUSAGE:\n    imdl torrent verify <INPUT> --base-directory \ | ||||
|        <BASE-DIRECTORY> --content <PATH>\n\nFor more information try --help\n" | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   #[test] | ||||
|   fn pass() -> Result<()> { | ||||
|     let mut create_env = test_env! { | ||||
| @ -355,62 +323,6 @@ 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! { | ||||
|  | ||||
| @ -37,19 +37,19 @@ macro_rules! test_env { | ||||
| 
 | ||||
| pub(crate) struct TestEnv { | ||||
|   env: Env, | ||||
|   err: Capture, | ||||
|   out: Capture, | ||||
|   #[allow(unused)] | ||||
|   tempdir: TempDir, | ||||
|   err: Capture, | ||||
|   out: Capture, | ||||
| } | ||||
| 
 | ||||
| impl TestEnv { | ||||
|   pub(crate) fn new(tempdir: TempDir, env: Env, err: Capture, out: Capture) -> TestEnv { | ||||
|     Self { | ||||
|       env, | ||||
|       err, | ||||
|       out, | ||||
|       tempdir, | ||||
|       err, | ||||
|       env, | ||||
|       out, | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| @ -77,14 +77,6 @@ impl TestEnv { | ||||
|     fs::create_dir(self.env.resolve(path).unwrap()).unwrap(); | ||||
|   } | ||||
| 
 | ||||
|   pub(crate) fn rename(&self, from: impl AsRef<Path>, to: impl AsRef<Path>) { | ||||
|     fs::rename( | ||||
|       self.env.resolve(from).unwrap(), | ||||
|       self.env.resolve(to).unwrap(), | ||||
|     ) | ||||
|     .unwrap(); | ||||
|   } | ||||
| 
 | ||||
|   pub(crate) fn read_to_string(&self, path: impl AsRef<Path>) -> String { | ||||
|     fs::read_to_string(self.env.resolve(path).unwrap()).unwrap() | ||||
|   } | ||||
|  | ||||
| @ -1,30 +1,30 @@ | ||||
| use crate::common::*; | ||||
| 
 | ||||
| pub struct TorrentSummary { | ||||
| pub(crate) struct TorrentSummary { | ||||
|   infohash: Infohash, | ||||
|   metainfo: Metainfo, | ||||
|   size: Bytes, | ||||
| } | ||||
| 
 | ||||
| #[derive(Serialize)] | ||||
| pub struct TorrentSummaryJson { | ||||
|   pub name: String, | ||||
|   pub comment: Option<String>, | ||||
|   pub creation_date: Option<u64>, | ||||
|   pub created_by: Option<String>, | ||||
|   pub source: Option<String>, | ||||
|   pub info_hash: String, | ||||
|   pub torrent_size: u64, | ||||
|   pub content_size: u64, | ||||
|   pub private: bool, | ||||
|   pub tracker: Option<String>, | ||||
|   pub announce_list: Vec<Vec<String>>, | ||||
|   pub update_url: Option<String>, | ||||
|   pub dht_nodes: Vec<String>, | ||||
|   pub piece_size: u64, | ||||
|   pub piece_count: usize, | ||||
|   pub file_count: usize, | ||||
|   pub files: Vec<String>, | ||||
| pub(crate) struct TorrentSummaryJson { | ||||
|   name: String, | ||||
|   comment: Option<String>, | ||||
|   creation_date: Option<u64>, | ||||
|   created_by: Option<String>, | ||||
|   source: Option<String>, | ||||
|   info_hash: String, | ||||
|   torrent_size: u64, | ||||
|   content_size: u64, | ||||
|   private: bool, | ||||
|   tracker: Option<String>, | ||||
|   announce_list: Vec<Vec<String>>, | ||||
|   update_url: Option<String>, | ||||
|   dht_nodes: Vec<String>, | ||||
|   piece_size: u64, | ||||
|   piece_count: usize, | ||||
|   file_count: usize, | ||||
|   files: Vec<String>, | ||||
| } | ||||
| 
 | ||||
| impl TorrentSummary { | ||||
| @ -37,14 +37,14 @@ impl TorrentSummary { | ||||
|   } | ||||
| 
 | ||||
|   /// See `Info::infohash_lossy` for details on when this function is lossy.
 | ||||
|   pub fn from_metainfo_lossy(metainfo: Metainfo) -> Result<Self> { | ||||
|   pub(crate) fn from_metainfo_lossy(metainfo: Metainfo) -> Result<Self> { | ||||
|     let bytes = metainfo.serialize()?; | ||||
|     let size = Bytes(bytes.len().into_u64()); | ||||
|     let infohash = metainfo.infohash_lossy()?; | ||||
|     Ok(Self::new(metainfo, infohash, size)) | ||||
|   } | ||||
| 
 | ||||
|   pub fn from_input(input: &Input) -> Result<Self> { | ||||
|   pub(crate) fn from_input(input: &Input) -> Result<Self> { | ||||
|     let metainfo = Metainfo::from_input(input)?; | ||||
|     let infohash = Infohash::from_input(input)?; | ||||
|     let size = Bytes(input.data().len().into_u64()); | ||||
| @ -52,7 +52,7 @@ impl TorrentSummary { | ||||
|     Ok(Self::new(metainfo, infohash, size)) | ||||
|   } | ||||
| 
 | ||||
|   pub fn write(&self, env: &mut Env) -> Result<()> { | ||||
|   pub(crate) fn write(&self, env: &mut Env) -> Result<()> { | ||||
|     let table = self.table(); | ||||
| 
 | ||||
|     if env.out().is_term() { | ||||
| @ -168,16 +168,16 @@ impl TorrentSummary { | ||||
|     table | ||||
|   } | ||||
| 
 | ||||
|   pub fn write_json(&self, env: &mut Env) -> Result<()> { | ||||
|   pub(crate) fn write_json(&self, env: &mut Env) -> Result<()> { | ||||
|     let data = self.torrent_summary_data(); | ||||
|     let json = serde_json::to_string(&data).context(error::JsonSerialize)?; | ||||
|     outln!(env, "{}", json)?; | ||||
|     Ok(()) | ||||
|   } | ||||
| 
 | ||||
|   pub fn torrent_summary_data(&self) -> TorrentSummaryJson { | ||||
|   fn torrent_summary_data(&self) -> TorrentSummaryJson { | ||||
|     let (file_count, files) = match &self.metainfo.info.mode { | ||||
|       Mode::Single { .. } => (1, vec![self.metainfo.info.name.clone()]), | ||||
|       Mode::Single { .. } => (1, vec![self.metainfo.info.name.to_owned()]), | ||||
|       Mode::Multiple { files } => ( | ||||
|         files.len(), | ||||
|         files | ||||
| @ -197,7 +197,7 @@ impl TorrentSummary { | ||||
|     }; | ||||
| 
 | ||||
|     TorrentSummaryJson { | ||||
|       name: self.metainfo.info.name.clone(), | ||||
|       name: self.metainfo.info.name.to_owned(), | ||||
|       comment: self.metainfo.comment.clone(), | ||||
|       creation_date: self.metainfo.creation_date, | ||||
|       created_by: self.metainfo.created_by.clone(), | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user