Skip to content

Commit cae562f

Browse files
committed
Auto merge of #4594 - behnam:workspace, r=alexcrichton
[core/workspace] Create WorkspaceRootConfig Create `WorkspaceRootConfig`, which knows its `root_dir` and lists of `members` and `excludes`, to answer queries on which paths are a member and which are not. ---- This is the first step of the fix, that's only a codemod to put together the relevant parts : `workspace.members`, `workspace.excludes`, and the `root_dir` (where `members` and `excludes` are relative to). There's no logic change in this PR to keep review easier. The added tests are commented out, because they fail with the current logic. The next step to get these steps to pass. Tracker: <#4089> Old PR: <#4297>
2 parents d6843a7 + fd07cfd commit cae562f

File tree

4 files changed

+231
-102
lines changed

4 files changed

+231
-102
lines changed

src/cargo/core/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub use self::resolver::Resolve;
1010
pub use self::shell::{Shell, Verbosity};
1111
pub use self::source::{Source, SourceId, SourceMap, GitReference};
1212
pub use self::summary::Summary;
13-
pub use self::workspace::{Members, Workspace, WorkspaceConfig};
13+
pub use self::workspace::{Members, Workspace, WorkspaceConfig, WorkspaceRootConfig};
1414

1515
pub mod source;
1616
pub mod package;

src/cargo/core/workspace.rs

Lines changed: 122 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,24 @@ enum MaybePackage {
7575
pub enum WorkspaceConfig {
7676
/// Indicates that `[workspace]` was present and the members were
7777
/// optionally specified as well.
78-
Root {
79-
members: Option<Vec<String>>,
80-
exclude: Vec<String>,
81-
},
78+
Root(WorkspaceRootConfig),
8279

8380
/// Indicates that `[workspace]` was present and the `root` field is the
8481
/// optional value of `package.workspace`, if present.
8582
Member { root: Option<String> },
8683
}
8784

85+
/// Intermediate configuration of a workspace root in a manifest.
86+
///
87+
/// Knows the Workspace Root path, as well as `members` and `exclude` lists of path patterns, which
88+
/// together tell if some path is recognized as a member by this root or not.
89+
#[derive(Debug, Clone)]
90+
pub struct WorkspaceRootConfig {
91+
root_dir: PathBuf,
92+
members: Option<Vec<String>>,
93+
exclude: Vec<String>,
94+
}
95+
8896
/// An iterator over the member packages of a workspace, returned by
8997
/// `Workspace::members`
9098
pub struct Members<'a, 'cfg: 'a> {
@@ -202,7 +210,7 @@ impl<'cfg> Workspace<'cfg> {
202210
let root = self.root_manifest.as_ref().unwrap_or(&self.current_manifest);
203211
match *self.packages.get(root) {
204212
MaybePackage::Package(ref p) => p.manifest().profiles(),
205-
MaybePackage::Virtual(ref m) => m.profiles(),
213+
MaybePackage::Virtual(ref vm) => vm.profiles(),
206214
}
207215
}
208216

@@ -233,7 +241,7 @@ impl<'cfg> Workspace<'cfg> {
233241
};
234242
match *self.packages.get(path) {
235243
MaybePackage::Package(ref p) => p.manifest().replace(),
236-
MaybePackage::Virtual(ref v) => v.replace(),
244+
MaybePackage::Virtual(ref vm) => vm.replace(),
237245
}
238246
}
239247

@@ -247,7 +255,7 @@ impl<'cfg> Workspace<'cfg> {
247255
};
248256
match *self.packages.get(path) {
249257
MaybePackage::Package(ref p) => p.manifest().patch(),
250-
MaybePackage::Virtual(ref v) => v.patch(),
258+
MaybePackage::Virtual(ref vm) => vm.patch(),
251259
}
252260
}
253261

