From 3c39ec458784639a3aabc17541dcc0e6f4d489d3 Mon Sep 17 00:00:00 2001 From: numtostr Date: Wed, 5 May 2021 21:58:58 +0530 Subject: [PATCH 01/10] init progress --- Cargo.lock | 65 +++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/archive.rs | 11 ++++++-- src/downloader.rs | 8 +++--- src/main.rs | 1 + src/progress_bar.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 src/progress_bar.rs diff --git a/Cargo.lock b/Cargo.lock index 5021ae5..617b90e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,6 +150,21 @@ dependencies = [ "winapi", ] +[[package]] +name = "console" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "regex", + "terminal_size", + "unicode-width", + "winapi", +] + [[package]] name = "crc32fast" version = "1.2.1" @@ -180,6 +195,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "filetime" version = "0.2.14" @@ -270,6 +291,18 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507cf157a0dab3c837bef6e2086466255d9de4a6b1af69e62b62c54cd52f6062" +dependencies = [ + "console", + "lazy_static", + "number_prefix", + "regex", +] + [[package]] name = "indoc" version = "1.0.3" @@ -341,6 +374,12 @@ dependencies = [ "adler32", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "once_cell" version = "1.5.2" @@ -481,6 +520,21 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "regex" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce5f1ceb7f74abbce32601642fcf8e8508a8a8991e0621c7d750295b9095702b" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -592,6 +646,7 @@ dependencies = [ "clap_generate", "colored", "dirs-next", + "indicatif", "indoc", "semver", "serde", @@ -661,6 +716,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ca8ced750734db02076f44132d802af0b33b09942331f4459dde8636fd2406" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "textwrap" version = "0.12.1" diff --git a/Cargo.toml b/Cargo.toml index 0d31de3..ce642cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ clap = "3.0.0-beta.2" clap_generate = "3.0.0-beta.2" colored = "2.0.0" dirs-next = "2.0.0" +indicatif = "0.16.0" indoc = "1.0.3" semver = "0.11.0" serde = { version = "1.0.123", features = ["derive"] } diff --git a/src/archive.rs b/src/archive.rs index b0138b7..3e4fd9b 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -1,3 +1,4 @@ +use crate::progress_bar::Bar; use std::path::Path; use ureq::Response; @@ -11,8 +12,14 @@ impl Archive { } #[cfg(unix)] - pub fn extract_into>(self, path: P) -> anyhow::Result<()> { - let xz_stream = xz2::read::XzDecoder::new(self.res.into_reader()); + pub fn extract_into>(self, path: P, ct_len: Option) -> anyhow::Result<()> { + let bar = Bar::new(ct_len); + + let reader = self.res.into_reader(); + + let buf = bar.read_start(reader)?; + + let xz_stream = xz2::read::XzDecoder::new(std::io::Cursor::new(buf)); let mut archive = tar::Archive::new(xz_stream); archive.unpack(path).map_err(|e| anyhow::Error::new(e)) } diff --git a/src/downloader.rs b/src/downloader.rs index dd7d1d9..0ed84a1 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -4,6 +4,7 @@ use crate::fetcher::Release; use crate::symlink::symlink_to; use crate::url; use colored::*; +use indicatif::HumanBytes; use std::path::PathBuf; use ureq; @@ -22,15 +23,14 @@ pub fn download(r: &Release, config: &Config) -> anyhow::Result { let res = ureq::get(&dist.url).call()?; let len = res .header("Content-Length") - .and_then(|x| x.parse::().ok()) + .and_then(|x| x.parse::().ok()) .ok_or(anyhow::Error::msg("Unable to get content length."))?; println!("Installing : {}", &r.version.to_string().bold()); println!("Downloading : {}", &dist.url.bold()); - println!("Size : {}", &len.to_string().bold()); - println!("---"); + println!("Size : {}", HumanBytes(len).to_string().bold()); - Archive::new(res).extract_into(&release_dir)?; + Archive::new(res).extract_into(&release_dir, Some(len))?; std::fs::rename(&release_dir.join(dist.name), &dest)?; diff --git a/src/main.rs b/src/main.rs index dfd7ccf..1dd086a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ mod cmd; mod config; mod downloader; mod fetcher; +mod progress_bar; mod shell; mod symlink; mod sysinfo; diff --git a/src/progress_bar.rs b/src/progress_bar.rs new file mode 100644 index 0000000..f47b072 --- /dev/null +++ b/src/progress_bar.rs @@ -0,0 +1,64 @@ +// https://mattgathu.github.io/2017/08/29/writing-cli-app-rust.html +use indicatif::{ProgressBar, ProgressStyle}; +use std::io::Read; + +const TEMPLATE: &'static str = + "{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})"; + +pub struct Bar { + pub bar: ProgressBar, + pub chunk_size: usize, +} + +impl Bar { + pub fn new(len: Option) -> Self { + let (bar, chunk_size) = match len { + Some(x) => { + let bar = ProgressBar::new(x); + + bar.set_style( + ProgressStyle::default_bar() + .template(TEMPLATE) + .progress_chars("#>-"), + ); + + (bar, x as usize / 99) + } + None => { + let bar = ProgressBar::new_spinner(); + + bar.set_style(ProgressStyle::default_spinner()); + + (bar, 1024usize) + } + }; + + Self { bar, chunk_size } + } + + pub fn read_start(&self, mut reader: T) -> anyhow::Result> + where + T: Read + Send, + { + let mut buf: Vec = Vec::new(); + + loop { + let mut buffer = vec![0; self.chunk_size]; + let bcount = reader.read(&mut buffer[..])?; + + buffer.truncate(bcount); + + if !buffer.is_empty() { + buf.extend(buffer.into_boxed_slice().into_vec().iter().cloned()); + + self.bar.inc(bcount as u64); + } else { + break; + } + } + + self.bar.finish(); + + Ok(buf) + } +} From fe8ed8e727dc97ee204407045632155626ba9f07 Mon Sep 17 00:00:00 2001 From: numtostr Date: Wed, 5 May 2021 22:19:19 +0530 Subject: [PATCH 02/10] refactor crate::archive --- src/archive.rs | 26 ++++++++++++-------------- src/downloader.rs | 6 ++++-- src/progress_bar.rs | 5 +---- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/archive.rs b/src/archive.rs index 3e4fd9b..12a4525 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -1,29 +1,27 @@ -use crate::progress_bar::Bar; -use std::path::Path; -use ureq::Response; +use std::{ + io::{Cursor, Read}, + path::Path, +}; pub struct Archive { - res: Response, + reader: Box, } impl Archive { - pub fn new(res: Response) -> Self { - Archive { res } + pub fn new(buf: Vec) -> Self { + Self { + reader: Box::new(Cursor::new(buf)), + } } #[cfg(unix)] - pub fn extract_into>(self, path: P, ct_len: Option) -> anyhow::Result<()> { - let bar = Bar::new(ct_len); - - let reader = self.res.into_reader(); - - let buf = bar.read_start(reader)?; - - let xz_stream = xz2::read::XzDecoder::new(std::io::Cursor::new(buf)); + pub fn extract_into>(self, path: P) -> anyhow::Result<()> { + let xz_stream = xz2::read::XzDecoder::new(self.reader); let mut archive = tar::Archive::new(xz_stream); archive.unpack(path).map_err(|e| anyhow::Error::new(e)) } + // FIXME: Fix windows zip extraction #[cfg(windows)] pub fn extract_into>(self, path: P) -> anyhow::Result<()> { use std::{fs, io}; diff --git a/src/downloader.rs b/src/downloader.rs index 0ed84a1..992ee30 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -1,8 +1,8 @@ -use crate::archive::Archive; use crate::config::Config; use crate::fetcher::Release; use crate::symlink::symlink_to; use crate::url; +use crate::{archive::Archive, progress_bar::Bar}; use colored::*; use indicatif::HumanBytes; use std::path::PathBuf; @@ -30,7 +30,9 @@ pub fn download(r: &Release, config: &Config) -> anyhow::Result { println!("Downloading : {}", &dist.url.bold()); println!("Size : {}", HumanBytes(len).to_string().bold()); - Archive::new(res).extract_into(&release_dir, Some(len))?; + let buf = Bar::new(Some(len)).read_start(res.into_reader())?; + + Archive::new(buf).extract_into(&release_dir)?; std::fs::rename(&release_dir.join(dist.name), &dest)?; diff --git a/src/progress_bar.rs b/src/progress_bar.rs index f47b072..a298786 100644 --- a/src/progress_bar.rs +++ b/src/progress_bar.rs @@ -36,10 +36,7 @@ impl Bar { Self { bar, chunk_size } } - pub fn read_start(&self, mut reader: T) -> anyhow::Result> - where - T: Read + Send, - { + pub fn read_start(&self, mut reader: impl Read) -> anyhow::Result> { let mut buf: Vec = Vec::new(); loop { From 7a81f4d62e400b5e844630d799b93a116ab2ca7c Mon Sep 17 00:00:00 2001 From: numtostr Date: Wed, 5 May 2021 22:22:55 +0530 Subject: [PATCH 03/10] refactor Size printing --- src/downloader.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/downloader.rs b/src/downloader.rs index 992ee30..129b93a 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -23,14 +23,18 @@ pub fn download(r: &Release, config: &Config) -> anyhow::Result { let res = ureq::get(&dist.url).call()?; let len = res .header("Content-Length") - .and_then(|x| x.parse::().ok()) - .ok_or(anyhow::Error::msg("Unable to get content length."))?; + .and_then(|x| x.parse::().ok()); - println!("Installing : {}", &r.version.to_string().bold()); - println!("Downloading : {}", &dist.url.bold()); - println!("Size : {}", HumanBytes(len).to_string().bold()); + let size = match len { + Some(l) => HumanBytes(l).to_string(), + None => "unknown".into(), + }; - let buf = Bar::new(Some(len)).read_start(res.into_reader())?; + println!("Installing : {}", r.version.to_string().bold()); + println!("Downloading : {}", dist.url.bold()); + println!("Size : {}", size.bold()); + + let buf = Bar::new(len).read_start(res.into_reader())?; Archive::new(buf).extract_into(&release_dir)?; From d62c3a7b9b4977e8dab4cc77b40590766bb533eb Mon Sep 17 00:00:00 2001 From: numtostr Date: Thu, 6 May 2021 13:23:03 +0530 Subject: [PATCH 04/10] fix windows zip extraction --- src/archive.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/archive.rs b/src/archive.rs index 12a4525..ebe374b 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -1,16 +1,13 @@ -use std::{ - io::{Cursor, Read}, - path::Path, -}; +use std::{io::Cursor, path::Path}; pub struct Archive { - reader: Box, + reader: Cursor>, } impl Archive { pub fn new(buf: Vec) -> Self { Self { - reader: Box::new(Cursor::new(buf)), + reader: Cursor::new(buf), } } @@ -21,15 +18,11 @@ impl Archive { archive.unpack(path).map_err(|e| anyhow::Error::new(e)) } - // FIXME: Fix windows zip extraction #[cfg(windows)] pub fn extract_into>(self, path: P) -> anyhow::Result<()> { use std::{fs, io}; - let mut reader = self.res.into_reader(); - let mut temp_zip = tempfile::tempfile()?; - std::io::copy(&mut reader, &mut temp_zip)?; - let mut archive = zip::read::ZipArchive::new(&mut temp_zip)?; + let mut archive = zip::read::ZipArchive::new(self.reader)?; for i in 0..archive.len() { let mut file = archive.by_index(i)?; From c8800d6ea774f63e8c12b6781da8dd1c830c4297 Mon Sep 17 00:00:00 2001 From: numtostr Date: Thu, 6 May 2021 13:33:19 +0530 Subject: [PATCH 05/10] make struct Bar fields private --- src/progress_bar.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/progress_bar.rs b/src/progress_bar.rs index a298786..8940a8e 100644 --- a/src/progress_bar.rs +++ b/src/progress_bar.rs @@ -6,8 +6,8 @@ const TEMPLATE: &'static str = "{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})"; pub struct Bar { - pub bar: ProgressBar, - pub chunk_size: usize, + bar: ProgressBar, + chunk_size: usize, } impl Bar { From f45ba816b3cc93ac029bd5e6a6300930202e51bc Mon Sep 17 00:00:00 2001 From: numtostr Date: Thu, 6 May 2021 14:43:03 +0530 Subject: [PATCH 06/10] some changes --- src/progress_bar.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/progress_bar.rs b/src/progress_bar.rs index 8940a8e..9a7fa50 100644 --- a/src/progress_bar.rs +++ b/src/progress_bar.rs @@ -6,6 +6,7 @@ const TEMPLATE: &'static str = "{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})"; pub struct Bar { + len: Option, bar: ProgressBar, chunk_size: usize, } @@ -33,11 +34,18 @@ impl Bar { } }; - Self { bar, chunk_size } + Self { + len, + bar, + chunk_size, + } } pub fn read_start(&self, mut reader: impl Read) -> anyhow::Result> { - let mut buf: Vec = Vec::new(); + let mut buf: Vec = match self.len { + Some(x) => Vec::with_capacity(x as usize), + None => Vec::new(), + }; loop { let mut buffer = vec![0; self.chunk_size]; @@ -46,7 +54,7 @@ impl Bar { buffer.truncate(bcount); if !buffer.is_empty() { - buf.extend(buffer.into_boxed_slice().into_vec().iter().cloned()); + buf.extend(buffer.iter()); self.bar.inc(bcount as u64); } else { From ff23b9dd1af27442436e0950000c0f514cae962b Mon Sep 17 00:00:00 2001 From: numtostr Date: Thu, 6 May 2021 15:55:32 +0530 Subject: [PATCH 07/10] added some space before and after the progress bar --- src/downloader.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/downloader.rs b/src/downloader.rs index 129b93a..5cedcd1 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -34,8 +34,12 @@ pub fn download(r: &Release, config: &Config) -> anyhow::Result { println!("Downloading : {}", dist.url.bold()); println!("Size : {}", size.bold()); + println!(""); + let buf = Bar::new(len).read_start(res.into_reader())?; + println!(""); + Archive::new(buf).extract_into(&release_dir)?; std::fs::rename(&release_dir.join(dist.name), &dest)?; From a4d90d571a3de0f9b4b5e9691b74cb9a8c6d2656 Mon Sep 17 00:00:00 2001 From: numtostr Date: Thu, 6 May 2021 15:56:02 +0530 Subject: [PATCH 08/10] wow --- src/downloader.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/downloader.rs b/src/downloader.rs index 5cedcd1..07fb59b 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -34,11 +34,11 @@ pub fn download(r: &Release, config: &Config) -> anyhow::Result { println!("Downloading : {}", dist.url.bold()); println!("Size : {}", size.bold()); - println!(""); + println!(); let buf = Bar::new(len).read_start(res.into_reader())?; - println!(""); + println!(); Archive::new(buf).extract_into(&release_dir)?; From 034e56eaf64c15dc461792a9f0b9cf46887af7f1 Mon Sep 17 00:00:00 2001 From: numtostr Date: Thu, 6 May 2021 16:07:23 +0530 Subject: [PATCH 09/10] removed tempfile --- Cargo.lock | 70 ------------------------------------------------------ Cargo.toml | 1 - 2 files changed, 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 617b90e..e588264 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -413,12 +413,6 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" -[[package]] -name = "ppv-lite86" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -461,46 +455,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", - "rand_hc", -] - -[[package]] -name = "rand_chacha" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", -] - [[package]] name = "redox_syscall" version = "0.2.4" @@ -535,15 +489,6 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "ring" version = "0.16.20" @@ -652,7 +597,6 @@ dependencies = [ "serde", "serde_json", "tar", - "tempfile", "ureq", "url", "xz2", @@ -693,20 +637,6 @@ dependencies = [ "xattr", ] -[[package]] -name = "tempfile" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "rand", - "redox_syscall", - "remove_dir_all", - "winapi", -] - [[package]] name = "termcolor" version = "1.1.2" diff --git a/Cargo.toml b/Cargo.toml index ce642cb..dcd4f02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ semver = "0.11.0" serde = { version = "1.0.123", features = ["derive"] } serde_json = "1.0.62" tar = "0.4.32" -tempfile = "3.2.0" ureq = { version = "2.0.1", features = ["json"] } url = "2.2.0" xz2 = "0.1.6" From 32e77eca713b6b77569826a1e167c21568c7e126 Mon Sep 17 00:00:00 2001 From: numtostr Date: Thu, 6 May 2021 17:01:22 +0530 Subject: [PATCH 10/10] ci check