From cd36aed8f6b540d58ff4eb805cb2a20985f0122e Mon Sep 17 00:00:00 2001 From: Frederick Zhang Date: Tue, 26 Sep 2017 19:16:26 +1000 Subject: [PATCH] feat: loop through workspace members --- src/cargo_ops/elaborate_workspace.rs | 116 +++++++++++++++++++-------- src/cargo_ops/temp_project.rs | 45 +++++------ src/main.rs | 31 +++++-- 3 files changed, 125 insertions(+), 67 deletions(-) diff --git a/src/cargo_ops/elaborate_workspace.rs b/src/cargo_ops/elaborate_workspace.rs index 4bdcc5b..ea59d92 100644 --- a/src/cargo_ops/elaborate_workspace.rs +++ b/src/cargo_ops/elaborate_workspace.rs @@ -12,8 +12,6 @@ use super::pkg_status::*; /// An elaborate workspace containing resolved dependencies and /// the update status of packages pub struct ElaborateWorkspace<'ela> { - /// Package which is treated as the root of the dependency tree - pub root: PackageId, pub workspace: &'ela Workspace<'ela>, pub pkgs: HashMap, pub pkg_deps: HashMap>, @@ -23,6 +21,8 @@ pub struct ElaborateWorkspace<'ela> { /// which influences the status of current, a tuple of /// `(grand, parent, current)` should be used as the unique id pub pkg_status: HashMap<(Option, Option, PackageId), PkgStatus>, + /// Whether running against a virtual manifest + pub virtual_manifest: bool, } impl<'ela> ElaborateWorkspace<'ela> { @@ -58,14 +58,24 @@ impl<'ela> ElaborateWorkspace<'ela> { pkg_deps.insert(pkg_id.clone(), dep_map); } - let root = { - let determine_root = || if let Some(ref root_name) = options.flag_root { - let workspace_root = workspace.current()?; + Ok(ElaborateWorkspace { + workspace: workspace, + pkgs: pkgs, + pkg_deps: pkg_deps, + pkg_status: HashMap::new(), + virtual_manifest: workspace.current().is_err(), + }) + } + + /// Determine root package based on current workspace and CLI options + pub fn determine_root(&self, options: &Options) -> CargoResult { + if let Some(ref root_name) = options.flag_root { + if let Ok(workspace_root) = self.workspace.current() { if root_name == workspace_root.name() { Ok(workspace_root.package_id().clone()) } else { - for direct_dep in pkg_deps[workspace_root.package_id()].keys() { - if pkgs[direct_dep].name() == root_name { + for direct_dep in self.pkg_deps[workspace_root.package_id()].keys() { + if self.pkgs[direct_dep].name() == root_name { return Ok(direct_dep.clone()); } } @@ -74,19 +84,27 @@ impl<'ela> ElaborateWorkspace<'ela> { ))); } } else { - Ok(workspace.current()?.package_id().clone()) - }; - - determine_root()? - }; + Err(CargoError::from_kind(CargoErrorKind::Msg( + "--root is not allowed when running against a virtual manifest".to_owned(), + ))) + } + } else { + Ok(self.workspace.current()?.package_id().clone()) + } + } - Ok(ElaborateWorkspace { - root: root, - workspace: workspace, - pkgs: pkgs, - pkg_deps: pkg_deps, - pkg_status: HashMap::new(), - }) + /// Find a member based on member name + fn find_member(&self, member: &PackageId) -> CargoResult { + for m in self.workspace.members() { + // members with the same name in a workspace is not allowed + // even with different paths + if member.name() == m.name() { + return Ok(m.package_id().clone()); + } + } + Err(CargoError::from_kind(CargoErrorKind::Msg( + format!("Workspace member {} not found", member.name()), + ))) } /// Resolve compatible and latest status from the corresponding `ElaborateWorkspace`s @@ -96,20 +114,30 @@ impl<'ela> ElaborateWorkspace<'ela> { latest: &ElaborateWorkspace, options: &Options, config: &Config, + root: &PackageId, ) -> CargoResult<()> { - let root_parent = if &self.root == self.workspace.current()?.package_id() { + self.pkg_status.clear(); + let root_parent = if self.virtual_manifest || root == self.workspace.current()?.package_id() + { None } else { Some(self.workspace.current()?.package_id()) }; - let root_id = self.root.clone(); + let (compat_root, latest_root) = if self.virtual_manifest { + (compat.find_member(root)?, latest.find_member(root)?) + } else { + ( + compat.determine_root(options)?, + latest.determine_root(options)?, + ) + }; self.resolve_status_recursive( None, root_parent, - &root_id, - Some(&compat.root), + root, + Some(&compat_root), compat, - Some(&latest.root), + Some(&latest_root), latest, options.flag_depth, config, @@ -223,10 +251,15 @@ impl<'ela> ElaborateWorkspace<'ela> { } /// Print package status to `TabWriter` - pub fn print_list(&self, options: &Options, config: &Config) -> CargoResult { - verbose!(config, "Printing...", "list format"); + pub fn print_list( + &self, + options: &Options, + root: &PackageId, + preceding_line: bool, + ) -> CargoResult { let mut lines = vec![]; - let root_parent = if &self.root == self.workspace.current()?.package_id() { + let root_parent = if self.virtual_manifest || root == self.workspace.current()?.package_id() + { None } else { Some(self.workspace.current()?.package_id()) @@ -237,7 +270,7 @@ impl<'ela> ElaborateWorkspace<'ela> { options, None, root_parent, - &self.root, + root, options.flag_depth, &mut lines, &mut printed, @@ -247,10 +280,17 @@ impl<'ela> ElaborateWorkspace<'ela> { lines.dedup(); let lines_len = lines.len(); - verbose!(config, "Printing...", "with tab writer"); if lines.is_empty() { - println!("All dependencies are up to date, yay!"); + if !self.virtual_manifest { + println!("All dependencies are up to date, yay!"); + } } else { + if preceding_line { + println!(); + } + if self.virtual_manifest { + println!("{}\n================", root.name()); + } let mut tw = TabWriter::new(vec![]); write!(&mut tw, "Name\tProject\tCompat\tLatest\tKind\tPlatform\n")?; write!(&mut tw, "----\t-------\t------\t------\t----\t--------\n")?; @@ -297,11 +337,12 @@ impl<'ela> ElaborateWorkspace<'ela> { // name version compatible latest kind platform if let Some(parent) = parent { let dependency = &self.pkg_deps[parent][pkg_id]; - let label = if parent == self.workspace.current()?.package_id() { - pkg.name().to_owned() - } else { - format!("{}->{}", self.pkgs[parent].name(), pkg.name()) - }; + let label = + if self.virtual_manifest || parent == self.workspace.current()?.package_id() { + pkg.name().to_owned() + } else { + format!("{}->{}", self.pkgs[parent].name(), pkg.name()) + }; let line = format!( "{}\t{}\t{}\t{}\t{:?}\t{}\n", label, @@ -332,6 +373,11 @@ impl<'ela> ElaborateWorkspace<'ela> { } for dep in self.pkg_deps[pkg_id].keys() { + // if executed against a virtual manifest, we should stop if a dependency + // is another member to prevent duplicated output + if self.virtual_manifest && self.workspace.members().any(|m| m.package_id() == dep) { + continue; + } self.print_list_recursive( options, parent, diff --git a/src/cargo_ops/temp_project.rs b/src/cargo_ops/temp_project.rs index d89691c..948af17 100644 --- a/src/cargo_ops/temp_project.rs +++ b/src/cargo_ops/temp_project.rs @@ -330,25 +330,15 @@ impl<'tmp> TempProject<'tmp> { } } +/// Paths of all manifest files in current workspace fn manifest_paths(elab: &ElaborateWorkspace) -> CargoResult> { let mut visited: HashSet = HashSet::new(); let mut manifest_paths = vec![]; - let workspace_members: HashSet<_> = elab.workspace - .members() - .map(|pkg| pkg.package_id()) - .collect(); - for member in &workspace_members { - manifest_paths.push(elab.pkgs[member].manifest_path().to_owned()); - } - let root_pkg = elab.workspace.current()?.package_id(); - // e.g. /path/to/project - let workspace_path = elab.workspace.current()?.root().to_string_lossy(); fn manifest_paths_recursive( pkg_id: &PackageId, elab: &ElaborateWorkspace, workspace_path: &str, - members: &HashSet<&PackageId>, visited: &mut HashSet, manifest_paths: &mut Vec, ) -> CargoResult<()> { @@ -356,29 +346,32 @@ fn manifest_paths(elab: &ElaborateWorkspace) -> CargoResult> { return Ok(()); } visited.insert(pkg_id.clone()); - if !members.contains(pkg_id) { - let pkg = &elab.pkgs[pkg_id]; - let pkg_path = pkg.root().to_string_lossy(); - if pkg_path.starts_with(workspace_path) { - manifest_paths.push(pkg.manifest_path().to_owned()); - } + let pkg = &elab.pkgs[pkg_id]; + let pkg_path = pkg.root().to_string_lossy(); + if pkg_path.starts_with(workspace_path) { + manifest_paths.push(pkg.manifest_path().to_owned()); } for dep in elab.pkg_deps[pkg_id].keys() { - manifest_paths_recursive(dep, elab, workspace_path, members, visited, manifest_paths)?; + manifest_paths_recursive(dep, elab, workspace_path, visited, manifest_paths)?; } Ok(()) }; - manifest_paths_recursive( - root_pkg, - elab, - &workspace_path, - &workspace_members, - &mut visited, - &mut manifest_paths, - )?; + // executed against a virtual manifest + let workspace_path = elab.workspace.root().to_string_lossy(); + // if cargo workspace is not explicitly used, the pacakge itself would be a member + for member in elab.workspace.members() { + let root_pkg_id = member.package_id(); + manifest_paths_recursive( + root_pkg_id, + elab, + &workspace_path, + &mut visited, + &mut manifest_paths, + )?; + } Ok(manifest_paths) } diff --git a/src/main.rs b/src/main.rs index 1529b18..b819125 100644 --- a/src/main.rs +++ b/src/main.rs @@ -280,12 +280,31 @@ pub fn execute(options: Options, config: &Config) -> CargoResult { let ela_latest = ElaborateWorkspace::from_workspace(latest_workspace.as_ref().unwrap(), &options)?; - verbose!(config, "Resolving...", "package status"); - ela_curr.resolve_status(&ela_compat, &ela_latest, &options, config)?; - - let count = ela_curr.print_list(&options, config)?; - - Ok(count) + if ela_curr.virtual_manifest { + let mut sum = 0; + verbose!(config, "Printing...", "Package status in list format"); + for member in ela_curr.workspace.members() { + ela_curr.resolve_status( + &ela_compat, + &ela_latest, + &options, + config, + member.package_id(), + )?; + sum += ela_curr.print_list(&options, member.package_id(), sum > 0)?; + } + if sum == 0 { + println!("All dependencies are up to date, yay!"); + } + Ok(sum) + } else { + verbose!(config, "Resolving...", "package status"); + let root = ela_curr.determine_root(&options)?; + ela_curr.resolve_status(&ela_compat, &ela_latest, &options, config, &root)?; + verbose!(config, "Printing...", "list format"); + let count = ela_curr.print_list(&options, &root, false)?; + Ok(count) + } } #[allow(unknown_lints)]