Skip to content

Commit 538fb1b

Browse files
committed
Effectively revert #8364
This commit is intended to be an effective but not literal revert of #8364. Internally Cargo will still distinguish between `DefaultBranch` and `Branch("master")` when reading `Cargo.toml` files, but for almost all purposes the two are equivalent. This will namely fix the issue we have with lock file encodings where both are encoded with no `branch` (and without a branch it's parsed from a lock file as `DefaultBranch`). This will preserve the change that `cargo vendor` will not print out `branch = "master"` annotations but that desugars to match the lock file on the other end, so it should continue to work. Tests have been added in this commit for the regressions found on #8468.
1 parent aa68721 commit 538fb1b

File tree

3 files changed

+216
-18
lines changed

3 files changed

+216
-18
lines changed

src/cargo/core/source/source_id.rs

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::cmp::{self, Ordering};
22
use std::collections::HashSet;
33
use std::fmt::{self, Formatter};
4-
use std::hash::{self, Hash};
4+
use std::hash::{self, Hash, Hasher};
55
use std::path::Path;
66
use std::ptr;
77
use std::sync::Mutex;
@@ -59,7 +59,7 @@ enum SourceKind {
5959
}
6060

6161
/// Information to find a specific commit in a Git repository.
62-
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
62+
#[derive(Debug, Clone)]
6363
pub enum GitReference {
6464
/// From a tag.
6565
Tag(String),
@@ -553,8 +553,11 @@ impl GitReference {
553553
/// Returns a `Display`able view of this git reference, or None if using
554554
/// the head of the default branch
555555
pub fn pretty_ref(&self) -> Option<PrettyRef<'_>> {
556-
match *self {
556+
match self {
557557
GitReference::DefaultBranch => None,
558+
// See module comments in src/cargo/sources/git/utils.rs for why
559+
// `DefaultBranch` is treated specially here.
560+
GitReference::Branch(m) if m == "master" => None,
558561
_ => Some(PrettyRef { inner: self }),
559562
}
560563
}
@@ -576,6 +579,77 @@ impl<'a> fmt::Display for PrettyRef<'a> {
576579
}
577580
}
578581

582+
// See module comments in src/cargo/sources/git/utils.rs for why `DefaultBranch`
583+
// is treated specially here.
584+
impl PartialEq for GitReference {
585+
fn eq(&self, other: &GitReference) -> bool {
586+
match (self, other) {
587+
(GitReference::Tag(a), GitReference::Tag(b)) => a == b,
588+
(GitReference::Rev(a), GitReference::Rev(b)) => a == b,
589+
(GitReference::Branch(b), GitReference::DefaultBranch)
590+
| (GitReference::DefaultBranch, GitReference::Branch(b)) => b == "master",
591+
(GitReference::DefaultBranch, GitReference::DefaultBranch) => true,
592+
(GitReference::Branch(a), GitReference::Branch(b)) => a == b,
593+
_ => false,
594+
}
595+
}
596+
}
597+
598+
impl Eq for GitReference {}
599+
600+
// See module comments in src/cargo/sources/git/utils.rs for why `DefaultBranch`
601+
// is treated specially here.
602+
impl Hash for GitReference {
603+
fn hash<H: Hasher>(&self, hasher: &mut H) {
604+
match self {
605+
GitReference::Tag(a) => {
606+
0u8.hash(hasher);
607+
a.hash(hasher);
608+
}
609+
GitReference::Rev(a) => {
610+
1u8.hash(hasher);
611+
a.hash(hasher);
612+
}
613+
GitReference::Branch(a) => {
614+
2u8.hash(hasher);
615+
a.hash(hasher);
616+
}
617+
GitReference::DefaultBranch => {
618+
2u8.hash(hasher);
619+
"master".hash(hasher);
620+
}
621+
}
622+
}
623+
}
624+
625+
impl PartialOrd for GitReference {
626+
fn partial_cmp(&self, other: &GitReference) -> Option<Ordering> {
627+
Some(self.cmp(other))
628+
}
629+
}
630+
631+
// See module comments in src/cargo/sources/git/utils.rs for why `DefaultBranch`
632+
// is treated specially here.
633+
impl Ord for GitReference {
634+
fn cmp(&self, other: &GitReference) -> Ordering {
635+
use GitReference::*;
636+
match (self, other) {
637+
(Tag(a), Tag(b)) => a.cmp(b),
638+
(Tag(_), _) => Ordering::Less,
639+
(_, Tag(_)) => Ordering::Greater,
640+
641+
(Rev(a), Rev(b)) => a.cmp(b),
642+
(Rev(_), _) => Ordering::Less,
643+
(_, Rev(_)) => Ordering::Greater,
644+
645+
(Branch(b), DefaultBranch) => b.as_str().cmp("master"),
646+
(DefaultBranch, Branch(b)) => "master".cmp(b),
647+
(Branch(a), Branch(b)) => a.cmp(b),
648+
(DefaultBranch, DefaultBranch) => Ordering::Equal,
649+
}
650+
}
651+
}
652+
579653
#[cfg(test)]
580654
mod tests {
581655
use super::{GitReference, SourceId, SourceKind};

src/cargo/sources/git/utils.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,17 @@ impl GitReference {
217217
.target()
218218
.ok_or_else(|| anyhow::format_err!("branch `{}` did not have a target", s))?
219219
}
220+
221+
// See the module docs for why we're using `master` here.
220222
GitReference::DefaultBranch => {
221-
let refname = "refs/remotes/origin/HEAD";
222-
let id = repo.refname_to_id(refname)?;
223-
let obj = repo.find_object(id, None)?;
224-
let obj = obj.peel(ObjectType::Commit)?;
225-
obj.id()
223+
let master = repo
224+
.find_branch("origin/master", git2::BranchType::Remote)
225+
.chain_err(|| "failed to find branch `master`")?;
226+
let master = master
227+
.get()
228+
.target()
229+
.ok_or_else(|| anyhow::format_err!("branch `master` did not have a target"))?;
230+
master
226231
}
227232

228233
GitReference::Rev(s) => {
@@ -757,6 +762,7 @@ pub fn fetch(
757762
}
758763

759764
GitReference::DefaultBranch => {
765+
refspecs.push(format!("refs/heads/master:refs/remotes/origin/master"));
760766
refspecs.push(String::from("HEAD:refs/remotes/origin/HEAD"));
761767
}
762768

@@ -984,7 +990,8 @@ fn github_up_to_date(
984990
let github_branch_name = match reference {
985991
GitReference::Branch(branch) => branch,
986992
GitReference::Tag(tag) => tag,
987-
GitReference::DefaultBranch => "HEAD",
993+
// See the module docs for why we're using `master` here.
994+
GitReference::DefaultBranch => "master",
988995
GitReference::Rev(_) => {
989996
debug!("can't use github fast path with `rev`");
990997
return Ok(false);

tests/testsuite/git.rs

Lines changed: 126 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::fs;
55
use std::io::prelude::*;
66
use std::net::{TcpListener, TcpStream};
77
use std::path::Path;
8+
use std::str;
89
use std::sync::atomic::{AtomicBool, Ordering};
910
use std::sync::Arc;
1011
use std::thread;
@@ -2789,19 +2790,23 @@ to proceed despite [..]
27892790
fn default_not_master() {
27902791
let project = project();
27912792

2792-
// Create a repository with a `master` branch ...
2793+
// Create a repository with a `master` branch, but switch the head to a
2794+
// branch called `main` at the same time.
27932795
let (git_project, repo) = git::new_repo("dep1", |project| {
2794-
project.file("Cargo.toml", &basic_lib_manifest("dep1"))
2796+
project
2797+
.file("Cargo.toml", &basic_lib_manifest("dep1"))
2798+
.file("src/lib.rs", "pub fn foo() {}")
27952799
});
2800+
let head_id = repo.head().unwrap().target().unwrap();
2801+
let head = repo.find_commit(head_id).unwrap();
2802+
repo.branch("main", &head, false).unwrap();
2803+
repo.set_head("refs/heads/main").unwrap();
27962804

2797-
// Then create a `main` branch with actual code, and set the head of the
2798-
// repository (default branch) to `main`.
2799-
git_project.change_file("src/lib.rs", "pub fn foo() {}");
2805+
// Then create a commit on the new `main` branch so `master` and `main`
2806+
// differ.
2807+
git_project.change_file("src/lib.rs", "");
28002808
git::add(&repo);
2801-
let rev = git::commit(&repo);
2802-
let commit = repo.find_commit(rev).unwrap();
2803-
repo.branch("main", &commit, false).unwrap();
2804-
repo.set_head("refs/heads/main").unwrap();
2809+
git::commit(&repo);
28052810

28062811
let project = project
28072812
.file(
@@ -2832,3 +2837,115 @@ fn default_not_master() {
28322837
)
28332838
.run();
28342839
}
2840+
2841+
#[cargo_test]
2842+
fn historical_lockfile_works() {
2843+
let project = project();
2844+
2845+
let (git_project, repo) = git::new_repo("dep1", |project| {
2846+
project
2847+
.file("Cargo.toml", &basic_lib_manifest("dep1"))
2848+
.file("src/lib.rs", "")
2849+
});
2850+
let head_id = repo.head().unwrap().target().unwrap();
2851+
2852+
let project = project
2853+
.file(
2854+
"Cargo.toml",
2855+
&format!(
2856+
r#"
2857+
[project]
2858+
name = "foo"
2859+
version = "0.5.0"
2860+
2861+
[dependencies]
2862+
dep1 = {{ git = '{}', branch = 'master' }}
2863+
"#,
2864+
git_project.url()
2865+
),
2866+
)
2867+
.file("src/lib.rs", "")
2868+
.build();
2869+
2870+
project.cargo("build").run();
2871+
project.change_file(
2872+
"Cargo.lock",
2873+
&format!(
2874+
r#"# This file is automatically @generated by Cargo.
2875+
# It is not intended for manual editing.
2876+
[[package]]
2877+
name = "dep1"
2878+
version = "0.5.0"
2879+
source = "git+{}#{}"
2880+
2881+
[[package]]
2882+
name = "foo"
2883+
version = "0.5.0"
2884+
dependencies = [
2885+
"dep1",
2886+
]
2887+
"#,
2888+
git_project.url(),
2889+
head_id
2890+
),
2891+
);
2892+
project
2893+
.cargo("build")
2894+
.with_stderr("[FINISHED] [..]\n")
2895+
.run();
2896+
}
2897+
2898+
#[cargo_test]
2899+
fn historical_lockfile_works_with_vendor() {
2900+
let project = project();
2901+
2902+
let (git_project, repo) = git::new_repo("dep1", |project| {
2903+
project
2904+
.file("Cargo.toml", &basic_lib_manifest("dep1"))
2905+
.file("src/lib.rs", "")
2906+
});
2907+
let head_id = repo.head().unwrap().target().unwrap();
2908+
2909+
let project = project
2910+
.file(
2911+
"Cargo.toml",
2912+
&format!(
2913+
r#"
2914+
[project]
2915+
name = "foo"
2916+
version = "0.5.0"
2917+
2918+
[dependencies]
2919+
dep1 = {{ git = '{}', branch = 'master' }}
2920+
"#,
2921+
git_project.url()
2922+
),
2923+
)
2924+
.file("src/lib.rs", "")
2925+
.build();
2926+
2927+
let output = project.cargo("vendor").exec_with_output().unwrap();
2928+
project.change_file(".cargo/config", str::from_utf8(&output.stdout).unwrap());
2929+
project.change_file(
2930+
"Cargo.lock",
2931+
&format!(
2932+
r#"# This file is automatically @generated by Cargo.
2933+
# It is not intended for manual editing.
2934+
[[package]]
2935+
name = "dep1"
2936+
version = "0.5.0"
2937+
source = "git+{}#{}"
2938+
2939+
[[package]]
2940+
name = "foo"
2941+
version = "0.5.0"
2942+
dependencies = [
2943+
"dep1",
2944+
]
2945+
"#,
2946+
git_project.url(),
2947+
head_id
2948+
),
2949+
);
2950+
project.cargo("build").run();
2951+
}

0 commit comments

Comments
 (0)