Skip to content

feat: cloning remote repository #420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
5 changes: 1 addition & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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);
Expand Down
9 changes: 9 additions & 0 deletions src/onefetch/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub struct Cli {
pub art_off: bool,
pub text_colors: Vec<String>,
pub iso_time: bool,
pub is_remote: bool,
}

impl Cli {
Expand Down Expand Up @@ -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"),
)
Comment on lines +257 to +261
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be useful if this arg either

  • Had another arg that required this arg
  • Took a second value

So that the user could specify whether the cloned repo should be deleted or kept.

e.g. onefetch --remote <my URL> --keep to keep the repo after cloning it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be useful if this arg either

* Had another arg that [required](https://docs.rs/clap/2.33.3/clap/struct.Arg.html#method.requires) this arg

* Took a second value

So that the user could specify whether the cloned repo should be deleted or kept.

e.g. onefetch --remote <my URL> --keep to keep the repo after cloning it.

Where would you like to keep this repository?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could probably just clone it to the current directory if it's being kept.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could probably just clone it to the current directory if it's being kept.

I think it does not make much sense, because you could just do git clone and then run onefetch there.

Purpose of this feature is to quickly look up information about repository while not caring at all about the repository itself, but just about statistics.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Purpose of this feature is to quickly look up information about repository while not caring at all about the repository itself, but just about statistics.

Yes, that makes sense, but, since it is not doing a shallow clone, you're getting the whole repository anyway. For example, if this feature was used on the Linux repo, it would take a long time. Worse if the user uses this feature and then decides to clone it to do some work on it. It is hardly "quickly looking up information."

For example, somebody could use this feature, and then decide it's a repository that they would want to work on based on the stats. If this feature doesn't support keeping the repository, they would have to clone it a second time.

Although I agree that it is unnecessary to add a --keep option if the repo is cloned with a shallow depth, since onefetch's clone would take less time, and a shallow clone isn't that useful for actual work. 🙂

.get_matches();

let true_color = match matches.value_of("true-color") {
Expand Down Expand Up @@ -349,6 +355,8 @@ impl Cli {
Vec::new()
};

let is_remote = matches.is_present("remote");

Ok(Cli {
repo_path,
ascii_input,
Expand All @@ -370,6 +378,7 @@ impl Cli {
text_colors,
art_off,
iso_time,
is_remote,
})
}
}
14 changes: 10 additions & 4 deletions src/onefetch/info.rs
Original file line number Diff line number Diff line change
@@ -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,
};
Expand Down Expand Up @@ -210,7 +216,7 @@ impl std::fmt::Display for Info {
impl Info {
pub fn new(config: Cli) -> Result<Info> {
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()?;
Expand Down
62 changes: 60 additions & 2 deletions src/onefetch/repo.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -264,7 +267,62 @@ impl<'a> Repo<'a> {
}
}

pub fn is_valid(repo_path: &str) -> Result<bool> {
pub fn get_repo(is_remote: bool, repo_path: &str) -> Result<Repository> {
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<Repository> {
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<bool> {
let repo = Repository::open_ext(repo_path, RepositoryOpenFlags::empty(), Vec::<&Path>::new());
Ok(repo.is_ok() && !repo?.is_bare())
}