mirror of https://github.com/rust-lang/cargo
Compare commits
8 Commits
74ea1bf9f6
...
42be9d1ae7
Author | SHA1 | Date |
---|---|---|
Lin Yihai | 42be9d1ae7 | |
bors | eee4ea2f5a | |
bors | c4e19cc890 | |
Eric Huss | 06fb65e753 | |
Scott Schafer | cf197fc499 | |
Scott Schafer | c3b104e11e | |
Lin Yihai | 3a580a4714 | |
Lin Yihai | a15a5077e3 |
|
@ -154,7 +154,7 @@ impl EncodableResolve {
|
|||
/// primary uses is to be used with `resolve_with_previous` to guide the
|
||||
/// resolver to create a complete Resolve.
|
||||
pub fn into_resolve(self, original: &str, ws: &Workspace<'_>) -> CargoResult<Resolve> {
|
||||
let path_deps = build_path_deps(ws)?;
|
||||
let path_deps: HashMap<String, HashMap<semver::Version, SourceId>> = build_path_deps(ws)?;
|
||||
let mut checksums = HashMap::new();
|
||||
|
||||
let mut version = match self.version {
|
||||
|
@ -202,7 +202,11 @@ impl EncodableResolve {
|
|||
if !all_pkgs.insert(enc_id.clone()) {
|
||||
anyhow::bail!("package `{}` is specified twice in the lockfile", pkg.name);
|
||||
}
|
||||
let id = match pkg.source.as_deref().or_else(|| path_deps.get(&pkg.name)) {
|
||||
let id = match pkg
|
||||
.source
|
||||
.as_deref()
|
||||
.or_else(|| get_source_id(&path_deps, pkg))
|
||||
{
|
||||
// We failed to find a local package in the workspace.
|
||||
// It must have been removed and should be ignored.
|
||||
None => {
|
||||
|
@ -364,7 +368,11 @@ impl EncodableResolve {
|
|||
|
||||
let mut unused_patches = Vec::new();
|
||||
for pkg in self.patch.unused {
|
||||
let id = match pkg.source.as_deref().or_else(|| path_deps.get(&pkg.name)) {
|
||||
let id = match pkg
|
||||
.source
|
||||
.as_deref()
|
||||
.or_else(|| get_source_id(&path_deps, &pkg))
|
||||
{
|
||||
Some(&src) => PackageId::try_new(&pkg.name, &pkg.version, src)?,
|
||||
None => continue,
|
||||
};
|
||||
|
@ -395,7 +403,7 @@ impl EncodableResolve {
|
|||
version = ResolveVersion::V2;
|
||||
}
|
||||
|
||||
Ok(Resolve::new(
|
||||
return Ok(Resolve::new(
|
||||
g,
|
||||
replacements,
|
||||
HashMap::new(),
|
||||
|
@ -404,11 +412,33 @@ impl EncodableResolve {
|
|||
unused_patches,
|
||||
version,
|
||||
HashMap::new(),
|
||||
))
|
||||
));
|
||||
|
||||
fn get_source_id<'a>(
|
||||
path_deps: &'a HashMap<String, HashMap<semver::Version, SourceId>>,
|
||||
pkg: &'a EncodableDependency,
|
||||
) -> Option<&'a SourceId> {
|
||||
path_deps.iter().find_map(|(name, version_source)| {
|
||||
if name == &pkg.name {
|
||||
// If there are multiple candidates for the same name, it needs to be determined by combining versions (See #13405).
|
||||
if version_source.len() > 1 {
|
||||
if let Ok(pkg_version) = pkg.version.parse::<semver::Version>() {
|
||||
if let Some(source_id) = version_source.get(&pkg_version) {
|
||||
return Some(source_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Some(version_source.values().next().unwrap());
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>> {
|
||||
fn build_path_deps(
|
||||
ws: &Workspace<'_>,
|
||||
) -> CargoResult<HashMap<String, HashMap<semver::Version, SourceId>>> {
|
||||
// If a crate is **not** a path source, then we're probably in a situation
|
||||
// such as `cargo install` with a lock file from a remote dependency. In
|
||||
// that case we don't need to fixup any path dependencies (as they're not
|
||||
|
@ -418,13 +448,15 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
|
|||
.filter(|p| p.package_id().source_id().is_path())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut ret = HashMap::new();
|
||||
let mut ret: HashMap<String, HashMap<semver::Version, SourceId>> = HashMap::new();
|
||||
let mut visited = HashSet::new();
|
||||
for member in members.iter() {
|
||||
ret.insert(
|
||||
member.package_id().name().to_string(),
|
||||
member.package_id().source_id(),
|
||||
);
|
||||
ret.entry(member.package_id().name().to_string())
|
||||
.or_insert_with(HashMap::new)
|
||||
.insert(
|
||||
member.package_id().version().clone(),
|
||||
member.package_id().source_id(),
|
||||
);
|
||||
visited.insert(member.package_id().source_id());
|
||||
}
|
||||
for member in members.iter() {
|
||||
|
@ -444,7 +476,7 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
|
|||
fn build_pkg(
|
||||
pkg: &Package,
|
||||
ws: &Workspace<'_>,
|
||||
ret: &mut HashMap<String, SourceId>,
|
||||
ret: &mut HashMap<String, HashMap<semver::Version, SourceId>>,
|
||||
visited: &mut HashSet<SourceId>,
|
||||
) {
|
||||
for dep in pkg.dependencies() {
|
||||
|
@ -455,7 +487,7 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
|
|||
fn build_dep(
|
||||
dep: &Dependency,
|
||||
ws: &Workspace<'_>,
|
||||
ret: &mut HashMap<String, SourceId>,
|
||||
ret: &mut HashMap<String, HashMap<semver::Version, SourceId>>,
|
||||
visited: &mut HashSet<SourceId>,
|
||||
) {
|
||||
let id = dep.source_id();
|
||||
|
@ -467,7 +499,12 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
|
|||
Err(_) => return,
|
||||
};
|
||||
let Ok(pkg) = ws.load(&path) else { return };
|
||||
ret.insert(pkg.name().to_string(), pkg.package_id().source_id());
|
||||
ret.entry(pkg.package_id().name().to_string())
|
||||
.or_insert_with(HashMap::new)
|
||||
.insert(
|
||||
pkg.package_id().version().clone(),
|
||||
pkg.package_id().source_id(),
|
||||
);
|
||||
visited.insert(pkg.package_id().source_id());
|
||||
build_pkg(&pkg, ws, ret, visited);
|
||||
}
|
||||
|
|
|
@ -1147,11 +1147,26 @@ impl<'gctx> Workspace<'gctx> {
|
|||
}
|
||||
|
||||
pub fn emit_warnings(&self) -> CargoResult<()> {
|
||||
let ws_lints = self
|
||||
.root_maybe()
|
||||
.workspace_config()
|
||||
.inheritable()
|
||||
.and_then(|i| i.lints().ok())
|
||||
.unwrap_or_default();
|
||||
|
||||
let ws_cargo_lints = ws_lints
|
||||
.get("cargo")
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.replace('-', "_"), v))
|
||||
.collect();
|
||||
|
||||
for (path, maybe_pkg) in &self.packages.packages {
|
||||
let path = path.join("Cargo.toml");
|
||||
if let MaybePackage::Package(pkg) = maybe_pkg {
|
||||
if self.gctx.cli_unstable().cargo_lints {
|
||||
self.emit_lints(pkg, &path)?
|
||||
self.emit_lints(pkg, &path, &ws_cargo_lints)?
|
||||
}
|
||||
}
|
||||
let warnings = match maybe_pkg {
|
||||
|
@ -1179,22 +1194,12 @@ impl<'gctx> Workspace<'gctx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn emit_lints(&self, pkg: &Package, path: &Path) -> CargoResult<()> {
|
||||
let ws_lints = self
|
||||
.root_maybe()
|
||||
.workspace_config()
|
||||
.inheritable()
|
||||
.and_then(|i| i.lints().ok())
|
||||
.unwrap_or_default();
|
||||
|
||||
let ws_cargo_lints = ws_lints
|
||||
.get("cargo")
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.replace('-', "_"), v))
|
||||
.collect();
|
||||
|
||||
pub fn emit_lints(
|
||||
&self,
|
||||
pkg: &Package,
|
||||
path: &Path,
|
||||
ws_cargo_lints: &manifest::TomlToolLints,
|
||||
) -> CargoResult<()> {
|
||||
let mut error_count = 0;
|
||||
let toml_lints = pkg
|
||||
.manifest()
|
||||
|
@ -1212,11 +1217,21 @@ impl<'gctx> Workspace<'gctx> {
|
|||
.map(|(name, lint)| (name.replace('-', "_"), lint))
|
||||
.collect();
|
||||
|
||||
// We should only be using workspace lints if the `[lints]` table is
|
||||
// present in the manifest, and `workspace` is set to `true`
|
||||
let ws_cargo_lints = pkg
|
||||
.manifest()
|
||||
.resolved_toml()
|
||||
.lints
|
||||
.as_ref()
|
||||
.is_some_and(|l| l.workspace)
|
||||
.then(|| ws_cargo_lints);
|
||||
|
||||
check_im_a_teapot(
|
||||
pkg,
|
||||
&path,
|
||||
&normalized_lints,
|
||||
&ws_cargo_lints,
|
||||
ws_cargo_lints,
|
||||
&mut error_count,
|
||||
self.gctx,
|
||||
)?;
|
||||
|
@ -1224,7 +1239,7 @@ impl<'gctx> Workspace<'gctx> {
|
|||
pkg,
|
||||
&path,
|
||||
&normalized_lints,
|
||||
&ws_cargo_lints,
|
||||
ws_cargo_lints,
|
||||
&mut error_count,
|
||||
self.gctx,
|
||||
)?;
|
||||
|
@ -1232,7 +1247,7 @@ impl<'gctx> Workspace<'gctx> {
|
|||
pkg,
|
||||
&path,
|
||||
&normalized_lints,
|
||||
&ws_cargo_lints,
|
||||
ws_cargo_lints,
|
||||
&mut error_count,
|
||||
self.gctx,
|
||||
)?;
|
||||
|
|
|
@ -88,7 +88,7 @@ impl Lint {
|
|||
pub fn level(
|
||||
&self,
|
||||
pkg_lints: &TomlToolLints,
|
||||
ws_lints: &TomlToolLints,
|
||||
ws_lints: Option<&TomlToolLints>,
|
||||
edition: Edition,
|
||||
) -> (LintLevel, LintLevelReason) {
|
||||
self.groups
|
||||
|
@ -188,7 +188,7 @@ fn level_priority(
|
|||
default_level: LintLevel,
|
||||
edition_lint_opts: Option<(Edition, LintLevel)>,
|
||||
pkg_lints: &TomlToolLints,
|
||||
ws_lints: &TomlToolLints,
|
||||
ws_lints: Option<&TomlToolLints>,
|
||||
edition: Edition,
|
||||
) -> (LintLevel, LintLevelReason, i8) {
|
||||
let (unspecified_level, reason) = if let Some(level) = edition_lint_opts
|
||||
|
@ -211,7 +211,7 @@ fn level_priority(
|
|||
LintLevelReason::Package,
|
||||
defined_level.priority(),
|
||||
)
|
||||
} else if let Some(defined_level) = ws_lints.get(name) {
|
||||
} else if let Some(defined_level) = ws_lints.and_then(|l| l.get(name)) {
|
||||
(
|
||||
defined_level.level().into(),
|
||||
LintLevelReason::Workspace,
|
||||
|
@ -234,7 +234,7 @@ pub fn check_im_a_teapot(
|
|||
pkg: &Package,
|
||||
path: &Path,
|
||||
pkg_lints: &TomlToolLints,
|
||||
ws_lints: &TomlToolLints,
|
||||
ws_lints: Option<&TomlToolLints>,
|
||||
error_count: &mut usize,
|
||||
gctx: &GlobalContext,
|
||||
) -> CargoResult<()> {
|
||||
|
@ -306,7 +306,7 @@ pub fn check_implicit_features(
|
|||
pkg: &Package,
|
||||
path: &Path,
|
||||
pkg_lints: &TomlToolLints,
|
||||
ws_lints: &TomlToolLints,
|
||||
ws_lints: Option<&TomlToolLints>,
|
||||
error_count: &mut usize,
|
||||
gctx: &GlobalContext,
|
||||
) -> CargoResult<()> {
|
||||
|
@ -390,7 +390,7 @@ pub fn unused_dependencies(
|
|||
pkg: &Package,
|
||||
path: &Path,
|
||||
pkg_lints: &TomlToolLints,
|
||||
ws_lints: &TomlToolLints,
|
||||
ws_lints: Option<&TomlToolLints>,
|
||||
error_count: &mut usize,
|
||||
gctx: &GlobalContext,
|
||||
) -> CargoResult<()> {
|
||||
|
|
|
@ -90,13 +90,15 @@ impl<T> SleepTracker<T> {
|
|||
#[test]
|
||||
fn returns_in_order() {
|
||||
let mut s = SleepTracker::new();
|
||||
s.push(3, 3);
|
||||
s.push(30_000, 30_000);
|
||||
s.push(1, 1);
|
||||
s.push(6, 6);
|
||||
s.push(5, 5);
|
||||
s.push(2, 2);
|
||||
s.push(10000, 10000);
|
||||
assert_eq!(s.len(), 6);
|
||||
std::thread::sleep(Duration::from_millis(100));
|
||||
assert_eq!(s.to_retry(), &[1, 2, 3, 5, 6]);
|
||||
assert_eq!(s.len(), 2);
|
||||
std::thread::sleep(Duration::from_millis(2));
|
||||
assert_eq!(s.to_retry(), &[1]);
|
||||
assert!(s.to_retry().is_empty());
|
||||
let next = s.time_to_next().expect("should be next");
|
||||
assert!(
|
||||
next < Duration::from_millis(30_000),
|
||||
"{next:?} should be less than 30s"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -982,3 +982,43 @@ error: `im_a_teapot` is specified
|
|||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn dont_always_inherit_workspace_lints() {
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[workspace]
|
||||
members = ["foo"]
|
||||
|
||||
[workspace.lints.cargo]
|
||||
im-a-teapot = "warn"
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"foo/Cargo.toml",
|
||||
r#"
|
||||
cargo-features = ["test-dummy-unstable"]
|
||||
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
edition = "2015"
|
||||
authors = []
|
||||
im-a-teapot = true
|
||||
"#,
|
||||
)
|
||||
.file("foo/src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check -Zcargo-lints")
|
||||
.masquerade_as_nightly_cargo(&["cargo-lints"])
|
||||
.with_stderr(
|
||||
"\
|
||||
[CHECKING] foo v0.0.1 ([CWD]/foo)
|
||||
[FINISHED] [..]
|
||||
",
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
|
|
@ -2914,3 +2914,91 @@ Caused by:
|
|||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn patched_reexport_stays_locked() {
|
||||
// Patch example where you emulate a semver-incompatible patch via a re-export.
|
||||
// Testing an issue where the lockfile does not stay locked after a new version is published.
|
||||
Package::new("bar", "1.0.0").publish();
|
||||
Package::new("bar", "2.0.0").publish();
|
||||
Package::new("bar", "3.0.0").publish();
|
||||
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[workspace]
|
||||
|
||||
|
||||
[package]
|
||||
name = "foo"
|
||||
|
||||
[dependencies]
|
||||
bar1 = {package="bar", version="1.0.0"}
|
||||
bar2 = {package="bar", version="2.0.0"}
|
||||
|
||||
[patch.crates-io]
|
||||
bar1 = { package = "bar", path = "bar-1-as-3" }
|
||||
bar2 = { package = "bar", path = "bar-2-as-3" }
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.file(
|
||||
"bar-1-as-3/Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "bar"
|
||||
version = "1.0.999"
|
||||
|
||||
[dependencies]
|
||||
bar = "3.0.0"
|
||||
"#,
|
||||
)
|
||||
.file("bar-1-as-3/src/lib.rs", "")
|
||||
.file(
|
||||
"bar-2-as-3/Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "bar"
|
||||
version = "2.0.999"
|
||||
|
||||
[dependencies]
|
||||
bar = "3.0.0"
|
||||
"#,
|
||||
)
|
||||
.file("bar-2-as-3/src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("tree")
|
||||
.with_stdout(
|
||||
"\
|
||||
foo v0.0.0 ([ROOT]/foo)
|
||||
├── bar v1.0.999 ([ROOT]/foo/bar-1-as-3)
|
||||
│ └── bar v3.0.0
|
||||
└── bar v2.0.999 ([ROOT]/foo/bar-2-as-3)
|
||||
└── bar v3.0.0
|
||||
",
|
||||
)
|
||||
.run();
|
||||
|
||||
std::fs::copy(
|
||||
p.root().join("Cargo.lock"),
|
||||
p.root().join("Cargo.lock.orig"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Package::new("bar", "3.0.1").publish();
|
||||
p.cargo("tree")
|
||||
.with_stdout(
|
||||
"\
|
||||
foo v0.0.0 ([ROOT]/foo)
|
||||
├── bar v1.0.999 ([ROOT]/foo/bar-1-as-3)
|
||||
│ └── bar v3.0.0
|
||||
└── bar v2.0.999 ([ROOT]/foo/bar-2-as-3)
|
||||
└── bar v3.0.0
|
||||
",
|
||||
)
|
||||
.run();
|
||||
|
||||
assert_eq!(p.read_file("Cargo.lock"), p.read_file("Cargo.lock.orig"));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue