Move the original get_draw_order code into the tree_iter module.
This commit is contained in:
@@ -18,8 +18,8 @@ use crate::nix_util::RunningUpdate;
|
|||||||
|
|
||||||
pub(crate) async fn feed_logs(args: FeedLogArgs) -> Result<()> {
|
pub(crate) async fn feed_logs(args: FeedLogArgs) -> Result<()> {
|
||||||
let db_handle = DbHandle::new::<String>(None).await?;
|
let db_handle = DbHandle::new::<String>(None).await?;
|
||||||
let mut running_build = RunningUpdate::new()?;
|
// let mut running_build = RunningUpdate::new()?;
|
||||||
// let mut running_build = RunningBuild::new(&db_handle)?;
|
let mut running_build = RunningBuild::new(&db_handle)?;
|
||||||
let file_stream = FileStream::new(args.input).await?;
|
let file_stream = FileStream::new(args.input).await?;
|
||||||
let mut nix_output_stream = NixOutputStream::new(file_stream);
|
let mut nix_output_stream = NixOutputStream::new(file_stream);
|
||||||
while let Some(message) = nix_output_stream.next().await? {
|
while let Some(message) = nix_output_stream.next().await? {
|
||||||
|
|||||||
@@ -126,26 +126,6 @@ impl Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_transparent(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Activity::Root(_activity_root) => true,
|
|
||||||
Activity::Unknown(_activity_unknown) => false,
|
|
||||||
Activity::CopyPath(_activity_copy_path) => false,
|
|
||||||
Activity::FileTransfer(_activity_file_transfer) => false,
|
|
||||||
Activity::Realize(_activity_realize) => true,
|
|
||||||
Activity::CopyPaths(_activity_copy_paths) => true,
|
|
||||||
Activity::Builds(_activity_builds) => true,
|
|
||||||
Activity::Build(_activity_build) => false,
|
|
||||||
Activity::OptimizeStore(_activity_optimize_store) => false,
|
|
||||||
Activity::VerifyPaths(_activity_verify_paths) => false,
|
|
||||||
Activity::Substitute(_activity_substitute) => false,
|
|
||||||
Activity::QueryPathInfo(_activity_query_path_info) => false,
|
|
||||||
Activity::PostBuildHook(_activity_post_build_hook) => false,
|
|
||||||
Activity::BuildWaiting(_activity_build_waiting) => true,
|
|
||||||
Activity::FetchTree(_activity_fetch_tree) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn display_name(&self) -> Option<Cow<'_, str>> {
|
pub(crate) fn display_name(&self) -> Option<Cow<'_, str>> {
|
||||||
match self {
|
match self {
|
||||||
Activity::Root(_activity_root) => {
|
Activity::Root(_activity_root) => {
|
||||||
@@ -204,63 +184,43 @@ impl Activity {
|
|||||||
|
|
||||||
pub(crate) fn get_progress_text(&self) -> Option<Cow<'_, str>> {
|
pub(crate) fn get_progress_text(&self) -> Option<Cow<'_, str>> {
|
||||||
match self {
|
match self {
|
||||||
Activity::Root(_activity_root) => {
|
Activity::Root(_activity_root) => None,
|
||||||
// TODO
|
|
||||||
panic!("Attempted to get_progress_text of a root activity.");
|
|
||||||
}
|
|
||||||
Activity::Unknown(_activity_unknown) => None,
|
Activity::Unknown(_activity_unknown) => None,
|
||||||
Activity::CopyPath(activity_copy_path) => Some(Cow::Owned(format!(
|
Activity::CopyPath(activity_copy_path) => {
|
||||||
"[{}/{}]",
|
get_progress_bar(activity_copy_path.done, activity_copy_path.expected).or_else(
|
||||||
activity_copy_path.done, activity_copy_path.expected
|
|| get_progress_text(activity_copy_path.done, activity_copy_path.expected),
|
||||||
))),
|
)
|
||||||
Activity::FileTransfer(activity_file_transfer) => Some(Cow::Owned(format!(
|
}
|
||||||
"[{}/{}]",
|
Activity::FileTransfer(activity_file_transfer) => {
|
||||||
activity_file_transfer.done, activity_file_transfer.expected
|
get_progress_bar(activity_file_transfer.done, activity_file_transfer.expected)
|
||||||
))),
|
.or_else(|| {
|
||||||
Activity::Realize(_activity_realize) => {
|
get_progress_text(
|
||||||
// TODO
|
activity_file_transfer.done,
|
||||||
panic!("Attempted to get_progress_text of a realize activity.");
|
activity_file_transfer.expected,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Activity::Realize(_activity_realize) => None,
|
||||||
|
Activity::CopyPaths(activity_copy_paths) => {
|
||||||
|
get_progress_bar(activity_copy_paths.done, activity_copy_paths.expected).or_else(
|
||||||
|
|| get_progress_text(activity_copy_paths.done, activity_copy_paths.expected),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Activity::Builds(activity_builds) => {
|
||||||
|
get_progress_bar(activity_builds.done, activity_builds.expected)
|
||||||
|
.or_else(|| get_progress_text(activity_builds.done, activity_builds.expected))
|
||||||
}
|
}
|
||||||
Activity::CopyPaths(activity_copy_paths) => Some(Cow::Owned(format!(
|
|
||||||
"[{}/{}]",
|
|
||||||
activity_copy_paths.done, activity_copy_paths.expected
|
|
||||||
))),
|
|
||||||
Activity::Builds(activity_builds) => Some(Cow::Owned(format!(
|
|
||||||
"[{}/{}]",
|
|
||||||
activity_builds.done, activity_builds.expected
|
|
||||||
))),
|
|
||||||
Activity::Build(activity_build) => activity_build
|
Activity::Build(activity_build) => activity_build
|
||||||
.phase
|
.phase
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|phase| Cow::Owned(format!("[{}]", phase))),
|
.map(|phase| Cow::Owned(format!("[{}]", phase))),
|
||||||
Activity::OptimizeStore(_activity_optimize_store) => {
|
Activity::OptimizeStore(_activity_optimize_store) => None,
|
||||||
// TODO
|
Activity::VerifyPaths(_activity_verify_paths) => None,
|
||||||
panic!("Attempted to get_progress_text of a optimize store activity.");
|
Activity::Substitute(_activity_substitute) => None,
|
||||||
}
|
Activity::QueryPathInfo(_activity_query_path_info) => None,
|
||||||
Activity::VerifyPaths(_activity_verify_paths) => {
|
Activity::PostBuildHook(_activity_post_build_hook) => None,
|
||||||
// TODO
|
Activity::BuildWaiting(_activity_build_waiting) => None,
|
||||||
panic!("Attempted to get_progress_text of a verify paths activity.");
|
Activity::FetchTree(_activity_fetch_tree) => None,
|
||||||
}
|
|
||||||
Activity::Substitute(_activity_substitute) => {
|
|
||||||
// TODO
|
|
||||||
panic!("Attempted to get_progress_text of a substitute activity.");
|
|
||||||
}
|
|
||||||
Activity::QueryPathInfo(_activity_query_path_info) => {
|
|
||||||
// TODO
|
|
||||||
panic!("Attempted to get_progress_text of a query path info activity.");
|
|
||||||
}
|
|
||||||
Activity::PostBuildHook(_activity_post_build_hook) => {
|
|
||||||
// TODO
|
|
||||||
panic!("Attempted to get_progress_text of a post build hook activity.");
|
|
||||||
}
|
|
||||||
Activity::BuildWaiting(_activity_build_waiting) => {
|
|
||||||
// TODO
|
|
||||||
panic!("Attempted to get_progress_text of a build waiting activity.");
|
|
||||||
}
|
|
||||||
Activity::FetchTree(_activity_fetch_tree) => {
|
|
||||||
// TODO
|
|
||||||
panic!("Attempted to get_progress_text of a fetch tree activity.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,3 +491,35 @@ impl Default for ActivityState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_progress_bar(done: u64, expected: u64) -> Option<Cow<'static, str>> {
|
||||||
|
if expected == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let percent = done as f32 / expected as f32;
|
||||||
|
// ○◔◑◕●
|
||||||
|
// ○◎◉●
|
||||||
|
// ▁▂▃▄▅▆▇█
|
||||||
|
// ▏▎▍▌▋▊▉█
|
||||||
|
// ░▒▓█
|
||||||
|
//
|
||||||
|
// 🮷 download
|
||||||
|
// 🮸 upload
|
||||||
|
// 🮵
|
||||||
|
// 🮶
|
||||||
|
if percent < 0.33 {
|
||||||
|
Some(Cow::Borrowed("░"))
|
||||||
|
} else if percent < 0.66 {
|
||||||
|
Some(Cow::Borrowed("▒"))
|
||||||
|
} else if percent < 1.0 {
|
||||||
|
Some(Cow::Borrowed("▓"))
|
||||||
|
} else if percent >= 1.0 {
|
||||||
|
Some(Cow::Borrowed("█"))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_progress_text(done: u64, expected: u64) -> Option<Cow<'static, str>> {
|
||||||
|
Some(Cow::Owned(format!("[{}/{}]", done, expected)))
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::ops::Deref;
|
|||||||
use super::activity::Activity;
|
use super::activity::Activity;
|
||||||
use super::activity::ActivityRoot;
|
use super::activity::ActivityRoot;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub(crate) struct ActivityId {
|
pub(crate) struct ActivityId {
|
||||||
id: u64,
|
id: u64,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ mod nix_output_stream;
|
|||||||
mod output_stream;
|
mod output_stream;
|
||||||
mod running_build;
|
mod running_build;
|
||||||
mod running_update;
|
mod running_update;
|
||||||
mod transparent_iter;
|
|
||||||
mod tree_iter;
|
mod tree_iter;
|
||||||
pub(crate) use activity_tree::ActivityIdAlreadyInTreeError;
|
pub(crate) use activity_tree::ActivityIdAlreadyInTreeError;
|
||||||
pub(crate) use activity_tree::ActivityIdNotInTreeError;
|
pub(crate) use activity_tree::ActivityIdNotInTreeError;
|
||||||
|
|||||||
@@ -12,13 +12,16 @@ use crate::database::db_handle::DbHandle;
|
|||||||
use crate::nix_util::nix_output_stream::NixAction;
|
use crate::nix_util::nix_output_stream::NixAction;
|
||||||
use crate::nix_util::nix_output_stream::NixOutputStream;
|
use crate::nix_util::nix_output_stream::NixOutputStream;
|
||||||
use crate::nix_util::output_stream::OutputStream;
|
use crate::nix_util::output_stream::OutputStream;
|
||||||
use crate::nix_util::transparent_iter::TransparentIter;
|
|
||||||
|
|
||||||
use super::activity_tree::ActivityId;
|
use super::activity::Activity;
|
||||||
|
use super::activity_tree::ActivityTree;
|
||||||
use super::activity_tree::ActivityTreeEntry;
|
use super::activity_tree::ActivityTreeEntry;
|
||||||
use super::activity_tree_stream::ActivityTreeStream;
|
use super::activity_tree_stream::ActivityTreeStream;
|
||||||
use super::nix_output_stream::ActivityResultMessage;
|
use super::nix_output_stream::ActivityResultMessage;
|
||||||
use super::nix_output_stream::NixMessage;
|
use super::nix_output_stream::NixMessage;
|
||||||
|
use super::tree_iter::DrawDagEntry;
|
||||||
|
use super::tree_iter::ReverseTreeIter;
|
||||||
|
use super::tree_iter::get_draw_order;
|
||||||
|
|
||||||
pub(crate) struct RunningBuild<'db> {
|
pub(crate) struct RunningBuild<'db> {
|
||||||
db_handle: &'db DbHandle,
|
db_handle: &'db DbHandle,
|
||||||
@@ -159,143 +162,83 @@ impl<'db> RunningBuild<'db> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_current_status(&mut self) -> () {
|
fn print_current_status(&mut self) -> () {
|
||||||
let mut tree = String::new();
|
// let draw_order = get_draw_order(self.activity_tree.get_tree());
|
||||||
let draw_order = self.get_draw_order();
|
let draw_order = ReverseTreeIter::new(
|
||||||
for dag_entry in draw_order {
|
self.activity_tree.get_tree(),
|
||||||
let leading_bars = {
|
None,
|
||||||
let mut leading_bars = String::with_capacity(3 * dag_entry.depth.len());
|
is_match_predicate,
|
||||||
for leading_bar in dag_entry
|
is_transparent_predicate,
|
||||||
.depth
|
is_alive_predicate,
|
||||||
.iter()
|
)
|
||||||
.map(|depth| if *depth { " " } else { " " })
|
.get_draw_order();
|
||||||
{
|
|
||||||
leading_bars.push_str(leading_bar);
|
print_dag(self.activity_tree.get_tree(), draw_order);
|
||||||
}
|
|
||||||
leading_bars
|
|
||||||
};
|
|
||||||
let branch = if dag_entry.has_later_siblings {
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
};
|
|
||||||
let activity = self.activity_tree.get_tree().get(&dag_entry.activity_id);
|
|
||||||
let display_name = activity
|
|
||||||
.get_activity()
|
|
||||||
.display_name()
|
|
||||||
.expect("Currently we always return a display name.");
|
|
||||||
let progress_text = activity.get_activity().get_progress_text();
|
|
||||||
let (progress, progress_sep) = match progress_text {
|
|
||||||
Some(text) => (text, " "),
|
|
||||||
None => (Cow::Borrowed(""), ""),
|
|
||||||
};
|
|
||||||
tree += &format!("{leading_bars}{branch} {progress}{progress_sep}{display_name}\n");
|
|
||||||
}
|
|
||||||
if tree.is_empty() {
|
|
||||||
println!("No active activities.");
|
|
||||||
} else {
|
|
||||||
print!("\n{}\n", tree);
|
|
||||||
}
|
|
||||||
self.last_announce = Some(Instant::now());
|
self.last_announce = Some(Instant::now());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_draw_order(&self) -> Vec<DrawDagEntry> {
|
|
||||||
let mut draw_order: Vec<DrawDagEntry> = Vec::new();
|
|
||||||
let mut stack: Vec<DrawStackEntry> = self
|
|
||||||
.get_children_in_order(self.activity_tree.get_tree().get_root_id())
|
|
||||||
.filter_map(|child| {
|
|
||||||
if child.get_activity().is_active() {
|
|
||||||
Some(DrawStackEntry::HasNotVisitedChildren(DrawDagEntry {
|
|
||||||
activity_id: child.get_activity_id().clone(),
|
|
||||||
depth: Vec::new(),
|
|
||||||
has_later_siblings: true,
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
if stack.len() == 0 {
|
|
||||||
return draw_order;
|
|
||||||
}
|
|
||||||
stack
|
|
||||||
.last_mut()
|
|
||||||
.expect("If-statement ensured this is Some()")
|
|
||||||
.set_no_later_siblings();
|
|
||||||
|
|
||||||
while !stack.is_empty() {
|
|
||||||
let current_entry = stack.pop().expect("While-loop ensured this is Some.");
|
|
||||||
match current_entry {
|
|
||||||
DrawStackEntry::HasNotVisitedChildren(draw_dag_entry) => {
|
|
||||||
let current_id = draw_dag_entry.activity_id.clone();
|
|
||||||
let mut current_depth = draw_dag_entry.depth.clone();
|
|
||||||
current_depth.push(draw_dag_entry.has_later_siblings);
|
|
||||||
stack.push(DrawStackEntry::VisitedChildren(draw_dag_entry));
|
|
||||||
let children: Vec<ActivityId> = self
|
|
||||||
.get_children_in_order(current_id)
|
|
||||||
.filter_map(|child| {
|
|
||||||
if child.get_activity().is_active() {
|
|
||||||
Some(child.get_activity_id().clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let has_children = !children.is_empty();
|
|
||||||
stack.extend(children.into_iter().map(|child_id| {
|
|
||||||
DrawStackEntry::HasNotVisitedChildren(DrawDagEntry {
|
|
||||||
activity_id: child_id,
|
|
||||||
depth: current_depth.clone(),
|
|
||||||
has_later_siblings: true,
|
|
||||||
})
|
|
||||||
}));
|
|
||||||
if has_children {
|
|
||||||
stack
|
|
||||||
.last_mut()
|
|
||||||
.expect("If-statement ensured this is Some()")
|
|
||||||
.set_no_later_siblings();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DrawStackEntry::VisitedChildren(draw_dag_entry) => {
|
|
||||||
draw_order.push(draw_dag_entry);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
draw_order
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_children_in_order(
|
|
||||||
&self,
|
|
||||||
parent_id: ActivityId,
|
|
||||||
) -> impl Iterator<Item = &ActivityTreeEntry> {
|
|
||||||
let parent = self.activity_tree.get_tree().get(&parent_id);
|
|
||||||
parent
|
|
||||||
.get_child_ids()
|
|
||||||
.iter()
|
|
||||||
.map(|child_id| self.activity_tree.get_tree().get(child_id))
|
|
||||||
.flat_map(|child| TransparentIter::new(self.activity_tree.get_tree(), child))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DrawStackEntry {
|
pub(crate) fn print_dag(activity_tree: &ActivityTree, draw_order: Vec<DrawDagEntry>) -> () {
|
||||||
HasNotVisitedChildren(DrawDagEntry),
|
let mut tree = String::new();
|
||||||
VisitedChildren(DrawDagEntry),
|
for dag_entry in draw_order {
|
||||||
}
|
let leading_bars = {
|
||||||
|
let mut leading_bars = String::with_capacity(3 * dag_entry.depth.len());
|
||||||
struct DrawDagEntry {
|
for leading_bar in dag_entry
|
||||||
activity_id: ActivityId,
|
.depth
|
||||||
depth: Vec<bool>,
|
.iter()
|
||||||
has_later_siblings: bool,
|
.map(|depth| if *depth { " " } else { " " })
|
||||||
}
|
{
|
||||||
|
leading_bars.push_str(leading_bar);
|
||||||
impl DrawStackEntry {
|
|
||||||
fn set_no_later_siblings(&mut self) -> () {
|
|
||||||
match self {
|
|
||||||
DrawStackEntry::HasNotVisitedChildren(draw_dag_entry) => {
|
|
||||||
draw_dag_entry.has_later_siblings = false
|
|
||||||
}
|
|
||||||
DrawStackEntry::VisitedChildren(draw_dag_entry) => {
|
|
||||||
draw_dag_entry.has_later_siblings = false
|
|
||||||
}
|
}
|
||||||
|
leading_bars
|
||||||
};
|
};
|
||||||
|
let branch = if dag_entry.has_later_siblings {
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
let activity = activity_tree.get(&dag_entry.activity_id);
|
||||||
|
let display_name = activity
|
||||||
|
.get_activity()
|
||||||
|
.display_name()
|
||||||
|
.expect("Currently we always return a display name.");
|
||||||
|
let progress_text = activity.get_activity().get_progress_text();
|
||||||
|
let (progress, progress_sep) = match progress_text {
|
||||||
|
Some(text) => (text, " "),
|
||||||
|
None => (Cow::Borrowed(""), ""),
|
||||||
|
};
|
||||||
|
tree += &format!("{leading_bars}{branch} {progress}{progress_sep}{display_name}\n");
|
||||||
|
}
|
||||||
|
if tree.is_empty() {
|
||||||
|
println!("No active activities.");
|
||||||
|
} else {
|
||||||
|
print!("\n{}\n", tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_match_predicate(_entry: &ActivityTreeEntry) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_transparent_predicate(entry: &ActivityTreeEntry) -> bool {
|
||||||
|
match entry.get_activity() {
|
||||||
|
Activity::Root(_activity_root) => true,
|
||||||
|
Activity::Unknown(_activity_unknown) => false,
|
||||||
|
Activity::CopyPath(_activity_copy_path) => false,
|
||||||
|
Activity::FileTransfer(_activity_file_transfer) => false,
|
||||||
|
Activity::Realize(_activity_realize) => true,
|
||||||
|
Activity::CopyPaths(_activity_copy_paths) => true,
|
||||||
|
Activity::Builds(_activity_builds) => true,
|
||||||
|
Activity::Build(_activity_build) => false,
|
||||||
|
Activity::OptimizeStore(_activity_optimize_store) => false,
|
||||||
|
Activity::VerifyPaths(_activity_verify_paths) => false,
|
||||||
|
Activity::Substitute(_activity_substitute) => false,
|
||||||
|
Activity::QueryPathInfo(_activity_query_path_info) => false,
|
||||||
|
Activity::PostBuildHook(_activity_post_build_hook) => false,
|
||||||
|
Activity::BuildWaiting(_activity_build_waiting) => true,
|
||||||
|
Activity::FetchTree(_activity_fetch_tree) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_alive_predicate(entry: &ActivityTreeEntry) -> bool {
|
||||||
|
entry.get_activity().is_active()
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
use tokio::process::Child;
|
use tokio::process::Child;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
@@ -9,21 +12,22 @@ use crate::nix_util::nix_output_stream::NixAction;
|
|||||||
use crate::nix_util::output_stream::OutputStream;
|
use crate::nix_util::output_stream::OutputStream;
|
||||||
use crate::nix_util::tree_iter::ForwardTreeIter;
|
use crate::nix_util::tree_iter::ForwardTreeIter;
|
||||||
|
|
||||||
use super::activity_tree::ActivityId;
|
use super::activity::Activity;
|
||||||
use super::activity_tree::ActivityTreeEntry;
|
use super::activity_tree::ActivityTreeEntry;
|
||||||
use super::activity_tree_stream::ActivityTreeStream;
|
use super::activity_tree_stream::ActivityTreeStream;
|
||||||
use super::nix_output_stream::ActivityResultMessage;
|
use super::nix_output_stream::ActivityResultMessage;
|
||||||
use super::nix_output_stream::NixMessage;
|
use super::nix_output_stream::NixMessage;
|
||||||
use super::transparent_iter::TransparentIter;
|
|
||||||
|
|
||||||
pub(crate) struct RunningUpdate {
|
pub(crate) struct RunningUpdate {
|
||||||
activity_tree: ActivityTreeStream,
|
activity_tree: ActivityTreeStream,
|
||||||
|
last_announce: Option<Instant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunningUpdate {
|
impl RunningUpdate {
|
||||||
pub(crate) fn new() -> Result<Self> {
|
pub(crate) fn new() -> Result<Self> {
|
||||||
Ok(RunningUpdate {
|
Ok(RunningUpdate {
|
||||||
activity_tree: ActivityTreeStream::new(),
|
activity_tree: ActivityTreeStream::new(),
|
||||||
|
last_announce: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,11 +75,11 @@ impl RunningUpdate {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
NixAction::Start(activity_start_message) => {
|
NixAction::Start(activity_start_message) => {
|
||||||
println!("START: {}", serde_json::to_string(&activity_start_message)?);
|
// println!("START: {}", serde_json::to_string(&activity_start_message)?);
|
||||||
self.print_current_status();
|
self.print_current_status();
|
||||||
}
|
}
|
||||||
NixAction::Stop(stop_message) => {
|
NixAction::Stop(stop_message) => {
|
||||||
println!("STOP: {}", serde_json::to_string(&stop_message)?);
|
// println!("STOP: {}", serde_json::to_string(&stop_message)?);
|
||||||
self.print_current_status();
|
self.print_current_status();
|
||||||
}
|
}
|
||||||
NixAction::Result(activity_result_message) => {
|
NixAction::Result(activity_result_message) => {
|
||||||
@@ -87,19 +91,19 @@ impl RunningUpdate {
|
|||||||
ActivityResultMessage::SetPhase(_activity_result_set_phase) => {}
|
ActivityResultMessage::SetPhase(_activity_result_set_phase) => {}
|
||||||
ActivityResultMessage::Progress(activity_result_progress) => {
|
ActivityResultMessage::Progress(activity_result_progress) => {
|
||||||
// if activity_result_progress.expected != 0 {
|
// if activity_result_progress.expected != 0 {
|
||||||
println!(
|
// println!(
|
||||||
"PROGRESS: {}",
|
// "PROGRESS: {}",
|
||||||
serde_json::to_string(&activity_result_progress)?
|
// serde_json::to_string(&activity_result_progress)?
|
||||||
);
|
// );
|
||||||
// }
|
// }
|
||||||
self.maybe_print_current_status();
|
self.maybe_print_current_status();
|
||||||
}
|
}
|
||||||
ActivityResultMessage::SetExpected(activity_result_set_expected) => {
|
ActivityResultMessage::SetExpected(activity_result_set_expected) => {
|
||||||
// if activity_result_set_expected.expected != 0 {
|
// if activity_result_set_expected.expected != 0 {
|
||||||
println!(
|
// println!(
|
||||||
"EXPECTED: {}",
|
// "EXPECTED: {}",
|
||||||
serde_json::to_string(&activity_result_set_expected)?
|
// serde_json::to_string(&activity_result_set_expected)?
|
||||||
);
|
// );
|
||||||
// }
|
// }
|
||||||
self.maybe_print_current_status();
|
self.maybe_print_current_status();
|
||||||
}
|
}
|
||||||
@@ -113,24 +117,81 @@ impl RunningUpdate {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_print_current_status(&mut self) -> () {}
|
fn maybe_print_current_status(&mut self) -> () {
|
||||||
|
let last_announce = match self.last_announce {
|
||||||
|
Some(instant) => instant,
|
||||||
|
None => {
|
||||||
|
// If we haven't announced before, always announce.
|
||||||
|
return self.print_current_status();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let now = Instant::now();
|
||||||
|
let time_since_last_announce = now.duration_since(last_announce);
|
||||||
|
if time_since_last_announce > Duration::new(5, 0) {
|
||||||
|
return self.print_current_status();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn print_current_status(&mut self) -> () {
|
fn print_current_status(&mut self) -> () {
|
||||||
let nodes = ForwardTreeIter::new(
|
let nodes = ForwardTreeIter::new(
|
||||||
self.activity_tree.get_tree(),
|
self.activity_tree.get_tree(),
|
||||||
None,
|
None,
|
||||||
|entry| true,
|
is_match_predicate,
|
||||||
|entry| false,
|
is_transparent_predicate,
|
||||||
|entry| true,
|
is_alive_predicate,
|
||||||
);
|
);
|
||||||
println!("\n\n\nvvvvvv\n\n");
|
let mut out = Vec::new();
|
||||||
for (depth, is_match, is_transparent, node) in nodes {
|
for (depth, _is_match, _is_transparent, node) in nodes {
|
||||||
|
let progress_text = node
|
||||||
|
.get_activity()
|
||||||
|
.get_progress_text()
|
||||||
|
.unwrap_or(Cow::Borrowed(""));
|
||||||
let name = node
|
let name = node
|
||||||
.get_activity()
|
.get_activity()
|
||||||
.display_name()
|
.display_name()
|
||||||
.unwrap_or(Cow::Borrowed("null"));
|
.unwrap_or(Cow::Borrowed("null"));
|
||||||
println!("{depth}\t{is_match}\t{is_transparent}\t{name}");
|
out.push(format!("{depth}\t{progress_text}\t{name}"))
|
||||||
}
|
}
|
||||||
println!("\n\n\n^^^^^^\n\n");
|
|
||||||
|
if out.is_empty() {
|
||||||
|
println!("No active activities.");
|
||||||
|
} else {
|
||||||
|
println!("\n");
|
||||||
|
for l in out {
|
||||||
|
println!("{l}\n");
|
||||||
|
}
|
||||||
|
println!("\n");
|
||||||
|
}
|
||||||
|
self.last_announce = Some(Instant::now());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_match_predicate(entry: &ActivityTreeEntry) -> bool {
|
||||||
|
entry.get_activity().get_progress_text().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_transparent_predicate(entry: &ActivityTreeEntry) -> bool {
|
||||||
|
return false;
|
||||||
|
// match entry.get_activity() {
|
||||||
|
// Activity::Root(_activity_root) => true,
|
||||||
|
// Activity::Unknown(_activity_unknown) => false,
|
||||||
|
// Activity::CopyPath(_activity_copy_path) => false,
|
||||||
|
// Activity::FileTransfer(_activity_file_transfer) => false,
|
||||||
|
// Activity::Realize(_activity_realize) => true,
|
||||||
|
// Activity::CopyPaths(_activity_copy_paths) => true,
|
||||||
|
// Activity::Builds(_activity_builds) => true,
|
||||||
|
// Activity::Build(_activity_build) => false,
|
||||||
|
// Activity::OptimizeStore(_activity_optimize_store) => false,
|
||||||
|
// Activity::VerifyPaths(_activity_verify_paths) => false,
|
||||||
|
// Activity::Substitute(_activity_substitute) => false,
|
||||||
|
// Activity::QueryPathInfo(_activity_query_path_info) => false,
|
||||||
|
// Activity::PostBuildHook(_activity_post_build_hook) => false,
|
||||||
|
// Activity::BuildWaiting(_activity_build_waiting) => true,
|
||||||
|
// Activity::FetchTree(_activity_fetch_tree) => false,
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_alive_predicate(entry: &ActivityTreeEntry) -> bool {
|
||||||
|
entry.get_activity().is_active()
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,22 +8,22 @@ use test::Bencher;
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Build an ActivityTree matching the description at the top of the file.
|
|
||||||
fn build_example_tree(
|
fn build_example_tree(
|
||||||
num_levels: u64,
|
num_levels: u64,
|
||||||
num_children_per_node: u64,
|
num_children_per_node: u64,
|
||||||
) -> Result<ActivityTree, Box<dyn std::error::Error>> {
|
) -> Result<ActivityTree, Box<dyn std::error::Error>> {
|
||||||
let mut activity_tree = ActivityTree::new();
|
let mut activity_tree = ActivityTree::new();
|
||||||
let mut next_index = 1;
|
let mut next_index = 1;
|
||||||
let mut previous_level: Vec<u64> = Vec::new();
|
let mut previous_level: Vec<u64> = vec![0];
|
||||||
|
|
||||||
for _ in 0..num_levels {
|
for _ in 0..num_levels {
|
||||||
if previous_level.is_empty() {
|
let mut current_parents = Vec::new();
|
||||||
// first level, add num_children
|
std::mem::swap(&mut previous_level, &mut current_parents);
|
||||||
|
for parent in current_parents {
|
||||||
for _ in 0..num_children_per_node {
|
for _ in 0..num_children_per_node {
|
||||||
activity_tree.add_activity(
|
activity_tree.add_activity(
|
||||||
next_index,
|
next_index,
|
||||||
0,
|
parent,
|
||||||
Activity::Unknown(ActivityUnknown {
|
Activity::Unknown(ActivityUnknown {
|
||||||
state: ActivityState::Stopped,
|
state: ActivityState::Stopped,
|
||||||
text: format!("N{next_index}"),
|
text: format!("N{next_index}"),
|
||||||
@@ -32,24 +32,6 @@ fn build_example_tree(
|
|||||||
previous_level.push(next_index);
|
previous_level.push(next_index);
|
||||||
next_index += 1;
|
next_index += 1;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Subsequent levels, add num_children to each node of the previous level.
|
|
||||||
let mut current_parents = Vec::new();
|
|
||||||
std::mem::swap(&mut previous_level, &mut current_parents);
|
|
||||||
for parent in current_parents {
|
|
||||||
for _ in 0..num_children_per_node {
|
|
||||||
activity_tree.add_activity(
|
|
||||||
next_index,
|
|
||||||
parent,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: format!("N{next_index}"),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
previous_level.push(next_index);
|
|
||||||
next_index += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,13 +43,13 @@ use super::stack_entry::StackEntry;
|
|||||||
/// you would get the following output:
|
/// you would get the following output:
|
||||||
///
|
///
|
||||||
/// ```text
|
/// ```text
|
||||||
/// 1 False False A
|
/// 0 False False A
|
||||||
/// 2 True False B
|
/// 1 True False B
|
||||||
/// 3 False True D
|
/// 2 False True D
|
||||||
/// 3 True False E
|
/// 2 True False E
|
||||||
/// 2 False False H
|
/// 1 False False H
|
||||||
/// 3 False False I
|
/// 2 False False I
|
||||||
/// 4 True False J
|
/// 3 True False J
|
||||||
/// ```
|
/// ```
|
||||||
pub(crate) struct ForwardTreeIter<'tree, MP, TP, AP> {
|
pub(crate) struct ForwardTreeIter<'tree, MP, TP, AP> {
|
||||||
activity_tree: &'tree ActivityTree,
|
activity_tree: &'tree ActivityTree,
|
||||||
@@ -91,10 +91,15 @@ where
|
|||||||
fn get_next_announce<'iter>(
|
fn get_next_announce<'iter>(
|
||||||
&'iter mut self,
|
&'iter mut self,
|
||||||
) -> Option<(usize, bool, bool, &'tree ActivityTreeEntry)> {
|
) -> Option<(usize, bool, bool, &'tree ActivityTreeEntry)> {
|
||||||
|
let origin_activity_id = *self.origin.get_activity_id().deref();
|
||||||
let (activity, is_match, is_transparent) = match self
|
let (activity, is_match, is_transparent) = match self
|
||||||
.stack
|
.stack
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter(|entry| entry.should_announce() && !entry.is_announced())
|
.filter(|entry| {
|
||||||
|
entry.should_announce()
|
||||||
|
&& !entry.is_announced()
|
||||||
|
&& *entry.get_node().get_activity_id().deref() != origin_activity_id
|
||||||
|
})
|
||||||
.next()
|
.next()
|
||||||
{
|
{
|
||||||
Some(entry) => {
|
Some(entry) => {
|
||||||
@@ -110,7 +115,10 @@ where
|
|||||||
|
|
||||||
let depth = self
|
let depth = self
|
||||||
.walk_up_stack(activity)
|
.walk_up_stack(activity)
|
||||||
.filter(|node| !node.is_transparent())
|
.filter(|node| {
|
||||||
|
!node.is_transparent()
|
||||||
|
&& *node.get_node().get_activity_id().deref() != origin_activity_id
|
||||||
|
})
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
Some((depth, is_match, is_transparent, activity))
|
Some((depth, is_match, is_transparent, activity))
|
||||||
|
|||||||
@@ -1,114 +1,19 @@
|
|||||||
use crate::nix_util::activity::Activity;
|
use crate::nix_util::running_build::is_transparent_predicate;
|
||||||
use crate::nix_util::activity::ActivityState;
|
use crate::nix_util::tree_iter::test_util::build_example_tree;
|
||||||
use crate::nix_util::activity::ActivityUnknown;
|
use crate::nix_util::tree_iter::test_util::is_alive_predicate;
|
||||||
|
use crate::nix_util::tree_iter::test_util::is_match_predicate;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Build an ActivityTree matching the description at the top of the file.
|
|
||||||
fn build_example_tree() -> Result<ActivityTree, Box<dyn std::error::Error>> {
|
|
||||||
let mut activity_tree = ActivityTree::new();
|
|
||||||
activity_tree.add_activity(
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "A".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "B".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
3,
|
|
||||||
2,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "C".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
4,
|
|
||||||
2,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "D".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
5,
|
|
||||||
4,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "E".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
6,
|
|
||||||
4,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "F".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
7,
|
|
||||||
1,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "G".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
8,
|
|
||||||
1,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "H".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
9,
|
|
||||||
8,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "I".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
10,
|
|
||||||
9,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "J".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(activity_tree)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn forward_tree_order() -> Result<(), Box<dyn std::error::Error>> {
|
fn forward_tree_order() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let activity_tree = build_example_tree()?;
|
let activity_tree = build_example_tree()?;
|
||||||
let nodes = ForwardTreeIter::new(
|
let nodes = ForwardTreeIter::new(
|
||||||
&activity_tree,
|
&activity_tree,
|
||||||
None,
|
None,
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
is_match_predicate,
|
||||||
2 | 5 | 10 => true,
|
is_transparent_predicate,
|
||||||
_ => false,
|
is_alive_predicate,
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
4 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let output: Vec<_> = nodes
|
let output: Vec<_> = nodes
|
||||||
@@ -124,13 +29,20 @@ fn forward_tree_order() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
(1, false, false, "Unknown(A)".into()),
|
(0, false, false, "Unknown(N1)".into()),
|
||||||
(2, true, false, "Unknown(B)".into()),
|
(1, true, false, "Unknown(N2)".into()),
|
||||||
(3, false, true, "Unknown(D)".into()),
|
(2, false, true, "Realize".into()), // N4
|
||||||
(3, true, false, "Unknown(E)".into()),
|
(2, true, false, "Unknown(N5)".into()),
|
||||||
(2, false, false, "Unknown(H)".into()),
|
(1, false, false, "Unknown(N8)".into()),
|
||||||
(3, false, false, "Unknown(I)".into()),
|
(2, false, false, "Unknown(N9)".into()),
|
||||||
(4, true, false, "Unknown(J)".into()),
|
(3, true, false, "Unknown(N10)".into()),
|
||||||
|
(0, false, false, "Unknown(N11)".into()),
|
||||||
|
(1, true, false, "Unknown(N12)".into()),
|
||||||
|
(2, false, true, "Realize".into()), // N14
|
||||||
|
(2, true, false, "Unknown(N15)".into()),
|
||||||
|
(1, false, false, "Unknown(N18)".into()),
|
||||||
|
(2, false, false, "Unknown(N19)".into()),
|
||||||
|
(3, true, false, "Unknown(N20)".into()),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
@@ -144,18 +56,9 @@ fn start_from_a() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let nodes = ForwardTreeIter::new(
|
let nodes = ForwardTreeIter::new(
|
||||||
&activity_tree,
|
&activity_tree,
|
||||||
Some(activity_tree.get(&activity_tree.get_activity_id(1)?)),
|
Some(activity_tree.get(&activity_tree.get_activity_id(1)?)),
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
is_match_predicate,
|
||||||
2 | 5 | 10 => true,
|
is_transparent_predicate,
|
||||||
_ => false,
|
is_alive_predicate,
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
4 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let output: Vec<_> = nodes
|
let output: Vec<_> = nodes
|
||||||
@@ -171,12 +74,12 @@ fn start_from_a() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
(1, true, false, "Unknown(B)".into()),
|
(0, true, false, "Unknown(N2)".into()),
|
||||||
(2, false, true, "Unknown(D)".into()),
|
(1, false, true, "Realize".into()), // N4
|
||||||
(2, true, false, "Unknown(E)".into()),
|
(1, true, false, "Unknown(N5)".into()),
|
||||||
(1, false, false, "Unknown(H)".into()),
|
(0, false, false, "Unknown(N8)".into()),
|
||||||
(2, false, false, "Unknown(I)".into()),
|
(1, false, false, "Unknown(N9)".into()),
|
||||||
(3, true, false, "Unknown(J)".into()),
|
(2, true, false, "Unknown(N10)".into()),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
@@ -190,18 +93,9 @@ fn start_from_h() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let nodes = ForwardTreeIter::new(
|
let nodes = ForwardTreeIter::new(
|
||||||
&activity_tree,
|
&activity_tree,
|
||||||
Some(activity_tree.get(&activity_tree.get_activity_id(8)?)),
|
Some(activity_tree.get(&activity_tree.get_activity_id(8)?)),
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
is_match_predicate,
|
||||||
2 | 5 | 10 => true,
|
is_transparent_predicate,
|
||||||
_ => false,
|
is_alive_predicate,
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
4 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let output: Vec<_> = nodes
|
let output: Vec<_> = nodes
|
||||||
@@ -217,8 +111,8 @@ fn start_from_h() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
(1, false, false, "Unknown(I)".into()),
|
(0, false, false, "Unknown(N9)".into()),
|
||||||
(2, true, false, "Unknown(J)".into()),
|
(1, true, false, "Unknown(N10)".into()),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
@@ -232,18 +126,9 @@ fn start_from_c() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let nodes = ForwardTreeIter::new(
|
let nodes = ForwardTreeIter::new(
|
||||||
&activity_tree,
|
&activity_tree,
|
||||||
Some(activity_tree.get(&activity_tree.get_activity_id(3)?)),
|
Some(activity_tree.get(&activity_tree.get_activity_id(3)?)),
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
is_match_predicate,
|
||||||
2 | 5 | 10 => true,
|
is_transparent_predicate,
|
||||||
_ => false,
|
is_alive_predicate,
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
4 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let output: Vec<_> = nodes
|
let output: Vec<_> = nodes
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test_util;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
mod forward_tree_iter;
|
mod forward_tree_iter;
|
||||||
|
mod original_implementation;
|
||||||
mod reverse_tree_iter;
|
mod reverse_tree_iter;
|
||||||
mod stack_entry;
|
mod stack_entry;
|
||||||
|
|
||||||
pub(crate) use forward_tree_iter::ForwardTreeIter;
|
pub(crate) use forward_tree_iter::ForwardTreeIter;
|
||||||
|
pub(crate) use original_implementation::DrawDagEntry;
|
||||||
|
pub(crate) use original_implementation::get_draw_order;
|
||||||
pub(crate) use reverse_tree_iter::ReverseTreeIter;
|
pub(crate) use reverse_tree_iter::ReverseTreeIter;
|
||||||
|
|||||||
85
src/nix_util/tree_iter/original_implementation/benchmarks.rs
Normal file
85
src/nix_util/tree_iter/original_implementation/benchmarks.rs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
use test::Bencher;
|
||||||
|
use test::black_box;
|
||||||
|
|
||||||
|
use crate::nix_util::activity::Activity;
|
||||||
|
use crate::nix_util::activity::ActivityRealize;
|
||||||
|
use crate::nix_util::activity::ActivityState;
|
||||||
|
use crate::nix_util::activity::ActivityUnknown;
|
||||||
|
use crate::nix_util::activity_tree::ActivityTree;
|
||||||
|
|
||||||
|
use super::get_draw_order;
|
||||||
|
|
||||||
|
fn build_example_tree(
|
||||||
|
num_levels: u64,
|
||||||
|
num_children_per_node: u64,
|
||||||
|
) -> Result<ActivityTree, Box<dyn std::error::Error>> {
|
||||||
|
let mut activity_tree = ActivityTree::new();
|
||||||
|
let mut next_index = 1;
|
||||||
|
let mut previous_level: Vec<u64> = vec![0];
|
||||||
|
|
||||||
|
for _ in 0..num_levels {
|
||||||
|
let mut current_parents = Vec::new();
|
||||||
|
std::mem::swap(&mut previous_level, &mut current_parents);
|
||||||
|
for parent in current_parents {
|
||||||
|
for _ in 0..num_children_per_node {
|
||||||
|
// transparent = prime
|
||||||
|
let activity = if primal::is_prime(next_index as u64) {
|
||||||
|
Activity::Realize(ActivityRealize {
|
||||||
|
state: ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Activity::Unknown(ActivityUnknown {
|
||||||
|
state: ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
},
|
||||||
|
text: format!("N{next_index}"),
|
||||||
|
})
|
||||||
|
};
|
||||||
|
// if next_index is prime {} else {}
|
||||||
|
activity_tree.add_activity(next_index, parent, activity)?;
|
||||||
|
previous_level.push(next_index);
|
||||||
|
next_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(activity_tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test a tree with few levels but many nodes per level.
|
||||||
|
#[bench]
|
||||||
|
fn bench_shallow_wide_tree(b: &mut Bencher) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let num_levels: u64 = 3;
|
||||||
|
let num_children_per_node: u64 = 27;
|
||||||
|
|
||||||
|
let activity_tree = build_example_tree(num_levels, num_children_per_node)?;
|
||||||
|
|
||||||
|
b.iter(|| {
|
||||||
|
let _ = black_box(get_draw_order(&activity_tree));
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test a tree with many levels but few nodes per level.
|
||||||
|
#[bench]
|
||||||
|
fn bench_deep_narrow_tree(b: &mut Bencher) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let num_levels: u64 = 9;
|
||||||
|
let num_children_per_node: u64 = 3;
|
||||||
|
|
||||||
|
let activity_tree = build_example_tree(num_levels, num_children_per_node)?;
|
||||||
|
|
||||||
|
b.iter(|| {
|
||||||
|
let _ = black_box(get_draw_order(&activity_tree));
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
112
src/nix_util/tree_iter/original_implementation/mod.rs
Normal file
112
src/nix_util/tree_iter/original_implementation/mod.rs
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod benchmarks;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
mod transparent_iter;
|
||||||
|
|
||||||
|
use crate::nix_util::activity_tree::ActivityId;
|
||||||
|
use crate::nix_util::activity_tree::ActivityTree;
|
||||||
|
use crate::nix_util::activity_tree::ActivityTreeEntry;
|
||||||
|
|
||||||
|
use self::transparent_iter::TransparentIter;
|
||||||
|
|
||||||
|
pub(crate) fn get_draw_order(activity_tree: &ActivityTree) -> Vec<DrawDagEntry> {
|
||||||
|
let mut draw_order: Vec<DrawDagEntry> = Vec::new();
|
||||||
|
let mut stack: Vec<DrawStackEntry> =
|
||||||
|
get_children_in_order(activity_tree, activity_tree.get_root_id())
|
||||||
|
.filter_map(|child| {
|
||||||
|
if child.get_activity().is_active() {
|
||||||
|
Some(DrawStackEntry::HasNotVisitedChildren(DrawDagEntry {
|
||||||
|
activity_id: child.get_activity_id().clone(),
|
||||||
|
depth: Vec::new(),
|
||||||
|
has_later_siblings: true,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
if stack.len() == 0 {
|
||||||
|
return draw_order;
|
||||||
|
}
|
||||||
|
stack
|
||||||
|
.last_mut()
|
||||||
|
.expect("If-statement ensured this is Some()")
|
||||||
|
.set_no_later_siblings();
|
||||||
|
|
||||||
|
while !stack.is_empty() {
|
||||||
|
let current_entry = stack.pop().expect("While-loop ensured this is Some.");
|
||||||
|
match current_entry {
|
||||||
|
DrawStackEntry::HasNotVisitedChildren(draw_dag_entry) => {
|
||||||
|
let current_id = draw_dag_entry.activity_id.clone();
|
||||||
|
let mut current_depth = draw_dag_entry.depth.clone();
|
||||||
|
current_depth.push(draw_dag_entry.has_later_siblings);
|
||||||
|
stack.push(DrawStackEntry::VisitedChildren(draw_dag_entry));
|
||||||
|
let children: Vec<ActivityId> = get_children_in_order(activity_tree, current_id)
|
||||||
|
.filter_map(|child| {
|
||||||
|
if child.get_activity().is_active() {
|
||||||
|
Some(child.get_activity_id().clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let has_children = !children.is_empty();
|
||||||
|
stack.extend(children.into_iter().map(|child_id| {
|
||||||
|
DrawStackEntry::HasNotVisitedChildren(DrawDagEntry {
|
||||||
|
activity_id: child_id,
|
||||||
|
depth: current_depth.clone(),
|
||||||
|
has_later_siblings: true,
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
if has_children {
|
||||||
|
stack
|
||||||
|
.last_mut()
|
||||||
|
.expect("If-statement ensured this is Some()")
|
||||||
|
.set_no_later_siblings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DrawStackEntry::VisitedChildren(draw_dag_entry) => {
|
||||||
|
draw_order.push(draw_dag_entry);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
draw_order
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_children_in_order(
|
||||||
|
activity_tree: &ActivityTree,
|
||||||
|
parent_id: ActivityId,
|
||||||
|
) -> impl Iterator<Item = &ActivityTreeEntry> {
|
||||||
|
let parent = activity_tree.get(&parent_id);
|
||||||
|
parent
|
||||||
|
.get_child_ids()
|
||||||
|
.iter()
|
||||||
|
.map(|child_id| activity_tree.get(child_id))
|
||||||
|
.flat_map(|child| TransparentIter::new(activity_tree, child))
|
||||||
|
}
|
||||||
|
|
||||||
|
enum DrawStackEntry {
|
||||||
|
HasNotVisitedChildren(DrawDagEntry),
|
||||||
|
VisitedChildren(DrawDagEntry),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub(crate) struct DrawDagEntry {
|
||||||
|
pub(crate) activity_id: ActivityId,
|
||||||
|
pub(crate) depth: Vec<bool>,
|
||||||
|
pub(crate) has_later_siblings: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DrawStackEntry {
|
||||||
|
fn set_no_later_siblings(&mut self) -> () {
|
||||||
|
match self {
|
||||||
|
DrawStackEntry::HasNotVisitedChildren(draw_dag_entry) => {
|
||||||
|
draw_dag_entry.has_later_siblings = false
|
||||||
|
}
|
||||||
|
DrawStackEntry::VisitedChildren(draw_dag_entry) => {
|
||||||
|
draw_dag_entry.has_later_siblings = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/nix_util/tree_iter/original_implementation/tests.rs
Normal file
1
src/nix_util/tree_iter/original_implementation/tests.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
use super::activity_tree::ActivityTree;
|
use crate::nix_util::activity_tree::ActivityTree;
|
||||||
use super::activity_tree::ActivityTreeEntry;
|
use crate::nix_util::activity_tree::ActivityTreeEntry;
|
||||||
|
use crate::nix_util::running_build::is_transparent_predicate;
|
||||||
|
|
||||||
/// An iterator that returns either the original activity if it is not transparent, or if it is transparent, the earliest non-transparent children.
|
/// An iterator that returns either the original activity if it is not transparent, or if it is transparent, the earliest non-transparent children.
|
||||||
pub(crate) struct TransparentIter<'tree> {
|
pub(crate) struct TransparentIter<'tree> {
|
||||||
@@ -19,7 +20,7 @@ impl<'tree> Iterator for TransparentIter<'tree> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if !origin.get_activity().is_transparent() {
|
if !is_transparent_predicate(origin) {
|
||||||
let origin = self
|
let origin = self
|
||||||
.origin
|
.origin
|
||||||
.take()
|
.take()
|
||||||
@@ -34,7 +35,7 @@ impl<'tree> Iterator for TransparentIter<'tree> {
|
|||||||
loop {
|
loop {
|
||||||
let current_entry = self.get_current_entry();
|
let current_entry = self.get_current_entry();
|
||||||
if let Some(child) = current_entry {
|
if let Some(child) = current_entry {
|
||||||
if child.get_activity().is_transparent() {
|
if !is_transparent_predicate(child) {
|
||||||
self.child_index.push(0);
|
self.child_index.push(0);
|
||||||
} else {
|
} else {
|
||||||
let last_index = self.child_index.last_mut().expect("Stack cannot be empty.");
|
let last_index = self.child_index.last_mut().expect("Stack cannot be empty.");
|
||||||
@@ -5,25 +5,27 @@ use crate::nix_util::activity::ActivityState;
|
|||||||
use crate::nix_util::activity::ActivityUnknown;
|
use crate::nix_util::activity::ActivityUnknown;
|
||||||
|
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
use test::black_box;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Build an ActivityTree matching the description at the top of the file.
|
|
||||||
fn build_example_tree(
|
fn build_example_tree(
|
||||||
num_levels: u64,
|
num_levels: u64,
|
||||||
num_children_per_node: u64,
|
num_children_per_node: u64,
|
||||||
) -> Result<ActivityTree, Box<dyn std::error::Error>> {
|
) -> Result<ActivityTree, Box<dyn std::error::Error>> {
|
||||||
let mut activity_tree = ActivityTree::new();
|
let mut activity_tree = ActivityTree::new();
|
||||||
let mut next_index = 1;
|
let mut next_index = 1;
|
||||||
let mut previous_level: Vec<u64> = Vec::new();
|
let mut previous_level: Vec<u64> = vec![0];
|
||||||
|
|
||||||
for _ in 0..num_levels {
|
for _ in 0..num_levels {
|
||||||
if previous_level.is_empty() {
|
// Subsequent levels, add num_children to each node of the previous level.
|
||||||
// first level, add num_children
|
let mut current_parents = Vec::new();
|
||||||
|
std::mem::swap(&mut previous_level, &mut current_parents);
|
||||||
|
for parent in current_parents {
|
||||||
for _ in 0..num_children_per_node {
|
for _ in 0..num_children_per_node {
|
||||||
activity_tree.add_activity(
|
activity_tree.add_activity(
|
||||||
next_index,
|
next_index,
|
||||||
0,
|
parent,
|
||||||
Activity::Unknown(ActivityUnknown {
|
Activity::Unknown(ActivityUnknown {
|
||||||
state: ActivityState::Stopped,
|
state: ActivityState::Stopped,
|
||||||
text: format!("N{next_index}"),
|
text: format!("N{next_index}"),
|
||||||
@@ -32,24 +34,6 @@ fn build_example_tree(
|
|||||||
previous_level.push(next_index);
|
previous_level.push(next_index);
|
||||||
next_index += 1;
|
next_index += 1;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Subsequent levels, add num_children to each node of the previous level.
|
|
||||||
let mut current_parents = Vec::new();
|
|
||||||
std::mem::swap(&mut previous_level, &mut current_parents);
|
|
||||||
for parent in current_parents {
|
|
||||||
for _ in 0..num_children_per_node {
|
|
||||||
activity_tree.add_activity(
|
|
||||||
next_index,
|
|
||||||
parent,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: format!("N{next_index}"),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
previous_level.push(next_index);
|
|
||||||
next_index += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,9 +74,36 @@ fn bench_shallow_wide_tree(b: &mut Bencher) -> Result<(), Box<dyn std::error::Er
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test a tree with few levels but many nodes per level.
|
||||||
|
#[bench]
|
||||||
|
fn bench_shallow_wide_tree_draw(b: &mut Bencher) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let num_levels: u64 = 3;
|
||||||
|
let num_children_per_node: u64 = 27;
|
||||||
|
let total_nodes = num_children_per_node.pow(num_levels as u32);
|
||||||
|
|
||||||
|
let primes = get_primes(total_nodes);
|
||||||
|
// match = power of 2
|
||||||
|
// transparent = prime
|
||||||
|
let activity_tree = build_example_tree(num_levels, num_children_per_node)?;
|
||||||
|
|
||||||
|
b.iter(|| {
|
||||||
|
let nodes = ReverseTreeIter::new(
|
||||||
|
&activity_tree,
|
||||||
|
None,
|
||||||
|
|entry| (*entry.get_activity_id().deref()).count_ones() == 1,
|
||||||
|
|entry| primes.contains(entry.get_activity_id().deref()),
|
||||||
|
|_entry| true,
|
||||||
|
);
|
||||||
|
|
||||||
|
let _ = black_box(nodes.get_draw_order());
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Test a tree with many levels but few nodes per level.
|
/// Test a tree with many levels but few nodes per level.
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_deep_narrow_tree(b: &mut Bencher) -> Result<(), Box<dyn std::error::Error>> {
|
fn bench_deep_narrow_tree_draw(b: &mut Bencher) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let num_levels: u64 = 9;
|
let num_levels: u64 = 9;
|
||||||
let num_children_per_node: u64 = 3;
|
let num_children_per_node: u64 = 3;
|
||||||
let total_nodes = num_children_per_node.pow(num_levels as u32);
|
let total_nodes = num_children_per_node.pow(num_levels as u32);
|
||||||
@@ -111,7 +122,7 @@ fn bench_deep_narrow_tree(b: &mut Bencher) -> Result<(), Box<dyn std::error::Err
|
|||||||
|_entry| true,
|
|_entry| true,
|
||||||
);
|
);
|
||||||
|
|
||||||
for _ in nodes {}
|
let _ = black_box(nodes.get_draw_order());
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use std::ops::Deref;
|
|||||||
use crate::nix_util::activity_tree::ActivityTree;
|
use crate::nix_util::activity_tree::ActivityTree;
|
||||||
use crate::nix_util::activity_tree::ActivityTreeEntry;
|
use crate::nix_util::activity_tree::ActivityTreeEntry;
|
||||||
|
|
||||||
|
use super::original_implementation::DrawDagEntry;
|
||||||
use super::stack_entry::StackEntry;
|
use super::stack_entry::StackEntry;
|
||||||
|
|
||||||
/// An iterator over the activity tree that will return nodes in the tree matching the supplied criteria.
|
/// An iterator over the activity tree that will return nodes in the tree matching the supplied criteria.
|
||||||
@@ -43,13 +44,13 @@ use super::stack_entry::StackEntry;
|
|||||||
/// you would get the following output:
|
/// you would get the following output:
|
||||||
///
|
///
|
||||||
/// ```text
|
/// ```text
|
||||||
/// 4 True False J
|
/// 3 True False J
|
||||||
/// 3 False False I
|
/// 2 False False I
|
||||||
/// 2 False False H
|
/// 1 False False H
|
||||||
/// 3 True False E
|
/// 2 True False E
|
||||||
/// 3 False True D
|
/// 2 False True D
|
||||||
/// 2 True False B
|
/// 1 True False B
|
||||||
/// 1 False False A
|
/// 0 False False A
|
||||||
/// ```
|
/// ```
|
||||||
pub(crate) struct ReverseTreeIter<'tree, MP, TP, AP> {
|
pub(crate) struct ReverseTreeIter<'tree, MP, TP, AP> {
|
||||||
activity_tree: &'tree ActivityTree,
|
activity_tree: &'tree ActivityTree,
|
||||||
@@ -115,6 +116,36 @@ where
|
|||||||
.skip(1)
|
.skip(1)
|
||||||
.filter(|node| node.is_visited())
|
.filter(|node| node.is_visited())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_draw_order(self) -> Vec<DrawDagEntry> {
|
||||||
|
let mut order = Vec::new();
|
||||||
|
let mut walk_depth: Vec<usize> = Vec::new();
|
||||||
|
|
||||||
|
for (inp_depth, _is_match, _is_transparent, entry) in
|
||||||
|
self.filter(|(_inp_depth, _is_match, is_transparent, _entry)| !*is_transparent)
|
||||||
|
{
|
||||||
|
let mut depth = vec![false; inp_depth];
|
||||||
|
let mut high_water_mark = inp_depth;
|
||||||
|
for preceding_depth in walk_depth.iter().rev() {
|
||||||
|
if *preceding_depth < high_water_mark {
|
||||||
|
depth[*preceding_depth] = true;
|
||||||
|
high_water_mark = *preceding_depth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
order.push(DrawDagEntry {
|
||||||
|
activity_id: entry.get_activity_id().clone(),
|
||||||
|
depth,
|
||||||
|
has_later_siblings: walk_depth
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.take_while(|wd| **wd >= inp_depth)
|
||||||
|
.any(|wd| *wd == inp_depth),
|
||||||
|
});
|
||||||
|
walk_depth.push(inp_depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
order
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tree, MP, TP, AP> Iterator for ReverseTreeIter<'tree, MP, TP, AP>
|
impl<'tree, MP, TP, AP> Iterator for ReverseTreeIter<'tree, MP, TP, AP>
|
||||||
@@ -126,6 +157,8 @@ where
|
|||||||
type Item = (usize, bool, bool, &'tree ActivityTreeEntry);
|
type Item = (usize, bool, bool, &'tree ActivityTreeEntry);
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let origin_activity_id = *self.origin.get_activity_id().deref();
|
||||||
|
|
||||||
// Walk through stack
|
// Walk through stack
|
||||||
loop {
|
loop {
|
||||||
let mut should_check_for_output = false;
|
let mut should_check_for_output = false;
|
||||||
@@ -144,8 +177,8 @@ where
|
|||||||
let is_transparent = stack_entry.is_transparent();
|
let is_transparent = stack_entry.is_transparent();
|
||||||
|
|
||||||
// If we've already processed the children, remove it from the stack.
|
// If we've already processed the children, remove it from the stack.
|
||||||
if stack_entry.is_visited() {
|
if is_visited {
|
||||||
if stack_entry.should_announce() {
|
if should_announce && *node.get_activity_id().deref() != origin_activity_id {
|
||||||
let output = Some(self.announce(node, is_match, is_transparent));
|
let output = Some(self.announce(node, is_match, is_transparent));
|
||||||
self.stack.pop();
|
self.stack.pop();
|
||||||
return output;
|
return output;
|
||||||
@@ -158,7 +191,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
if is_visited {
|
if is_visited {
|
||||||
if should_announce {
|
if should_announce && *node.get_activity_id().deref() != origin_activity_id {
|
||||||
let output = Some(self.announce(node, is_match, is_transparent));
|
let output = Some(self.announce(node, is_match, is_transparent));
|
||||||
self.stack.pop();
|
self.stack.pop();
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
@@ -1,114 +1,19 @@
|
|||||||
use crate::nix_util::activity::Activity;
|
use crate::nix_util::running_build::is_transparent_predicate;
|
||||||
use crate::nix_util::activity::ActivityState;
|
use crate::nix_util::tree_iter::test_util::build_example_tree;
|
||||||
use crate::nix_util::activity::ActivityUnknown;
|
use crate::nix_util::tree_iter::test_util::is_alive_predicate;
|
||||||
|
use crate::nix_util::tree_iter::test_util::is_match_predicate;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Build an ActivityTree matching the description at the top of the file.
|
|
||||||
fn build_example_tree() -> Result<ActivityTree, Box<dyn std::error::Error>> {
|
|
||||||
let mut activity_tree = ActivityTree::new();
|
|
||||||
activity_tree.add_activity(
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "A".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "B".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
3,
|
|
||||||
2,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "C".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
4,
|
|
||||||
2,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "D".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
5,
|
|
||||||
4,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "E".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
6,
|
|
||||||
4,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "F".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
7,
|
|
||||||
1,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "G".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
8,
|
|
||||||
1,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "H".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
9,
|
|
||||||
8,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "I".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
activity_tree.add_activity(
|
|
||||||
10,
|
|
||||||
9,
|
|
||||||
Activity::Unknown(ActivityUnknown {
|
|
||||||
state: ActivityState::Stopped,
|
|
||||||
text: "J".to_owned(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(activity_tree)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reverse_tree_order() -> Result<(), Box<dyn std::error::Error>> {
|
fn reverse_tree_order() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let activity_tree = build_example_tree()?;
|
let activity_tree = build_example_tree()?;
|
||||||
let nodes = ReverseTreeIter::new(
|
let nodes = ReverseTreeIter::new(
|
||||||
&activity_tree,
|
&activity_tree,
|
||||||
None,
|
None,
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
is_match_predicate,
|
||||||
2 | 5 | 10 => true,
|
is_transparent_predicate,
|
||||||
_ => false,
|
is_alive_predicate,
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
4 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let output: Vec<_> = nodes
|
let output: Vec<_> = nodes
|
||||||
@@ -124,13 +29,20 @@ fn reverse_tree_order() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
(4, true, false, "Unknown(J)".into()),
|
(3, true, false, "Unknown(N20)".into()),
|
||||||
(3, false, false, "Unknown(I)".into()),
|
(2, false, false, "Unknown(N19)".into()),
|
||||||
(2, false, false, "Unknown(H)".into()),
|
(1, false, false, "Unknown(N18)".into()),
|
||||||
(3, true, false, "Unknown(E)".into()),
|
(2, true, false, "Unknown(N15)".into()),
|
||||||
(3, false, true, "Unknown(D)".into()),
|
(2, false, true, "Realize".into()),
|
||||||
(2, true, false, "Unknown(B)".into()),
|
(1, true, false, "Unknown(N12)".into()),
|
||||||
(1, false, false, "Unknown(A)".into()),
|
(0, false, false, "Unknown(N11)".into()),
|
||||||
|
(3, true, false, "Unknown(N10)".into()),
|
||||||
|
(2, false, false, "Unknown(N9)".into()),
|
||||||
|
(1, false, false, "Unknown(N8)".into()),
|
||||||
|
(2, true, false, "Unknown(N5)".into()),
|
||||||
|
(2, false, true, "Realize".into()),
|
||||||
|
(1, true, false, "Unknown(N2)".into()),
|
||||||
|
(0, false, false, "Unknown(N1)".into()),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
@@ -139,23 +51,14 @@ fn reverse_tree_order() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn start_from_a() -> Result<(), Box<dyn std::error::Error>> {
|
fn start_from_1() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let activity_tree = build_example_tree()?;
|
let activity_tree = build_example_tree()?;
|
||||||
let nodes = ReverseTreeIter::new(
|
let nodes = ReverseTreeIter::new(
|
||||||
&activity_tree,
|
&activity_tree,
|
||||||
Some(activity_tree.get(&activity_tree.get_activity_id(1)?)),
|
Some(activity_tree.get(&activity_tree.get_activity_id(1)?)),
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
is_match_predicate,
|
||||||
2 | 5 | 10 => true,
|
is_transparent_predicate,
|
||||||
_ => false,
|
is_alive_predicate,
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
4 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let output: Vec<_> = nodes
|
let output: Vec<_> = nodes
|
||||||
@@ -171,12 +74,12 @@ fn start_from_a() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
(3, true, false, "Unknown(J)".into()),
|
(3, true, false, "Unknown(N10)".into()),
|
||||||
(2, false, false, "Unknown(I)".into()),
|
(2, false, false, "Unknown(N9)".into()),
|
||||||
(1, false, false, "Unknown(H)".into()),
|
(1, false, false, "Unknown(N8)".into()),
|
||||||
(2, true, false, "Unknown(E)".into()),
|
(2, true, false, "Unknown(N5)".into()),
|
||||||
(2, false, true, "Unknown(D)".into()),
|
(2, false, true, "Realize".into()), // N4
|
||||||
(1, true, false, "Unknown(B)".into()),
|
(1, true, false, "Unknown(N2)".into()),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
@@ -185,23 +88,14 @@ fn start_from_a() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn start_from_h() -> Result<(), Box<dyn std::error::Error>> {
|
fn start_from_8() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let activity_tree = build_example_tree()?;
|
let activity_tree = build_example_tree()?;
|
||||||
let nodes = ReverseTreeIter::new(
|
let nodes = ReverseTreeIter::new(
|
||||||
&activity_tree,
|
&activity_tree,
|
||||||
Some(activity_tree.get(&activity_tree.get_activity_id(8)?)),
|
Some(activity_tree.get(&activity_tree.get_activity_id(8)?)),
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
is_match_predicate,
|
||||||
2 | 5 | 10 => true,
|
is_transparent_predicate,
|
||||||
_ => false,
|
is_alive_predicate,
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
4 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let output: Vec<_> = nodes
|
let output: Vec<_> = nodes
|
||||||
@@ -217,8 +111,8 @@ fn start_from_h() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
(2, true, false, "Unknown(J)".into()),
|
(2, true, false, "Unknown(N10)".into()),
|
||||||
(1, false, false, "Unknown(I)".into()),
|
(1, false, false, "Unknown(N9)".into()),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
@@ -227,23 +121,14 @@ fn start_from_h() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn start_from_c() -> Result<(), Box<dyn std::error::Error>> {
|
fn start_from_3() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let activity_tree = build_example_tree()?;
|
let activity_tree = build_example_tree()?;
|
||||||
let nodes = ReverseTreeIter::new(
|
let nodes = ReverseTreeIter::new(
|
||||||
&activity_tree,
|
&activity_tree,
|
||||||
Some(activity_tree.get(&activity_tree.get_activity_id(3)?)),
|
Some(activity_tree.get(&activity_tree.get_activity_id(3)?)),
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
is_match_predicate,
|
||||||
2 | 5 | 10 => true,
|
is_transparent_predicate,
|
||||||
_ => false,
|
is_alive_predicate,
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
4 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|entry| match *entry.get_activity_id().deref() {
|
|
||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let output: Vec<_> = nodes
|
let output: Vec<_> = nodes
|
||||||
@@ -264,3 +149,82 @@ fn start_from_c() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reverse_tree_draw_order() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let activity_tree = build_example_tree()?;
|
||||||
|
let expected = vec![
|
||||||
|
DrawDagEntry {
|
||||||
|
activity_id: activity_tree.get_activity_id(20).unwrap(),
|
||||||
|
depth: vec![false, false, false],
|
||||||
|
has_later_siblings: false,
|
||||||
|
},
|
||||||
|
DrawDagEntry {
|
||||||
|
activity_id: activity_tree.get_activity_id(19).unwrap(),
|
||||||
|
depth: vec![false, false],
|
||||||
|
has_later_siblings: false,
|
||||||
|
},
|
||||||
|
DrawDagEntry {
|
||||||
|
activity_id: activity_tree.get_activity_id(18).unwrap(),
|
||||||
|
depth: vec![false],
|
||||||
|
has_later_siblings: false,
|
||||||
|
},
|
||||||
|
DrawDagEntry {
|
||||||
|
activity_id: activity_tree.get_activity_id(15).unwrap(),
|
||||||
|
depth: vec![false, true],
|
||||||
|
has_later_siblings: false,
|
||||||
|
},
|
||||||
|
DrawDagEntry {
|
||||||
|
activity_id: activity_tree.get_activity_id(12).unwrap(),
|
||||||
|
depth: vec![false],
|
||||||
|
has_later_siblings: true,
|
||||||
|
},
|
||||||
|
DrawDagEntry {
|
||||||
|
activity_id: activity_tree.get_activity_id(11).unwrap(),
|
||||||
|
depth: vec![],
|
||||||
|
has_later_siblings: false,
|
||||||
|
},
|
||||||
|
DrawDagEntry {
|
||||||
|
activity_id: activity_tree.get_activity_id(10).unwrap(),
|
||||||
|
depth: vec![true, false, false],
|
||||||
|
has_later_siblings: false,
|
||||||
|
},
|
||||||
|
DrawDagEntry {
|
||||||
|
activity_id: activity_tree.get_activity_id(9).unwrap(),
|
||||||
|
depth: vec![true, false],
|
||||||
|
has_later_siblings: false,
|
||||||
|
},
|
||||||
|
DrawDagEntry {
|
||||||
|
activity_id: activity_tree.get_activity_id(8).unwrap(),
|
||||||
|
depth: vec![true],
|
||||||
|
has_later_siblings: false,
|
||||||
|
},
|
||||||
|
DrawDagEntry {
|
||||||
|
activity_id: activity_tree.get_activity_id(5).unwrap(),
|
||||||
|
depth: vec![true, true],
|
||||||
|
has_later_siblings: false,
|
||||||
|
},
|
||||||
|
DrawDagEntry {
|
||||||
|
activity_id: activity_tree.get_activity_id(2).unwrap(),
|
||||||
|
depth: vec![true],
|
||||||
|
has_later_siblings: true,
|
||||||
|
},
|
||||||
|
DrawDagEntry {
|
||||||
|
activity_id: activity_tree.get_activity_id(1).unwrap(),
|
||||||
|
depth: vec![],
|
||||||
|
has_later_siblings: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let reverse_draw_order = ReverseTreeIter::new(
|
||||||
|
&activity_tree,
|
||||||
|
None,
|
||||||
|
is_match_predicate,
|
||||||
|
is_transparent_predicate,
|
||||||
|
is_alive_predicate,
|
||||||
|
)
|
||||||
|
.get_draw_order();
|
||||||
|
|
||||||
|
assert_eq!(reverse_draw_order, expected);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
392
src/nix_util/tree_iter/test_util.rs
Normal file
392
src/nix_util/tree_iter/test_util.rs
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use crate::nix_util::activity::Activity;
|
||||||
|
use crate::nix_util::activity::ActivityRealize;
|
||||||
|
use crate::nix_util::activity::ActivityState;
|
||||||
|
use crate::nix_util::activity::ActivityUnknown;
|
||||||
|
use crate::nix_util::activity_tree::ActivityTree;
|
||||||
|
use crate::nix_util::activity_tree::ActivityTreeEntry;
|
||||||
|
|
||||||
|
impl Activity {
|
||||||
|
pub(crate) fn start(&mut self) -> () {
|
||||||
|
match self {
|
||||||
|
Activity::Root(_activity_root) => {
|
||||||
|
panic!("Attempted to start root activity.");
|
||||||
|
}
|
||||||
|
Activity::Unknown(activity_unknown) => {
|
||||||
|
activity_unknown.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::CopyPath(activity_copy_path) => {
|
||||||
|
activity_copy_path.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::FileTransfer(activity_file_transfer) => {
|
||||||
|
activity_file_transfer.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::Realize(activity_realize) => {
|
||||||
|
activity_realize.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::CopyPaths(activity_copy_paths) => {
|
||||||
|
activity_copy_paths.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::Builds(activity_builds) => {
|
||||||
|
activity_builds.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::Build(activity_build) => {
|
||||||
|
activity_build.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::OptimizeStore(activity_optimize_store) => {
|
||||||
|
activity_optimize_store.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::VerifyPaths(activity_verify_paths) => {
|
||||||
|
activity_verify_paths.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::Substitute(activity_substitute) => {
|
||||||
|
activity_substitute.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::QueryPathInfo(activity_query_path_info) => {
|
||||||
|
activity_query_path_info.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::PostBuildHook(activity_post_build_hook) => {
|
||||||
|
activity_post_build_hook.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::BuildWaiting(activity_build_waiting) => {
|
||||||
|
activity_build_waiting.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Activity::FetchTree(activity_fetch_tree) => {
|
||||||
|
activity_fetch_tree.state = ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build the following ActivityTree:
|
||||||
|
///
|
||||||
|
/// Unknown(N20)
|
||||||
|
/// Unknown(N19)
|
||||||
|
/// Unknown(N18)
|
||||||
|
/// Unknown(N15)
|
||||||
|
/// Unknown(N12)
|
||||||
|
/// Unknown(N11)
|
||||||
|
/// Unknown(N10)
|
||||||
|
/// Unknown(N9)
|
||||||
|
/// Unknown(N8)
|
||||||
|
/// Unknown(N5)
|
||||||
|
/// Unknown(N2)
|
||||||
|
/// Unknown(N1)
|
||||||
|
pub(crate) fn build_example_tree() -> Result<ActivityTree, Box<dyn std::error::Error>> {
|
||||||
|
let instructions = vec![
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 1,
|
||||||
|
parent_id: 0,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 2,
|
||||||
|
parent_id: 1,
|
||||||
|
is_match: true,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 3,
|
||||||
|
parent_id: 2,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 4,
|
||||||
|
parent_id: 2,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: true,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 5,
|
||||||
|
parent_id: 4,
|
||||||
|
is_match: true,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 6,
|
||||||
|
parent_id: 4,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 7,
|
||||||
|
parent_id: 1,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 8,
|
||||||
|
parent_id: 1,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 9,
|
||||||
|
parent_id: 8,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 10,
|
||||||
|
parent_id: 9,
|
||||||
|
is_match: true,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 11,
|
||||||
|
parent_id: 0,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 12,
|
||||||
|
parent_id: 11,
|
||||||
|
is_match: true,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 13,
|
||||||
|
parent_id: 12,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 14,
|
||||||
|
parent_id: 12,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: true,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 15,
|
||||||
|
parent_id: 14,
|
||||||
|
is_match: true,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 16,
|
||||||
|
parent_id: 14,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 17,
|
||||||
|
parent_id: 11,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 18,
|
||||||
|
parent_id: 11,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 19,
|
||||||
|
parent_id: 18,
|
||||||
|
is_match: false,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
BuildInstruction {
|
||||||
|
activity_id: 20,
|
||||||
|
parent_id: 19,
|
||||||
|
is_match: true,
|
||||||
|
is_transparent: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let activity_tree = build_activity_tree_from_instructions(&instructions, false)?;
|
||||||
|
|
||||||
|
Ok(activity_tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct BuildInstruction {
|
||||||
|
activity_id: u64,
|
||||||
|
parent_id: u64,
|
||||||
|
is_transparent: bool,
|
||||||
|
is_match: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_every_possible_addition<'old, 'new>(
|
||||||
|
old_state: &'old Vec<BuildInstruction>,
|
||||||
|
) -> Vec<Vec<BuildInstruction>> {
|
||||||
|
let mut out = Vec::new();
|
||||||
|
for is_transparent in [true, false] {
|
||||||
|
for is_match in [true, false] {
|
||||||
|
let next_activity_id = old_state.last().map(|bi| bi.activity_id).unwrap_or(0) + 1;
|
||||||
|
for parent_id in 0..next_activity_id {
|
||||||
|
let mut new_state = old_state.clone();
|
||||||
|
new_state.push(BuildInstruction {
|
||||||
|
activity_id: next_activity_id,
|
||||||
|
parent_id,
|
||||||
|
is_transparent,
|
||||||
|
is_match,
|
||||||
|
});
|
||||||
|
out.push(new_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn build_activity_tree_from_instructions(
|
||||||
|
instructions: &Vec<BuildInstruction>,
|
||||||
|
start_parents: bool,
|
||||||
|
) -> Result<ActivityTree, Box<dyn std::error::Error>> {
|
||||||
|
let mut activity_tree = ActivityTree::new();
|
||||||
|
for instruct in instructions {
|
||||||
|
match (instruct.is_transparent, instruct.is_match) {
|
||||||
|
(true, true) => {
|
||||||
|
activity_tree.add_activity(
|
||||||
|
instruct.activity_id,
|
||||||
|
instruct.parent_id,
|
||||||
|
Activity::Realize(ActivityRealize {
|
||||||
|
state: ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
// Walk up tree marking parents as match
|
||||||
|
if start_parents {
|
||||||
|
let mut parent_id = instruct.parent_id;
|
||||||
|
while parent_id > 0 {
|
||||||
|
let parent =
|
||||||
|
activity_tree.get_mut(&activity_tree.get_activity_id(parent_id)?);
|
||||||
|
parent.get_mut_activity().start();
|
||||||
|
parent_id = *parent.get_parent_id().deref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(true, false) => {
|
||||||
|
activity_tree.add_activity(
|
||||||
|
instruct.activity_id,
|
||||||
|
instruct.parent_id,
|
||||||
|
Activity::Realize(ActivityRealize {
|
||||||
|
state: ActivityState::Stopped,
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
(false, true) => {
|
||||||
|
activity_tree.add_activity(
|
||||||
|
instruct.activity_id,
|
||||||
|
instruct.parent_id,
|
||||||
|
Activity::Unknown(ActivityUnknown {
|
||||||
|
state: ActivityState::Started {
|
||||||
|
progress_numerator: 0,
|
||||||
|
progress_denominator: 0,
|
||||||
|
progress_running: 0,
|
||||||
|
progress_failed: 0,
|
||||||
|
},
|
||||||
|
text: format!("N{}", instruct.activity_id),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
// Walk up tree marking parents as match
|
||||||
|
if start_parents {
|
||||||
|
let mut parent_id = instruct.parent_id;
|
||||||
|
while parent_id > 0 {
|
||||||
|
let parent =
|
||||||
|
activity_tree.get_mut(&activity_tree.get_activity_id(parent_id)?);
|
||||||
|
parent.get_mut_activity().start();
|
||||||
|
parent_id = *parent.get_parent_id().deref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(false, false) => {
|
||||||
|
activity_tree.add_activity(
|
||||||
|
instruct.activity_id,
|
||||||
|
instruct.parent_id,
|
||||||
|
Activity::Unknown(ActivityUnknown {
|
||||||
|
state: ActivityState::Stopped,
|
||||||
|
text: format!("N{}", instruct.activity_id),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(activity_tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_match_predicate(entry: &ActivityTreeEntry) -> bool {
|
||||||
|
entry.get_activity().is_active()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_alive_predicate(_entry: &ActivityTreeEntry) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
55
src/nix_util/tree_iter/tests.rs
Normal file
55
src/nix_util/tree_iter/tests.rs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
use crate::nix_util::running_build::is_transparent_predicate;
|
||||||
|
use crate::nix_util::running_build::print_dag;
|
||||||
|
|
||||||
|
use super::ReverseTreeIter;
|
||||||
|
use super::get_draw_order;
|
||||||
|
use super::test_util::BuildInstruction;
|
||||||
|
use super::test_util::build_activity_tree_from_instructions;
|
||||||
|
use super::test_util::get_every_possible_addition;
|
||||||
|
|
||||||
|
fn compare_single_tree(
|
||||||
|
instructions: &Vec<BuildInstruction>,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let activity_tree = build_activity_tree_from_instructions(instructions, true)?;
|
||||||
|
let original_draw_order = get_draw_order(&activity_tree);
|
||||||
|
let reverse_draw_order = ReverseTreeIter::new(
|
||||||
|
&activity_tree,
|
||||||
|
None,
|
||||||
|
|entry| entry.get_activity().is_active(),
|
||||||
|
is_transparent_predicate,
|
||||||
|
|_entry| true,
|
||||||
|
)
|
||||||
|
.get_draw_order();
|
||||||
|
|
||||||
|
if original_draw_order != reverse_draw_order {
|
||||||
|
println!("Draw order mismatch!");
|
||||||
|
println!("Instructions: {:?}", instructions);
|
||||||
|
println!("Original: {:?}", original_draw_order);
|
||||||
|
println!("Reverse: {:?}", reverse_draw_order);
|
||||||
|
print_dag(&activity_tree, original_draw_order);
|
||||||
|
print_dag(&activity_tree, reverse_draw_order);
|
||||||
|
return Err("mismatch".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn reverse_tree_order_draw_order_iterative() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut prev_generation: Vec<Vec<BuildInstruction>> = Vec::new();
|
||||||
|
let mut current_generation: Vec<Vec<BuildInstruction>> = vec![vec![]];
|
||||||
|
|
||||||
|
// Iterate through every possible tree with N nodes.
|
||||||
|
for _ in 0..7 {
|
||||||
|
std::mem::swap(&mut prev_generation, &mut current_generation);
|
||||||
|
for old_state in prev_generation.drain(..) {
|
||||||
|
for new_state in get_every_possible_addition(&old_state) {
|
||||||
|
compare_single_tree(&new_state)?;
|
||||||
|
current_generation.push(new_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user