Skip to content

Commit a3388a1

Browse files
committed
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
1 parent cc88d01 commit a3388a1

File tree

3 files changed

+84
-2
lines changed

3 files changed

+84
-2
lines changed

src/cargo/sources/git/utils.rs

+33-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ use serde::ser;
1111
use url::Url;
1212

1313
use core::GitReference;
14-
use util::{internal, network, Config, Progress, ToUrl};
15-
use util::paths;
1614
use util::errors::{CargoError, CargoResult, CargoResultExt};
15+
use util::paths;
16+
use util::process_builder::process;
17+
use util::{internal, network, Config, Progress, ToUrl};
1718

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

695+
// Unfortuantely `libgit2` is notably lacking in the realm of authentication
696+
// when compared to the `git` command line. As a result, allow an escape
697+
// hatch for users that would prefer to use `git`-the-CLI for fetching
698+
// repositories instead of `libgit2`-the-library. This should make more
699+
// flavors of authentication possible while also still giving us all the
700+
// speed and portability of using `libgit2`.
701+
if let Some(val) = config.get_bool("net.git-fetch-with-cli")? {
702+
if val.val {
703+
return fetch_with_cli(repo, url, refspec, config);
704+
}
705+
}
706+
694707
debug!("doing a fetch for {}", url);
695708
let git_config = git2::Config::open_default()?;
696709
with_fetch_options(&git_config, url, config, &mut |mut opts| {
@@ -732,6 +745,24 @@ pub fn fetch(
732745
})
733746
}
734747

748+
fn fetch_with_cli(
749+
repo: &mut git2::Repository,
750+
url: &Url,
751+
refspec: &str,
752+
config: &Config,
753+
) -> CargoResult<()> {
754+
let mut cmd = process("git");
755+
cmd.arg("fetch")
756+
.arg("--tags") // fetch all tags
757+
.arg("--quiet")
758+
.arg(url.to_string())
759+
.arg(refspec)
760+
.cwd(repo.path());
761+
config.shell().verbose(|s| s.status("Running", &cmd.to_string()))?;
762+
cmd.exec()?;
763+
Ok(())
764+
}
765+
735766
/// Cargo has a bunch of long-lived git repositories in its global cache and
736767
/// some, like the index, are updated very frequently. Right now each update
737768
/// creates a new "pack file" inside the git database, and over time this can

src/doc/src/reference/config.md

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ color = 'auto' # whether cargo colorizes output
113113
# Network configuration
114114
[net]
115115
retry = 2 # number of times a network call will automatically retried
116+
git-fetch-with-cli = false # if `true` we'll use `git`-the-CLI to fetch git repos
116117

117118
# Alias cargo commands. The first 3 aliases are built in. If your
118119
# command requires grouped whitespace use the list format.

tests/testsuite/git.rs

+50
Original file line numberDiff line numberDiff line change
@@ -2748,3 +2748,53 @@ fn failed_submodule_checkout() {
27482748
drop(TcpStream::connect(&addr));
27492749
t.join().unwrap();
27502750
}
2751+
2752+
#[test]
2753+
fn use_the_cli() {
2754+
let project = project();
2755+
let git_project = git::new("dep1", |project| {
2756+
project.file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
2757+
.file("src/lib.rs", "")
2758+
}).unwrap();
2759+
2760+
let project = project
2761+
.file(
2762+
"Cargo.toml",
2763+
&format!(
2764+
r#"
2765+
[project]
2766+
name = "foo"
2767+
version = "0.5.0"
2768+
authors = []
2769+
2770+
[dependencies]
2771+
dep1 = {{ git = '{}' }}
2772+
"#,
2773+
git_project.url()
2774+
),
2775+
)
2776+
.file("src/lib.rs", "")
2777+
.file(
2778+
".cargo/config",
2779+
"
2780+
[net]
2781+
git-fetch-with-cli = true
2782+
"
2783+
)
2784+
.build();
2785+
2786+
let stderr = "\
2787+
[UPDATING] git repository `[..]`
2788+
[RUNNING] `git fetch [..]`
2789+
[COMPILING] dep1 [..]
2790+
[RUNNING] `rustc [..]`
2791+
[COMPILING] foo [..]
2792+
[RUNNING] `rustc [..]`
2793+
[FINISHED] [..]
2794+
";
2795+
2796+
assert_that(
2797+
project.cargo("build -v"),
2798+
execs().with_stderr(stderr)
2799+
);
2800+
}

0 commit comments

Comments
 (0)