@@ -289,7 +297,7 @@ impl<'cfg> Workspace<'cfg> {
289297
{
290298
let current = self.packages.load(manifest_path)?;
291299
match *current.workspace_config() {
292-
WorkspaceConfig::Root { .. } => {
300+
WorkspaceConfig::Root(_) => {
293301
debug!("find_root - is root {}", manifest_path.display());
294302
return Ok(Some(manifest_path.to_path_buf()))
295303
}
@@ -301,20 +309,20 @@ impl<'cfg> Workspace<'cfg> {
301309
}
302310

303311
for path in paths::ancestors(manifest_path).skip(2) {
304-
let manifest = path.join("Cargo.toml");
305-
debug!("find_root - trying {}", manifest.display());
306-
if manifest.exists() {
307-
match *self.packages.load(&manifest)?.workspace_config() {
308-
WorkspaceConfig::Root { ref exclude, ref members } => {
312+
let ances_manifest_path = path.join("Cargo.toml");
313+
debug!("find_root - trying {}", ances_manifest_path.display());
314+
if ances_manifest_path.exists() {
315+
match *self.packages.load(&ances_manifest_path)?.workspace_config() {
316+
WorkspaceConfig::Root(ref ances_root_config) => {
309317
debug!("find_root - found a root checking exclusion");
310-
if !is_excluded(members, exclude, path, manifest_path) {
318+
if !ances_root_config.is_excluded(&manifest_path) {
311319
debug!("find_root - found!");
312-
return Ok(Some(manifest))
320+
return Ok(Some(ances_manifest_path))
313321
}
314322
}
315323
WorkspaceConfig::Member { root: Some(ref path_to_root) } => {
316324
debug!("find_root - found pointer");
317-
return Ok(Some(read_root_pointer(&manifest, path_to_root)?))
325+
return Ok(Some(read_root_pointer(&ances_manifest_path, path_to_root)?))
318326
}
319327
WorkspaceConfig::Member { .. } => {}
320328
}
@@ -332,47 +340,29 @@ impl<'cfg> Workspace<'cfg> {
332340
/// will transitively follow all `path` dependencies looking for members of
333341
/// the workspace.
334342
fn find_members(&mut self) -> CargoResult<()> {
335-
let root_manifest = match self.root_manifest {
343+
let root_manifest_path = match self.root_manifest {
336344
Some(ref path) => path.clone(),
337345
None => {
338346
debug!("find_members - only me as a member");
339347
self.members.push(self.current_manifest.clone());
340348
return Ok(())
341349
}
342350
};
343-
let members = {
344-
let root = self.packages.load(&root_manifest)?;
345-
match *root.workspace_config() {
346-
WorkspaceConfig::Root { ref members, .. } => members.clone(),
351+
352+
let members_paths = {
353+
let root_package = self.packages.load(&root_manifest_path)?;
354+
match *root_package.workspace_config() {
355+
WorkspaceConfig::Root(ref root_config) => root_config.members_paths()?,
347356
_ => bail!("root of a workspace inferred but wasn't a root: {}",
348-
root_manifest.display()),
357+
root_manifest_path.display()),
349358
}
350359
};
351360

352-
if let Some(list) = members {
353-
let root = root_manifest.parent().unwrap();
354-
355-
let mut expanded_list = Vec::new();
356-
for path in list {
357-
let pathbuf = root.join(path);
358-
let expanded_paths = expand_member_path(&pathbuf)?;
359-
360-
// If glob does not find any valid paths, then put the original
361-
// path in the expanded list to maintain backwards compatibility.
362-
if expanded_paths.is_empty() {
363-
expanded_list.push(pathbuf);
364-
} else {
365-
expanded_list.extend(expanded_paths);
366-
}
367-
}
368-
369-
for path in expanded_list {
370-
let manifest_path = path.join("Cargo.toml");
371-
self.find_path_deps(&manifest_path, &root_manifest, false)?;
372-
}
361+
for path in members_paths {
362+
self.find_path_deps(&path.join("Cargo.toml"), &root_manifest_path, false)?;
373363
}
374364

375-
self.find_path_deps(&root_manifest, &root_manifest, false)
365+
self.find_path_deps(&root_manifest_path, &root_manifest_path, false)
376366
}
377367

378368
fn find_path_deps(&mut self,
@@ -391,10 +381,9 @@ impl<'cfg> Workspace<'cfg> {
391381
return Ok(())
392382
}
393383

394-
let root = root_manifest.parent().unwrap();
395384
match *self.packages.load(root_manifest)?.workspace_config() {
396-
WorkspaceConfig::Root { ref members, ref exclude } => {
397-
if is_excluded(members, exclude, root, &manifest_path) {
385+
WorkspaceConfig::Root(ref root_config) => {
386+
if root_config.is_excluded(&manifest_path) {
398387
return Ok(())
399388
}
400389
}
@@ -439,7 +428,7 @@ impl<'cfg> Workspace<'cfg> {
439428
for member in self.members.iter() {
440429
let package = self.packages.get(member);
441430
match *package.workspace_config() {
442-
WorkspaceConfig::Root { .. } => {
431+
WorkspaceConfig::Root(_) => {
443432
roots.push(member.parent().unwrap().to_path_buf());
444433
}
445434
WorkspaceConfig::Member { .. } => {}
@@ -505,6 +494,8 @@ impl<'cfg> Workspace<'cfg> {
505494
let current_dir = self.current_manifest.parent().unwrap();
506495
let root_pkg = self.packages.get(root);
507496

497+
// FIXME: Make this more generic by using a relative path resolver between member and
498+
// root.
508499
let members_msg = match current_dir.strip_prefix(root_dir) {
509500
Ok(rel) => {
510501
format!("this may be fixable by adding `{}` to the \
@@ -522,11 +513,11 @@ impl<'cfg> Workspace<'cfg> {
522513
let extra = match *root_pkg {
523514
MaybePackage::Virtual(_) => members_msg,
524515
MaybePackage::Package(ref p) => {
525-
let members = match *p.manifest().workspace_config() {
526-
WorkspaceConfig::Root { ref members, .. } => members,
516+
let has_members_list = match *p.manifest().workspace_config() {
517+
WorkspaceConfig::Root(ref root_config) => root_config.has_members_list(),
527518
WorkspaceConfig::Member { .. } => unreachable!(),
528519
};
529-
if members.is_none() {
520+
if !has_members_list {
530521
format!("this may be fixable by ensuring that this \
531522
crate is depended on by the workspace \
532523
root: {}", root.display())
@@ -576,41 +567,6 @@ impl<'cfg> Workspace<'cfg> {
576567
}
577568
}
578569

579-
fn expand_member_path(path: &Path) -> CargoResult<Vec<PathBuf>> {
580-
let path = match path.to_str() {
581-
Some(p) => p,
582-
None => return Ok(Vec::new()),
583-
};
584-
let res = glob(path).chain_err(|| {
585-
format!("could not parse pattern `{}`", &path)
586-
})?;
587-
res.map(|p| {
588-
p.chain_err(|| {
589-
format!("unable to match path to pattern `{}`", &path)
590-
})
591-
}).collect()
592-
}
593-
594-
fn is_excluded(members: &Option<Vec<String>>,
595-
exclude: &[String],
596-
root_path: &Path,
597-
manifest_path: &Path) -> bool {
598-
let excluded = exclude.iter().any(|ex| {
599-
manifest_path.starts_with(root_path.join(ex))
600-
});
601-
602-
let explicit_member = match *members {
603-
Some(ref members) => {
604-
members.iter().any(|mem| {
605-
manifest_path.starts_with(root_path.join(mem))
606-
})
607-
}
608-
None => false,
609-
};
610-
611-
!explicit_member && excluded
612-
}
613-
614570

615571
impl<'cfg> Packages<'cfg> {
616572
fn get(&self, manifest_path: &Path) -> &MaybePackage {
@@ -627,11 +583,10 @@ impl<'cfg> Packages<'cfg> {
627583
read_manifest(manifest_path, &source_id, self.config)?;
628584
Ok(v.insert(match manifest {
629585
EitherManifest::Real(manifest) => {
630-
MaybePackage::Package(Package::new(manifest,
631-
manifest_path))
586+
MaybePackage::Package(Package::new(manifest, manifest_path))
632587
}
633-
EitherManifest::Virtual(v) => {
634-
MaybePackage::Virtual(v)
588+
EitherManifest::Virtual(vm) => {
589+
MaybePackage::Virtual(vm)
635590
}
636591
}))
637592
}
@@ -665,8 +620,83 @@ impl<'a, 'cfg> Iterator for Members<'a, 'cfg> {
665620
impl MaybePackage {
666621
fn workspace_config(&self) -> &WorkspaceConfig {
667622
match *self {
668-
MaybePackage::Virtual(ref v) => v.workspace_config(),
669-
MaybePackage::Package(ref v) => v.manifest().workspace_config(),
623+
MaybePackage::Package(ref p) => p.manifest().workspace_config(),
624+
MaybePackage::Virtual(ref vm) => vm.workspace_config(),
670625
}
671626
}
672627
}
628+
629+
impl WorkspaceRootConfig {
630+
/// Create a new Intermediate Workspace Root configuration.
631+
pub fn new(
632+
root_dir: &Path,
633+
members: &Option<Vec<String>>,
634+
exclude: &Option<Vec<String>>,
635+
) -> WorkspaceRootConfig {
636+
WorkspaceRootConfig {
637+
root_dir: root_dir.to_path_buf(),
638+
members: members.clone(),
639+
exclude: exclude.clone().unwrap_or_default(),
640+
}
641+
}
642+
643+
/// Checks the path against the `excluded` list.
644+
///
645+
/// This method does NOT consider the `members` list.
646+
fn is_excluded(&self, manifest_path: &Path) -> bool {
647+
let excluded = self.exclude.iter().any(|ex| {
648+
manifest_path.starts_with(self.root_dir.join(ex))
649+
});
650+
651+
let explicit_member = match self.members {
652+
Some(ref members) => {
653+
members.iter().any(|mem| {
654+
manifest_path.starts_with(self.root_dir.join(mem))
655+
})
656+
}
657+
None => false,
658+
};
659+
660+
!explicit_member && excluded
661+
}
662+
663+
fn has_members_list(&self) -> bool {
664+
self.members.is_some()
665+
}
666+
667+
fn members_paths(&self) -> CargoResult<Vec<PathBuf>> {
668+
let mut expanded_list = Vec::new();
669+
670+
if let Some(globs) = self.members.clone() {
671+
for glob in globs {
672+
let pathbuf = self.root_dir.join(glob);
673+
let expanded_paths = Self::expand_member_path(&pathbuf)?;
674+
675+
// If glob does not find any valid paths, then put the original
676+
// path in the expanded list to maintain backwards compatibility.
677+
if expanded_paths.is_empty() {
678+
expanded_list.push(pathbuf);
679+
} else {
680+
expanded_list.extend(expanded_paths);
681+
}
682+
}
683+
}
684+
685+
Ok(expanded_list)
686+
}
687+
688+
fn expand_member_path(path: &Path) -> CargoResult<Vec<PathBuf>> {
689+
let path = match path.to_str() {
690+
Some(p) => p,
691+
None => return Ok(Vec::new()),
692+
};
693+
let res = glob(path).chain_err(|| {
694+
format!("could not parse pattern `{}`", &path)
695+
})?;
696+
res.map(|p| {
697+
p.chain_err(|| {
698+
format!("unable to match path to pattern `{}`", &path)
699+
})
700+
}).collect()
701+
}
702+
}

src/cargo/util/toml/mod.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use serde_ignored;
1212
use toml;
1313
use url::Url;
1414

15-
use core::{SourceId, Profiles, PackageIdSpec, GitReference, WorkspaceConfig};
15+
use core::{SourceId, Profiles, PackageIdSpec, GitReference, WorkspaceConfig, WorkspaceRootConfig};
1616
use core::{Summary, Manifest, Target, Dependency, PackageId};
1717
use core::{EitherManifest, VirtualManifest, Features};
1818
use core::dependency::{Kind, Platform};
@@ -634,10 +634,9 @@ impl TomlManifest {
634634
let workspace_config = match (me.workspace.as_ref(),
635635
project.workspace.as_ref()) {
636636
(Some(config), None) => {
637-
WorkspaceConfig::Root {
638-
members: config.members.clone(),
639-
exclude: config.exclude.clone().unwrap_or_default(),
640-
}
637+
WorkspaceConfig::Root(
638+
WorkspaceRootConfig::new(&package_root, &config.members, &config.exclude)
639+
)
641640
}
642641
(None, root) => {
643642
WorkspaceConfig::Member { root: root.cloned() }
@@ -728,10 +727,9 @@ impl TomlManifest {
728727
let profiles = build_profiles(&me.profile);
729728
let workspace_config = match me.workspace {
730729
Some(ref config) => {
731-
WorkspaceConfig::Root {
732-
members: config.members.clone(),
733-
exclude: config.exclude.clone().unwrap_or_default(),
734-
}
730+
WorkspaceConfig::Root(
731+
WorkspaceRootConfig::new(&root, &config.members, &config.exclude)
732+
)
735733
}
736734
None => {
737735
bail!("virtual manifests must be configured with [workspace]");

0 commit comments

Comments
 (0)