Skip to content

Commit

Permalink
Auto merge of #5914 - alexcrichton:system-git, r=dwijnand
Browse files Browse the repository at this point in the history
Add a configuration option to fetch with git-the-CLI

Currently Cargo always uses `libgit2` to perform all fetches of git
repositories, but sometimes this is not sufficient. The `libgit2` library
doesn't support all authentication schemes that `git` does and it isn't always
quite at feature parity with `git` itself, especially in terms of network
configuration.

This commit adds a configuration option to Cargo for fetching git repositories
with the `git` CLI tool rather than the internal `libgit2`. While this exposes
us to changes over time in the `git` CLI it's hopefully a very targeted use case
that doesn't change much. The internal `libgit2` library should be sufficient
for all other forms of git repository management. (and using `git` for only
fetches shouldn't slow us down much)

The new configuration option in `.cargo/config` is:

    [net]
    git-fetch-with-cli = true

which can also be specified with `CARGO_NET_GIT_FETCH_WITH_CLI=true` via an
environment variable.

Closes #5903
  • Loading branch information
bors committed Aug 21, 2018
2 parents 0ec7281 + a0591ee commit 7ff1bdb
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 2 deletions.
35 changes: 33 additions & 2 deletions src/cargo/sources/git/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ use serde::ser;
use url::Url;

use core::GitReference;
use util::{internal, network, Config, Progress, ToUrl};
use util::paths;
use util::errors::{CargoError, CargoResult, CargoResultExt};
use util::paths;
use util::process_builder::process;
use util::{internal, network, Config, Progress, ToUrl};

#[derive(PartialEq, Clone, Debug)]
pub struct GitRevision(git2::Oid);
Expand Down Expand Up @@ -691,6 +692,18 @@ pub fn fetch(
// request we're about to issue.
maybe_gc_repo(repo)?;

// Unfortuantely `libgit2` is notably lacking in the realm of authentication
// when compared to the `git` command line. As a result, allow an escape
// hatch for users that would prefer to use `git`-the-CLI for fetching
// repositories instead of `libgit2`-the-library. This should make more
// flavors of authentication possible while also still giving us all the
// speed and portability of using `libgit2`.
if let Some(val) = config.get_bool("net.git-fetch-with-cli")? {
if val.val {
return fetch_with_cli(repo, url, refspec, config);
}
}

debug!("doing a fetch for {}", url);
let git_config = git2::Config::open_default()?;
with_fetch_options(&git_config, url, config, &mut |mut opts| {
Expand Down Expand Up @@ -732,6 +745,24 @@ pub fn fetch(
})
}

fn fetch_with_cli(
repo: &mut git2::Repository,
url: &Url,
refspec: &str,
config: &Config,
) -> CargoResult<()> {
let mut cmd = process("git");
cmd.arg("fetch")
.arg("--tags") // fetch all tags
.arg("--quiet")
.arg(url.to_string())
.arg(refspec)
.cwd(repo.path());
config.shell().verbose(|s| s.status("Running", &cmd.to_string()))?;
cmd.exec()?;
Ok(())
}

/// Cargo has a bunch of long-lived git repositories in its global cache and
/// some, like the index, are updated very frequently. Right now each update
/// creates a new "pack file" inside the git database, and over time this can
Expand Down
1 change: 1 addition & 0 deletions src/doc/src/reference/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ color = 'auto' # whether cargo colorizes output
# Network configuration
[net]
retry = 2 # number of times a network call will automatically retried
git-fetch-with-cli = false # if `true` we'll use `git`-the-CLI to fetch git repos

# Alias cargo commands. The first 3 aliases are built in. If your
# command requires grouped whitespace use the list format.
Expand Down
50 changes: 50 additions & 0 deletions tests/testsuite/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2748,3 +2748,53 @@ fn failed_submodule_checkout() {
drop(TcpStream::connect(&addr));
t.join().unwrap();
}

#[test]
fn use_the_cli() {
let project = project();
let git_project = git::new("dep1", |project| {
project.file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
.file("src/lib.rs", "")
}).unwrap();

let project = project
.file(
"Cargo.toml",
&format!(
r#"
[project]
name = "foo"
version = "0.5.0"
authors = []
[dependencies]
dep1 = {{ git = '{}' }}
"#,
git_project.url()
),
)
.file("src/lib.rs", "")
.file(
".cargo/config",
"
[net]
git-fetch-with-cli = true
"
)
.build();

let stderr = "\
[UPDATING] git repository `[..]`
[RUNNING] `git fetch [..]`
[COMPILING] dep1 [..]
[RUNNING] `rustc [..]`
[COMPILING] foo [..]
[RUNNING] `rustc [..]`
[FINISHED] [..]
";

assert_that(
project.cargo("build -v"),
execs().with_stderr(stderr)
);
}

0 comments on commit 7ff1bdb

Please sign in to comment.