200 lines
No EOL
5.7 KiB
Ruby
200 lines
No EOL
5.7 KiB
Ruby
|
|
require 'digest'
|
|
|
|
require_relative 'artefact_engine.rb'
|
|
|
|
require_relative 'context.rb'
|
|
|
|
module Comfpile
|
|
class Core
|
|
attr_reader :processing_stack
|
|
|
|
def initialize(build_dir_path: File.join('/tmp/comfpile/', Digest::MD5.hexdigest(Dir.pwd)))
|
|
@build_dir_path = File.expand_path(build_dir_path)
|
|
|
|
@artefact_engines = []
|
|
@artefact_prio_counter = 0
|
|
|
|
# Artefacts are arranged in a double-hash.
|
|
# First query is stage, second filename.
|
|
@artefacts = {}
|
|
|
|
# Stack-style processing queue for item processing
|
|
@processing_stack = []
|
|
|
|
@context_key_provider = ContextKeyProvider.new()
|
|
end
|
|
|
|
def get_context_key(key)
|
|
return @context_key_provider.provide_context(key)
|
|
end
|
|
|
|
def find_artefact(stage, file = :none, context = :default)
|
|
context = get_context_key(context)
|
|
|
|
@artefacts.dig(context, stage, file)
|
|
end
|
|
|
|
# Create or find a new artefact.
|
|
#
|
|
# This will first see if a given artefact matching
|
|
# the stage and target descriptions already exists, and
|
|
# will return it, if found. Otherwise it will
|
|
# consult all given artefact crafting engines to
|
|
# see if a new artefact can be created, which will be returned.
|
|
#
|
|
# If no artefact can be made, nil is returned
|
|
#
|
|
# @param [Symbol, String] stage State that shall be created (e.g. :parsed, :compiled, etc.)
|
|
# @param [String] file File or other target that shall be looked at (e.g. "main.cpp")
|
|
#
|
|
# @return [Comfpile::Artefact, nil] Found or created artefact, or nil if nothing could be done
|
|
#
|
|
def craft_artefact(stage, file = :none, context = :default)
|
|
context = get_context_key(context)
|
|
|
|
artefact = find_artefact(stage, file, context)
|
|
|
|
return artefact unless artefact.nil?
|
|
|
|
@artefact_engines.each do |engine|
|
|
artefact = engine.craft stage, file, context
|
|
|
|
if artefact
|
|
@artefacts[context] ||= {}
|
|
@artefacts[context][stage] ||= {}
|
|
@artefacts[context][stage][file] = artefact
|
|
|
|
@processing_stack.push artefact
|
|
|
|
return artefact
|
|
end
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
def add_artefact(stage, file = :none, context = :default, engine: nil, artefact_class: Comfpile::Artefact)
|
|
context = get_context_key context
|
|
|
|
return unless find_artefact(stage, file, context).nil?
|
|
|
|
a = Artefact.new(self, engine, stage, file, context);
|
|
|
|
@artefacts[context] ||= {}
|
|
@artefacts[context][stage] ||= {}
|
|
@artefacts[context][stage][file] = a
|
|
|
|
yield(a) if block_given?
|
|
|
|
nil
|
|
end
|
|
|
|
# @yieldparam [Comfpile::ArtefactEngine] Engine that was newly created
|
|
def add_artefact_engine(engine_class = Comfpile::ArtefactEngine, **options)
|
|
|
|
new_engine = if(engine_class.is_a? Comfpile::ArtefactEngine)
|
|
engine_class
|
|
else
|
|
engine = engine_class.new(self,
|
|
subpriority: @artefact_prio_counter, **options)
|
|
@artefact_prio_counter += 1
|
|
|
|
engine
|
|
end
|
|
|
|
yield(new_engine) if block_given?
|
|
|
|
@artefact_engines << new_engine
|
|
@artefact_engines.sort!
|
|
|
|
new_engine
|
|
end
|
|
|
|
def processing_stack_prune()
|
|
loop do
|
|
return if @processing_stack.empty?
|
|
|
|
if @processing_stack[-1].completed?
|
|
@processing_stack.pop
|
|
else
|
|
break
|
|
end
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
def processing_stack_find_next()
|
|
return nil if @processing_stack.empty?
|
|
|
|
i = 0
|
|
@processing_stack.reverse_each do |a|
|
|
i += 1
|
|
if a.waiting?
|
|
# puts "DBG - Found item after #{i} checks"
|
|
return a
|
|
end
|
|
end
|
|
|
|
# TODO: Fix up later-on for parallel runner capabilities
|
|
raise "Deadlock found, no item was willing to run!"
|
|
|
|
nil
|
|
end
|
|
|
|
def get_context_build_dir_path(context)
|
|
context = context.context if context.is_a? Artefact
|
|
|
|
File.expand_path(File.join(@build_dir_path, context.to_s))
|
|
end
|
|
|
|
def execute_step
|
|
return if @processing_stack.empty?
|
|
# puts "Got #{@processing_stack.length} items..."
|
|
|
|
processing_stack_prune
|
|
|
|
artefact = processing_stack_find_next
|
|
|
|
return nil if artefact.nil?
|
|
|
|
# puts "Processing artefact #{artefact.stage} #{artefact.target}"
|
|
|
|
build_path = get_context_build_dir_path(artefact)
|
|
FileUtils.mkpath build_path
|
|
|
|
Dir.chdir build_path do
|
|
begin
|
|
artefact.execute_step
|
|
rescue ArtefactExecSkipError
|
|
end
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
def execute_all
|
|
step_count = 0
|
|
|
|
until @processing_stack.empty?
|
|
execute_step()
|
|
step_count += 1
|
|
end
|
|
|
|
puts "Done after #{step_count} exec loops..."
|
|
end
|
|
|
|
def craft_and_complete(stage, target)
|
|
artefact = craft_artefact(stage, target)
|
|
|
|
return nil if artefact.nil?
|
|
|
|
while artefact.in_progress?
|
|
execute_step
|
|
end
|
|
|
|
artefact
|
|
end
|
|
end
|
|
end |