Add progress messages to imdl torrent create
- Add messages showing overall progress - Add file search spinner type: added
This commit is contained in:
parent
2415d88d92
commit
c6cd78f565
62
Cargo.lock
generated
62
Cargo.lock
generated
|
@ -148,6 +148,34 @@ dependencies = [
|
|||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clicolors-control"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45e0f3986890b3acbc782009e2629dfe2baa430ac091519ce3be26164a2ae6c0"
|
||||
dependencies = [
|
||||
"clicolors-control",
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"regex",
|
||||
"termios",
|
||||
"unicode-width",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.12"
|
||||
|
@ -170,6 +198,12 @@ version = "0.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97"
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.7.1"
|
||||
|
@ -288,6 +322,7 @@ dependencies = [
|
|||
"bendy",
|
||||
"chrono",
|
||||
"globset",
|
||||
"indicatif",
|
||||
"libc",
|
||||
"md5",
|
||||
"pretty_assertions",
|
||||
|
@ -309,6 +344,18 @@ dependencies = [
|
|||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indicatif"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49a68371cf417889c9d7f98235b7102ea7c54fc59bcbd22f3dea785be9d27e40"
|
||||
dependencies = [
|
||||
"console",
|
||||
"lazy_static",
|
||||
"number_prefix",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
|
@ -389,6 +436,12 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "number_prefix"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a"
|
||||
|
||||
[[package]]
|
||||
name = "output_vt100"
|
||||
version = "0.1.2"
|
||||
|
@ -798,6 +851,15 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termios"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
|
|
|
@ -17,6 +17,7 @@ ansi_term = "0.12.0"
|
|||
atty = "0.2.0"
|
||||
chrono = "0.4.1"
|
||||
globset = "0.4.0"
|
||||
indicatif = "0.14.0"
|
||||
libc = "0.2.0"
|
||||
md5 = "0.7.0"
|
||||
pretty_assertions = "0.6.0"
|
||||
|
|
|
@ -24,6 +24,7 @@ pub(crate) use std::{
|
|||
pub(crate) use bendy::{decoding::FromBencode, encoding::ToBencode, value::Value};
|
||||
pub(crate) use chrono::{TimeZone, Utc};
|
||||
pub(crate) use globset::{Glob, GlobMatcher};
|
||||
pub(crate) use indicatif::{ProgressBar, ProgressStyle};
|
||||
pub(crate) use libc::EXIT_FAILURE;
|
||||
pub(crate) use regex::{Regex, RegexSet};
|
||||
pub(crate) use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
|
|
@ -7,8 +7,8 @@ pub(crate) struct Status {
|
|||
}
|
||||
|
||||
impl Status {
|
||||
pub(crate) fn new(pieces: bool, files: Vec<FileStatus>) -> Status {
|
||||
Status { pieces, files }
|
||||
pub(crate) fn new(pieces: bool, files: Vec<FileStatus>) -> Self {
|
||||
Self { pieces, files }
|
||||
}
|
||||
|
||||
pub(crate) fn pieces(&self) -> bool {
|
||||
|
|
|
@ -184,11 +184,31 @@ impl Create {
|
|||
pub(crate) fn run(self, env: &mut Env) -> Result<(), Error> {
|
||||
let input = env.resolve(&self.input);
|
||||
|
||||
let mut announce_list = Vec::new();
|
||||
for tier in &self.announce_tiers {
|
||||
let tier = tier.split(',').map(str::to_string).collect::<Vec<String>>();
|
||||
|
||||
tier
|
||||
.iter()
|
||||
.map(|announce| announce.parse())
|
||||
.collect::<Result<Vec<Url>, url::ParseError>>()
|
||||
.context(error::AnnounceUrlParse)?;
|
||||
|
||||
announce_list.push(tier);
|
||||
}
|
||||
|
||||
errln!(env, "[1/3] \u{1F9FF} Searching for files…");
|
||||
|
||||
let style = ProgressStyle::default_spinner().template("{spinner} {msg}…");
|
||||
|
||||
let spinner = ProgressBar::new_spinner().with_style(style);
|
||||
|
||||
let files = Walker::new(&input)
|
||||
.include_junk(self.include_junk)
|
||||
.include_hidden(self.include_hidden)
|
||||
.follow_symlinks(self.follow_symlinks)
|
||||
.globs(&self.globs)?
|
||||
.spinner(spinner)
|
||||
.files()?;
|
||||
|
||||
let piece_length = self
|
||||
|
@ -212,19 +232,6 @@ impl Create {
|
|||
return Err(Error::PieceLengthSmall);
|
||||
}
|
||||
|
||||
let mut announce_list = Vec::new();
|
||||
for tier in &self.announce_tiers {
|
||||
let tier = tier.split(',').map(str::to_string).collect::<Vec<String>>();
|
||||
|
||||
tier
|
||||
.iter()
|
||||
.map(|announce| announce.parse())
|
||||
.collect::<Result<Vec<Url>, url::ParseError>>()
|
||||
.context(error::AnnounceUrlParse)?;
|
||||
|
||||
announce_list.push(tier);
|
||||
}
|
||||
|
||||
let filename = input.file_name().ok_or_else(|| Error::FilenameExtract {
|
||||
path: input.clone(),
|
||||
})?;
|
||||
|
@ -268,12 +275,16 @@ impl Create {
|
|||
Some(String::from(consts::CREATED_BY_DEFAULT))
|
||||
};
|
||||
|
||||
errln!(env, "[2/3] \u{1F9EE} Hashing pieces…");
|
||||
|
||||
let (mode, pieces) = Hasher::hash(
|
||||
&files,
|
||||
self.md5sum,
|
||||
piece_length.as_piece_length()?.into_usize(),
|
||||
)?;
|
||||
|
||||
errln!(env, "[3/3] \u{1F4BE} Writing metainfo to {}…", output);
|
||||
|
||||
let info = Info {
|
||||
source: self.source,
|
||||
piece_length,
|
||||
|
@ -345,6 +356,8 @@ impl Create {
|
|||
}
|
||||
}
|
||||
|
||||
errln!(env, "\u{2728}\u{2728} Done! \u{2728}\u{2728}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -2118,4 +2131,31 @@ Content Size 9 bytes
|
|||
]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_progress_messages() {
|
||||
let mut env = TestEnvBuilder::new()
|
||||
.arg_slice(&[
|
||||
"imdl",
|
||||
"torrent",
|
||||
"create",
|
||||
"--input",
|
||||
"foo",
|
||||
"--announce",
|
||||
"http://bar",
|
||||
])
|
||||
.build();
|
||||
|
||||
fs::write(env.resolve("foo"), "").unwrap();
|
||||
|
||||
let want = format!(
|
||||
"[1/3] \u{1F9FF} Searching for files…\n[2/3] \u{1F9EE} Hashing pieces…\n[3/3] \u{1F4BE} \
|
||||
Writing metainfo to `{}`…\n\u{2728}\u{2728} Done! \u{2728}\u{2728}\n",
|
||||
env.resolve("foo.torrent").display()
|
||||
);
|
||||
|
||||
env.run().unwrap();
|
||||
|
||||
assert_eq!(env.err(), want);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,15 @@ impl From<&OsStr> for Target {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for Target {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Stdio => write!(f, "standard I/O"),
|
||||
Self::File(path) => write!(f, "`{}`", path.display()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -38,4 +47,19 @@ mod tests {
|
|||
fn stdio() {
|
||||
assert_eq!(Target::from(OsStr::new("-")), Target::Stdio);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_file() {
|
||||
let path = PathBuf::from("./path");
|
||||
let have = Target::File(path).to_string();
|
||||
let want = "`./path`";
|
||||
assert_eq!(have, want);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_stdio() {
|
||||
let have = Target::Stdio.to_string();
|
||||
let want = "standard I/O";
|
||||
assert_eq!(have, want);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,28 +14,30 @@ pub(crate) struct Walker {
|
|||
include_junk: bool,
|
||||
patterns: Vec<Pattern>,
|
||||
root: PathBuf,
|
||||
spinner: Option<ProgressBar>,
|
||||
}
|
||||
|
||||
impl Walker {
|
||||
pub(crate) fn new(root: &Path) -> Walker {
|
||||
Walker {
|
||||
pub(crate) fn new(root: &Path) -> Self {
|
||||
Self {
|
||||
follow_symlinks: false,
|
||||
include_hidden: false,
|
||||
include_junk: false,
|
||||
patterns: Vec::new(),
|
||||
root: root.to_owned(),
|
||||
spinner: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn include_junk(self, include_junk: bool) -> Self {
|
||||
Walker {
|
||||
Self {
|
||||
include_junk,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn include_hidden(self, include_hidden: bool) -> Self {
|
||||
Walker {
|
||||
Self {
|
||||
include_hidden,
|
||||
..self
|
||||
}
|
||||
|
@ -55,12 +57,19 @@ impl Walker {
|
|||
}
|
||||
|
||||
pub(crate) fn follow_symlinks(self, follow_symlinks: bool) -> Self {
|
||||
Walker {
|
||||
Self {
|
||||
follow_symlinks,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn spinner(self, spinner: ProgressBar) -> Self {
|
||||
Self {
|
||||
spinner: Some(spinner),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn files(self) -> Result<Files, Error> {
|
||||
if !self.follow_symlinks
|
||||
&& self
|
||||
|
@ -85,6 +94,12 @@ impl Walker {
|
|||
let filter = |entry: &walkdir::DirEntry| {
|
||||
let path = entry.path();
|
||||
|
||||
if let Some(s) = &self.spinner {
|
||||
let display_path = path.strip_prefix(&self.root).unwrap_or(&path);
|
||||
s.set_message(&display_path.display().to_string());
|
||||
s.tick();
|
||||
}
|
||||
|
||||
let file_name = entry.file_name();
|
||||
|
||||
if !self.include_hidden && file_name.to_string_lossy().starts_with('.') {
|
||||
|
|
Loading…
Reference in New Issue
Block a user