Class: Litbuild::Blueprint

Inherits:
Object
  • Object
show all
Defined in:
lib/litbuild/blueprint.rb

Overview

Blueprints are described in the ‘doc` directory.

tl;dr: Blueprints are considered as “chunks” separated by blank lines. Each chunk can be either directives or narrative. Narrative is AsciiDoc and does not get parsed or transformed. Directives are basically a simplified version of YAML.

After parsing, the narrative is found in the ‘grafs` variables and directives are found in `directive` hashes.

Direct Known Subclasses

Commands, Narrative, Package, Section

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(text:) ⇒ Blueprint

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



36
37
38
39
40
41
42
43
# File 'lib/litbuild/blueprint.rb', line 36

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

Instance Attribute Details

#active_phaseObject (readonly)

Returns the value of attribute active_phase.



28
29
30
# File 'lib/litbuild/blueprint.rb', line 28

def active_phase
  @active_phase
end

#base_grafsObject (readonly)

Returns the value of attribute base_grafs.



28
29
30
# File 'lib/litbuild/blueprint.rb', line 28

def base_grafs
  @base_grafs
end

#logfile_namerObject (readonly)

Returns the value of attribute logfile_namer.



28
29
30
# File 'lib/litbuild/blueprint.rb', line 28

def logfile_namer
  @logfile_namer
end

Class Method Details

.descendantsObject



30
31
32
# File 'lib/litbuild/blueprint.rb', line 30

def self.descendants
  ObjectSpace.each_object(Class).select { |c| c < self }
end

.directory_nameObject

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



23
24
25
# File 'lib/litbuild/blueprint.rb', line 23

def self.directory_name
  raise(SubclassResponsibility)
end

Instance Method Details

#[](directive) ⇒ Object



101
102
103
# File 'lib/litbuild/blueprint.rb', line 101

def [](directive)
  directives[directive]
end

#accept(visitor:) ⇒ Object

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!



67
68
69
# File 'lib/litbuild/blueprint.rb', line 67

def accept(visitor:)
  send_to_dependencies(visitor: visitor)
end

#deduped_dependency_namesObject

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.



188
189
190
191
192
193
194
195
196
# File 'lib/litbuild/blueprint.rb', line 188

def deduped_dependency_names
  dep_names = self['depends-on'].clone || []
  deps_with_phase = dep_names.select { |dep| dep.include?('::') }
  deps_with_phase.each do |dep|
    dep_without_phase = dep.split('::')[0]
    dep_names.delete(dep_without_phase)
  end
  dep_names
end

#directivesObject



93
94
95
96
97
98
99
# File 'lib/litbuild/blueprint.rb', line 93

def directives
  if active_phase
    @phase_directives[active_phase]
  else
    @base_directives
  end
end

#failure_lineObject



180
181
182
# File 'lib/litbuild/blueprint.rb', line 180

def failure_line
  'FAILURE'
end

#file_nameObject



129
130
131
132
133
134
135
# File 'lib/litbuild/blueprint.rb', line 129

def file_name
  if active_phase
    "#{name}-#{active_phase}"
  else
    name
  end.tr(' ', '-')
end

#for_phase(new_active_phase) ⇒ Object

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



73
74
75
76
77
78
79
# File 'lib/litbuild/blueprint.rb', line 73

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_nameObject



125
126
127
# File 'lib/litbuild/blueprint.rb', line 125

def full_name
  value('full-name')
end

#header_textObject



137
138
139
# File 'lib/litbuild/blueprint.rb', line 137

def header_text
  value('full-name')
end

#header_text_with_phaseObject



141
142
143
# File 'lib/litbuild/blueprint.rb', line 141

def header_text_with_phase
  "#{header_text} (#{active_phase} phase)"
end

#logfile(stage_name, phase_name = nil) ⇒ Object



145
146
147
148
# File 'lib/litbuild/blueprint.rb', line 145

def logfile(stage_name, phase_name = nil)
  phase = phase_name&.tr(' ', '_')
  @logfile_namer.path_for(name, phase, stage_name)
end

#nameObject



113
114
115
# File 'lib/litbuild/blueprint.rb', line 113

def name
  value('name')
end

#name_with_phaseObject



117
118
119
120
121
122
123
# File 'lib/litbuild/blueprint.rb', line 117

def name_with_phase
  if active_phase
    "#{name}::#{active_phase}"
  else
    name
  end
end

#parameter_defaultsObject



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/litbuild/blueprint.rb', line 150

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_grafsObject



89
90
91
# File 'lib/litbuild/blueprint.rb', line 89

def phase_grafs
  @phase_grafs[active_phase]
end

#phasesObject



81
82
83
# File 'lib/litbuild/blueprint.rb', line 81

def phases
  @phase_directives.keys
end

#phases?Boolean

Returns:

  • (Boolean)


85
86
87
# File 'lib/litbuild/blueprint.rb', line 85

def phases?
  !@phase_directives.empty?
end

#prepare(parameters:, logfile_namer:, library:) ⇒ Object

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.



54
55
56
57
58
59
60
61
# File 'lib/litbuild/blueprint.rb', line 54

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_lineObject



176
177
178
# File 'lib/litbuild/blueprint.rb', line 176

def success_line
  'SUCCESS'
end

#target_nameObject



168
169
170
171
172
173
174
# File 'lib/litbuild/blueprint.rb', line 168

def target_name
  if active_phase
    "#{name}::#{active_phase}"
  else
    name
  end
end

#value(directive) ⇒ Object

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`.



109
110
111
# File 'lib/litbuild/blueprint.rb', line 109

def value(directive)
  self[directive]&.first
end