Switch to a new ActivityTree implementation.

This new implementation explicitly tracks the children of each node, eliminating many iterations through the full tree.
This commit is contained in:
Tom Alexander
2026-02-25 21:24:42 -05:00
parent 87fbaf4aeb
commit 2b7349a7ae
7 changed files with 743 additions and 719 deletions

View File

@@ -1,11 +1,6 @@
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use sqlx::Row;
use tokio::process::Child;
use tracing::error;
use tracing::warn;
use crate::Result;
use crate::database::db_handle::DbHandle;
@@ -13,20 +8,40 @@ use crate::nix_util::nix_output_stream::ActivityStartMessage;
use crate::nix_util::nix_output_stream::NixAction;
use crate::nix_util::nix_output_stream::NixOutputStream;
use crate::nix_util::output_stream::OutputStream;
use crate::nix_util::transparent_iter::TransparentIter;
use super::activity::Activity;
use super::activity::ActivityBuild;
use super::activity::ActivityBuildWaiting;
use super::activity::ActivityBuilds;
use super::activity::ActivityCopyPath;
use super::activity::ActivityCopyPaths;
use super::activity::ActivityFetchTree;
use super::activity::ActivityFileTransfer;
use super::activity::ActivityOptimizeStore;
use super::activity::ActivityPostBuildHook;
use super::activity::ActivityQueryPathInfo;
use super::activity::ActivityRealize;
use super::activity::ActivityState;
use super::activity::ActivitySubstitute;
use super::activity::ActivityUnknown;
use super::activity::ActivityVerifyPaths;
use super::activity_tree::ActivityId;
use super::activity_tree::ActivityTree;
use super::activity_tree::ActivityTreeEntry;
use super::nix_output_stream::ActivityResultMessage;
use super::nix_output_stream::NixMessage;
pub(crate) struct RunningBuild<'db> {
db_handle: &'db DbHandle,
activity_tree: BTreeMap<u64, Activity>,
activity_tree: ActivityTree,
}
impl<'db> RunningBuild<'db> {
pub(crate) fn new(db_handle: &'db DbHandle) -> Result<Self> {
Ok(RunningBuild {
db_handle,
activity_tree: BTreeMap::new(),
activity_tree: ActivityTree::new(),
})
}
@@ -98,135 +113,157 @@ impl<'db> RunningBuild<'db> {
// For now we can ignore the messages.
}
NixAction::Start(activity_start_message) => {
let id = activity_start_message.get_id();
let entry = self.activity_tree.entry(id);
let entry = match entry {
std::collections::btree_map::Entry::Vacant(vacant_entry) => vacant_entry,
std::collections::btree_map::Entry::Occupied(_occupied_entry) => {
panic!("Started an already started activity: {id}.")
}
};
match activity_start_message {
ActivityStartMessage::Unknown(activity_start_unknown) => {
entry.insert(Activity::Unknown(ActivityUnknown {
id: activity_start_unknown.id,
parent: activity_start_unknown.parent,
state: ActivityState::default(),
}));
self.activity_tree.add_activity(
activity_start_unknown.id,
activity_start_unknown.parent,
Activity::Unknown(ActivityUnknown {
state: ActivityState::default(),
text: activity_start_unknown.text,
}),
)?;
}
ActivityStartMessage::CopyPath(activity_start_copy_path) => {
entry.insert(Activity::CopyPath(ActivityCopyPath {
id: activity_start_copy_path.id,
parent: activity_start_copy_path.parent,
state: ActivityState::default(),
}));
self.activity_tree.add_activity(
activity_start_copy_path.id,
activity_start_copy_path.parent,
Activity::CopyPath(ActivityCopyPath {
state: ActivityState::default(),
missing_path: activity_start_copy_path.missing_path,
source: activity_start_copy_path.source,
destination: activity_start_copy_path.destination,
}),
)?;
}
ActivityStartMessage::FileTransfer(activity_start_file_transfer) => {
entry.insert(Activity::FileTransfer(ActivityFileTransfer {
id: activity_start_file_transfer.id,
parent: activity_start_file_transfer.parent,
state: ActivityState::default(),
url: activity_start_file_transfer.url,
}));
self.activity_tree.add_activity(
activity_start_file_transfer.id,
activity_start_file_transfer.parent,
Activity::FileTransfer(ActivityFileTransfer {
state: ActivityState::default(),
url: activity_start_file_transfer.url,
}),
)?;
}
ActivityStartMessage::Realize(activity_start_realize) => {
entry.insert(Activity::Realize(ActivityRealize {
id: activity_start_realize.id,
parent: activity_start_realize.parent,
state: ActivityState::default(),
}));
self.activity_tree.add_activity(
activity_start_realize.id,
activity_start_realize.parent,
Activity::Realize(ActivityRealize {
state: ActivityState::default(),
}),
)?;
}
ActivityStartMessage::CopyPaths(activity_start_copy_paths) => {
entry.insert(Activity::CopyPaths(ActivityCopyPaths {
id: activity_start_copy_paths.id,
parent: activity_start_copy_paths.parent,
state: ActivityState::default(),
}));
self.activity_tree.add_activity(
activity_start_copy_paths.id,
activity_start_copy_paths.parent,
Activity::CopyPaths(ActivityCopyPaths {
state: ActivityState::default(),
text: activity_start_copy_paths.text,
}),
)?;
}
ActivityStartMessage::Builds(activity_start_builds) => {
entry.insert(Activity::Builds(ActivityBuilds {
id: activity_start_builds.id,
parent: activity_start_builds.parent,
state: ActivityState::default(),
}));
self.activity_tree.add_activity(
activity_start_builds.id,
activity_start_builds.parent,
Activity::Builds(ActivityBuilds {
state: ActivityState::default(),
}),
)?;
}
ActivityStartMessage::Build(activity_start_build) => {
entry.insert(Activity::Build(ActivityBuild {
id: activity_start_build.id,
parent: activity_start_build.parent,
state: ActivityState::default(),
drv_path: activity_start_build.drv_path,
machine_name: if activity_start_build.machine_name.len() > 0 {
Some(activity_start_build.machine_name)
} else {
None
},
}));
self.activity_tree.add_activity(
activity_start_build.id,
activity_start_build.parent,
Activity::Build(ActivityBuild {
state: ActivityState::default(),
drv_path: activity_start_build.drv_path,
machine_name: if activity_start_build.machine_name.len() > 0 {
Some(activity_start_build.machine_name)
} else {
None
},
}),
)?;
}
ActivityStartMessage::OptimizeStore(activity_start_optimize_store) => {
entry.insert(Activity::OptimizeStore(ActivityOptimizeStore {
id: activity_start_optimize_store.id,
parent: activity_start_optimize_store.parent,
state: ActivityState::default(),
}));
self.activity_tree.add_activity(
activity_start_optimize_store.id,
activity_start_optimize_store.parent,
Activity::OptimizeStore(ActivityOptimizeStore {
state: ActivityState::default(),
}),
)?;
}
ActivityStartMessage::VerifyPaths(activity_start_verify_paths) => {
entry.insert(Activity::VerifyPaths(ActivityVerifyPaths {
id: activity_start_verify_paths.id,
parent: activity_start_verify_paths.parent,
state: ActivityState::default(),
}));
self.activity_tree.add_activity(
activity_start_verify_paths.id,
activity_start_verify_paths.parent,
Activity::VerifyPaths(ActivityVerifyPaths {
state: ActivityState::default(),
}),
)?;
}
ActivityStartMessage::Substitute(activity_start_substitute) => {
entry.insert(Activity::Substitute(ActivitySubstitute {
id: activity_start_substitute.id,
parent: activity_start_substitute.parent,
state: ActivityState::default(),
}));
self.activity_tree.add_activity(
activity_start_substitute.id,
activity_start_substitute.parent,
Activity::Substitute(ActivitySubstitute {
state: ActivityState::default(),
}),
)?;
}
ActivityStartMessage::QueryPathInfo(activity_start_query_path_info) => {
entry.insert(Activity::QueryPathInfo(ActivityQueryPathInfo {
id: activity_start_query_path_info.id,
parent: activity_start_query_path_info.parent,
state: ActivityState::default(),
}));
self.activity_tree.add_activity(
activity_start_query_path_info.id,
activity_start_query_path_info.parent,
Activity::QueryPathInfo(ActivityQueryPathInfo {
state: ActivityState::default(),
}),
)?;
}
ActivityStartMessage::PostBuildHook(activity_start_post_build_hook) => {
entry.insert(Activity::PostBuildHook(ActivityPostBuildHook {
id: activity_start_post_build_hook.id,
parent: activity_start_post_build_hook.parent,
state: ActivityState::default(),
}));
self.activity_tree.add_activity(
activity_start_post_build_hook.id,
activity_start_post_build_hook.parent,
Activity::PostBuildHook(ActivityPostBuildHook {
state: ActivityState::default(),
}),
)?;
}
ActivityStartMessage::BuildWaiting(activity_start_build_waiting) => {
entry.insert(Activity::BuildWaiting(ActivityBuildWaiting {
id: activity_start_build_waiting.id,
state: ActivityState::default(),
}));
self.activity_tree.add_activity(
activity_start_build_waiting.id,
0,
Activity::BuildWaiting(ActivityBuildWaiting {
state: ActivityState::default(),
text: activity_start_build_waiting.text,
drv_path: activity_start_build_waiting.drv_path,
path_resolved: activity_start_build_waiting.path_resolved,
}),
)?;
}
ActivityStartMessage::FetchTree(activity_start_fetch_tree) => {
entry.insert(Activity::FetchTree(ActivityFetchTree {
id: activity_start_fetch_tree.id,
parent: activity_start_fetch_tree.parent,
state: ActivityState::default(),
}));
self.activity_tree.add_activity(
activity_start_fetch_tree.id,
activity_start_fetch_tree.parent,
Activity::FetchTree(ActivityFetchTree {
state: ActivityState::default(),
}),
)?;
}
};
self.print_current_status();
}
NixAction::Stop(stop_message) => {
let entry = self.activity_tree.entry(stop_message.id);
match entry {
std::collections::btree_map::Entry::Vacant(_vacant_entry) => {
panic!(
"Stopped an activity that is not in the tree: {}",
stop_message.id
);
}
std::collections::btree_map::Entry::Occupied(mut occupied_entry) => {
occupied_entry.get_mut().stop();
}
};
let activity = self
.activity_tree
.get_activity_id(stop_message.id)
.map(|activity_id| self.activity_tree.get_mut(&activity_id))?;
activity.get_mut_activity().stop();
self.print_current_status();
// println!("{}", serde_json::to_string(&message)?);
}
@@ -302,11 +339,9 @@ impl<'db> RunningBuild<'db> {
} else {
"𜸛"
};
let activity = self
.activity_tree
.get(&dag_entry.activity_id)
.expect("Activity should exist in the tree.");
let activity = self.activity_tree.get(&dag_entry.activity_id);
let display_name = activity
.get_activity()
.display_name()
.expect("Currently we always return a display name.");
let activity_id = activity.get_activity_id();
@@ -321,22 +356,13 @@ impl<'db> RunningBuild<'db> {
}
fn get_draw_order(&self) -> Vec<DrawDagEntry> {
let active_activity_ids: BTreeSet<u64> = self
.activity_tree
.iter()
.filter(|(activity_id, activity)| activity.is_active())
.flat_map(|(activity_id, activity)| {
PathToRootIter::new(&self.activity_tree, *activity_id)
})
.collect();
let mut draw_order: Vec<DrawDagEntry> = Vec::new();
let mut stack: Vec<DrawStackEntry> = self
.get_children_in_order(0)
.filter_map(|child_id| {
if active_activity_ids.contains(&child_id) {
.get_children_in_order(self.activity_tree.get_root_id())
.filter_map(|child| {
if child.get_activity().is_active() {
Some(DrawStackEntry::HasNotVisitedChildren(DrawDagEntry {
activity_id: child_id,
activity_id: child.get_activity_id().clone(),
depth: Vec::new(),
has_later_siblings: true,
}))
@@ -357,14 +383,19 @@ impl<'db> RunningBuild<'db> {
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;
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<u64> = self
let children: Vec<ActivityId> = self
.get_children_in_order(current_id)
.into_iter()
.filter(|child_id| active_activity_ids.contains(child_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| {
@@ -389,35 +420,16 @@ impl<'db> RunningBuild<'db> {
draw_order
}
fn get_children_in_order(&self, parent_id: u64) -> impl Iterator<Item = u64> {
let child_ids = self
.activity_tree
fn get_children_in_order(
&self,
parent_id: ActivityId,
) -> impl Iterator<Item = &ActivityTreeEntry> {
let parent = self.activity_tree.get(&parent_id);
parent
.get_child_ids()
.iter()
.filter(move |(_child_id, activity)| activity.get_parent_id() == parent_id)
.flat_map(|(_child_id, activity)| TransparentIter::new(&self.activity_tree, activity))
.map(|activity| activity.get_activity_id());
child_ids
}
}
enum ActivityState {
Started {
progress_numerator: u64,
progress_denominator: u64,
progress_running: u64,
progress_failed: u64,
},
Stopped,
}
impl Default for ActivityState {
fn default() -> Self {
ActivityState::Started {
progress_numerator: 0,
progress_denominator: 0,
progress_running: 0,
progress_failed: 0,
}
.map(|child_id| self.activity_tree.get(child_id))
.flat_map(|child| TransparentIter::new(&self.activity_tree, child))
}
}
@@ -427,7 +439,7 @@ enum DrawStackEntry {
}
struct DrawDagEntry {
activity_id: u64,
activity_id: ActivityId,
depth: Vec<bool>,
has_later_siblings: bool,
}
@@ -444,569 +456,3 @@ impl DrawStackEntry {
};
}
}
struct PathToRootIter<'tree> {
activity_tree: &'tree BTreeMap<u64, Activity>,
next_activity_id: u64,
}
impl<'tree> PathToRootIter<'tree> {
fn new(
activity_tree: &'tree BTreeMap<u64, Activity>,
next_activity_id: u64,
) -> PathToRootIter<'tree> {
PathToRootIter {
activity_tree,
next_activity_id,
}
}
}
impl<'tree> Iterator for PathToRootIter<'tree> {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
if self.next_activity_id == 0 {
return None;
}
let next_activity = self.activity_tree.get(&self.next_activity_id).expect(
"There shouldn't be a reference to an activity that does not exist in the tree.",
);
self.next_activity_id = next_activity.get_parent_id();
Some(next_activity.get_activity_id())
}
}
/// An iterator that returns either the original activity if it is not transparent, or if it is transparent, the earliest non-transparent children.
struct TransparentIter<'tree> {
activity_tree: &'tree BTreeMap<u64, Activity>,
parent: &'tree Activity,
child_index: usize,
}
impl<'tree> TransparentIter<'tree> {
fn new(
activity_tree: &'tree BTreeMap<u64, Activity>,
parent: &'tree Activity,
) -> TransparentIter<'tree> {
TransparentIter {
activity_tree,
parent,
child_index: 0,
}
}
}
impl<'tree> Iterator for TransparentIter<'tree> {
type Item = &'tree Activity;
fn next(&mut self) -> Option<Self::Item> {
if self.child_index == usize::max_value() {
return None;
}
if !self.parent.is_transparent() {
self.child_index = usize::max_value();
return Some(self.parent);
}
let mut visible_children_remaining = self.child_index;
for (_child_id, child) in self.activity_tree.iter() {
if child.get_parent_id() != self.parent.get_activity_id() {
continue;
}
for visible_child in TransparentIter::new(self.activity_tree, child) {
if visible_children_remaining > 0 {
visible_children_remaining -= 1;
} else {
self.child_index += 1;
return Some(visible_child);
}
}
}
return None;
}
}
#[repr(u8)]
enum Activity {
Unknown(ActivityUnknown),
CopyPath(ActivityCopyPath),
FileTransfer(ActivityFileTransfer),
Realize(ActivityRealize),
CopyPaths(ActivityCopyPaths),
Builds(ActivityBuilds),
Build(ActivityBuild),
OptimizeStore(ActivityOptimizeStore),
VerifyPaths(ActivityVerifyPaths),
Substitute(ActivitySubstitute),
QueryPathInfo(ActivityQueryPathInfo),
PostBuildHook(ActivityPostBuildHook),
BuildWaiting(ActivityBuildWaiting),
FetchTree(ActivityFetchTree),
}
impl Activity {
fn stop(&mut self) -> () {
match self {
Activity::Unknown(activity_unknown) => {
activity_unknown.state = ActivityState::Stopped;
}
Activity::CopyPath(activity_copy_path) => {
activity_copy_path.state = ActivityState::Stopped;
}
Activity::FileTransfer(activity_file_transfer) => {
activity_file_transfer.state = ActivityState::Stopped;
}
Activity::Realize(activity_realize) => {
activity_realize.state = ActivityState::Stopped;
}
Activity::CopyPaths(activity_copy_paths) => {
activity_copy_paths.state = ActivityState::Stopped;
}
Activity::Builds(activity_builds) => {
activity_builds.state = ActivityState::Stopped;
}
Activity::Build(activity_build) => {
activity_build.state = ActivityState::Stopped;
}
Activity::OptimizeStore(activity_optimize_store) => {
activity_optimize_store.state = ActivityState::Stopped;
}
Activity::VerifyPaths(activity_verify_paths) => {
activity_verify_paths.state = ActivityState::Stopped;
}
Activity::Substitute(activity_substitute) => {
activity_substitute.state = ActivityState::Stopped;
}
Activity::QueryPathInfo(activity_query_path_info) => {
activity_query_path_info.state = ActivityState::Stopped;
}
Activity::PostBuildHook(activity_post_build_hook) => {
activity_post_build_hook.state = ActivityState::Stopped;
}
Activity::BuildWaiting(activity_build_waiting) => {
activity_build_waiting.state = ActivityState::Stopped;
}
Activity::FetchTree(activity_fetch_tree) => {
activity_fetch_tree.state = ActivityState::Stopped;
}
}
}
fn is_active(&self) -> bool {
match self {
Activity::Unknown(activity_unknown) => {
matches!(activity_unknown.state, ActivityState::Started { .. })
}
Activity::CopyPath(activity_copy_path) => {
matches!(activity_copy_path.state, ActivityState::Started { .. })
}
Activity::FileTransfer(activity_file_transfer) => {
matches!(activity_file_transfer.state, ActivityState::Started { .. })
}
Activity::Realize(activity_realize) => {
matches!(activity_realize.state, ActivityState::Started { .. })
}
Activity::CopyPaths(activity_copy_paths) => {
matches!(activity_copy_paths.state, ActivityState::Started { .. })
}
Activity::Builds(activity_builds) => {
matches!(activity_builds.state, ActivityState::Started { .. })
}
Activity::Build(activity_build) => {
matches!(activity_build.state, ActivityState::Started { .. })
}
Activity::OptimizeStore(activity_optimize_store) => {
matches!(activity_optimize_store.state, ActivityState::Started { .. })
}
Activity::VerifyPaths(activity_verify_paths) => {
matches!(activity_verify_paths.state, ActivityState::Started { .. })
}
Activity::Substitute(activity_substitute) => {
matches!(activity_substitute.state, ActivityState::Started { .. })
}
Activity::QueryPathInfo(activity_query_path_info) => {
matches!(
activity_query_path_info.state,
ActivityState::Started { .. }
)
}
Activity::PostBuildHook(activity_post_build_hook) => {
matches!(
activity_post_build_hook.state,
ActivityState::Started { .. }
)
}
Activity::BuildWaiting(activity_build_waiting) => {
matches!(activity_build_waiting.state, ActivityState::Started { .. })
}
Activity::FetchTree(activity_fetch_tree) => {
matches!(activity_fetch_tree.state, ActivityState::Started { .. })
}
}
}
fn is_transparent(&self) -> bool {
match self {
Activity::Unknown(_activity_unknown) => false,
Activity::CopyPath(_activity_copy_path) => false,
Activity::FileTransfer(_activity_file_transfer) => false,
Activity::Realize(_activity_realize) => false,
Activity::CopyPaths(_activity_copy_paths) => false,
Activity::Builds(_activity_builds) => false,
Activity::Build(_activity_build) => true,
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 display_name(&self) -> Option<Cow<'_, str>> {
match self {
Activity::Unknown(activity_unknown) => {
warn!("Unimplemented display_name Unknown");
// TODO
Some(Cow::Borrowed("Unknown"))
}
Activity::CopyPath(activity_copy_path) => {
warn!("Unimplemented display_name CopyPath");
// TODO
Some(Cow::Borrowed("CopyPath"))
}
Activity::FileTransfer(activity_file_transfer) => Some(Cow::Owned(format!(
"FileTransfer({})",
activity_file_transfer.url
))),
Activity::Realize(activity_realize) => {
// TODO what is a good display name for this? Maybe Realize(<parent display name>) ?
Some(Cow::Borrowed("Realize"))
}
Activity::CopyPaths(activity_copy_paths) => {
warn!("Unimplemented display_name CopyPaths");
// TODO
Some(Cow::Borrowed("CopyPaths"))
}
Activity::Builds(activity_builds) => {
warn!("Unimplemented display_name Builds");
// TODO
Some(Cow::Borrowed("Builds"))
}
Activity::Build(activity_build) => {
if let Some(machine_name) = &activity_build.machine_name {
Some(Cow::Owned(format!(
"Build({}@{machine_name})",
activity_build.drv_path
)))
} else {
Some(Cow::Owned(format!("Build({})", activity_build.drv_path)))
}
}
Activity::OptimizeStore(activity_optimize_store) => {
warn!("Unimplemented display_name OptimizeStore");
// TODO
Some(Cow::Borrowed("OptimizeStore"))
}
Activity::VerifyPaths(activity_verify_paths) => {
warn!("Unimplemented display_name VerifyPaths");
// TODO
Some(Cow::Borrowed("VerifyPaths"))
}
Activity::Substitute(activity_substitute) => {
warn!("Unimplemented display_name Substitute");
// TODO
Some(Cow::Borrowed("Substitute"))
}
Activity::QueryPathInfo(activity_query_path_info) => {
warn!("Unimplemented display_name QueryPathInfo");
// TODO
Some(Cow::Borrowed("QueryPathInfo"))
}
Activity::PostBuildHook(activity_post_build_hook) => {
warn!("Unimplemented display_name PostBuildHook");
// TODO
Some(Cow::Borrowed("PostBuildHook"))
}
Activity::BuildWaiting(activity_build_waiting) => {
warn!("Unimplemented display_name BuildWaiting");
// TODO
Some(Cow::Borrowed("BuildWaiting"))
}
Activity::FetchTree(activity_fetch_tree) => {
warn!("Unimplemented display_name FetchTree");
// TODO
Some(Cow::Borrowed("FetchTree"))
}
}
}
}
struct ActivityUnknown {
id: u64,
parent: u64,
state: ActivityState,
}
struct ActivityCopyPath {
id: u64,
parent: u64,
state: ActivityState,
}
struct ActivityFileTransfer {
id: u64,
parent: u64,
state: ActivityState,
url: String,
}
struct ActivityRealize {
id: u64,
parent: u64,
state: ActivityState,
}
struct ActivityCopyPaths {
id: u64,
parent: u64,
state: ActivityState,
}
struct ActivityBuilds {
id: u64,
parent: u64,
state: ActivityState,
}
struct ActivityBuild {
id: u64,
parent: u64,
state: ActivityState,
drv_path: String,
machine_name: Option<String>,
}
struct ActivityOptimizeStore {
id: u64,
parent: u64,
state: ActivityState,
}
struct ActivityVerifyPaths {
id: u64,
parent: u64,
state: ActivityState,
}
struct ActivitySubstitute {
id: u64,
parent: u64,
state: ActivityState,
}
struct ActivityQueryPathInfo {
id: u64,
parent: u64,
state: ActivityState,
}
struct ActivityPostBuildHook {
id: u64,
parent: u64,
state: ActivityState,
}
struct ActivityBuildWaiting {
id: u64,
state: ActivityState,
}
struct ActivityFetchTree {
id: u64,
parent: u64,
state: ActivityState,
}
trait ActivityTreeEntry {
fn get_activity_id(&self) -> u64;
fn get_parent_id(&self) -> u64;
}
impl ActivityTreeEntry for Activity {
fn get_activity_id(&self) -> u64 {
match self {
Activity::Unknown(activity_unknown) => activity_unknown.get_activity_id(),
Activity::CopyPath(activity_copy_path) => activity_copy_path.get_activity_id(),
Activity::FileTransfer(activity_file_transfer) => {
activity_file_transfer.get_activity_id()
}
Activity::Realize(activity_realize) => activity_realize.get_activity_id(),
Activity::CopyPaths(activity_copy_paths) => activity_copy_paths.get_activity_id(),
Activity::Builds(activity_builds) => activity_builds.get_activity_id(),
Activity::Build(activity_build) => activity_build.get_activity_id(),
Activity::OptimizeStore(activity_optimize_store) => {
activity_optimize_store.get_activity_id()
}
Activity::VerifyPaths(activity_verify_paths) => activity_verify_paths.get_activity_id(),
Activity::Substitute(activity_substitute) => activity_substitute.get_activity_id(),
Activity::QueryPathInfo(activity_query_path_info) => {
activity_query_path_info.get_activity_id()
}
Activity::PostBuildHook(activity_post_build_hook) => {
activity_post_build_hook.get_activity_id()
}
Activity::BuildWaiting(activity_build_waiting) => {
activity_build_waiting.get_activity_id()
}
Activity::FetchTree(activity_fetch_tree) => activity_fetch_tree.get_activity_id(),
}
}
fn get_parent_id(&self) -> u64 {
match self {
Activity::Unknown(activity_unknown) => activity_unknown.get_parent_id(),
Activity::CopyPath(activity_copy_path) => activity_copy_path.get_parent_id(),
Activity::FileTransfer(activity_file_transfer) => {
activity_file_transfer.get_parent_id()
}
Activity::Realize(activity_realize) => activity_realize.get_parent_id(),
Activity::CopyPaths(activity_copy_paths) => activity_copy_paths.get_parent_id(),
Activity::Builds(activity_builds) => activity_builds.get_parent_id(),
Activity::Build(activity_build) => activity_build.get_parent_id(),
Activity::OptimizeStore(activity_optimize_store) => {
activity_optimize_store.get_parent_id()
}
Activity::VerifyPaths(activity_verify_paths) => activity_verify_paths.get_parent_id(),
Activity::Substitute(activity_substitute) => activity_substitute.get_parent_id(),
Activity::QueryPathInfo(activity_query_path_info) => {
activity_query_path_info.get_parent_id()
}
Activity::PostBuildHook(activity_post_build_hook) => {
activity_post_build_hook.get_parent_id()
}
Activity::BuildWaiting(activity_build_waiting) => {
activity_build_waiting.get_parent_id()
}
Activity::FetchTree(activity_fetch_tree) => activity_fetch_tree.get_parent_id(),
}
}
}
impl ActivityTreeEntry for ActivityUnknown {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}
impl ActivityTreeEntry for ActivityCopyPath {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}
impl ActivityTreeEntry for ActivityFileTransfer {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}
impl ActivityTreeEntry for ActivityRealize {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}
impl ActivityTreeEntry for ActivityCopyPaths {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}
impl ActivityTreeEntry for ActivityBuilds {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}
impl ActivityTreeEntry for ActivityBuild {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}
impl ActivityTreeEntry for ActivityOptimizeStore {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}
impl ActivityTreeEntry for ActivityVerifyPaths {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}
impl ActivityTreeEntry for ActivitySubstitute {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}
impl ActivityTreeEntry for ActivityQueryPathInfo {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}
impl ActivityTreeEntry for ActivityPostBuildHook {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}
impl ActivityTreeEntry for ActivityBuildWaiting {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
// Parent seems to always be zero?
0
}
}
impl ActivityTreeEntry for ActivityFetchTree {
fn get_activity_id(&self) -> u64 {
self.id
}
fn get_parent_id(&self) -> u64 {
self.parent
}
}