BuildSourceBuildController

class Controller

Represents the top-level build controller that manages the walker and process group.

Definitions

def initialize(limit: nil)

Initialize the controller, yielding self to allow adding chain nodes.

Signature

parameter limit Integer | Nil

Maximum number of concurrent processes.

Implementation

def initialize(limit: nil)
	@module = Module.new
	
	# Top level nodes, for sanity this is a static list.
	@nodes = []
	yield self
	@nodes.freeze
	
	@group = Process::Group.new(limit: limit)
	
	# The task class is captured as we traverse all the top level targets:
	@task_class = nil
	
	@walker = Graph::Walker.new(&self.method(:step))
end

def step(walker, node, parent_task = nil)

Execute a single step of the build graph for the given node.

Signature

parameter walker Build::Graph::Walker

The graph walker.

parameter node Build::Graph::Node

The node to process.

parameter parent_task Build::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)
	
	task.visit do
		task.update
	end
end

def failed?

Signature

returns Boolean

Whether the build has failed.

Implementation

def failed?
	@walker.failed?
end

def add_chain(chain, arguments = [], environment)

Add a build environment to the controller.

Implementation

def add_chain(chain, arguments = [], environment)
	@nodes << ChainNode.new(chain, arguments, environment)
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