Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Part 2 of RFC2906 -- allow inheriting from a different Cargo.toml #10517

Merged
merged 4 commits into from
Apr 5, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/cargo/core/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ pub enum EitherManifest {
Virtual(VirtualManifest),
}

impl EitherManifest {
pub(crate) fn workspace_config(&self) -> &WorkspaceConfig {
match *self {
EitherManifest::Real(ref r) => r.workspace_config(),
EitherManifest::Virtual(ref v) => v.workspace_config(),
}
}
}

/// Contains all the information about a package, as loaded from a `Cargo.toml`.
///
/// This is deserialized using the [`TomlManifest`] type.
Expand Down
3 changes: 2 additions & 1 deletion src/cargo/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ pub use self::shell::{Shell, Verbosity};
pub use self::source::{GitReference, Source, SourceId, SourceMap};
pub use self::summary::{FeatureMap, FeatureValue, Summary};
pub use self::workspace::{
InheritableFields, MaybePackage, Workspace, WorkspaceConfig, WorkspaceRootConfig,
find_workspace_root, InheritableFields, MaybePackage, Workspace, WorkspaceConfig,
WorkspaceRootConfig,
};

pub mod compiler;
Expand Down
177 changes: 132 additions & 45 deletions src/cargo/core/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -591,16 +591,6 @@ impl<'cfg> Workspace<'cfg> {
/// Returns an error if `manifest_path` isn't actually a valid manifest or
/// if some other transient error happens.
fn find_root(&mut self, manifest_path: &Path) -> CargoResult<Option<PathBuf>> {
fn read_root_pointer(member_manifest: &Path, root_link: &str) -> PathBuf {
let path = member_manifest
.parent()
.unwrap()
.join(root_link)
.join("Cargo.toml");
debug!("find_root - pointer {}", path.display());
paths::normalize_path(&path)
}

{
let current = self.packages.load(manifest_path)?;
match *current.workspace_config() {
Expand All @@ -615,43 +605,33 @@ impl<'cfg> Workspace<'cfg> {
}
}

for path in paths::ancestors(manifest_path, None).skip(2) {
if path.ends_with("target/package") {
break;
}

let ances_manifest_path = path.join("Cargo.toml");
debug!("find_root - trying {}", ances_manifest_path.display());
if ances_manifest_path.exists() {
match *self.packages.load(&ances_manifest_path)?.workspace_config() {
WorkspaceConfig::Root(ref ances_root_config) => {
debug!("find_root - found a root checking exclusion");
if !ances_root_config.is_excluded(manifest_path) {
debug!("find_root - found!");
return Ok(Some(ances_manifest_path));
find_root_iter(manifest_path, self.config)
.find_map(|ances_manifest_path| {
Muscraft marked this conversation as resolved.
Show resolved Hide resolved
debug!("find_root - trying {}", ances_manifest_path.display());
let manifest = self.packages.load(&ances_manifest_path);
match manifest {
Ok(manifest) => match *manifest.workspace_config() {
WorkspaceConfig::Root(ref ances_root_config) => {
debug!("find_root - found a root checking exclusion");
if !ances_root_config.is_excluded(manifest_path) {
debug!("find_root - found!");
Some(Ok(ances_manifest_path))
} else {
None
}
}
}
WorkspaceConfig::Member {
root: Some(ref path_to_root),
} => {
debug!("find_root - found pointer");
return Ok(Some(read_root_pointer(&ances_manifest_path, path_to_root)));
}
WorkspaceConfig::Member { .. } => {}
WorkspaceConfig::Member {
root: Some(ref path_to_root),
} => {
debug!("find_root - found pointer");
Some(Ok(read_root_pointer(&ances_manifest_path, path_to_root)))
}
WorkspaceConfig::Member { .. } => None,
},
Err(e) => Some(Err(e)),
}
}

// Don't walk across `CARGO_HOME` when we're looking for the
// workspace root. Sometimes a package will be organized with
// `CARGO_HOME` pointing inside of the workspace root or in the
// current package, but we don't want to mistakenly try to put
// crates.io crates into the workspace by accident.
if self.config.home() == path {
break;
}
}

Ok(None)
})
.transpose()
}

/// After the root of a workspace has been located, probes for all members
Expand Down Expand Up @@ -1653,6 +1633,10 @@ impl WorkspaceRootConfig {
.collect::<Result<Vec<_>, _>>()?;
Ok(res)
}

pub fn inheritable(&self) -> &InheritableFields {
&self.inheritable_fields
}
}

/// A group of fields that are inheritable by members of the workspace
Expand Down Expand Up @@ -1841,3 +1825,106 @@ impl InheritableFields {
})
}
}

