class Bake::Context

Represents a context of task execution, containing all relevant state.

def self.bakefile_path(path, bakefile: BAKEFILE)

@returns [String | Nil] The path to the bakefile if it could be found.
If path points to a file, assume it's a `bake.rb` file. Otherwise, recursively search up the directory tree starting from `path` to find the specified bakefile.
Search upwards from the specified path for a {BAKEFILE}.
def self.bakefile_path(path, bakefile: BAKEFILE)
	if File.file?(path)
		return path
	end
	
	current = path
	
	while current
		bakefile_path = File.join(current, BAKEFILE)
		
		if File.exist?(bakefile_path)
			return bakefile_path
		end
		
		parent = File.dirname(current)
		
		if current == parent
			break
		else
			current = parent
		end
	end
	
	return nil
end

def self.load(path = Dir.pwd)

@path [String] A file-system path.
Load a context from the specified path.
def self.load(path = Dir.pwd)
	if bakefile_path = self.bakefile_path(path)
		scope = Scope.load(bakefile_path)
		
		working_directory = File.dirname(bakefile_path)
		loaders = Loaders.default(working_directory)
	else
		scope = nil
		
		working_directory = path
		loaders = Loaders.default(working_directory)
	end
	
	return self.new(loaders, scope, working_directory)
end

def base_for(path)

@parameter path [Array] the path for the scope.
def base_for(path)
	base = nil
	
	@loaders.each do |loader|
		if scope = loader.scope_for(path)
			base ||= Base.derive(path)
			
			base.prepend(scope)
		end
	end
	
	return base
end

def call(*commands)

@parameter commands [Array(String)]
Invoke recipes on the context using command line arguments.
def call(*commands)
	last_result = nil
	
	while command = commands.shift
		if recipe = @recipes[command]
			arguments, options = recipe.prepare(commands)
			last_result = recipe.call(*arguments, **options)
		else
			raise ArgumentError, "Could not find recipe for #{command}!"
		end
	end
	
	return last_result
end

def initialize(loaders, scope = nil, root = nil)

@parameter loaders [Loaders]
Initialize the context with the specified loaders.
def initialize(loaders, scope = nil, root = nil)
	@loaders = loaders
	
	@stack = []
	
	@instances = Hash.new do |hash, key|
		hash[key] = instance_for(key)
	end
	
	@scope = scope
	@root = root
	
	if @scope
		base = Base.derive
		base.prepend(@scope)
		
		@instances[[]] = base.new(self)
	end
	
	@recipes = Hash.new do |hash, key|
		hash[key] = recipe_for(key)
	end
end

def instance_for(path)

def instance_for(path)
	if base = base_for(path)
		return base.new(self)
	end
end

def lookup(command)

@parameter command [String] The command name, e.g. `bundler:release`.
Lookup a recipe for the given command name.
def lookup(command)
	@recipes[command]
end

def recipe_for(command)

def recipe_for(command)
	path = command.split(":")
	
	if instance = @instances[path] and instance.respond_to?(path.last)
		return instance.recipe_for(path.last)
	else
		*path, name = *path
		
		if instance = @instances[path] and instance.respond_to?(name)
			return instance.recipe_for(name)
		end
	end
	
	return nil
end

def to_s

def to_s
	if @root
		"#{self.class} #{File.basename(@root)}"
	else
		self.class.name
	end
end