diff --git a/Cargo.lock b/Cargo.lock index 63d7c67034d..b6d04b8a045 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -581,7 +581,7 @@ dependencies = [ [[package]] name = "cargo-util-schemas" -version = "0.14.4" +version = "0.15.0" dependencies = [ "jiff", "schemars", diff --git a/Cargo.toml b/Cargo.toml index 118765b0170..de068415902 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ cargo-platform = { path = "crates/cargo-platform", version = "0.3.3" } cargo-test-macro = { version = "0.4.15", path = "crates/cargo-test-macro" } cargo-test-support = { version = "0.12.0", path = "crates/cargo-test-support" } cargo-util = { version = "0.2.33", path = "crates/cargo-util" } -cargo-util-schemas = { version = "0.14.4", path = "crates/cargo-util-schemas" } +cargo-util-schemas = { version = "0.15.0", path = "crates/cargo-util-schemas" } cargo-util-terminal = { version = "0.1.3", path = "crates/cargo-util-terminal" } cargo_metadata = "0.23.1" clap = "4.6.0" diff --git a/crates/cargo-util-schemas/Cargo.toml b/crates/cargo-util-schemas/Cargo.toml index 489c2b52ce3..e17feac3275 100644 --- a/crates/cargo-util-schemas/Cargo.toml +++ b/crates/cargo-util-schemas/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-util-schemas" -version = "0.14.4" +version = "0.15.0" rust-version = "1.98" # MSRV:1 edition.workspace = true license.workspace = true diff --git a/crates/cargo-util-schemas/src/core/source_kind.rs b/crates/cargo-util-schemas/src/core/source_kind.rs index 3794791114d..1c16a251371 100644 --- a/crates/cargo-util-schemas/src/core/source_kind.rs +++ b/crates/cargo-util-schemas/src/core/source_kind.rs @@ -15,6 +15,8 @@ pub enum SourceKind { LocalRegistry, /// A directory-based registry. Directory, + /// Package sources distributed with the rust toolchain + Builtin, } // The hash here is important for what folder packages get downloaded into. @@ -40,6 +42,7 @@ impl SourceKind { SourceKind::SparseRegistry => None, SourceKind::LocalRegistry => Some("local-registry"), SourceKind::Directory => Some("directory"), + SourceKind::Builtin => Some("builtin"), } } } @@ -71,6 +74,10 @@ impl Ord for SourceKind { (_, SourceKind::Directory) => Ordering::Greater, (SourceKind::Git(a), SourceKind::Git(b)) => a.cmp(b), + (SourceKind::Git(_), _) => Ordering::Less, + (_, SourceKind::Git(_)) => Ordering::Greater, + + (SourceKind::Builtin, SourceKind::Builtin) => Ordering::Equal, } } } diff --git a/crates/resolver-tests/src/helpers.rs b/crates/resolver-tests/src/helpers.rs index dec0250eb02..604d09a1018 100644 --- a/crates/resolver-tests/src/helpers.rs +++ b/crates/resolver-tests/src/helpers.rs @@ -87,6 +87,17 @@ impl, U: AsRef> ToPkgId for (T, U) { } } +#[derive(Copy, Clone)] +pub struct BuiltinPid { + pub name: &'static str, +} + +impl ToPkgId for BuiltinPid { + fn to_pkgid(&self) -> PackageId { + PackageId::try_new(self.name, "0.0.0", builtin_loc()).unwrap() + } +} + #[macro_export] macro_rules! pkg { ($pkgid:expr => [$($deps:expr),* $(,)? ]) => ({ @@ -108,6 +119,13 @@ fn registry_loc() -> SourceId { *example_dot } +fn builtin_loc() -> SourceId { + static LOCAL_PATH: OnceLock = OnceLock::new(); + let local_path = LOCAL_PATH + .get_or_init(|| SourceId::for_builtin(&std::env::current_dir().unwrap()).unwrap()); + *local_path +} + pub fn pkg(name: T) -> Summary { pkg_dep(name, Vec::new()) } @@ -215,6 +233,10 @@ pub fn dep_loc(name: &str, location: &str) -> Dependency { Dependency::parse(name, Some("1.0.0"), source_id).unwrap() } +pub fn dep_builtin(name: &str) -> Dependency { + Dependency::parse(name, None, builtin_loc()).unwrap() +} + pub fn dep_kind(name: &str, kind: DepKind) -> Dependency { let mut dep = dep(name); dep.set_kind(kind); @@ -235,6 +257,12 @@ pub fn names(names: &[P]) -> Vec { names.iter().map(|name| name.to_pkgid()).collect() } +/// For a set of name specifiers of varying types +#[macro_export] +macro_rules! names { + ($($name:expr),* $(,)?) => {&vec![$($name.to_pkgid()),*]}; +} + pub fn loc_names(names: &[(&'static str, &'static str)]) -> Vec { names .iter() diff --git a/crates/resolver-tests/tests/resolve.rs b/crates/resolver-tests/tests/resolve.rs index 20d32fbf884..7c890596d11 100644 --- a/crates/resolver-tests/tests/resolve.rs +++ b/crates/resolver-tests/tests/resolve.rs @@ -1,15 +1,16 @@ use cargo::util::GlobalContext; use cargo::workspace::Dependency; use cargo::workspace::dependency::DepKind; +use resolver_tests::helpers::dep_builtin; use snapbox::assert_data_eq; use snapbox::str; use resolver_tests::{ helpers::{ - ToDep, ToPkgId, assert_contains, assert_same, dep, dep_kind, dep_loc, dep_req, loc_names, - names, pkg, pkg_dep, pkg_dep_with, pkg_id, pkg_loc, registry, + BuiltinPid, ToDep, ToPkgId, assert_contains, assert_same, dep, dep_kind, dep_loc, dep_req, + loc_names, names, pkg, pkg_dep, pkg_dep_with, pkg_id, pkg_loc, registry, }, - pkg, resolve, resolve_with_global_context, + names, pkg, resolve, resolve_with_global_context, }; #[test] @@ -1036,3 +1037,28 @@ failed to select a version for `F` which could resolve this conflict "#]] ); } + +#[test] +fn test_builtin_dependency() { + let core = BuiltinPid { name: "core" }; + let reg = registry(vec![pkg!(core)]); + + let builtin_dep = dep_builtin("core"); + + let res = resolve(vec![builtin_dep], ®).unwrap(); + + assert_same(&res, &names!("root", core)); +} + +#[test] +fn normal_dependency_is_not_satisfied_by_builtin_package() { + let core = BuiltinPid { name: "core" }; + let reg = registry(vec![pkg!(core)]); + + assert!(resolve(vec![dep("core")], ®).is_err()); +} + +#[test] +fn missing_builtin_dependency_errors() { + assert!(resolve(vec![dep_builtin("core")], ®istry(vec![])).is_err()); +} diff --git a/src/resolver/encode.rs b/src/resolver/encode.rs index 3bc4d0921af..6ef1752f265 100644 --- a/src/resolver/encode.rs +++ b/src/resolver/encode.rs @@ -661,7 +661,7 @@ pub fn encodable_package_id( } fn encodable_source_id(id: SourceId, version: ResolveVersion) -> Option { - if id.is_path() { + if id.is_path() || id.is_builtin() { None } else { Some( diff --git a/src/workspace/source_id.rs b/src/workspace/source_id.rs index dbfbc367dae..6c8d043e969 100644 --- a/src/workspace/source_id.rs +++ b/src/workspace/source_id.rs @@ -204,6 +204,14 @@ impl SourceId { SourceId::new(SourceKind::Path, url, None) } + /// Creates a `SourceId` from a filesystem path representing a builtin package. + /// + /// `path`: an absolute path. + pub fn for_builtin(path: &Path) -> CargoResult { + let url = path.into_url()?; + SourceId::new(SourceKind::Builtin, url, None) + } + /// Creates a `SourceId` from a filesystem path. /// /// `path`: an absolute path. @@ -345,6 +353,11 @@ impl SourceId { self.inner.kind == SourceKind::Path } + /// Returns `true` if this source is built into Cargo + pub fn is_builtin(self) -> bool { + self.inner.kind == SourceKind::Builtin + } + /// Returns the local path if this is a path dependency. pub fn local_path(self) -> Option { if self.inner.kind != SourceKind::Path { @@ -403,6 +416,7 @@ impl SourceId { } Ok(Box::new(PathSource::new(&path, self, gctx))) } + SourceKind::Builtin => todo!("builtin source"), SourceKind::Registry | SourceKind::SparseRegistry => { Ok(Box::new(RegistrySource::remote(self, gctx)?)) } @@ -663,6 +677,7 @@ impl fmt::Display for SourceId { Ok(()) } SourceKind::Path => write!(f, "{}", url_display(&self.inner.url)), + SourceKind::Builtin => write!(f, "builtin {}", url_display(&self.inner.url)), SourceKind::Registry | SourceKind::SparseRegistry => { write!(f, "registry `{}`", self.display_registry_name()) }