fn parse_manifest(manifest_path: &Path, config: &Config) -> CargoResult<EitherManifest> {
let key = manifest_path.parent().unwrap();
let source_id = SourceId::for_path(key)?;
let (manifest, _nested_paths) = read_manifest(manifest_path, source_id, config)?;
Ok(manifest)
}

pub fn find_workspace_root(manifest_path: &Path, config: &Config) -> CargoResult<Option<PathBuf>> {
epage marked this conversation as resolved.
Show resolved Hide resolved
find_root_iter(manifest_path, config)
.find_map(|ances_manifest_path| {
Muscraft marked this conversation as resolved.
Show resolved Hide resolved
let manifest = parse_manifest(&ances_manifest_path, config);
match manifest {
Ok(manifest) => match *manifest.workspace_config() {
WorkspaceConfig::Root(ref ances_root_config) => {
debug!("find_root - found a root checking exclusion");
if !ances_root_config.is_excluded(manifest_path) {
debug!("find_root - found!");
Some(Ok(ances_manifest_path))
} else {
None
}
}
WorkspaceConfig::Member {
root: Some(ref path_to_root),
} => {
debug!("find_root - found pointer");
Some(Ok(read_root_pointer(&ances_manifest_path, path_to_root)))
}
WorkspaceConfig::Member { .. } => None,
},
Err(e) => Some(Err(e)),
}
})
.transpose()
}

fn read_root_pointer(member_manifest: &Path, root_link: &str) -> PathBuf {
let path = member_manifest
.parent()
.unwrap()
.join(root_link)
.join("Cargo.toml");
debug!("find_root - pointer {}", path.display());
paths::normalize_path(&path)
}

fn find_root_iter<'a>(
manifest_path: &'a Path,
config: &'a Config,
) -> impl Iterator<Item = PathBuf> + 'a {
LookBehind::new(paths::ancestors(manifest_path, None).skip(2))
.into_iter()
Muscraft marked this conversation as resolved.
Show resolved Hide resolved
.take_while(|path| !path.curr.ends_with("target/package"))
// Don't walk across `CARGO_HOME` when we're looking for the
// workspace root. Sometimes a package will be organized with
// `CARGO_HOME` pointing inside of the workspace root or in the
// current package, but we don't want to mistakenly try to put
// crates.io crates into the workspace by accident.
.take_while(|path| {
if let Some(last) = path.last {
config.home() != last
} else {
true
}
})
.map(|path| path.curr.join("Cargo.toml"))
.filter(|ances_manifest_path| ances_manifest_path.exists())
}

struct LookBehindWindow<'a, T: ?Sized> {
curr: &'a T,
last: Option<&'a T>,
}

struct LookBehind<'a, T: ?Sized, K: Iterator<Item = &'a T>> {
iter: K,
last: Option<&'a T>,
}

impl<'a, T: ?Sized, K: Iterator<Item = &'a T>> LookBehind<'a, T, K> {
fn new(items: K) -> Self {
Self {
iter: items,
last: None,
}
}
}

impl<'a, T: ?Sized, K: Iterator<Item = &'a T>> Iterator for LookBehind<'a, T, K> {
type Item = LookBehindWindow<'a, T>;

fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
None => None,
Some(next) => {
let last = self.last;
self.last = Some(next);
Some(LookBehindWindow { curr: next, last })
}
}
}
}
Loading