Skip to content

Commit 4f5aa4d

Browse files
adamgemmellc272
andcommitted
Verify build-std resolve against original lockfile
Co-authored-by: Lawrence Tang <[email protected]>
1 parent 2f17770 commit 4f5aa4d

File tree

5 files changed

+83
-4
lines changed

5 files changed

+83
-4
lines changed

src/cargo/core/compiler/standard_lib.rs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::core::compiler::UnitInterner;
55
use crate::core::compiler::{CompileKind, CompileMode, RustcTargetData, Unit};
66
use crate::core::profiles::{Profiles, UnitFor};
77
use crate::core::resolver::features::{CliFeatures, FeaturesFor, ResolvedFeatures};
8-
use crate::core::resolver::HasDevUnits;
8+
use crate::core::resolver::{EncodableResolve, HasDevUnits};
99
use crate::core::{Dependency, PackageId, PackageSet, Resolve, SourceId, Workspace};
1010
use crate::ops::{self, Packages};
1111
use crate::util::errors::CargoResult;
@@ -125,9 +125,12 @@ pub fn resolve_std<'gctx>(
125125
// now. Perhaps in the future features will be decoupled from the resolver
126126
// and it will be easier to control feature selection.
127127
let current_manifest = src_path.join("library/sysroot/Cargo.toml");
128-
// TODO: Consider doing something to enforce --locked? Or to prevent the
129-
// lock file from being written, such as setting ephemeral.
130-
let mut std_ws = Workspace::new_virtual(src_path, current_manifest, virtual_manifest, gctx)?;
128+
let mut std_ws =
129+
Workspace::new_virtual(src_path.clone(), current_manifest, virtual_manifest, gctx)?;
130+
131+
// The source checkout isn't managed by us, so setting ephemeral here
132+
// ensures the lockfile isn't updated.
133+
std_ws.set_ephemeral(true);
131134
// Don't require optional dependencies in this workspace, aka std's own
132135
// `[dev-dependencies]`. No need for us to generate a `Resolve` which has
133136
// those included because we'll never use them anyway.
@@ -158,6 +161,47 @@ pub fn resolve_std<'gctx>(
158161
HasDevUnits::No,
159162
crate::core::resolver::features::ForceAllTargets::No,
160163
)?;
164+
165+
// Verify that we have resolved to a subset of the lockfile
166+
let lockfile = std::fs::read_to_string(&src_path.join("Cargo.lock"))
167+
.expect("Couldn't read the Rust source's lockfile");
168+
169+
let encoded_lockfile: EncodableResolve = toml::from_str(&lockfile).unwrap();
170+
let lockfile_packages = encoded_lockfile.package().expect("libstd has no packages!");
171+
172+
for resolved_pkg in resolve.targeted_resolve.iter() {
173+
let pkg_name = resolved_pkg.name().to_string();
174+
let pkg_ver = resolved_pkg.version().to_string();
175+
let lockfile_pkg = lockfile_packages.binary_search_by_key(
176+
&(pkg_name.as_str(), pkg_ver.as_str()),
177+
|p| (p.name(), p.version())
178+
)
179+
.and_then(|idx| Ok(&lockfile_packages[idx]))
180+
.unwrap_or_else(|_|
181+
panic!("Standard library's package graph changed during resolution:
182+
Package '{}' ({}) was present in the resolve but not in the original lockfile",
183+
resolved_pkg.name(), resolved_pkg.version())
184+
);
185+
// If the lockfile wasn't sorted then the binary search result can be nonsensical
186+
assert!(lockfile_pkg.name() == pkg_name);
187+
188+
for (dep, _) in resolve.targeted_resolve.deps(resolved_pkg) {
189+
lockfile_pkg.dependencies()
190+
.and_then(|deps| {
191+
deps.iter().find(|pkg| {
192+
pkg.name() == dep.name().as_str()
193+
&& (pkg.version() == None
194+
|| pkg.version() == Some(dep.version().to_string().as_str()))
195+
})
196+
})
197+
.unwrap_or_else(||
198+
panic!("Standard library's package graph changed during resolution:
199+
Package '{}' ({}) was present as a dependency of '{} ({}) in the resolve but not in the lockfile",
200+
dep.name(), dep.version(), resolved_pkg.name(), resolved_pkg.version())
201+
);
202+
}
203+
}
204+
161205
Ok((
162206
resolve.pkg_set,
163207
resolve.targeted_resolve,

src/cargo/core/resolver/encode.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,10 @@ impl EncodableResolve {
406406
HashMap::new(),
407407
))
408408
}
409+
410+
pub fn package(&self) -> Option<&Vec<EncodableDependency>> {
411+
self.package.as_ref()
412+
}
409413
}
410414

411415
fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>> {
@@ -489,6 +493,20 @@ pub struct EncodableDependency {
489493
replace: Option<EncodablePackageId>,
490494
}
491495

496+
impl EncodableDependency {
497+
pub fn name(&self) -> &str {
498+
&self.name
499+
}
500+
501+
pub fn version(&self) -> &str {
502+
&self.version
503+
}
504+
505+
pub fn dependencies(&self) -> Option<&Vec<EncodablePackageId>> {
506+
self.dependencies.as_ref()
507+
}
508+
}
509+
492510
/// Pretty much equivalent to [`SourceId`] with a different serialization method.
493511
///
494512
/// The serialization for `SourceId` doesn't do URL encode for parameters.
@@ -574,6 +592,16 @@ pub struct EncodablePackageId {
574592
source: Option<EncodableSourceId>,
575593
}
576594

595+
impl EncodablePackageId {
596+
pub fn name(&self) -> &str {
597+
&self.name
598+
}
599+
600+
pub fn version(&self) -> Option<&str> {
601+
self.version.as_ref().map(String::as_str)
602+
}
603+
}
604+
577605
impl fmt::Display for EncodablePackageId {
578606
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
579607
write!(f, "{}", self.name)?;

src/cargo/core/workspace.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,11 @@ impl<'gctx> Workspace<'gctx> {
622622
self.is_ephemeral
623623
}
624624

625+
pub fn set_ephemeral(&mut self, is_ephemeral: bool) -> &mut Workspace<'gctx> {
626+
self.is_ephemeral = is_ephemeral;
627+
self
628+
}
629+
625630
pub fn require_optional_deps(&self) -> bool {
626631
self.require_optional_deps
627632
}

tests/testsuite/mock-std/library/alloc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ authors = ["Alex Crichton <[email protected]>"]
55
edition = "2018"
66

77
[dependencies]
8+
core = { path = "../core" }
89
registry-dep-using-core = { version = "*", features = ['mockbuild'] }

tests/testsuite/mock-std/library/std/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ authors = ["Alex Crichton <[email protected]>"]
55
edition = "2018"
66

77
[dependencies]
8+
alloc = { path = "../alloc" }
89
registry-dep-using-alloc = { version = "*", features = ['mockbuild'] }
910

1011
[features]

0 commit comments

Comments
 (0)