diff --git a/Cargo.lock b/Cargo.lock index a77dc9212..c4589d5b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -286,6 +286,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 = "constant_time_eq" version = "0.1.5" @@ -414,6 +429,12 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "encoding_rs" version = "0.8.28" @@ -568,6 +589,8 @@ dependencies = [ "libc", "libgit2-sys", "log", + "openssl-probe", + "openssl-sys", "url", ] @@ -643,6 +666,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "humansize" version = "1.1.0" @@ -703,6 +732,18 @@ dependencies = [ "tiff", ] +[[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 = "instant" version = "0.1.9" @@ -768,11 +809,27 @@ name = "libgit2-sys" version = "0.12.19+1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f322155d574c8b9ebe991a04f6908bb49e68a79463338d24a43d6274cb6443e6" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libssh2-sys" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0186af0d8f171ae6b9c4c90ec51898bad5d08a2d5e470903a50d9ad8959cbee" dependencies = [ "cc", "libc", "libz-sys", + "openssl-sys", "pkg-config", + "vcpkg", ] [[package]] @@ -823,6 +880,12 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + [[package]] name = "memchr" version = "2.3.4" @@ -940,6 +1003,12 @@ dependencies = [ "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "object" version = "0.23.0" @@ -968,9 +1037,12 @@ dependencies = [ "colored", "error-chain", "git2", + "hex", "image", + "indicatif", "json", "libc", + "md5", "more-asserts", "paste", "regex", @@ -990,6 +1062,25 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +[[package]] +name = "openssl-probe" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" + +[[package]] +name = "openssl-sys" +version = "0.9.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52160d45fa2e7608d504b7c3a3355afed615e6d8b627a74458634ba21b69bd" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "parking_lot" version = "0.11.1" @@ -1456,6 +1547,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.11.0" diff --git a/Cargo.toml b/Cargo.toml index 3c508452d..4e42cfe6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,9 +29,12 @@ clap = "2.33.3" color_quant = "1.1.0" colored = "2.0.0" error-chain = "0.12" -git2 = {version = "0.13.18", default-features = false} +git2 = "0.13.18" +hex = "0.4" image = "0.23.14" +indicatif = "0.16" json = "0.12.4" +md5 = "0.7" regex = "1.4.6" serde = "1.0.125" serde_json = "1.0.64" diff --git a/src/main.rs b/src/main.rs index d7bbfa9a5..d45186fe8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ #![recursion_limit = "1024"] #![cfg_attr(feature = "fail-on-deprecated", deny(deprecated))] -use onefetch::{cli::Cli, cli_utils, error::*, info, printer::Printer, repo}; +use onefetch::{cli::Cli, cli_utils, error::*, info, printer::Printer}; use std::{io, process}; @@ -22,9 +22,6 @@ fn run() -> Result<()> { return cli_utils::print_supported_package_managers(); } - if !repo::is_valid(&config.repo_path)? { - return Err("please run onefetch inside of a non-bare git repository".into()); - } let info = info::Info::new(config)?; let mut printer = Printer::new(io::BufWriter::new(io::stdout()), info); diff --git a/src/onefetch/cli.rs b/src/onefetch/cli.rs index 9cde0f92a..e51e3e22f 100644 --- a/src/onefetch/cli.rs +++ b/src/onefetch/cli.rs @@ -37,6 +37,7 @@ pub struct Cli { pub art_off: bool, pub text_colors: Vec, pub iso_time: bool, + pub is_remote: bool, } impl Cli { @@ -253,6 +254,11 @@ impl Cli { .takes_value(true) .help("Ignore all files & directories matching EXCLUDE."), ) + .arg( + Arg::with_name("remote") + .long("remote") + .help("Clone repository from remote"), + ) .get_matches(); let true_color = match matches.value_of("true-color") { @@ -349,6 +355,8 @@ impl Cli { Vec::new() }; + let is_remote = matches.is_present("remote"); + Ok(Cli { repo_path, ascii_input, @@ -370,6 +378,7 @@ impl Cli { text_colors, art_off, iso_time, + is_remote, }) } } diff --git a/src/onefetch/info.rs b/src/onefetch/info.rs index 8f3bef150..ef84024f1 100644 --- a/src/onefetch/info.rs +++ b/src/onefetch/info.rs @@ -1,10 +1,16 @@ use { crate::onefetch::{ - cli::Cli, cli_utils, commit_info::CommitInfo, error::*, language::Language, - license::Detector, package_managers::DependencyDetector, repo::Repo, text_color::TextColor, + cli::Cli, + cli_utils, + commit_info::CommitInfo, + error::*, + language::Language, + license::Detector, + package_managers::DependencyDetector, + repo::{get_repo, Repo}, + text_color::TextColor, }, colored::{Color, ColoredString, Colorize}, - git2::Repository, serde::ser::SerializeStruct, serde::Serialize, }; @@ -210,7 +216,7 @@ impl std::fmt::Display for Info { impl Info { pub fn new(config: Cli) -> Result { let git_version = cli_utils::get_git_version(); - let repo = Repository::discover(&config.repo_path)?; + let repo = get_repo(config.is_remote, &config.repo_path)?; let internal_repo = Repo::new(&repo, config.no_merges)?; let (repo_name, repo_url) = internal_repo.get_name_and_url()?; let head_refs = internal_repo.get_head_refs()?; diff --git a/src/onefetch/repo.rs b/src/onefetch/repo.rs index f1176839c..261cb12c8 100644 --- a/src/onefetch/repo.rs +++ b/src/onefetch/repo.rs @@ -1,7 +1,10 @@ use crate::onefetch::{commit_info::CommitInfo, error::*, utils}; +use colored::*; use git2::{ - BranchType, Commit, Repository, RepositoryOpenFlags, Status, StatusOptions, StatusShow, + build::RepoBuilder, BranchType, Commit, FetchOptions, RemoteCallbacks, Repository, + RepositoryOpenFlags, Status, StatusOptions, StatusShow, }; +use indicatif::{ProgressBar, ProgressStyle}; use regex::Regex; use std::path::Path; @@ -264,7 +267,62 @@ impl<'a> Repo<'a> { } } -pub fn is_valid(repo_path: &str) -> Result { +pub fn get_repo(is_remote: bool, repo_path: &str) -> Result { + let repo = if is_remote { + let temp_directory = std::env::temp_dir(); + let repo_digest = md5::compute(repo_path); + let mut repo_directory = temp_directory; + repo_directory.push("onefetch"); + repo_directory.push(hex::encode(repo_digest.0)); + if repo_directory.exists() { + Repository::discover(repo_directory)? + } else { + clone_remote(repo_path, &repo_directory)? + } + } else { + if !is_valid(repo_path)? { + return Err("please run onefetch inside of a non-bare git repository".into()); + } + Repository::discover(repo_path)? + }; + Ok(repo) +} + +fn clone_remote(url: &str, path: &std::path::PathBuf) -> Result { + let progress_bar = ProgressBar::new(1); + let progress_bar_style = ProgressStyle::default_bar() + .template("{msg}\n{spinner:.green} [{elapsed}] [{wide_bar:.cyan/blue}] {pos}/{len}") + .progress_chars("#>-"); + + progress_bar.set_style(progress_bar_style); + progress_bar.set_message("- Cloning Git repository".bold().to_string()); + let remote_callbacks = { + let mut v = RemoteCallbacks::new(); + v.transfer_progress(|v| { + progress_bar.set_length(v.total_objects() as u64); + progress_bar.set_position(v.received_objects() as u64); + true + }); + + v + }; + + let fetch_options = { + let mut v = FetchOptions::new(); + v.remote_callbacks(remote_callbacks); + v + }; + let mut builder = { + let mut v = RepoBuilder::new(); + v.fetch_options(fetch_options); + v + }; + let repository = builder.clone(url, path)?; + progress_bar.finish_and_clear(); + Ok(repository) +} + +fn is_valid(repo_path: &str) -> Result { let repo = Repository::open_ext(repo_path, RepositoryOpenFlags::empty(), Vec::<&Path>::new()); Ok(repo.is_ok() && !repo?.is_bare()) }