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:
@@ -3,6 +3,9 @@ use std::num::TryFromIntError;
|
|||||||
use std::str::Utf8Error;
|
use std::str::Utf8Error;
|
||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
|
|
||||||
|
use crate::nix_util::ActivityIdAlreadyInTreeError;
|
||||||
|
use crate::nix_util::ActivityIdNotInTreeError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum CustomError {
|
pub(crate) enum CustomError {
|
||||||
Static(#[allow(dead_code)] &'static str),
|
Static(#[allow(dead_code)] &'static str),
|
||||||
@@ -19,6 +22,8 @@ pub(crate) enum CustomError {
|
|||||||
Migrate(#[allow(dead_code)] sqlx::migrate::MigrateError),
|
Migrate(#[allow(dead_code)] sqlx::migrate::MigrateError),
|
||||||
Sql(#[allow(dead_code)] sqlx::Error),
|
Sql(#[allow(dead_code)] sqlx::Error),
|
||||||
TryFromIntError(#[allow(dead_code)] TryFromIntError),
|
TryFromIntError(#[allow(dead_code)] TryFromIntError),
|
||||||
|
ActivityIdNotInTreeError(#[allow(dead_code)] ActivityIdNotInTreeError),
|
||||||
|
ActivityIdAlreadyInTreeError(#[allow(dead_code)] ActivityIdAlreadyInTreeError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for CustomError {
|
impl Display for CustomError {
|
||||||
@@ -110,3 +115,15 @@ impl From<TryFromIntError> for CustomError {
|
|||||||
CustomError::TryFromIntError(value)
|
CustomError::TryFromIntError(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ActivityIdNotInTreeError> for CustomError {
|
||||||
|
fn from(value: ActivityIdNotInTreeError) -> Self {
|
||||||
|
CustomError::ActivityIdNotInTreeError(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ActivityIdAlreadyInTreeError> for CustomError {
|
||||||
|
fn from(value: ActivityIdAlreadyInTreeError) -> Self {
|
||||||
|
CustomError::ActivityIdAlreadyInTreeError(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
284
src/nix_util/activity.rs
Normal file
284
src/nix_util/activity.rs
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
pub(crate) enum Activity {
|
||||||
|
Root(ActivityRoot),
|
||||||
|
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 {
|
||||||
|
pub(crate) fn stop(&mut self) -> () {
|
||||||
|
match self {
|
||||||
|
Activity::Root(_activity_root) => {
|
||||||
|
panic!("Attempted to start root activity.");
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_active(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Activity::Root(_activity_root) => true,
|
||||||
|
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 { .. })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>> {
|
||||||
|
match self {
|
||||||
|
Activity::Root(_activity_root) => {
|
||||||
|
warn!("Unexpected display of root activity.");
|
||||||
|
Some(Cow::Borrowed("Root"))
|
||||||
|
}
|
||||||
|
Activity::Unknown(activity_unknown) => {
|
||||||
|
Some(Cow::Owned(format!("Unknown({})", activity_unknown.text)))
|
||||||
|
}
|
||||||
|
Activity::CopyPath(activity_copy_path) => Some(Cow::Owned(format!(
|
||||||
|
"CopyPath({} | {} -> {})",
|
||||||
|
activity_copy_path.missing_path,
|
||||||
|
activity_copy_path.source,
|
||||||
|
activity_copy_path.destination
|
||||||
|
))),
|
||||||
|
Activity::FileTransfer(activity_file_transfer) => Some(Cow::Owned(format!(
|
||||||
|
"FileTransfer({})",
|
||||||
|
activity_file_transfer.url
|
||||||
|
))),
|
||||||
|
Activity::Realize(_activity_realize) => Some(Cow::Borrowed("Realize")),
|
||||||
|
Activity::CopyPaths(activity_copy_paths) => Some(Cow::Owned(format!(
|
||||||
|
"CopyPaths({})",
|
||||||
|
activity_copy_paths.text
|
||||||
|
))),
|
||||||
|
Activity::Builds(_activity_builds) => 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) => {
|
||||||
|
Some(Cow::Borrowed("OptimizeStore"))
|
||||||
|
}
|
||||||
|
Activity::VerifyPaths(_activity_verify_paths) => Some(Cow::Borrowed("VerifyPaths")),
|
||||||
|
Activity::Substitute(_activity_substitute) => Some(Cow::Borrowed("Substitute")),
|
||||||
|
Activity::QueryPathInfo(_activity_query_path_info) => {
|
||||||
|
Some(Cow::Borrowed("QueryPathInfo"))
|
||||||
|
}
|
||||||
|
Activity::PostBuildHook(_activity_post_build_hook) => {
|
||||||
|
Some(Cow::Borrowed("PostBuildHook"))
|
||||||
|
}
|
||||||
|
Activity::BuildWaiting(activity_build_waiting) => Some(Cow::Owned(format!(
|
||||||
|
"BuildWaiting({:?} | {:?} | {})",
|
||||||
|
activity_build_waiting.drv_path,
|
||||||
|
activity_build_waiting.path_resolved,
|
||||||
|
activity_build_waiting.text
|
||||||
|
))),
|
||||||
|
Activity::FetchTree(_activity_fetch_tree) => Some(Cow::Borrowed("FetchTree")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct ActivityRoot {}
|
||||||
|
pub(crate) struct ActivityUnknown {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
pub(crate) text: String,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivityCopyPath {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
pub(crate) missing_path: String,
|
||||||
|
|
||||||
|
/// The machine with the file(s)
|
||||||
|
pub(crate) source: String,
|
||||||
|
|
||||||
|
/// The machine that is receiving the file(s)
|
||||||
|
pub(crate) destination: String,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivityFileTransfer {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
pub(crate) url: String,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivityRealize {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivityCopyPaths {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
pub(crate) text: String,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivityBuilds {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivityBuild {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
pub(crate) drv_path: String,
|
||||||
|
pub(crate) machine_name: Option<String>,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivityOptimizeStore {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivityVerifyPaths {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivitySubstitute {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivityQueryPathInfo {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivityPostBuildHook {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivityBuildWaiting {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
pub(crate) text: String,
|
||||||
|
pub(crate) drv_path: Option<String>,
|
||||||
|
pub(crate) path_resolved: Option<String>,
|
||||||
|
}
|
||||||
|
pub(crate) struct ActivityFetchTree {
|
||||||
|
pub(crate) state: ActivityState,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
180
src/nix_util/activity_tree.rs
Normal file
180
src/nix_util/activity_tree.rs
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
use crate::Result;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use super::activity::Activity;
|
||||||
|
use super::activity::ActivityRoot;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct ActivityId {
|
||||||
|
id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActivityId {
|
||||||
|
fn new(id: u64) -> ActivityId {
|
||||||
|
ActivityId { id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for ActivityId {
|
||||||
|
type Target = u64;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ActivityId {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
Display::fmt(&**self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct ActivityTree {
|
||||||
|
activities: BTreeMap<u64, ActivityTreeEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActivityTree {
|
||||||
|
pub(crate) fn new() -> ActivityTree {
|
||||||
|
let mut activities = BTreeMap::new();
|
||||||
|
activities.insert(
|
||||||
|
0,
|
||||||
|
ActivityTreeEntry {
|
||||||
|
id: ActivityId::new(0),
|
||||||
|
parent_id: ActivityId::new(0),
|
||||||
|
child_ids: Vec::new(),
|
||||||
|
activity: Activity::Root(ActivityRoot {}),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
ActivityTree { activities }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_activity(
|
||||||
|
&mut self,
|
||||||
|
activity_id: u64,
|
||||||
|
parent_id: u64,
|
||||||
|
activity: Activity,
|
||||||
|
) -> Result<&ActivityTreeEntry> {
|
||||||
|
// The activity_id is not yet in the tree, so we can't use get_activity_id.
|
||||||
|
let activity_id = ActivityId::new(activity_id);
|
||||||
|
let parent_id = self.get_activity_id(parent_id)?;
|
||||||
|
match self.activities.entry(activity_id.id) {
|
||||||
|
std::collections::btree_map::Entry::Vacant(vacant_entry) => {
|
||||||
|
vacant_entry.insert(ActivityTreeEntry {
|
||||||
|
id: activity_id.clone(),
|
||||||
|
parent_id: parent_id.clone(),
|
||||||
|
child_ids: Vec::new(),
|
||||||
|
activity,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
std::collections::btree_map::Entry::Occupied(_occupied_entry) => {
|
||||||
|
return Err(ActivityIdAlreadyInTreeError::new(*activity_id).into());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.get_mut(&parent_id).child_ids.push(activity_id.clone());
|
||||||
|
let tree_entry = self
|
||||||
|
.activities
|
||||||
|
.get(&*activity_id)
|
||||||
|
.expect("We just created this entry so it must exist.");
|
||||||
|
|
||||||
|
Ok(tree_entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_activity_id(&self, activity_id: u64) -> Result<ActivityId> {
|
||||||
|
if activity_id == 0 || self.activities.contains_key(&activity_id) {
|
||||||
|
Ok(ActivityId::new(activity_id))
|
||||||
|
} else {
|
||||||
|
Err(ActivityIdNotInTreeError::new(activity_id).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_root_id(&self) -> ActivityId {
|
||||||
|
// The root always exists, so there is no need to check.
|
||||||
|
ActivityId::new(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get(&self, activity_id: &ActivityId) -> &ActivityTreeEntry {
|
||||||
|
self.activities
|
||||||
|
.get(activity_id)
|
||||||
|
.expect("You cannot create an ActivityId if the activity is not in the tree.")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_mut(&mut self, activity_id: &ActivityId) -> &mut ActivityTreeEntry {
|
||||||
|
self.activities
|
||||||
|
.get_mut(activity_id)
|
||||||
|
.expect("You cannot create an ActivityId if the activity is not in the tree.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct ActivityTreeEntry {
|
||||||
|
id: ActivityId,
|
||||||
|
parent_id: ActivityId,
|
||||||
|
child_ids: Vec<ActivityId>,
|
||||||
|
activity: Activity,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActivityTreeEntry {
|
||||||
|
pub(crate) fn get_activity_id(&self) -> &ActivityId {
|
||||||
|
&self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_parent_id(&self) -> &ActivityId {
|
||||||
|
&self.parent_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_activity(&self) -> &Activity {
|
||||||
|
&self.activity
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_mut_activity(&mut self) -> &mut Activity {
|
||||||
|
&mut self.activity
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_child_ids(&self) -> &Vec<ActivityId> {
|
||||||
|
&self.child_ids
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn iter_children<'tree>(
|
||||||
|
&'_ self,
|
||||||
|
activity_tree: &'tree ActivityTree,
|
||||||
|
) -> impl Iterator<Item = &'tree ActivityTreeEntry> {
|
||||||
|
self.child_ids
|
||||||
|
.iter()
|
||||||
|
.map(|child_id| activity_tree.get(child_id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct ActivityIdNotInTreeError {
|
||||||
|
id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActivityIdNotInTreeError {
|
||||||
|
fn new(id: u64) -> ActivityIdNotInTreeError {
|
||||||
|
ActivityIdNotInTreeError { id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ActivityIdNotInTreeError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "Activity id {} not in the tree.", self.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct ActivityIdAlreadyInTreeError {
|
||||||
|
id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActivityIdAlreadyInTreeError {
|
||||||
|
fn new(id: u64) -> ActivityIdAlreadyInTreeError {
|
||||||
|
ActivityIdAlreadyInTreeError { id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ActivityIdAlreadyInTreeError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "Activity id {} already in the tree.", self.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
|
mod activity;
|
||||||
|
mod activity_tree;
|
||||||
mod high_level;
|
mod high_level;
|
||||||
mod nix_output_stream;
|
mod nix_output_stream;
|
||||||
mod output_stream;
|
mod output_stream;
|
||||||
mod running_build;
|
mod running_build;
|
||||||
|
mod transparent_iter;
|
||||||
|
pub(crate) use activity_tree::ActivityIdAlreadyInTreeError;
|
||||||
|
pub(crate) use activity_tree::ActivityIdNotInTreeError;
|
||||||
pub(crate) use high_level::*;
|
pub(crate) use high_level::*;
|
||||||
pub(crate) use nix_output_stream::NixOutputStream;
|
pub(crate) use nix_output_stream::NixOutputStream;
|
||||||
pub(crate) use output_stream::OutputLine;
|
pub(crate) use output_stream::OutputLine;
|
||||||
|
|||||||
@@ -722,6 +722,8 @@ pub(crate) struct ActivityStartCopyPaths {
|
|||||||
pub(crate) id: u64,
|
pub(crate) id: u64,
|
||||||
pub(crate) parent: u64,
|
pub(crate) parent: u64,
|
||||||
pub(crate) level: u8,
|
pub(crate) level: u8,
|
||||||
|
|
||||||
|
/// Seems to either be blank or "copying 9 paths"
|
||||||
pub(crate) text: String,
|
pub(crate) text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
use std::borrow::Cow;
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::collections::BTreeSet;
|
|
||||||
|
|
||||||
use sqlx::Row;
|
use sqlx::Row;
|
||||||
use tokio::process::Child;
|
use tokio::process::Child;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
use tracing::warn;
|
|
||||||
|
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use crate::database::db_handle::DbHandle;
|
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::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::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::ActivityResultMessage;
|
||||||
use super::nix_output_stream::NixMessage;
|
use super::nix_output_stream::NixMessage;
|
||||||
|
|
||||||
pub(crate) struct RunningBuild<'db> {
|
pub(crate) struct RunningBuild<'db> {
|
||||||
db_handle: &'db DbHandle,
|
db_handle: &'db DbHandle,
|
||||||
activity_tree: BTreeMap<u64, Activity>,
|
activity_tree: ActivityTree,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> RunningBuild<'db> {
|
impl<'db> RunningBuild<'db> {
|
||||||
pub(crate) fn new(db_handle: &'db DbHandle) -> Result<Self> {
|
pub(crate) fn new(db_handle: &'db DbHandle) -> Result<Self> {
|
||||||
Ok(RunningBuild {
|
Ok(RunningBuild {
|
||||||
db_handle,
|
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.
|
// For now we can ignore the messages.
|
||||||
}
|
}
|
||||||
NixAction::Start(activity_start_message) => {
|
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 {
|
match activity_start_message {
|
||||||
ActivityStartMessage::Unknown(activity_start_unknown) => {
|
ActivityStartMessage::Unknown(activity_start_unknown) => {
|
||||||
entry.insert(Activity::Unknown(ActivityUnknown {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_unknown.id,
|
activity_start_unknown.id,
|
||||||
parent: activity_start_unknown.parent,
|
activity_start_unknown.parent,
|
||||||
state: ActivityState::default(),
|
Activity::Unknown(ActivityUnknown {
|
||||||
}));
|
state: ActivityState::default(),
|
||||||
|
text: activity_start_unknown.text,
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
ActivityStartMessage::CopyPath(activity_start_copy_path) => {
|
ActivityStartMessage::CopyPath(activity_start_copy_path) => {
|
||||||
entry.insert(Activity::CopyPath(ActivityCopyPath {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_copy_path.id,
|
activity_start_copy_path.id,
|
||||||
parent: activity_start_copy_path.parent,
|
activity_start_copy_path.parent,
|
||||||
state: ActivityState::default(),
|
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) => {
|
ActivityStartMessage::FileTransfer(activity_start_file_transfer) => {
|
||||||
entry.insert(Activity::FileTransfer(ActivityFileTransfer {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_file_transfer.id,
|
activity_start_file_transfer.id,
|
||||||
parent: activity_start_file_transfer.parent,
|
activity_start_file_transfer.parent,
|
||||||
state: ActivityState::default(),
|
Activity::FileTransfer(ActivityFileTransfer {
|
||||||
url: activity_start_file_transfer.url,
|
state: ActivityState::default(),
|
||||||
}));
|
url: activity_start_file_transfer.url,
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
ActivityStartMessage::Realize(activity_start_realize) => {
|
ActivityStartMessage::Realize(activity_start_realize) => {
|
||||||
entry.insert(Activity::Realize(ActivityRealize {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_realize.id,
|
activity_start_realize.id,
|
||||||
parent: activity_start_realize.parent,
|
activity_start_realize.parent,
|
||||||
state: ActivityState::default(),
|
Activity::Realize(ActivityRealize {
|
||||||
}));
|
state: ActivityState::default(),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
ActivityStartMessage::CopyPaths(activity_start_copy_paths) => {
|
ActivityStartMessage::CopyPaths(activity_start_copy_paths) => {
|
||||||
entry.insert(Activity::CopyPaths(ActivityCopyPaths {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_copy_paths.id,
|
activity_start_copy_paths.id,
|
||||||
parent: activity_start_copy_paths.parent,
|
activity_start_copy_paths.parent,
|
||||||
state: ActivityState::default(),
|
Activity::CopyPaths(ActivityCopyPaths {
|
||||||
}));
|
state: ActivityState::default(),
|
||||||
|
text: activity_start_copy_paths.text,
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
ActivityStartMessage::Builds(activity_start_builds) => {
|
ActivityStartMessage::Builds(activity_start_builds) => {
|
||||||
entry.insert(Activity::Builds(ActivityBuilds {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_builds.id,
|
activity_start_builds.id,
|
||||||
parent: activity_start_builds.parent,
|
activity_start_builds.parent,
|
||||||
state: ActivityState::default(),
|
Activity::Builds(ActivityBuilds {
|
||||||
}));
|
state: ActivityState::default(),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
ActivityStartMessage::Build(activity_start_build) => {
|
ActivityStartMessage::Build(activity_start_build) => {
|
||||||
entry.insert(Activity::Build(ActivityBuild {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_build.id,
|
activity_start_build.id,
|
||||||
parent: activity_start_build.parent,
|
activity_start_build.parent,
|
||||||
state: ActivityState::default(),
|
Activity::Build(ActivityBuild {
|
||||||
drv_path: activity_start_build.drv_path,
|
state: ActivityState::default(),
|
||||||
machine_name: if activity_start_build.machine_name.len() > 0 {
|
drv_path: activity_start_build.drv_path,
|
||||||
Some(activity_start_build.machine_name)
|
machine_name: if activity_start_build.machine_name.len() > 0 {
|
||||||
} else {
|
Some(activity_start_build.machine_name)
|
||||||
None
|
} else {
|
||||||
},
|
None
|
||||||
}));
|
},
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
ActivityStartMessage::OptimizeStore(activity_start_optimize_store) => {
|
ActivityStartMessage::OptimizeStore(activity_start_optimize_store) => {
|
||||||
entry.insert(Activity::OptimizeStore(ActivityOptimizeStore {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_optimize_store.id,
|
activity_start_optimize_store.id,
|
||||||
parent: activity_start_optimize_store.parent,
|
activity_start_optimize_store.parent,
|
||||||
state: ActivityState::default(),
|
Activity::OptimizeStore(ActivityOptimizeStore {
|
||||||
}));
|
state: ActivityState::default(),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
ActivityStartMessage::VerifyPaths(activity_start_verify_paths) => {
|
ActivityStartMessage::VerifyPaths(activity_start_verify_paths) => {
|
||||||
entry.insert(Activity::VerifyPaths(ActivityVerifyPaths {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_verify_paths.id,
|
activity_start_verify_paths.id,
|
||||||
parent: activity_start_verify_paths.parent,
|
activity_start_verify_paths.parent,
|
||||||
state: ActivityState::default(),
|
Activity::VerifyPaths(ActivityVerifyPaths {
|
||||||
}));
|
state: ActivityState::default(),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
ActivityStartMessage::Substitute(activity_start_substitute) => {
|
ActivityStartMessage::Substitute(activity_start_substitute) => {
|
||||||
entry.insert(Activity::Substitute(ActivitySubstitute {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_substitute.id,
|
activity_start_substitute.id,
|
||||||
parent: activity_start_substitute.parent,
|
activity_start_substitute.parent,
|
||||||
state: ActivityState::default(),
|
Activity::Substitute(ActivitySubstitute {
|
||||||
}));
|
state: ActivityState::default(),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
ActivityStartMessage::QueryPathInfo(activity_start_query_path_info) => {
|
ActivityStartMessage::QueryPathInfo(activity_start_query_path_info) => {
|
||||||
entry.insert(Activity::QueryPathInfo(ActivityQueryPathInfo {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_query_path_info.id,
|
activity_start_query_path_info.id,
|
||||||
parent: activity_start_query_path_info.parent,
|
activity_start_query_path_info.parent,
|
||||||
state: ActivityState::default(),
|
Activity::QueryPathInfo(ActivityQueryPathInfo {
|
||||||
}));
|
state: ActivityState::default(),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
ActivityStartMessage::PostBuildHook(activity_start_post_build_hook) => {
|
ActivityStartMessage::PostBuildHook(activity_start_post_build_hook) => {
|
||||||
entry.insert(Activity::PostBuildHook(ActivityPostBuildHook {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_post_build_hook.id,
|
activity_start_post_build_hook.id,
|
||||||
parent: activity_start_post_build_hook.parent,
|
activity_start_post_build_hook.parent,
|
||||||
state: ActivityState::default(),
|
Activity::PostBuildHook(ActivityPostBuildHook {
|
||||||
}));
|
state: ActivityState::default(),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
ActivityStartMessage::BuildWaiting(activity_start_build_waiting) => {
|
ActivityStartMessage::BuildWaiting(activity_start_build_waiting) => {
|
||||||
entry.insert(Activity::BuildWaiting(ActivityBuildWaiting {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_build_waiting.id,
|
activity_start_build_waiting.id,
|
||||||
state: ActivityState::default(),
|
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) => {
|
ActivityStartMessage::FetchTree(activity_start_fetch_tree) => {
|
||||||
entry.insert(Activity::FetchTree(ActivityFetchTree {
|
self.activity_tree.add_activity(
|
||||||
id: activity_start_fetch_tree.id,
|
activity_start_fetch_tree.id,
|
||||||
parent: activity_start_fetch_tree.parent,
|
activity_start_fetch_tree.parent,
|
||||||
state: ActivityState::default(),
|
Activity::FetchTree(ActivityFetchTree {
|
||||||
}));
|
state: ActivityState::default(),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.print_current_status();
|
self.print_current_status();
|
||||||
}
|
}
|
||||||
NixAction::Stop(stop_message) => {
|
NixAction::Stop(stop_message) => {
|
||||||
let entry = self.activity_tree.entry(stop_message.id);
|
let activity = self
|
||||||
match entry {
|
.activity_tree
|
||||||
std::collections::btree_map::Entry::Vacant(_vacant_entry) => {
|
.get_activity_id(stop_message.id)
|
||||||
panic!(
|
.map(|activity_id| self.activity_tree.get_mut(&activity_id))?;
|
||||||
"Stopped an activity that is not in the tree: {}",
|
activity.get_mut_activity().stop();
|
||||||
stop_message.id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
std::collections::btree_map::Entry::Occupied(mut occupied_entry) => {
|
|
||||||
occupied_entry.get_mut().stop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.print_current_status();
|
self.print_current_status();
|
||||||
// println!("{}", serde_json::to_string(&message)?);
|
// println!("{}", serde_json::to_string(&message)?);
|
||||||
}
|
}
|
||||||
@@ -302,11 +339,9 @@ impl<'db> RunningBuild<'db> {
|
|||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
let activity = self
|
let activity = self.activity_tree.get(&dag_entry.activity_id);
|
||||||
.activity_tree
|
|
||||||
.get(&dag_entry.activity_id)
|
|
||||||
.expect("Activity should exist in the tree.");
|
|
||||||
let display_name = activity
|
let display_name = activity
|
||||||
|
.get_activity()
|
||||||
.display_name()
|
.display_name()
|
||||||
.expect("Currently we always return a display name.");
|
.expect("Currently we always return a display name.");
|
||||||
let activity_id = activity.get_activity_id();
|
let activity_id = activity.get_activity_id();
|
||||||
@@ -321,22 +356,13 @@ impl<'db> RunningBuild<'db> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_draw_order(&self) -> Vec<DrawDagEntry> {
|
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 draw_order: Vec<DrawDagEntry> = Vec::new();
|
||||||
let mut stack: Vec<DrawStackEntry> = self
|
let mut stack: Vec<DrawStackEntry> = self
|
||||||
.get_children_in_order(0)
|
.get_children_in_order(self.activity_tree.get_root_id())
|
||||||
.filter_map(|child_id| {
|
.filter_map(|child| {
|
||||||
if active_activity_ids.contains(&child_id) {
|
if child.get_activity().is_active() {
|
||||||
Some(DrawStackEntry::HasNotVisitedChildren(DrawDagEntry {
|
Some(DrawStackEntry::HasNotVisitedChildren(DrawDagEntry {
|
||||||
activity_id: child_id,
|
activity_id: child.get_activity_id().clone(),
|
||||||
depth: Vec::new(),
|
depth: Vec::new(),
|
||||||
has_later_siblings: true,
|
has_later_siblings: true,
|
||||||
}))
|
}))
|
||||||
@@ -357,14 +383,19 @@ impl<'db> RunningBuild<'db> {
|
|||||||
let current_entry = stack.pop().expect("While-loop ensured this is Some.");
|
let current_entry = stack.pop().expect("While-loop ensured this is Some.");
|
||||||
match current_entry {
|
match current_entry {
|
||||||
DrawStackEntry::HasNotVisitedChildren(draw_dag_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();
|
let mut current_depth = draw_dag_entry.depth.clone();
|
||||||
current_depth.push(draw_dag_entry.has_later_siblings);
|
current_depth.push(draw_dag_entry.has_later_siblings);
|
||||||
stack.push(DrawStackEntry::VisitedChildren(draw_dag_entry));
|
stack.push(DrawStackEntry::VisitedChildren(draw_dag_entry));
|
||||||
let children: Vec<u64> = self
|
let children: Vec<ActivityId> = self
|
||||||
.get_children_in_order(current_id)
|
.get_children_in_order(current_id)
|
||||||
.into_iter()
|
.filter_map(|child| {
|
||||||
.filter(|child_id| active_activity_ids.contains(child_id))
|
if child.get_activity().is_active() {
|
||||||
|
Some(child.get_activity_id().clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let has_children = !children.is_empty();
|
let has_children = !children.is_empty();
|
||||||
stack.extend(children.into_iter().map(|child_id| {
|
stack.extend(children.into_iter().map(|child_id| {
|
||||||
@@ -389,35 +420,16 @@ impl<'db> RunningBuild<'db> {
|
|||||||
draw_order
|
draw_order
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_children_in_order(&self, parent_id: u64) -> impl Iterator<Item = u64> {
|
fn get_children_in_order(
|
||||||
let child_ids = self
|
&self,
|
||||||
.activity_tree
|
parent_id: ActivityId,
|
||||||
|
) -> impl Iterator<Item = &ActivityTreeEntry> {
|
||||||
|
let parent = self.activity_tree.get(&parent_id);
|
||||||
|
parent
|
||||||
|
.get_child_ids()
|
||||||
.iter()
|
.iter()
|
||||||
.filter(move |(_child_id, activity)| activity.get_parent_id() == parent_id)
|
.map(|child_id| self.activity_tree.get(child_id))
|
||||||
.flat_map(|(_child_id, activity)| TransparentIter::new(&self.activity_tree, activity))
|
.flat_map(|child| TransparentIter::new(&self.activity_tree, child))
|
||||||
.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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,7 +439,7 @@ enum DrawStackEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct DrawDagEntry {
|
struct DrawDagEntry {
|
||||||
activity_id: u64,
|
activity_id: ActivityId,
|
||||||
depth: Vec<bool>,
|
depth: Vec<bool>,
|
||||||
has_later_siblings: 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
90
src/nix_util/transparent_iter.rs
Normal file
90
src/nix_util/transparent_iter.rs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
use super::activity_tree::ActivityTree;
|
||||||
|
use super::activity_tree::ActivityTreeEntry;
|
||||||
|
|
||||||
|
/// 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> {
|
||||||
|
activity_tree: &'tree ActivityTree,
|
||||||
|
origin: Option<&'tree ActivityTreeEntry>,
|
||||||
|
child_index: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tree> Iterator for TransparentIter<'tree> {
|
||||||
|
type Item = &'tree ActivityTreeEntry;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let origin = match self.origin {
|
||||||
|
Some(o) => o,
|
||||||
|
None => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !origin.get_activity().is_transparent() {
|
||||||
|
let origin = self
|
||||||
|
.origin
|
||||||
|
.take()
|
||||||
|
.expect("We would have returned early if origin was None.");
|
||||||
|
return Some(origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.child_index.is_empty() {
|
||||||
|
self.child_index.push(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let current_entry = self.get_current_entry();
|
||||||
|
if let Some(child) = current_entry {
|
||||||
|
if child.get_activity().is_transparent() {
|
||||||
|
self.child_index.push(0);
|
||||||
|
} else {
|
||||||
|
let last_index = self.child_index.last_mut().expect("Stack cannot be empty.");
|
||||||
|
*last_index += 1;
|
||||||
|
return Some(child);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.child_index.pop();
|
||||||
|
if self.child_index.is_empty() {
|
||||||
|
self.origin.take();
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let last_index = self.child_index.last_mut().expect("Stack cannot be empty.");
|
||||||
|
*last_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tree> TransparentIter<'tree> {
|
||||||
|
pub(crate) fn new(
|
||||||
|
activity_tree: &'tree ActivityTree,
|
||||||
|
origin: &'tree ActivityTreeEntry,
|
||||||
|
) -> TransparentIter<'tree> {
|
||||||
|
TransparentIter {
|
||||||
|
activity_tree,
|
||||||
|
origin: Some(origin),
|
||||||
|
child_index: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_current_entry(&mut self) -> Option<&'tree ActivityTreeEntry> {
|
||||||
|
let mut current_entry = match self.origin {
|
||||||
|
Some(o) => o,
|
||||||
|
None => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for ind in self.child_index.iter() {
|
||||||
|
if let Some(child) = current_entry
|
||||||
|
.get_child_ids()
|
||||||
|
.get(*ind)
|
||||||
|
.map(|child_index| self.activity_tree.get(child_index))
|
||||||
|
{
|
||||||
|
current_entry = child;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(current_entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user