diff --git a/eden/mononoke/tests/integration/newadmin/test-admin-commit-graph-ancestors-difference.t b/eden/mononoke/tests/integration/newadmin/test-admin-commit-graph-ancestors-difference.t index 865523f6171a9..3bb0f68f7f36f 100644 --- a/eden/mononoke/tests/integration/newadmin/test-admin-commit-graph-ancestors-difference.t +++ b/eden/mononoke/tests/integration/newadmin/test-admin-commit-graph-ancestors-difference.t @@ -51,3 +51,18 @@ returns D, E, F, G, H, I and J (order can vary since there are two branches so w * (glob) * (glob) * (glob) + +returns G, F, E, and C in graph form, and shows that E is a merge commit. + $ mononoke_admin commit-graph -R repo ancestors-difference --graph --heads $G --common $D + o 9711852ec4f4b42937dd5b760c7b3f84345bf48c74b7ef3ca7118d1d7928744d + │ + o 48779d8d497815015031dc3f3e9888abc8cf8273184ebd9ca8a395e24d501c90 + │ + o f0c81a03319da010415f712831abe8469ba3c30b93b0b07af175302b8c15f0e6 + ├─╮ + │ │ + │ ~ + │ + o e32a1e342cdb1e38e88466b4c1a01ae9f410024017aa21dc0a1c5da6b3963bf2 + │ + ~ diff --git a/eden/mononoke/tools/admin/Cargo.toml b/eden/mononoke/tools/admin/Cargo.toml index f789dd2f0b959..c0befb1dfeddb 100644 --- a/eden/mononoke/tools/admin/Cargo.toml +++ b/eden/mononoke/tools/admin/Cargo.toml @@ -102,6 +102,7 @@ repo_identity = { version = "0.1.0", path = "../../repo_attributes/repo_identity repo_lock = { version = "0.1.0", path = "../../repo_attributes/repo_lock/repo_lock" } sapling-dag = { version = "0.1.0", path = "../../../scm/lib/dag" } sapling-dag-types = { version = "0.1.0", path = "../../../scm/lib/dag/dag-types", features = ["for-tests", "serialize-abomonation"] } +sapling-renderdag = { version = "0.1.0", path = "../../../scm/lib/renderdag" } serde = { version = "1.0.185", features = ["derive", "rc"] } serde_json = { version = "1.0.132", features = ["float_roundtrip", "unbounded_depth"] } skeleton_manifest = { version = "0.1.0", path = "../../derived_data/skeleton_manifest" } diff --git a/eden/mononoke/tools/admin/src/commands/commit_graph/ancestors_difference.rs b/eden/mononoke/tools/admin/src/commands/commit_graph/ancestors_difference.rs index 5f0993b7da176..ba9714f461342 100644 --- a/eden/mononoke/tools/admin/src/commands/commit_graph/ancestors_difference.rs +++ b/eden/mononoke/tools/admin/src/commands/commit_graph/ancestors_difference.rs @@ -5,13 +5,22 @@ * GNU General Public License version 2. */ +use std::collections::HashSet; + use anyhow::Result; +use borrowed::borrowed; use clap::Args; use commit_graph::CommitGraphRef; use commit_id::parse_commit_id; use context::CoreContext; +use futures::future; use futures::future::try_join_all; -use futures::StreamExt; +use futures::stream; +use futures::stream::StreamExt; +use futures::stream::TryStreamExt; +use renderdag::Ancestor; +use renderdag::GraphRowRenderer; +use renderdag::Renderer; use super::Repo; @@ -24,6 +33,10 @@ pub struct AncestorsDifferenceArgs { /// Commit IDs to exclude ancestors of. #[clap(long, use_value_delimiter = true)] common: Vec, + + /// Render the commits as a graph. + #[clap(long, short = 'G')] + graph: bool, } pub async fn ancestors_difference( @@ -45,14 +58,56 @@ pub async fn ancestors_difference( .collect::>(), ) .await?; + let common_set = common.iter().copied().collect::>(); let mut ancestors_difference_stream = Box::pin( repo.commit_graph() .ancestors_difference_stream(ctx, heads, common) .await?, ); - while let Some(ancestor_result) = ancestors_difference_stream.next().await { - println!("{}", ancestor_result?); + if args.graph { + let mut renderer = GraphRowRenderer::new().output().build_box_drawing(); + + ancestors_difference_stream + .map_ok(|ancestor| { + borrowed!(common_set); + async move { + let parents = repo.commit_graph().changeset_parents(ctx, ancestor).await?; + let parents = stream::iter(parents) + .map(|parent| async move { + if repo + .commit_graph + .is_ancestor_of_any( + ctx, + parent, + common_set.iter().copied().collect(), + ) + .await? + { + // This parent is an ancestor of the common + // set, so it will not be shown. + anyhow::Ok(Ancestor::Anonymous) + } else { + anyhow::Ok(Ancestor::Parent(parent.to_string())) + } + }) + .buffered(10) + .try_collect::>() + .await?; + Ok((ancestor.to_string(), parents)) + } + }) + .try_buffered(1000) + .try_for_each(|(ancestor, parents)| { + let row = renderer.next_row(ancestor.clone(), parents, "o".to_string(), ancestor); + print!("{}", row); + future::ok(()) + }) + .await?; + } else { + while let Some(ancestor_result) = ancestors_difference_stream.next().await { + println!("{}", ancestor_result?); + } } Ok(())