feat: ✨ begin the repo a bit late but better than never
This commit is contained in:
commit
607159334b
22 changed files with 898 additions and 0 deletions
216
lib/comfpile/artefact.rb
Normal file
216
lib/comfpile/artefact.rb
Normal file
|
@ -0,0 +1,216 @@
|
|||
|
||||
require 'debug'
|
||||
|
||||
module Comfpile
|
||||
class ArtefactExecSkipError < StandardError
|
||||
end
|
||||
|
||||
class Artefact
|
||||
attr_reader :core, :engine
|
||||
|
||||
attr_reader :exit_state
|
||||
attr_reader :stage, :target
|
||||
|
||||
attr_reader :linked_artefacts
|
||||
|
||||
# ARTEFACT STATES
|
||||
#
|
||||
# The following states are known to the system:
|
||||
# - blocked: The Artefact is blocked and waiting on other artefacts
|
||||
# - waiting: The Artefact is idle and ready to be queued
|
||||
# - running: The Artefact is currently being run
|
||||
# Note that this is not a state, but is determined by the
|
||||
# @running flag
|
||||
# - succeeded: it has finished its work without issue
|
||||
# - skipped: it didn't run/won't run because of failed dependencies
|
||||
# - failed: it has failed due to a requirement not being met
|
||||
#
|
||||
# Meta-States exist:
|
||||
# - in_progress/completed: Anything but/Only succeeded, skipped, failed
|
||||
|
||||
def initialize(core, engine, stage, target)
|
||||
@core = core
|
||||
@engine = engine
|
||||
|
||||
@stage = stage
|
||||
@target = target
|
||||
|
||||
@age = Time.at(0)
|
||||
|
||||
@parent_artefact = nil
|
||||
|
||||
@required_artefacts = nil
|
||||
@linked_artefacts = nil
|
||||
|
||||
@steps = []
|
||||
@step_additions = nil
|
||||
|
||||
@waitlist = []
|
||||
|
||||
@steps_done_ctr = 0
|
||||
|
||||
@parameters = {}
|
||||
|
||||
@exit_state = nil
|
||||
@running = false
|
||||
end
|
||||
|
||||
def [](key)
|
||||
v = @parameters[key]
|
||||
return v unless v.nil?
|
||||
|
||||
if @parent_artefact
|
||||
return @parent_artefact[key]
|
||||
end
|
||||
end
|
||||
def []=(key, value)
|
||||
@parameters[key] = value
|
||||
end
|
||||
|
||||
private def add_step_data(data)
|
||||
@step_additions ||= []
|
||||
|
||||
@step_additions << data
|
||||
end
|
||||
private def process_additional_step_data
|
||||
unless @step_additions.nil?
|
||||
@steps.insert(@steps_done_ctr, @step_additions)
|
||||
@steps.flatten!
|
||||
@step_additions = nil
|
||||
end
|
||||
end
|
||||
|
||||
def add_step(&block)
|
||||
add_step_data({
|
||||
type: :block,
|
||||
executed: false,
|
||||
block: block
|
||||
})
|
||||
end
|
||||
|
||||
def parent_artefact(stage, target)
|
||||
@parent_artefact = require_artefact(stage, target)
|
||||
end
|
||||
|
||||
def require_artefact(stage, target)
|
||||
artefact = @core.craft_artefact(stage, target)
|
||||
|
||||
if(artefact.nil?)
|
||||
fail! "Missing artefact dependency for #{stage} #{target}!"
|
||||
else
|
||||
@waitlist << {
|
||||
artefact: artefact,
|
||||
required: true
|
||||
}
|
||||
end
|
||||
|
||||
@required_artefacts ||= {}
|
||||
@required_artefacts[stage] ||= {}
|
||||
@required_artefacts[stage][target] = artefact
|
||||
|
||||
artefact
|
||||
end
|
||||
|
||||
def craft_artefact(stage, target)
|
||||
artefact = @core.craft_artefact(stage, target)
|
||||
|
||||
artefact
|
||||
end
|
||||
|
||||
def waitlist_empty?
|
||||
return true if completed?
|
||||
|
||||
loop do
|
||||
return true if @waitlist.empty?
|
||||
|
||||
item = @waitlist[-1]
|
||||
|
||||
return false if item[:artefact].in_progress?
|
||||
|
||||
if not item[:required]
|
||||
@waitlist.pop
|
||||
elsif item[:artefact].succeeded?
|
||||
@waitlist.pop
|
||||
else
|
||||
skip! skip! "Failed artefact dependency: #{item[:artefact]}"
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def state
|
||||
return :blocked unless waitlist_empty?
|
||||
return @exit_state unless @exit_state.nil?
|
||||
|
||||
return :running if @running
|
||||
|
||||
return :waiting
|
||||
end
|
||||
|
||||
def completed?
|
||||
not @exit_state.nil?
|
||||
end
|
||||
|
||||
def succeeded?
|
||||
@exit_state == :succeeded
|
||||
end
|
||||
|
||||
def in_progress?
|
||||
not completed?
|
||||
end
|
||||
|
||||
def waiting?
|
||||
self.state == :waiting
|
||||
end
|
||||
|
||||
private def mark_state_change(state, reason, abort: false)
|
||||
puts "#{@stage} #{target}: Reached state #{state}: #{reason}"
|
||||
@exit_state = state
|
||||
@reason = reason
|
||||
|
||||
abort_step! if abort
|
||||
end
|
||||
|
||||
def skip!(reason, **opts)
|
||||
mark_state_change(:skipped, reason, **opts)
|
||||
end
|
||||
def fail!(reason, **opts)
|
||||
mark_state_change(:failed, reason, **opts)
|
||||
end
|
||||
def succeed!(reason, **opts)
|
||||
mark_state_change(:succeeded, reason, **opts)
|
||||
end
|
||||
|
||||
def abort_step!
|
||||
raise ArtefactExecSkipError
|
||||
end
|
||||
|
||||
def execute_step
|
||||
return unless waiting?
|
||||
@running = true
|
||||
|
||||
process_additional_step_data
|
||||
|
||||
next_step = @steps[@steps_done_ctr]
|
||||
succeed! "All done", abort: true if next_step.nil?
|
||||
|
||||
case next_step[:type]
|
||||
when :block
|
||||
instance_exec &next_step[:block]
|
||||
else
|
||||
fail! "Unknown artefact step taken!", abort: true
|
||||
end
|
||||
|
||||
@steps_done_ctr += 1
|
||||
succeed! "All done", abort: true if @steps_done_ctr >= @steps.length
|
||||
|
||||
ensure
|
||||
@running = false
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#<Compfile::Artefact #{@stage} #{@target}>"
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue