litbuild 1.0.3 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/lb +2 -6
- data/lib/litbuild/ascii_doc_visitor.rb +12 -11
- data/lib/litbuild/bash_script_visitor.rb +51 -22
- data/lib/litbuild/blueprint.rb +14 -8
- data/lib/litbuild/blueprint_library.rb +13 -13
- data/lib/litbuild/blueprint_parser.rb +37 -38
- data/lib/litbuild/commands.rb +1 -2
- data/lib/litbuild/logfile_namer.rb +2 -2
- data/lib/litbuild/multi_part_visitor.rb +1 -2
- data/lib/litbuild/section.rb +4 -4
- data/lib/litbuild/source_code_manager.rb +4 -6
- data/lib/litbuild/string_indentation.rb +33 -0
- data/lib/litbuild/version.rb +1 -1
- metadata +11 -35
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 450a93fb7a60735ed6618b58aff828dd2c6a8846b7664e7916df70ca319f1f4c
|
4
|
+
data.tar.gz: 0f7523cd36707b6748f868b6229d69413874503282511929891e1d4ea344d8df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '08ee5269104135777fb2dd06c225b03854b8b38c61723c0652b98aebc1fef19cad4ded3267249312e8821de764fab8360189216bf50e6b039f442a48cc9ed169'
|
7
|
+
data.tar.gz: 4626ce942e4afd88bca32d3613488bd2ac509107c90f467ae0deb3f14c0086ff6fd401647a9173ab5906284a042422802c0dc0fb067e80645217cf70e98e4686
|
data/bin/lb
CHANGED
@@ -4,14 +4,10 @@
|
|
4
4
|
gem 'litbuild'
|
5
5
|
require 'litbuild'
|
6
6
|
require 'optparse'
|
7
|
-
require 'ostruct'
|
8
7
|
require 'fileutils'
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
# defaults:
|
13
|
-
options.query = nil
|
14
|
-
options.version = false
|
9
|
+
Options = Struct.new(:query, :version)
|
10
|
+
options = Options.new(nil, false)
|
15
11
|
|
16
12
|
OptionParser.new do |opts|
|
17
13
|
opts.banner = 'Usage: lb [options] target'
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'stringio'
|
4
4
|
require 'litbuild/multi_part_visitor'
|
5
5
|
require 'litbuild/service_dir'
|
6
|
+
require 'litbuild/string_indentation'
|
6
7
|
|
7
8
|
module Litbuild
|
8
9
|
##
|
@@ -15,6 +16,8 @@ module Litbuild
|
|
15
16
|
# blueprint (phase). AsciiDocVisitor can also write a top-level
|
16
17
|
# AsciiDoc document that includes all top-level fragments.
|
17
18
|
class AsciiDocVisitor < MultiPartVisitor
|
19
|
+
include StringIndentation
|
20
|
+
|
18
21
|
def initialize(parameters:)
|
19
22
|
@parameters = parameters
|
20
23
|
super(directory: @parameters['DOCUMENT_DIR'])
|
@@ -139,10 +142,9 @@ module Litbuild
|
|
139
142
|
FileUtils.mkdir_p(location)
|
140
143
|
doc_name = format('%<count>02d-%<doc>s',
|
141
144
|
count: @written[location].size,
|
142
|
-
doc: blueprint.file_name
|
143
|
-
|
144
|
-
|
145
|
-
end
|
145
|
+
doc: "#{blueprint.file_name}.adoc")
|
146
|
+
content = to_asciidoc(blueprint, extra, summary, block)
|
147
|
+
File.write(File.join(location, doc_name), content)
|
146
148
|
@written[location] << doc_name
|
147
149
|
@all_written_targets << blueprint.target_name
|
148
150
|
end
|
@@ -180,12 +182,12 @@ module Litbuild
|
|
180
182
|
extra.call(doc)
|
181
183
|
# If there are any extraneous blank lines in the document, get rid
|
182
184
|
# of them.
|
183
|
-
doc.string.gsub(/\n\n\n+/, "\n\n").strip
|
185
|
+
"#{doc.string.gsub(/\n\n\n+/, "\n\n").strip}\n"
|
184
186
|
end
|
185
187
|
|
186
188
|
def phase_heading(level, blueprint)
|
187
189
|
"[[#{blueprint.name_with_phase},#{blueprint.header_text_with_phase}]]\n" \
|
188
|
-
|
190
|
+
"#{level} #{blueprint.header_text_with_phase}\n\n"
|
189
191
|
end
|
190
192
|
|
191
193
|
def render_grafs(doc, grafs, block)
|
@@ -275,7 +277,7 @@ module Litbuild
|
|
275
277
|
end
|
276
278
|
svc.multiline_files.keys.sort.each do |filename|
|
277
279
|
doc.puts("|#{filename.capitalize} script\nl|")
|
278
|
-
doc.puts(svc.multiline_files[filename])
|
280
|
+
doc.puts(strip_indentation_from_value(svc.multiline_files[filename]))
|
279
281
|
doc.puts
|
280
282
|
end
|
281
283
|
end
|
@@ -359,7 +361,7 @@ module Litbuild
|
|
359
361
|
end
|
360
362
|
doc.puts('[source,indent=0]')
|
361
363
|
doc.puts('----')
|
362
|
-
doc.puts(file['content'])
|
364
|
+
doc.puts(strip_indentation_from_value(file['content']))
|
363
365
|
doc.puts('----')
|
364
366
|
end
|
365
367
|
|
@@ -372,7 +374,7 @@ module Litbuild
|
|
372
374
|
doc.puts("=== #{filename}\n\n")
|
373
375
|
doc.puts('[source,indent=0]')
|
374
376
|
doc.puts('----')
|
375
|
-
doc.puts(files[filename])
|
377
|
+
doc.puts(strip_indentation_from_string(files[filename].join))
|
376
378
|
doc.puts('----')
|
377
379
|
end
|
378
380
|
end
|
@@ -397,9 +399,8 @@ module Litbuild
|
|
397
399
|
end
|
398
400
|
if !package.phases? || for_phase
|
399
401
|
write_environment_row(doc, package)
|
400
|
-
|
402
|
+
package.build_dir &&
|
401
403
|
doc.puts("|Build Directory| `#{package.build_dir}`")
|
402
|
-
end
|
403
404
|
end
|
404
405
|
doc.puts("|===\n\n")
|
405
406
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'litbuild/service_dir'
|
4
4
|
require 'litbuild/source_code_manager'
|
5
|
+
require 'litbuild/string_indentation'
|
5
6
|
require 'litbuild/visitor'
|
6
7
|
|
7
8
|
module Litbuild
|
@@ -13,6 +14,8 @@ module Litbuild
|
|
13
14
|
# phase) has already been written to any directory, BashScriptVisitor
|
14
15
|
# will ignore subsequent requests to write that blueprint (phase).
|
15
16
|
class BashScriptVisitor < Visitor
|
17
|
+
include StringIndentation
|
18
|
+
|
16
19
|
INSTALL_GID = 9999
|
17
20
|
|
18
21
|
attr_reader :blueprint_dir
|
@@ -104,6 +107,7 @@ module Litbuild
|
|
104
107
|
skip_line(f)
|
105
108
|
f.puts("trap 'echo UTTER FAILURE on line $LINENO' ERR")
|
106
109
|
f.puts('set -e -v')
|
110
|
+
f.puts('cd $(dirname $0)')
|
107
111
|
skip_line(f)
|
108
112
|
write_components(location: script_dir, script: f)
|
109
113
|
f.puts('set +v')
|
@@ -120,13 +124,11 @@ module Litbuild
|
|
120
124
|
FileUtils.mkdir_p(location)
|
121
125
|
script_name = format('%<count>02d-%<script>s',
|
122
126
|
count: @written[location].size,
|
123
|
-
script: blueprint.file_name
|
127
|
+
script: "#{blueprint.file_name}.sh")
|
124
128
|
script_path = File.join(location, script_name)
|
125
|
-
File.
|
126
|
-
f.write(to_bash_script(blueprint, block))
|
127
|
-
end
|
129
|
+
File.write(script_path, to_bash_script(blueprint, block))
|
128
130
|
FileUtils.chmod('ugo+x', script_path)
|
129
|
-
envcmds = environment_commands(blueprint).
|
131
|
+
envcmds = environment_commands(blueprint).grep_v(/^mkdir/)
|
130
132
|
unless envcmds.empty?
|
131
133
|
envscript = File.join(location, "env_#{blueprint.file_name}.sh")
|
132
134
|
File.open(envscript, 'w') do |f|
|
@@ -180,7 +182,7 @@ module Litbuild
|
|
180
182
|
blueprint.files.keys.sort.map do |name|
|
181
183
|
accum = StringIO.new
|
182
184
|
accum.puts("cat > #{name} <<'LBEOF'")
|
183
|
-
accum.puts(blueprint.files[name].string)
|
185
|
+
accum.puts(strip_indentation_from_string(blueprint.files[name].string))
|
184
186
|
accum.puts('LBEOF')
|
185
187
|
accum.string
|
186
188
|
end
|
@@ -214,11 +216,11 @@ module Litbuild
|
|
214
216
|
return [] if running_as_root
|
215
217
|
|
216
218
|
raw_sudo_cmds = @all_commands.select do |c|
|
217
|
-
c
|
219
|
+
c.include?('sudo ') && c.lines.size < 2
|
218
220
|
end.uniq
|
219
221
|
sudo_cmds = raw_sudo_cmds.map do |c|
|
220
222
|
sudoed_cmd = c.sub(/^.*sudo (.*)$/, '\\1')
|
221
|
-
sudoed_cmd = sudoed_cmd.sub(/;.*$/, '') if sudoed_cmd.
|
223
|
+
sudoed_cmd = sudoed_cmd.sub(/;.*$/, '') if sudoed_cmd.include?(';')
|
222
224
|
sudoed_cmd = convert_to_absolute(sudoed_cmd)
|
223
225
|
sudoed_cmd.gsub(/([,:=\\])/, '\\\\\1')
|
224
226
|
end
|
@@ -241,17 +243,39 @@ module Litbuild
|
|
241
243
|
build_location = dir_for_build(package)
|
242
244
|
|
243
245
|
if package.build_dir
|
244
|
-
render_command(script, "mkdir -p #{build_location}"
|
246
|
+
render_command(script, "mkdir -p #{build_location}")
|
245
247
|
skip_line(script)
|
246
248
|
end
|
247
249
|
|
250
|
+
# When actually running stage commands: if something goes wrong we
|
251
|
+
# want to try one more time without MAKEFLAGS set. This addresses
|
252
|
+
# the case where parallelism breaks builds, and also addresses
|
253
|
+
# ephemeral compiler errors that can crop up when using an
|
254
|
+
# emulated virtual machine.
|
255
|
+
#
|
256
|
+
# The simplest way of doing that, with proper `set -e` behavior,
|
257
|
+
# is to have a separate script for each stage and possibly run
|
258
|
+
# each script twice. (Shell functions don't work the same way.
|
259
|
+
# Bash is complicated.) So here we are going to write out
|
260
|
+
# temporary scripts that we can then invoke.
|
261
|
+
render_command(script, 'scriptdir=$(mktemp -d pkg.XXXXXX)')
|
262
|
+
render_command(script, 'trap "rm -rf $scriptdir" EXIT')
|
263
|
+
skip_line(script)
|
248
264
|
Package::BUILD_STAGES.each do |stage|
|
265
|
+
path = "$scriptdir/#{stage}.sh"
|
266
|
+
render_command(script, "cat > #{path} <<'LBEOF'")
|
267
|
+
render_command(script, '#!/bin/bash')
|
268
|
+
render_command(script, 'set -e')
|
249
269
|
log = package.logfile(stage, phase)
|
250
270
|
render_in_dir(script, build_location) do
|
251
271
|
package.build_commands(stage).each do |command|
|
252
272
|
render_command(script, command, log)
|
253
273
|
end
|
254
274
|
end
|
275
|
+
render_command(script, 'LBEOF')
|
276
|
+
render_command(script, "chmod 755 #{path}")
|
277
|
+
exec_cmd = "#{path} >> #{log} 2>&1"
|
278
|
+
render_command(script, "#{exec_cmd} || MAKEFLAGS='' #{exec_cmd}")
|
255
279
|
end
|
256
280
|
render_restart_trailer(script, restart_file, package.version)
|
257
281
|
end
|
@@ -311,7 +335,6 @@ module Litbuild
|
|
311
335
|
log = package.logfile('pkgusr')
|
312
336
|
pkgusr_dir = "~#{pkgusr}"
|
313
337
|
package.directives['configuration-files'] ||= []
|
314
|
-
package.directives['configuration-files'] << "~#{pkgusr}/options"
|
315
338
|
restart_file = ".#{package.active_phase || 'default'}"
|
316
339
|
render_restart_header(script, restart_file, package.version, pkgusr_dir)
|
317
340
|
pkgusr_srcdir = File.join(pkgusr_dir, package.name_and_version)
|
@@ -366,7 +389,7 @@ module Litbuild
|
|
366
389
|
package.build_dir && options.puts("export build_dir=#{package.build_dir}")
|
367
390
|
render_intree_commands(package, options)
|
368
391
|
Package::BUILD_STAGES.each do |stage|
|
369
|
-
options.puts("function #{stage}_commands
|
392
|
+
options.puts("function #{stage}_commands\n{")
|
370
393
|
cmds = package.build_commands(stage)
|
371
394
|
if cmds.empty?
|
372
395
|
options.puts(':')
|
@@ -425,11 +448,14 @@ module Litbuild
|
|
425
448
|
script.puts('fi')
|
426
449
|
end
|
427
450
|
|
428
|
-
def render_command(script, command, log)
|
451
|
+
def render_command(script, command, log = nil)
|
429
452
|
unfolded_command = command.gsub(/ ?\\\n */, ' ')
|
430
453
|
@all_commands << unfolded_command
|
431
|
-
|
432
|
-
|
454
|
+
|
455
|
+
# If a command's output is being redirected, it can't be logged.
|
456
|
+
# And if logging is being done elsewhere, we don't need to do it
|
457
|
+
# here.
|
458
|
+
if unfolded_command.include?('>') || log.nil?
|
433
459
|
script.puts(unfolded_command)
|
434
460
|
else
|
435
461
|
script.puts("#{unfolded_command} >> #{log} 2>&1")
|
@@ -485,9 +511,8 @@ module Litbuild
|
|
485
511
|
sdirs = spipe['servicedirs']
|
486
512
|
sdirs.each_with_index do |sdir, i|
|
487
513
|
render_service_dir(script, sdir)
|
488
|
-
|
514
|
+
i == sdirs.size - 1 &&
|
489
515
|
script.puts("echo #{pname} > #{sdir['name'].first}/pipeline-name")
|
490
|
-
end
|
491
516
|
if i < sdirs.size - 1
|
492
517
|
next_svc = sdirs[i + 1]['name'].first
|
493
518
|
script.puts("echo #{next_svc} > #{sdir['name'].first}/producer-for")
|
@@ -512,7 +537,7 @@ module Litbuild
|
|
512
537
|
end
|
513
538
|
multiline = sd.multiline_files
|
514
539
|
deps = sd.dependencies
|
515
|
-
multiline['dependencies'] = deps.join("\n") unless deps.empty?
|
540
|
+
multiline['dependencies'] = [deps.join("\n")] unless deps.empty?
|
516
541
|
multiline.keys.sort.each do |filename|
|
517
542
|
# I always terminate here documents in litbuild-generated
|
518
543
|
# scripts with "LBEOF", partly because I'm thinking "Litbuild
|
@@ -520,7 +545,7 @@ module Litbuild
|
|
520
545
|
# Shia LaBoeuf, and then I remember the Rob Cantor song of
|
521
546
|
# that name and giggle.
|
522
547
|
script.puts("cat > #{sd.name}/#{filename} <<'LBEOF'")
|
523
|
-
script.puts(multiline[filename])
|
548
|
+
script.puts(strip_indentation_from_value(multiline[filename]))
|
524
549
|
script.puts('LBEOF')
|
525
550
|
end
|
526
551
|
env = sd.env
|
@@ -537,7 +562,10 @@ module Litbuild
|
|
537
562
|
cfgs = blueprint['configuration-files']
|
538
563
|
return unless cfgs
|
539
564
|
|
540
|
-
|
565
|
+
unless cfgs.empty?
|
566
|
+
cmd = "cfggit add #{cfgs.join(' ')}"
|
567
|
+
render_command(script, cmd, log)
|
568
|
+
end
|
541
569
|
render_command(script, 'cfggit stageall', log)
|
542
570
|
bp = "#{blueprint.class.name.split('::').last} #{blueprint.name}"
|
543
571
|
cmd = "cfggit as-default -m 'Configuration files for #{bp}'"
|
@@ -553,11 +581,12 @@ module Litbuild
|
|
553
581
|
# now, if the value contains ' -- backslash-quote everything (incl spaces)
|
554
582
|
# if the value contains " -- single-quote the whole thing
|
555
583
|
# if the value contains other punctuation -- double-quote the whole thing
|
556
|
-
|
584
|
+
case oneline
|
585
|
+
when /'/
|
557
586
|
oneline.gsub(/([\\ "'`$])/, '\\\\\1')
|
558
|
-
|
587
|
+
when /"/
|
559
588
|
"'#{oneline}'"
|
560
|
-
|
589
|
+
when /[\\ `]/
|
561
590
|
"\"#{oneline}\""
|
562
591
|
else
|
563
592
|
oneline
|
data/lib/litbuild/blueprint.rb
CHANGED
@@ -7,8 +7,17 @@ require 'litbuild/logfile_namer'
|
|
7
7
|
require 'litbuild/visitor'
|
8
8
|
|
9
9
|
module Litbuild
|
10
|
+
# Blueprints are described in the `doc` directory.
|
11
|
+
#
|
12
|
+
# tl;dr: Blueprints are considered as "chunks" separated by blank
|
13
|
+
# lines. Each chunk can be either directives or narrative. Narrative
|
14
|
+
# is AsciiDoc and does not get parsed or transformed. Directives are
|
15
|
+
# basically a simplified version of YAML.
|
16
|
+
#
|
17
|
+
# After parsing, the narrative is found in the `grafs` variables and
|
18
|
+
# directives are found in `directive` hashes.
|
10
19
|
class Blueprint
|
11
|
-
class <<self
|
20
|
+
class << self
|
12
21
|
# This should simply be the name of the directory where blueprints
|
13
22
|
# of each specific type are expected to be found by Driver.
|
14
23
|
def self.directory_name
|
@@ -16,9 +25,7 @@ module Litbuild
|
|
16
25
|
end
|
17
26
|
end
|
18
27
|
|
19
|
-
attr_reader :active_phase
|
20
|
-
attr_reader :base_grafs
|
21
|
-
attr_writer :logfile_namer
|
28
|
+
attr_reader :active_phase, :base_grafs, :logfile_namer
|
22
29
|
|
23
30
|
def self.descendants
|
24
31
|
ObjectSpace.each_object(Class).select { |c| c < self }
|
@@ -180,7 +187,7 @@ module Litbuild
|
|
180
187
|
# to avoid including two versions of the dependency.
|
181
188
|
def deduped_dependency_names
|
182
189
|
dep_names = self['depends-on'].clone || []
|
183
|
-
deps_with_phase = dep_names.select { |dep| dep.
|
190
|
+
deps_with_phase = dep_names.select { |dep| dep.include?('::') }
|
184
191
|
deps_with_phase.each do |dep|
|
185
192
|
dep_without_phase = dep.split('::')[0]
|
186
193
|
dep_names.delete(dep_without_phase)
|
@@ -209,7 +216,7 @@ module Litbuild
|
|
209
216
|
def resolve_all(parameters, something)
|
210
217
|
case something
|
211
218
|
when Hash
|
212
|
-
something.
|
219
|
+
something.each_value { |element| resolve_all(parameters, element) }
|
213
220
|
when Array
|
214
221
|
something.each { |element| resolve_all(parameters, element) }
|
215
222
|
when String
|
@@ -220,9 +227,8 @@ module Litbuild
|
|
220
227
|
def resolve(parameters:, a_string:)
|
221
228
|
params = a_string.scan(/PARAM\[([A-Z_]+)\]/).flatten.sort.uniq
|
222
229
|
params.each do |p|
|
223
|
-
|
230
|
+
parameters[p] ||
|
224
231
|
raise(ParameterMissing, "Parameter #{p} is not defined")
|
225
|
-
end
|
226
232
|
|
227
233
|
a_string.gsub!(/PARAM\[#{p}\]/, parameters[p])
|
228
234
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'litbuild/commands
|
4
|
-
require 'litbuild/narrative
|
5
|
-
require 'litbuild/package
|
6
|
-
require 'litbuild/section
|
3
|
+
require 'litbuild/commands'
|
4
|
+
require 'litbuild/narrative'
|
5
|
+
require 'litbuild/package'
|
6
|
+
require 'litbuild/section'
|
7
7
|
|
8
8
|
module Litbuild
|
9
9
|
# BlueprintLibrary initializes and sets configuration parameters for
|
@@ -33,9 +33,7 @@ module Litbuild
|
|
33
33
|
def blueprint_for(target:)
|
34
34
|
name, phase = split_name_and_phase(target: target)
|
35
35
|
bp = blueprints[name]
|
36
|
-
|
37
|
-
raise(UnknownBlueprint, "Blueprint #{name} not found in library")
|
38
|
-
end
|
36
|
+
bp || raise(UnknownBlueprint, "Blueprint #{name} not found in library")
|
39
37
|
|
40
38
|
bp.for_phase(phase)
|
41
39
|
end
|
@@ -46,7 +44,7 @@ module Litbuild
|
|
46
44
|
def dependencies_for(blueprint)
|
47
45
|
dep_names = blueprint.deduped_dependency_names
|
48
46
|
dep_names.map do |dep|
|
49
|
-
if dep.
|
47
|
+
if dep.include?('::') # Explicit phase specified
|
50
48
|
blueprint_for(target: dep)
|
51
49
|
else
|
52
50
|
bp = blueprint_for(target: dep)
|
@@ -64,7 +62,7 @@ module Litbuild
|
|
64
62
|
# split a target name, like linux::headers, into a blueprint name
|
65
63
|
# (linux) and a phase name (headers).
|
66
64
|
def split_name_and_phase(target:)
|
67
|
-
if target.
|
65
|
+
if target.include?('::')
|
68
66
|
target.strip.match(/(.*)::(.*)/)[1..2]
|
69
67
|
else
|
70
68
|
[target.strip, nil]
|
@@ -82,13 +80,15 @@ module Litbuild
|
|
82
80
|
# works around the issue, whatever it is.
|
83
81
|
return unless blueprint_type.name
|
84
82
|
|
83
|
+
# All blueprints have a name and a full-name. If a blueprint has
|
84
|
+
# no `name:` or `full-name:` directive, they will be provided at
|
85
|
+
# load time.
|
86
|
+
automatic_directives = %w[name full-name]
|
87
|
+
|
85
88
|
Dir.glob("./#{blueprint_type.directory_name}/*.txt").each do |a_file|
|
86
89
|
bp_text = File.read(a_file)
|
87
90
|
begin
|
88
|
-
|
89
|
-
# has no `name:` or `full-name:` directive, they will be
|
90
|
-
# provided at load time.
|
91
|
-
%w[name full-name].each do |directive|
|
91
|
+
automatic_directives.each do |directive|
|
92
92
|
unless bp_text.match?(/^#{directive}:/)
|
93
93
|
bp_text = "#{directive}: #{File.basename(a_file, '.txt')}\n\n" +
|
94
94
|
bp_text
|
@@ -1,20 +1,18 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
2
|
|
3
3
|
require 'litbuild/errors'
|
4
|
+
require 'litbuild/string_indentation'
|
4
5
|
require 'json'
|
5
6
|
|
6
7
|
module Litbuild
|
7
8
|
# This is a kludgy hand-built parser. Blueprint structure is not (at
|
8
9
|
# least, at this point) complicated enough that I can see any point in
|
9
10
|
# defining a grammar and using a parser generator. The structure of
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# as well).
|
13
|
-
#
|
14
|
-
# tl;dr: each paragraph can be either directives or narrative.
|
15
|
-
# Narrative is AsciiDoc and does not get parsed or transformed.
|
16
|
-
# Directives are basically a simplified version of YAML.
|
11
|
+
# blueprints is described informally in `doc/blueprints.txt` (and
|
12
|
+
# blueprint-type-specific files under `doc` as well).
|
17
13
|
class BlueprintParser
|
14
|
+
include StringIndentation
|
15
|
+
|
18
16
|
# _directives_ are for use in scripts. _grafs_ are for use in
|
19
17
|
# documents.
|
20
18
|
attr_reader :base_directives, :phase_directives, :base_grafs, :phase_grafs
|
@@ -30,9 +28,8 @@ module Litbuild
|
|
30
28
|
# blueprint. If there are no phase directives, this is the entire
|
31
29
|
# blueprint, obvs.
|
32
30
|
@base_grafs = []
|
33
|
-
|
34
|
-
|
35
|
-
@base_directives = base
|
31
|
+
@base_directives = parse_phase(phase_chunks.shift, {}, @base_grafs)
|
32
|
+
@base_directives['full-name'] ||= @base_directives['name']
|
36
33
|
|
37
34
|
# The rest of the blueprint, if any, consists of directives and
|
38
35
|
# narrative for specific phases. The directives for each phase
|
@@ -42,13 +39,15 @@ module Litbuild
|
|
42
39
|
phase_name = phase_chunks.shift
|
43
40
|
phase_contents = phase_chunks.shift
|
44
41
|
grafs = []
|
45
|
-
@phase_directives[phase_name] = parse_phase(phase_contents,
|
42
|
+
@phase_directives[phase_name] = parse_phase(phase_contents,
|
43
|
+
@base_directives,
|
44
|
+
grafs)
|
46
45
|
@phase_grafs[phase_name] = grafs
|
47
46
|
end
|
48
47
|
|
49
48
|
# Any directives at the beginning of a blueprint are actually a
|
50
|
-
# file header that should not be
|
51
|
-
# for it.
|
49
|
+
# file header that should not be considered as part of the
|
50
|
+
# narrative for it.
|
52
51
|
@base_grafs.shift while @base_grafs[0].is_a?(Hash)
|
53
52
|
rescue StandardError => e
|
54
53
|
msg = "Cannot parse blueprint starting: #{@text.lines[0..3].join}"
|
@@ -97,7 +96,7 @@ module Litbuild
|
|
97
96
|
end
|
98
97
|
|
99
98
|
def directives?(paragraph)
|
100
|
-
paragraph.split
|
99
|
+
paragraph.split.first =~ /^[a-z-]+:/
|
101
100
|
end
|
102
101
|
|
103
102
|
def add_directives(directives, parsed)
|
@@ -122,15 +121,13 @@ module Litbuild
|
|
122
121
|
end
|
123
122
|
directive_name = md[1]
|
124
123
|
firstline_value = md[2]
|
125
|
-
value_lines = related_lines(directive_line, lines_to_process)
|
126
|
-
value = parse_directive_value(firstline_value, value_lines)
|
127
|
-
if value == "''"
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
graf_directives[directive_name] << value
|
133
|
-
end
|
124
|
+
value_lines, indent = related_lines(directive_line, lines_to_process)
|
125
|
+
value = parse_directive_value(firstline_value, value_lines, indent)
|
126
|
+
graf_directives[directive_name] << if value == "''"
|
127
|
+
''
|
128
|
+
else
|
129
|
+
value
|
130
|
+
end
|
134
131
|
graf_directives[directive_name].flatten!
|
135
132
|
end
|
136
133
|
graf_directives
|
@@ -139,7 +136,9 @@ module Litbuild
|
|
139
136
|
# Regardless of what kind of directive structure we're dealing with,
|
140
137
|
# all of the lines that are indented more than the initial directive
|
141
138
|
# line are part of that directive. This method finds all those
|
142
|
-
# related lines and strips away the common initial indentation
|
139
|
+
# related lines and strips away the common initial indentation; it
|
140
|
+
# returns both the related lines and the amount of indentation that
|
141
|
+
# was removed.
|
143
142
|
def related_lines(directive_line, lines_to_process)
|
144
143
|
directive_indent = indent_for(directive_line)
|
145
144
|
related = []
|
@@ -147,16 +146,15 @@ module Litbuild
|
|
147
146
|
(indent_for(lines_to_process[0]) > directive_indent)
|
148
147
|
related << lines_to_process.shift
|
149
148
|
end
|
150
|
-
|
151
|
-
related.map { |l| l.slice(common_indent..-1) }
|
149
|
+
strip_indentation_from_array(related)
|
152
150
|
end
|
153
151
|
|
154
152
|
# What kind of directive are we dealing with? Could be a simple
|
155
153
|
# value (with zero or more continuation lines), or a multiline
|
156
154
|
# value, or an array, or a subdirective block.
|
157
|
-
def parse_directive_value(firstline_value, other_lines)
|
155
|
+
def parse_directive_value(firstline_value, other_lines, indentation)
|
158
156
|
if firstline_value == '|'
|
159
|
-
multiline_value(other_lines)
|
157
|
+
multiline_value(other_lines, indentation)
|
160
158
|
elsif other_lines.empty?
|
161
159
|
firstline_value
|
162
160
|
elsif other_lines[0].match?(/^ *- /)
|
@@ -177,8 +175,15 @@ module Litbuild
|
|
177
175
|
stripped.join(" \\\n ")
|
178
176
|
end
|
179
177
|
|
180
|
-
|
181
|
-
|
178
|
+
# While parsing multiline values, we want to restore the indentation
|
179
|
+
# that was previously stripped away -- this is typically used for
|
180
|
+
# `file` directives, which often appear in multiple directive blocks
|
181
|
+
# and should be treated as a whole. The indentation for multi-line
|
182
|
+
# values must be removed *later*, during rendering of scripts and
|
183
|
+
# documents.
|
184
|
+
def multiline_value(lines, indentation)
|
185
|
+
lines_with_indentation = lines.map { |l| (' ' * indentation) + l }
|
186
|
+
"#{lines_with_indentation.join("\n")}\n"
|
182
187
|
end
|
183
188
|
|
184
189
|
def array_value(lines)
|
@@ -186,8 +191,8 @@ module Litbuild
|
|
186
191
|
until lines.empty?
|
187
192
|
array_member = lines.shift
|
188
193
|
firstline_value = /^- *(.*)$/.match(array_member)[1]
|
189
|
-
related = related_lines(array_member, lines)
|
190
|
-
value << parse_directive_value(firstline_value, related)
|
194
|
+
related, indentation = related_lines(array_member, lines)
|
195
|
+
value << parse_directive_value(firstline_value, related, indentation)
|
191
196
|
end
|
192
197
|
value
|
193
198
|
rescue StandardError
|
@@ -200,11 +205,5 @@ module Litbuild
|
|
200
205
|
def subdirective_value(lines)
|
201
206
|
parse_lines(lines)
|
202
207
|
end
|
203
|
-
|
204
|
-
# Utility method to find the amount of blank space at the beginning
|
205
|
-
# of a line.
|
206
|
-
def indent_for(line)
|
207
|
-
/^([[:blank:]]*).*/.match(line)[1].size
|
208
|
-
end
|
209
208
|
end
|
210
209
|
end
|
data/lib/litbuild/commands.rb
CHANGED
@@ -26,9 +26,8 @@ module Litbuild
|
|
26
26
|
protected
|
27
27
|
|
28
28
|
def add_file_content(directive)
|
29
|
-
|
29
|
+
(directive['name'] && directive['content']) ||
|
30
30
|
raise(InvalidDirective, 'file directive missing name or content')
|
31
|
-
end
|
32
31
|
|
33
32
|
content = @files[directive['name'].first] ||= StringIO.new
|
34
33
|
content.puts(directive['content'].first)
|
@@ -8,7 +8,7 @@ module Litbuild
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def path_for(blueprint, phase = nil, stage = nil)
|
11
|
-
count = format('
|
11
|
+
count = format('%<counter>03d', counter: @counter)
|
12
12
|
@counter += 1
|
13
13
|
file_name = build_name(count, blueprint, phase, stage)
|
14
14
|
File.join(@log_dir, file_name)
|
@@ -17,7 +17,7 @@ module Litbuild
|
|
17
17
|
protected
|
18
18
|
|
19
19
|
def build_name(*elements)
|
20
|
-
elements.uniq.compact.join('-')
|
20
|
+
"#{elements.uniq.compact.join('-')}.log"
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
data/lib/litbuild/section.rb
CHANGED
@@ -35,8 +35,8 @@ module Litbuild
|
|
35
35
|
|
36
36
|
blueprints = self['blueprints'].clone || []
|
37
37
|
if $DEBUG
|
38
|
-
warn("Explicit blueprints for section #{name}:" \
|
39
|
-
"
|
38
|
+
warn("Explicit blueprints for section #{name}: " \
|
39
|
+
"#{blueprints.join(', ')}")
|
40
40
|
end
|
41
41
|
blueprints << automatic_inclusions
|
42
42
|
deduped = blueprints.flatten.uniq
|
@@ -56,8 +56,8 @@ module Litbuild
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
if $DEBUG
|
59
|
-
warn("Automatically-added blueprints for section #{name}:" \
|
60
|
-
"
|
59
|
+
warn("Automatically-added blueprints for section #{name}: " \
|
60
|
+
"#{auto_adds.sort.join(', ')}")
|
61
61
|
end
|
62
62
|
auto_adds.sort
|
63
63
|
end
|
@@ -67,14 +67,12 @@ module Litbuild
|
|
67
67
|
end
|
68
68
|
copy_commands = []
|
69
69
|
package.tar_files_needed.each do |filename|
|
70
|
-
|
71
|
-
copy_commands << "cp #{find_tarfile(filename)} ~#{pkgusr}/src"
|
72
|
-
end
|
70
|
+
pkgusr_file_available?(package, filename) ||
|
71
|
+
(copy_commands << "cp #{find_tarfile(filename)} ~#{pkgusr}/src")
|
73
72
|
end
|
74
73
|
package.patch_files.each do |filename|
|
75
|
-
|
76
|
-
copy_commands << "cp #{find_file(filename)} ~#{pkgusr}/patches"
|
77
|
-
end
|
74
|
+
pkgusr_file_available?(package, filename) ||
|
75
|
+
(copy_commands << "cp #{find_file(filename)} ~#{pkgusr}/patches")
|
78
76
|
end
|
79
77
|
mkdir_commands + copy_commands.sort
|
80
78
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
module Litbuild
|
4
|
+
module StringIndentation
|
5
|
+
# Utility method to find the amount of blank space at the beginning
|
6
|
+
# of a line.
|
7
|
+
def indent_for(line)
|
8
|
+
/^([[:blank:]]*).*/.match(line)[1].size
|
9
|
+
end
|
10
|
+
|
11
|
+
# Utility method to strip the common indentation from all strings in
|
12
|
+
# an array. Returns both the stripped strings and the amount of
|
13
|
+
# indentation removed.
|
14
|
+
def strip_indentation_from_array(strings)
|
15
|
+
common_indent = strings.map { |l| indent_for(l) }.min
|
16
|
+
[strings.map { |l| l.slice(common_indent..-1) }, common_indent]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Utility method to strip the common indentation from all lines of a
|
20
|
+
# multi-line string. (Does not return the amount of indentation
|
21
|
+
# removed.)
|
22
|
+
def strip_indentation_from_string(string)
|
23
|
+
strip_indentation_from_array(string.lines)[0]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Utility method to strip the common indentation from all lines of a
|
27
|
+
# directive value (which is expected to be an array containing a
|
28
|
+
# single string element)
|
29
|
+
def strip_indentation_from_value(value)
|
30
|
+
strip_indentation_from_string(value[0])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/litbuild/version.rb
CHANGED
metadata
CHANGED
@@ -1,40 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: litbuild
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Neumeier
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
-
-
|
12
|
-
-----BEGIN CERTIFICATE-----
|
13
|
-
MIIEMDCCApigAwIBAgIBATANBgkqhkiG9w0BAQsFADAhMR8wHQYDVQQDDBZicmV0
|
14
|
-
dC9EQz1mcmVlc2EvREM9b3JnMB4XDTE5MDkwMTEyNDkxMFoXDTIwMDgzMTEyNDkx
|
15
|
-
MFowITEfMB0GA1UEAwwWYnJldHQvREM9ZnJlZXNhL0RDPW9yZzCCAaIwDQYJKoZI
|
16
|
-
hvcNAQEBBQADggGPADCCAYoCggGBALKrZnh07ME+wnUpu3EYsKisqaD68WomtNpt
|
17
|
-
pOIPUWtQnRD3iVKmPfIsCrwGbU1NQDohiwz0SdLlLVDHIovwZB/j9sI5tzSfltas
|
18
|
-
5dNgN4mgtURqlILYNmuyDbOOsWtOec9Nz7OJfvV6oat7m4prf+rU0j8JtzCAsFNT
|
19
|
-
B/IdLSqJlJEQ4UMeHPaC06RjOJJJOXSE+yh0Sm2dHjNnUyFnrzfHehMMFJ0wpL42
|
20
|
-
RFaxRNGp/U9fn/h94lXz8h42ksoWXWG8RrsnRA3Olsu6uWQJsggnMbD7zzHlQ9Xf
|
21
|
-
0cV9ePbXmyKm2EfvcoVLBybimPmvYxrXOOxblbIMFl3yWX+YfJKrEsLb5F54RSao
|
22
|
-
N4wy76RNF+d7m2yarhiqPf1dm8kzPRzJmhLLMpPa89N3mQaQtC+jrVEME6ahLNhl
|
23
|
-
lnxLd3zcT7ExrHJQQnQgei5AsJe80Noq9K2+8QjLSYDSNsc80SuBczqMeybHxVVA
|
24
|
-
4CJKSU+amFYp/Z414cJr9AG+/xal8wIDAQABo3MwcTAJBgNVHRMEAjAAMAsGA1Ud
|
25
|
-
DwQEAwIEsDAdBgNVHQ4EFgQUtedZFs4wsrrlPms2Gt+1jV7JYYwwGwYDVR0RBBQw
|
26
|
-
EoEQYnJldHRAZnJlZXNhLm9yZzAbBgNVHRIEFDASgRBicmV0dEBmcmVlc2Eub3Jn
|
27
|
-
MA0GCSqGSIb3DQEBCwUAA4IBgQAfjb44P0zp86q4cvN8Wv/VEyvVLEiTT/DFWmER
|
28
|
-
UBMPB1lIUxxgCs6MqxpRK8icX4IRb/W9qeC2nIBsmY7u4Xoj3JiaOLmoJImXt+tO
|
29
|
-
KdGUu7ygymVZ7991XaAf4dpOcVYMmUDqS+G7mo/nbHBT4440AG2SSL02Nj7zDfn8
|
30
|
-
Ut0XU+6UT3WxpBIA1o/BTmLkPvQhkOEMv7sWBWHdvS0eSxNTSfXpwkjIYpXMsUIg
|
31
|
-
BbgMcxnxUIv5Y+Xb/TIbrRYqiDtqsDT+vsadKk3qjN0bx7vCVdibh2cfGTJA9Spe
|
32
|
-
pi1q/NcnHXSeMFJ4iWyp6lyZxo+B7KIFkgD/irWbBoyZYpbMYJexasmoVuFgyvND
|
33
|
-
VBt/HnbucMCrdU4EqbBQHFimTIyvOaI12/TaU4362smlgZhZdnlHyBeOUBGzDSLX
|
34
|
-
PvrrfEkjwo+u4dPBTaO5ZBa4qsFE5bK/1l6d4AVV5Yi5NohUwmpp1bFFCGPqvzVA
|
35
|
-
bhee2x0YS1uGTnADpv2GLkmNMIA=
|
36
|
-
-----END CERTIFICATE-----
|
37
|
-
date: 2019-09-14 00:00:00.000000000 Z
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-12-19 00:00:00.000000000 Z
|
38
12
|
dependencies: []
|
39
13
|
description: A build system based on Knuth's idea of literate programming.
|
40
14
|
email:
|
@@ -65,14 +39,16 @@ files:
|
|
65
39
|
- lib/litbuild/service_dir.rb
|
66
40
|
- lib/litbuild/source_code_manager.rb
|
67
41
|
- lib/litbuild/source_files_visitor.rb
|
42
|
+
- lib/litbuild/string_indentation.rb
|
68
43
|
- lib/litbuild/url_visitor.rb
|
69
44
|
- lib/litbuild/version.rb
|
70
45
|
- lib/litbuild/visitor.rb
|
71
46
|
homepage: http://git.freesa.org/freesa/litbuild
|
72
47
|
licenses:
|
73
48
|
- GPL-3.0
|
74
|
-
metadata:
|
75
|
-
|
49
|
+
metadata:
|
50
|
+
rubygems_mfa_required: 'true'
|
51
|
+
post_install_message:
|
76
52
|
rdoc_options: []
|
77
53
|
require_paths:
|
78
54
|
- lib
|
@@ -80,15 +56,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
80
56
|
requirements:
|
81
57
|
- - ">="
|
82
58
|
- !ruby/object:Gem::Version
|
83
|
-
version: '
|
59
|
+
version: '3.0'
|
84
60
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
61
|
requirements:
|
86
62
|
- - ">="
|
87
63
|
- !ruby/object:Gem::Version
|
88
64
|
version: '0'
|
89
65
|
requirements: []
|
90
|
-
rubygems_version: 3.
|
91
|
-
signing_key:
|
66
|
+
rubygems_version: 3.2.3
|
67
|
+
signing_key:
|
92
68
|
specification_version: 4
|
93
69
|
summary: A literate build system
|
94
70
|
test_files: []
|
checksums.yaml.gz.sig
DELETED
Binary file
|
data.tar.gz.sig
DELETED
Binary file
|
metadata.gz.sig
DELETED