pub struct TaskGraph<T: TaskNodeData> { /* private fields */ }Expand description
Task graph for dependency resolution and execution ordering.
This is a generic graph that can hold any task type implementing TaskNodeData.
It provides methods for building the graph, resolving dependencies, and
computing execution order.
Implementations§
Source§impl<T: TaskNodeData> TaskGraph<T>
impl<T: TaskNodeData> TaskGraph<T>
Sourcepub fn add_task(&mut self, name: &str, task: T) -> Result<NodeIndex>
pub fn add_task(&mut self, name: &str, task: T) -> Result<NodeIndex>
Add a single task to the graph.
If a task with the same name already exists, returns the existing node index.
§Errors
Currently infallible, but returns Result for API consistency.
Sourcepub fn get_node_mut(&mut self, index: NodeIndex) -> Option<&mut GraphNode<T>>
pub fn get_node_mut(&mut self, index: NodeIndex) -> Option<&mut GraphNode<T>>
Get a mutable reference to a task node by index.
Sourcepub fn get_node_by_name(&self, name: &str) -> Option<&GraphNode<T>>
pub fn get_node_by_name(&self, name: &str) -> Option<&GraphNode<T>>
Get a reference to a task node by name.
Sourcepub fn register_group(&mut self, prefix: &str, children: Vec<String>)
pub fn register_group(&mut self, prefix: &str, children: Vec<String>)
Register a group of child task names under a group prefix.
This enables group-level dependency expansion where depending on a group name will expand to depend on all child tasks.
Sourcepub fn add_dependency_edges(&mut self) -> Result<()>
pub fn add_dependency_edges(&mut self) -> Result<()>
Add dependency edges after all tasks have been added.
This ensures proper cycle detection and missing dependency validation.
§Errors
Returns an error if any task depends on a non-existent task.
Sourcepub fn add_edge(&mut self, from: NodeIndex, to: NodeIndex)
pub fn add_edge(&mut self, from: NodeIndex, to: NodeIndex)
Add a direct edge between two tasks.
This is a low-level method for adding edges directly, typically used for sequential group ordering.
Sourcepub fn has_cycles(&self) -> bool
pub fn has_cycles(&self) -> bool
Check if the graph has cycles.
Sourcepub fn topological_sort(&self) -> Result<Vec<GraphNode<T>>>
pub fn topological_sort(&self) -> Result<Vec<GraphNode<T>>>
Sourcepub fn get_parallel_groups(&self) -> Result<Vec<Vec<GraphNode<T>>>>
pub fn get_parallel_groups(&self) -> Result<Vec<Vec<GraphNode<T>>>>
Get all tasks that can run in parallel (no dependencies between them).
Returns a vector of parallel groups, where each group contains tasks that can execute concurrently. Groups are ordered by dependency level.
§Errors
Returns an error if the graph contains cycles.
Sourcepub fn task_count(&self) -> usize
pub fn task_count(&self) -> usize
Get the number of tasks in the graph.
Sourcepub fn contains_task(&self, name: &str) -> bool
pub fn contains_task(&self, name: &str) -> bool
Check if a task exists in the graph.
Sourcepub fn get_node_index(&self, name: &str) -> Option<NodeIndex>
pub fn get_node_index(&self, name: &str) -> Option<NodeIndex>
Get the node index for a task by name.
Sourcepub fn iter_nodes(&self) -> impl Iterator<Item = (NodeIndex, &GraphNode<T>)>
pub fn iter_nodes(&self) -> impl Iterator<Item = (NodeIndex, &GraphNode<T>)>
Iterate over all nodes in the graph.
Sourcepub fn build_for_task<F>(&mut self, task_name: &str, get_task: F) -> Result<()>
pub fn build_for_task<F>(&mut self, task_name: &str, get_task: F) -> Result<()>
Build graph for a specific task and all its transitive dependencies.
This method takes an iterator of all available tasks and builds only the subgraph needed for the requested task.
§Arguments
task_name- The name of the task to build the graph forget_task- Function that returns the task data for a given name
§Errors
Returns an error if dependencies cannot be resolved.
Sourcepub fn build_for_task_with_resolver<R>(
&mut self,
task_name: &str,
resolver: &R,
) -> Result<()>where
R: TaskResolver<T>,
pub fn build_for_task_with_resolver<R>(
&mut self,
task_name: &str,
resolver: &R,
) -> Result<()>where
R: TaskResolver<T>,
Build graph for a specific task using a resolver that handles group expansion.
This method uses the TaskResolver trait to resolve task names, which enables
unified handling of single tasks and groups (sequential/parallel).
§Arguments
task_name- The name of the task to build the graph forresolver- Implementation ofTaskResolverthat provides task lookup and group expansion
§Errors
Returns an error if dependencies cannot be resolved.
Sourcepub fn compute_affected<F, E>(
&self,
pipeline_tasks: &[impl AsRef<str>],
is_directly_affected: F,
is_external_affected: Option<E>,
) -> Vec<String>
pub fn compute_affected<F, E>( &self, pipeline_tasks: &[impl AsRef<str>], is_directly_affected: F, is_external_affected: Option<E>, ) -> Vec<String>
Compute which tasks from a pipeline are affected, using transitive dependency propagation.
This method determines which tasks need to run based on:
- Direct effect: The predicate returns true for the task
- Transitive effect: A task depends on an affected task
- External effect: An external dependency (e.g.,
#project:task) is affected
§Arguments
pipeline_tasks- The names of tasks in the pipeline to checkis_directly_affected- Predicate that returns true if a task is directly affectedis_external_affected- Optional predicate for external dependencies (starting with#)
§Returns
A vector of task names that are affected, in pipeline order.
§Example
// Without external dependency checking
let affected = graph.compute_affected(
&["build", "test", "deploy"],
|task| task.is_affected_by(&changed_files, &project_root),
None::<fn(&str) -> bool>,
);
// With external dependency checking (for CI cross-project deps)
let affected = graph.compute_affected(
&["build", "test", "deploy"],
|task| task.is_affected_by(&changed_files, &project_root),
Some(|dep: &str| check_external_dependency(dep, &all_projects, &changed_files)),
);Source§impl<T: TaskNodeData> TaskGraph<T>
impl<T: TaskNodeData> TaskGraph<T>
Sourcepub fn validate(&self) -> ValidationResult
pub fn validate(&self) -> ValidationResult
Validate the graph structure.
Checks for:
- Cycles in the dependency graph
Note: Missing dependencies are caught during add_dependency_edges(),
so this method primarily checks for cycles after edges are added.