class Controller
Represents the top-level build controller that manages the walker and process group.
Nested
Definitions
def self.build(**options)
Create a new controller using a builder.
Implementation
def self.build(**options)
builder = Builder.new
yield builder
new(builder.nodes, **options)
end
def initialize(nodes = [], limit: nil, group: nil, walker: nil)
Initialize the controller, yielding self to allow adding chain nodes.
Signature
-
parameter
limitInteger | Nil Maximum number of concurrent processes.
Implementation
def initialize(nodes = [], limit: nil, group: nil, walker: nil)
@nodes = nodes.freeze
@group = group || Process::Group.new(limit: limit)
@walker = walker || Graph::Walker.new(&self.method(:step))
end
attr :nodes
Signature
-
attribute
Array(Graph::Node) The list of nodes to build.
attr :walker
Signature
-
attribute
Graph::Walker The graph walker used to traverse the build graph.
def visit(task)
Visit a task, executing its update method within the context of the task's visit method.
Signature
-
parameter
taskBuild::Task The task to visit.
Implementation
def visit(task)
task.visit do
task.update
end
end
def step(walker, node, parent_task = nil)
Execute a single step of the build graph for the given node.
Signature
-
parameter
walkerBuild::Graph::Walker The graph walker.
-
parameter
nodeBuild::Graph::Node The node to process.
-
parameter
parent_taskBuild::Task | Nil The parent task, if any.
Implementation
def step(walker, node, parent_task = nil)
task_class = node.task_class(parent_task) || Task
task = task_class.new(walker, node, @group)
self.visit(task)
end
def failed?
Signature
-
returns
Boolean Whether the build has failed.
Implementation
def failed?
@walker.failed?
end
def update
Execute all top-level nodes, waiting for each to complete.
Implementation
def update
@nodes.each do |node|
# We wait for all processes to complete within each node. The result is that we don't execute top level nodes concurrently, but we do execute within each node concurrently where possible. Ideally, some node could be executed concurrently, but right now expressing non-file dependencies between nodes is not possible.
@group.wait do
@walker.call(node)
end
end
end
def run
The entry point for running the walker over the build graph.
Implementation
def run
@walker.run do
self.update
yield @walker if block_given?
end
end