class Litbuild::Blueprint

Attributes

active_phase[R]
base_grafs[R]
logfile_namer[W]

Public Class Methods

descendants() click to toggle source
# File lib/litbuild/blueprint.rb, line 23
def self.descendants
  ObjectSpace.each_object(Class).select { |c| c < self }
end
directory_name() click to toggle source

This should simply be the name of the directory where blueprints of each specific type are expected to be found by Driver.

# File lib/litbuild/blueprint.rb, line 14
def self.directory_name
  raise(SubclassResponsibility)
end
new(text:) click to toggle source

WARNING: in most cases, a freshly-created blueprint cannot be used until it has also been prepared. (See below.)

# File lib/litbuild/blueprint.rb, line 29
def initialize(text:)
  parser = BlueprintParser.new(text)
  @base_directives = parser.base_directives
  @phase_directives = parser.phase_directives
  @base_grafs = parser.base_grafs
  @phase_grafs = parser.phase_grafs
  @active_phase = @base_directives['default-phase']&.first
end

Public Instance Methods

[](directive) click to toggle source
# File lib/litbuild/blueprint.rb, line 94
def [](directive)
  directives[directive]
end
accept(visitor:) click to toggle source

Dependencies need to be handled before their dependants; that's handled here. Subclasses should run `super` before doing anything else with the Visitor, or call the send_to_dependencies method directly, so that this happens properly!

# File lib/litbuild/blueprint.rb, line 60
def accept(visitor:)
  send_to_dependencies(visitor: visitor)
end
deduped_dependency_names() click to toggle source

If a dependency is declared both without a phase (typically in the base directives for the blueprint) and with a phase (typically in a phase of that blueprint), throw away the phaseless declaration to avoid including two versions of the dependency.

# File lib/litbuild/blueprint.rb, line 181
def deduped_dependency_names
  dep_names = self['depends-on'].clone || []
  deps_with_phase = dep_names.select { |dep| dep.match?(/::/) }
  deps_with_phase.each do |dep|
    dep_without_phase = dep.split('::')[0]
    dep_names.delete(dep_without_phase)
  end
  dep_names
end
directives() click to toggle source
# File lib/litbuild/blueprint.rb, line 86
def directives
  if active_phase
    @phase_directives[active_phase]
  else
    @base_directives
  end
end
failure_line() click to toggle source
# File lib/litbuild/blueprint.rb, line 173
def failure_line
  'FAILURE'
end
file_name() click to toggle source
# File lib/litbuild/blueprint.rb, line 122
def file_name
  if active_phase
    "#{name}-#{active_phase}"
  else
    name
  end.tr(' ', '-')
end
for_phase(new_active_phase) click to toggle source

Return a copy of this blueprint that is initialized to operate on the specified phase.

# File lib/litbuild/blueprint.rb, line 66
def for_phase(new_active_phase)
  return self unless phases?

  phased_blueprint = clone
  phased_blueprint.phase = new_active_phase if new_active_phase
  phased_blueprint
end
full_name() click to toggle source
# File lib/litbuild/blueprint.rb, line 118
def full_name
  value('full-name')
end
header_text() click to toggle source
# File lib/litbuild/blueprint.rb, line 130
def header_text
  value('full-name')
end
header_text_with_phase() click to toggle source
# File lib/litbuild/blueprint.rb, line 134
def header_text_with_phase
  "#{header_text} (#{active_phase} phase)"
end
logfile(stage_name, phase_name = nil) click to toggle source
# File lib/litbuild/blueprint.rb, line 138
def logfile(stage_name, phase_name = nil)
  phase = phase_name&.tr(' ', '_')
  @logfile_namer.path_for(name, phase, stage_name)
end
name() click to toggle source
# File lib/litbuild/blueprint.rb, line 106
def name
  value('name')
end
name_with_phase() click to toggle source
# File lib/litbuild/blueprint.rb, line 110
def name_with_phase
  if active_phase
    "#{name}::#{active_phase}"
  else
    name
  end
end
parameter_defaults() click to toggle source
# File lib/litbuild/blueprint.rb, line 143
def parameter_defaults
  values = {}
  all_directive_sets = [@base_directives, @phase_directives.values].flatten
  all_directive_sets.each do |dirset|
    next unless dirset.key?('parameter')

    dirset['parameter'].each do |a_param|
      val = a_param['default'].first
      values[a_param['name'].first] = if val == '(empty)'
                                        ''
                                      else
                                        val
                                      end
    end
  end
  values
end
phase_grafs() click to toggle source
# File lib/litbuild/blueprint.rb, line 82
def phase_grafs
  @phase_grafs[active_phase]
end
phases() click to toggle source
# File lib/litbuild/blueprint.rb, line 74
def phases
  @phase_directives.keys
end
phases?() click to toggle source
# File lib/litbuild/blueprint.rb, line 78
def phases?
  !@phase_directives.empty?
end
prepare(parameters:, logfile_namer:, library:) click to toggle source

This prepares a blueprint for use. This is separate from initialize because parameters are not available until after all blueprints have been parsed, and the logfile namer is not available until after the LOGFILE_DIR parameter can be resolved.

Parameters is a set of configuration parameters Logfile_namer is used to generate log file names Library is the BlueprintLibrary, used (for example) to find dependencies.

# File lib/litbuild/blueprint.rb, line 47
def prepare(parameters:, logfile_namer:, library:)
  @logfile_namer = logfile_namer
  @bp_library = library
  [@base_directives,
   @phase_directives,
   @base_grafs,
   @phase_grafs].each { |component| resolve_all(parameters, component) }
end
success_line() click to toggle source
# File lib/litbuild/blueprint.rb, line 169
def success_line
  'SUCCESS'
end
target_name() click to toggle source
# File lib/litbuild/blueprint.rb, line 161
def target_name
  if active_phase
    "#{name}::#{active_phase}"
  else
    name
  end
end
value(directive) click to toggle source

This is just like the [] operator method except that it always returns only the first value for a directive – which is helpful for all the directives that are only ever supposed to have a single value, like `name` or `full-name`.

# File lib/litbuild/blueprint.rb, line 102
def value(directive)
  self[directive]&.first
end

Protected Instance Methods

phase=(phase) click to toggle source
# File lib/litbuild/blueprint.rb, line 199
def phase=(phase)
  bptype = self.class.name.split('::').last
  msg = "#{bptype} #{name} does not have a phase '#{phase}'"
  raise(InvalidParameter, msg) unless phase.nil? || phases.include?(phase)

  @active_phase = phase
end
send_to_dependencies(visitor:) click to toggle source
# File lib/litbuild/blueprint.rb, line 193
def send_to_dependencies(visitor:)
  @bp_library.dependencies_for(self).each do |bp|
    bp.accept(visitor: visitor)
  end
end

Private Instance Methods

resolve(parameters:, a_string:) click to toggle source
# File lib/litbuild/blueprint.rb, line 220
def resolve(parameters:, a_string:)
  params = a_string.scan(/PARAM\[([A-Z_]+)\]/).flatten.sort.uniq
  params.each do |p|
    unless parameters[p]
      raise(ParameterMissing, "Parameter #{p} is not defined")
    end

    a_string.gsub!(/PARAM\[#{p}\]/, parameters[p])
  end
  a_string
end
resolve_all(parameters, something) click to toggle source
# File lib/litbuild/blueprint.rb, line 209
def resolve_all(parameters, something)
  case something
  when Hash
    something.values.each { |element| resolve_all(parameters, element) }
  when Array
    something.each { |element| resolve_all(parameters, element) }
  when String
    resolve(parameters: parameters, a_string: something)
  end
end