Skip to content

Commit b49ccad

Browse files
committed
Auto merge of #8522 - alexcrichton:revert-master, r=ehuss
Prepare for not defaulting to master branch for git deps This PR is the "equivalent" of #8503 for the nightly channel of Rust (the master branch of Cargo). The purpose of this change is to fix the breakage from #8364 but to still pave a path forward to enabling the feature added in #8364, namely reinterpreting dependency directives without a `branch` directive as depending on `HEAD` insead of depending on `master`. This is a series of commits which implements a few mitigation strategies, but they're all adding up into a larger plan to roll out this change with, ideally, no breaking changes for those "reasonably" keeping up with Rust. The changes here are: * Cargo still internally differentiates between `DefaultBranch` and `Branch("master")`, so it knows what you wrote in the manifest. These two, however, hash and equate together so everything in Cargo considers them equivalent. * Cargo will now issue a warning whenever it fetches a repository pinned to `DefaultBranch` and the branch's `master` branch doesn't actually match `HEAD`. This avenue of breakage didn't arise but I added it here for completionism about not having to deal with breakage from this change again. * Cargo has now implemented a new future lockfile format. Internally this is dubbed "v3". The changes in this format is that it will have a `version` marker at the top of the file as well as encoding git dependencies different. Today `DefaultBranch` and `Branch("master")` encode the same way, but in the future they will encode differently. * Cargo now has a warning where if you have a mixture of `DefaultBranch` and `Branch("master")` in your build. The intention here is to get everyone on one or the other so the transition to the new lock file format can go smoothly. With all of these pieces in place the intention is that there is no breakage from #8364 as well. Additionally projects that *would* break will receive warnings. (note that projects "broken" today, those we've got issues for, will likely not get warnings, but that's because it was accidental we broke them). The long-term plan is to let this bake for quite some time, and then as part of the same change land an update to the new lock file format as well as "fixing" `SourceId` to consider these two directives different. When this change happens we should have guaranteed, for all currently active projects, they're either only using `branch = "master"` or no directive at all. We can therefore unambiguosly read the previous `Cargo.lock` to transition it into a new `Cargo.lock` which will either have `?branch=master` or nothing. I'm not sure how long this will need to bake for because unfortunately version changes to `Cargo.lock` cannot be taken lightly. We haven't even bumped the default format for old lock files to `V2` yet, they're still on `V1`. Hopefully in getting this in early-ish, though, we can at least get the ball rolling. Closes #8468
2 parents 4ca9089 + 7f65cae commit b49ccad

File tree

14 files changed

+714
-157
lines changed

14 files changed

+714
-157
lines changed

src/cargo/core/dependency.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,16 @@ impl Dependency {
386386
self.source_id(),
387387
id
388388
);
389-
self.set_version_req(VersionReq::exact(id.version()))
390-
.set_source_id(id.source_id())
389+
let me = Rc::make_mut(&mut self.inner);
390+
me.req = VersionReq::exact(id.version());
391+
392+
// Only update the `precise` of this source to preserve other
393+
// information about dependency's source which may not otherwise be
394+
// tested during equality/hashing.
395+
me.source_id = me
396+
.source_id
397+
.with_precise(id.source_id().precise().map(|s| s.to_string()));
398+
self
391399
}
392400

393401
/// Returns `true` if this is a "locked" dependency, basically whether it has

src/cargo/core/registry.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
use std::collections::{HashMap, HashSet};
22

3-
use anyhow::bail;
4-
use log::{debug, trace};
5-
use semver::VersionReq;
6-
use url::Url;
7-
83
use crate::core::PackageSet;
94
use crate::core::{Dependency, PackageId, Source, SourceId, SourceMap, Summary};
105
use crate::sources::config::SourceConfigMap;
116
use crate::util::errors::{CargoResult, CargoResultExt};
127
use crate::util::interning::InternedString;
138
use crate::util::{profile, CanonicalUrl, Config};
9+
use anyhow::bail;
10+
use log::{debug, trace};
11+
use semver::VersionReq;
12+
use url::Url;
1413

1514
/// Source of information about a group of packages.
1615
///
@@ -135,22 +134,22 @@ impl<'cfg> PackageRegistry<'cfg> {
135134
// We've previously loaded this source, and we've already locked it,
136135
// so we're not allowed to change it even if `namespace` has a
137136
// slightly different precise version listed.
138-
Some(&(_, Kind::Locked)) => {
137+
Some((_, Kind::Locked)) => {
139138
debug!("load/locked {}", namespace);
140139
return Ok(());
141140
}
142141

143142
// If the previous source was not a precise source, then we can be
144143
// sure that it's already been updated if we've already loaded it.
145-
Some(&(ref previous, _)) if previous.precise().is_none() => {
144+
Some((previous, _)) if previous.precise().is_none() => {
146145
debug!("load/precise {}", namespace);
147146
return Ok(());
148147
}
149148

150149
// If the previous source has the same precise version as we do,
151150
// then we're done, otherwise we need to need to move forward
152151
// updating this source.
153-
Some(&(ref previous, _)) => {
152+
Some((previous, _)) => {
154153
if previous.precise() == namespace.precise() {
155154
debug!("load/match {}", namespace);
156155
return Ok(());

src/cargo/core/resolver/context.rs

+7-10
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
1-
use std::collections::HashMap;
2-
use std::num::NonZeroU64;
3-
4-
use anyhow::format_err;
5-
use log::debug;
6-
7-
use crate::core::{Dependency, PackageId, SourceId, Summary};
8-
use crate::util::interning::InternedString;
9-
use crate::util::Graph;
10-
111
use super::dep_cache::RegistryQueryer;
122
use super::errors::ActivateResult;
133
use super::types::{ConflictMap, ConflictReason, FeaturesSet, ResolveOpts};
4+
use crate::core::{Dependency, PackageId, SourceId, Summary};
5+
use crate::util::interning::InternedString;
6+
use crate::util::Graph;
7+
use anyhow::format_err;
8+
use log::debug;
9+
use std::collections::HashMap;
10+
use std::num::NonZeroU64;
1411

1512
pub use super::encode::Metadata;
1613
pub use super::encode::{EncodableDependency, EncodablePackageId, EncodableResolve};

src/cargo/core/resolver/dep_cache.rs

+54-9
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,19 @@
99
//!
1010
//! This module impl that cache in all the gory details
1111
12-
use std::cmp::Ordering;
13-
use std::collections::{BTreeSet, HashMap, HashSet};
14-
use std::rc::Rc;
15-
16-
use log::debug;
17-
1812
use crate::core::resolver::context::Context;
1913
use crate::core::resolver::errors::describe_path;
14+
use crate::core::resolver::types::{ConflictReason, DepInfo, FeaturesSet};
15+
use crate::core::resolver::{ActivateResult, ResolveOpts};
2016
use crate::core::{Dependency, FeatureValue, PackageId, PackageIdSpec, Registry, Summary};
17+
use crate::core::{GitReference, SourceId};
2118
use crate::util::errors::{CargoResult, CargoResultExt};
2219
use crate::util::interning::InternedString;
23-
24-
use crate::core::resolver::types::{ConflictReason, DepInfo, FeaturesSet};
25-
use crate::core::resolver::{ActivateResult, ResolveOpts};
20+
use crate::util::Config;
21+
use log::debug;
22+
use std::cmp::Ordering;
23+
use std::collections::{BTreeSet, HashMap, HashSet};
24+
use std::rc::Rc;
2625

2726
pub struct RegistryQueryer<'a> {
2827
pub registry: &'a mut (dyn Registry + 'a),
@@ -41,6 +40,10 @@ pub struct RegistryQueryer<'a> {
4140
>,
4241
/// all the cases we ended up using a supplied replacement
4342
used_replacements: HashMap<PackageId, Summary>,
43+
/// Where to print warnings, if configured.
44+
config: Option<&'a Config>,
45+
/// Sources that we've already wared about possibly colliding in the future.
46+
warned_git_collisions: HashSet<SourceId>,
4447
}
4548

4649
impl<'a> RegistryQueryer<'a> {
@@ -49,6 +52,7 @@ impl<'a> RegistryQueryer<'a> {
4952
replacements: &'a [(PackageIdSpec, Dependency)],
5053
try_to_use: &'a HashSet<PackageId>,
5154
minimal_versions: bool,
55+
config: Option<&'a Config>,
5256
) -> Self {
5357
RegistryQueryer {
5458
registry,
@@ -58,6 +62,8 @@ impl<'a> RegistryQueryer<'a> {
5862
registry_cache: HashMap::new(),
5963
summary_cache: HashMap::new(),
6064
used_replacements: HashMap::new(),
65+
config,
66+
warned_git_collisions: HashSet::new(),
6167
}
6268
}
6369

@@ -69,13 +75,52 @@ impl<'a> RegistryQueryer<'a> {
6975
self.used_replacements.get(&p)
7076
}
7177

78+
/// Issues a future-compatible warning targeted at removing reliance on
79+
/// unifying behavior between these two dependency directives:
80+
///
81+
/// ```toml
82+
/// [dependencies]
83+
/// a = { git = 'https://example.org/foo' }
84+
/// a = { git = 'https://example.org/foo', branch = 'master }
85+
/// ```
86+
///
87+
/// Historical versions of Cargo considered these equivalent but going
88+
/// forward we'd like to fix this. For more details see the comments in
89+
/// src/cargo/sources/git/utils.rs
90+
fn warn_colliding_git_sources(&mut self, id: SourceId) -> CargoResult<()> {
91+
let config = match self.config {
92+
Some(config) => config,
93+
None => return Ok(()),
94+
};
95+
let prev = match self.warned_git_collisions.replace(id) {
96+
Some(prev) => prev,
97+
None => return Ok(()),
98+
};
99+
match (id.git_reference(), prev.git_reference()) {
100+
(Some(GitReference::DefaultBranch), Some(GitReference::Branch(b)))
101+
| (Some(GitReference::Branch(b)), Some(GitReference::DefaultBranch))
102+
if b == "master" => {}
103+
_ => return Ok(()),
104+
}
105+
106+
config.shell().warn(&format!(
107+
"two git dependencies found for `{}` \
108+
where one uses `branch = \"master\"` and the other doesn't; \
109+
this will break in a future version of Cargo, so please \
110+
ensure the dependency forms are consistent",
111+
id.url(),
112+
))?;
113+
Ok(())
114+
}
115+
72116
/// Queries the `registry` to return a list of candidates for `dep`.
73117
///
74118
/// This method is the location where overrides are taken into account. If
75119
/// any candidates are returned which match an override then the override is
76120
/// applied by performing a second query for what the override should
77121
/// return.
78122
pub fn query(&mut self, dep: &Dependency) -> CargoResult<Rc<Vec<Summary>>> {
123+
self.warn_colliding_git_sources(dep.source_id())?;
79124
if let Some(out) = self.registry_cache.get(dep).cloned() {
80125
return Ok(out);
81126
}

0 commit comments

Comments
 (0)