metanorma 2.5.1 → 2.5.2
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/lib/metanorma/collection/collection.rb +20 -1
- data/lib/metanorma/collection/log.rb +7 -0
- data/lib/metanorma/collection/renderer/filelocation.rb +7 -3
- data/lib/metanorma/collection/renderer/fileprocess.rb +59 -3
- data/lib/metanorma/collection/renderer/renderer.rb +9 -2
- data/lib/metanorma/compile/render.rb +24 -9
- data/lib/metanorma/version.rb +1 -1
- metadata +1 -2
- data/.hound.yml +0 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cc6ddbece893102c78d8b27a94f175a85c45cfb911e8d7bc908440bd19a58e85
|
|
4
|
+
data.tar.gz: 226289825a52fe8da92a744a00a2239385e46f0964468be522f6b5bb7ba8066d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0d9c775a338fc4b30a27aa53e217037583228a702c61977070f7e76895718b7a1d8e138b26f3053eed4ae9bdfb361a9b4545b62ad4c6e98df5f187eef8209399
|
|
7
|
+
data.tar.gz: f5c41df1386891d848d76576e783335697c80adb75eefda918a990c414ec112844d53e9f94717049873171f9978acaa28e7eed98e04ab11eedcbb11d87119576
|
|
@@ -11,6 +11,9 @@ module Metanorma
|
|
|
11
11
|
|
|
12
12
|
class AdocFileNotFoundException < StandardError; end
|
|
13
13
|
|
|
14
|
+
# One or more collection members failed to render (#586)
|
|
15
|
+
class RenderFailureException < StandardError; end
|
|
16
|
+
|
|
14
17
|
# Metanorma collection of documents
|
|
15
18
|
class Collection
|
|
16
19
|
attr_reader :file, :prefatory, :final
|
|
@@ -132,8 +135,24 @@ module Metanorma
|
|
|
132
135
|
opts[:log] = @log
|
|
133
136
|
opts[:flavor] = @flavor
|
|
134
137
|
output_folder(opts)
|
|
135
|
-
::Metanorma::Collection::Renderer.render self, opts
|
|
138
|
+
cr = ::Metanorma::Collection::Renderer.render self, opts
|
|
136
139
|
clean_exit
|
|
140
|
+
render_failures_abort(cr)
|
|
141
|
+
cr
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# A member whose rendering fails no longer lets the collection
|
|
145
|
+
# report success with the document missing from the output (#586).
|
|
146
|
+
# Every member is rendered before aborting, so one run reports all
|
|
147
|
+
# failures; the raise makes callers (CLI, suma) exit non-zero. Runs
|
|
148
|
+
# after clean_exit so the failures are in the written log.
|
|
149
|
+
def render_failures_abort(renderer)
|
|
150
|
+
f = renderer.fatal_errors
|
|
151
|
+
f.empty? and return
|
|
152
|
+
raise RenderFailureException.new(
|
|
153
|
+
"Collection render failed for #{f.size} document(s):\n" +
|
|
154
|
+
f.join("\n"),
|
|
155
|
+
)
|
|
137
156
|
end
|
|
138
157
|
|
|
139
158
|
def output_folder(opts)
|
|
@@ -11,6 +11,13 @@ module Metanorma
|
|
|
11
11
|
"METANORMA_3": { category: "Cross-References",
|
|
12
12
|
error: "<strong>** Unresolved reference to document %s from eref</strong>",
|
|
13
13
|
severity: 2 },
|
|
14
|
+
"METANORMA_4": { category: "Rendering",
|
|
15
|
+
error: "Collection member %s: expected output " \
|
|
16
|
+
"file not generated: %s",
|
|
17
|
+
severity: 0 },
|
|
18
|
+
"METANORMA_5": { category: "Rendering",
|
|
19
|
+
error: "Collection member %s: rendering error: %s",
|
|
20
|
+
severity: 0 },
|
|
14
21
|
}.freeze
|
|
15
22
|
# rubocop:enable Naming/VariableNumber
|
|
16
23
|
end
|
|
@@ -26,12 +26,16 @@ module Metanorma
|
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
# Move file to new output filename if specified
|
|
29
|
+
# Move file to new output filename if specified. A member that
|
|
30
|
+
# failed to render has nothing to move: keep the original name
|
|
31
|
+
# registered so output verification reports it as missing, rather
|
|
32
|
+
# than crashing the whole collection on the mv (#586).
|
|
30
33
|
def handle_new_output_filename(output_fname, new_output_fname)
|
|
31
34
|
return output_fname unless new_output_fname
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
src = File.join(@outdir, output_fname)
|
|
37
|
+
File.exist?(src) or return output_fname
|
|
38
|
+
FileUtils.mv(src, File.join(@outdir, new_output_fname))
|
|
35
39
|
new_output_fname
|
|
36
40
|
end
|
|
37
41
|
|
|
@@ -18,9 +18,61 @@ module Metanorma
|
|
|
18
18
|
opts = compile_options_base(identifier)
|
|
19
19
|
.merge(compile_options_update(identifier))
|
|
20
20
|
|
|
21
|
+
err_count = @compile.errors.size
|
|
21
22
|
@compile.compile file, opts
|
|
22
23
|
@files.set(identifier, :outputs, {})
|
|
23
24
|
file_compile_formats(filename, identifier, opts)
|
|
25
|
+
file_compile_verify(identifier, @compile.errors[err_count..] || [])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# A member whose rendering raised produces no output file, but the
|
|
29
|
+
# collection build used to continue, exit 0, and link the absent
|
|
30
|
+
# document from index.html -- silent data loss (#586). Two
|
|
31
|
+
# complementary checks close that hole. (1) Compile pools rescued
|
|
32
|
+
# error messages in @compile.errors for its caller to surface; the
|
|
33
|
+
# standalone CLI does, but the collection pipeline never read the
|
|
34
|
+
# pool. The pool is shared across members and never reset, so the
|
|
35
|
+
# slice appended during this member's compile is this member's
|
|
36
|
+
# errors -- sound while members compile sequentially (the current
|
|
37
|
+
# design; @compile's own format-level parallelism is joined before
|
|
38
|
+
# compile returns). (2) Independently of whether anything was
|
|
39
|
+
# pooled, verify the outputs registered for the member exist on
|
|
40
|
+
# disk. Failures are reported here and accumulated; the collection
|
|
41
|
+
# renders every remaining member before Collection#render aborts,
|
|
42
|
+
# so one run reports all failed members.
|
|
43
|
+
def file_compile_verify(identifier, errors)
|
|
44
|
+
# Section-split parts (marked with :parentid) register format
|
|
45
|
+
# slots they never produce -- their :xml slot in particular is
|
|
46
|
+
# never written, and under filename renaming it aliases to the
|
|
47
|
+
# parent's name -- so verifying them is a false positive. #586
|
|
48
|
+
# was scoped to the non-sectionsplit path; parts are excluded
|
|
49
|
+
# like their parents (which return early above).
|
|
50
|
+
@files.get(identifier, :parentid) and return
|
|
51
|
+
missing = (@files.get(identifier, :outputs) || {})
|
|
52
|
+
.reject { |_fmt, path| File.exist?(path) }
|
|
53
|
+
errors.empty? && missing.empty? and return
|
|
54
|
+
file_compile_failure_log(identifier, errors, missing)
|
|
55
|
+
msg = file_compile_failure_msg(identifier, errors, missing)
|
|
56
|
+
::Metanorma::Util.log("[metanorma] Error: #{msg}", :error)
|
|
57
|
+
fatal_errors << msg
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def file_compile_failure_log(identifier, errors, missing)
|
|
61
|
+
missing.each_value do |path|
|
|
62
|
+
@log&.add("METANORMA_4", nil, params: [identifier, path])
|
|
63
|
+
end
|
|
64
|
+
errors.each do |e|
|
|
65
|
+
@log&.add("METANORMA_5", nil, params: [identifier, e])
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def file_compile_failure_msg(identifier, errors, missing)
|
|
70
|
+
ret = []
|
|
71
|
+
missing.empty? or
|
|
72
|
+
ret << "expected output not generated: " \
|
|
73
|
+
"#{missing.values.join(', ')}"
|
|
74
|
+
ret += errors
|
|
75
|
+
"Failed to render collection member #{identifier}: #{ret.join('; ')}"
|
|
24
76
|
end
|
|
25
77
|
|
|
26
78
|
def compile_options_base(identifier)
|
|
@@ -198,7 +250,7 @@ module Metanorma
|
|
|
198
250
|
end
|
|
199
251
|
|
|
200
252
|
def update_bibitem(bib, identifier)
|
|
201
|
-
newbib, url = update_bibitem_prep(bib, identifier)
|
|
253
|
+
newbib, url, attachment = update_bibitem_prep(bib, identifier)
|
|
202
254
|
newbib or return
|
|
203
255
|
dest = begin
|
|
204
256
|
newbib.at("./docidentifier") || newbib.at(ns("./docidentifier"))
|
|
@@ -206,18 +258,22 @@ module Metanorma
|
|
|
206
258
|
nil
|
|
207
259
|
end
|
|
208
260
|
dest or dest = newbib.elements[-1]
|
|
261
|
+
# An attachment carries both a <uri type="attachment"> (which drives
|
|
262
|
+
# isodoc's fmt-link attachment="true") and the citation uri; the
|
|
263
|
+
# attachment uri goes first. metanorma/iso-10303#208.
|
|
264
|
+
attachment and dest.previous = "<uri type='attachment'>#{url}</uri>"
|
|
209
265
|
dest.previous = "<uri type='citation'>#{url}</uri>"
|
|
210
266
|
bib.replace(newbib)
|
|
211
267
|
end
|
|
212
268
|
|
|
213
269
|
def update_bibitem_prep(bib, identifier)
|
|
214
|
-
docid = get_bibitem_docid(bib, identifier) or return [nil, nil]
|
|
270
|
+
docid = get_bibitem_docid(bib, identifier) or return [nil, nil, nil]
|
|
215
271
|
newbib = dup_bibitem(docid, bib)
|
|
216
272
|
attachment = @files.get(docid, :attachment)
|
|
217
273
|
url = @files.url(docid, relative: true, doc: !attachment)
|
|
218
274
|
current_html = referencing_html_location(identifier, attachment)
|
|
219
275
|
url = make_relative_path(current_html, url) if current_html
|
|
220
|
-
[newbib, url]
|
|
276
|
+
[newbib, url, attachment]
|
|
221
277
|
end
|
|
222
278
|
|
|
223
279
|
# Location of the HTML that will carry the cross-reference to the target,
|
|
@@ -19,7 +19,7 @@ module Metanorma
|
|
|
19
19
|
|
|
20
20
|
attr_accessor :isodoc, :isodoc_presxml
|
|
21
21
|
attr_reader :xml, :compile, :compile_options, :documents, :outdir,
|
|
22
|
-
:manifest
|
|
22
|
+
:manifest, :fatal_errors
|
|
23
23
|
|
|
24
24
|
# Run the block with the renderer in nested mode, restoring the previous
|
|
25
25
|
# mode afterwards. Nested mode (used by sectionsplit, which re-enters this
|
|
@@ -93,6 +93,10 @@ module Metanorma
|
|
|
93
93
|
@final = collection.final
|
|
94
94
|
@c = HTMLEntities.new
|
|
95
95
|
@files_to_delete = []
|
|
96
|
+
# Per-member rendering failures (missing outputs, pooled compile
|
|
97
|
+
# errors), accumulated by file_compile_verify; Collection#render
|
|
98
|
+
# aborts on them once every member has rendered (#586).
|
|
99
|
+
@fatal_errors = []
|
|
96
100
|
@nested = options[:nested]
|
|
97
101
|
# if false, this is the root instance of Renderer
|
|
98
102
|
# if true, then this is not the last time Renderer will be run
|
|
@@ -302,7 +306,10 @@ module Metanorma
|
|
|
302
306
|
# (Sectionsplit parents get a :presentation output upstream, so they
|
|
303
307
|
# inline whole for the PDF/presentation path.)
|
|
304
308
|
outputs = @files.get(id, :outputs)
|
|
305
|
-
|
|
309
|
+
# The registered path may exist without the file: a member whose
|
|
310
|
+
# rendering failed registers its intended outputs but writes
|
|
311
|
+
# nothing (#586), so check the disk, not just the registration.
|
|
312
|
+
if outputs.nil? || outputs[ext].nil? || !File.exist?(outputs[ext])
|
|
306
313
|
warn "[metanorma] collection document '#{id}' has no compiled " \
|
|
307
314
|
"#{ext} output to inline; skipping (its doc-container would " \
|
|
308
315
|
"otherwise be bibdata-only)."
|
|
@@ -135,8 +135,7 @@ module Metanorma
|
|
|
135
135
|
output_paths[:out], ext, isodoc_options)
|
|
136
136
|
wrap_html(options, output_paths[:ext], output_paths[:out])
|
|
137
137
|
rescue StandardError => e
|
|
138
|
-
|
|
139
|
-
isodoc_error_process(e, strict, false)
|
|
138
|
+
isodoc_error_process(e, strict_error?(ext, isodoc_options), false)
|
|
140
139
|
end
|
|
141
140
|
|
|
142
141
|
# Process format directly from semantic XML
|
|
@@ -145,8 +144,7 @@ module Metanorma
|
|
|
145
144
|
ext, isodoc_options)
|
|
146
145
|
true # Return as Thread equivalent
|
|
147
146
|
rescue StandardError => e
|
|
148
|
-
|
|
149
|
-
isodoc_error_process(e, strict, true)
|
|
147
|
+
isodoc_error_process(e, strict_error?(ext, isodoc_options), true)
|
|
150
148
|
ext != :presentation
|
|
151
149
|
end
|
|
152
150
|
|
|
@@ -168,12 +166,29 @@ module Metanorma
|
|
|
168
166
|
|
|
169
167
|
private
|
|
170
168
|
|
|
169
|
+
# A presentation failure is always strict: every downstream format
|
|
170
|
+
# needs the presentation XML. The :strict option arrives as a
|
|
171
|
+
# boolean from the CLI but as a string from document attributes, so
|
|
172
|
+
# accept both (the two rescue sites previously each checked only
|
|
173
|
+
# one form).
|
|
174
|
+
def strict_error?(ext, isodoc_options)
|
|
175
|
+
ext == :presentation ||
|
|
176
|
+
[true, "true"].include?(isodoc_options[:strict])
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# On the strict path the message is pooled into @errors for the
|
|
180
|
+
# caller to surface (the standalone CLI reports the pool and
|
|
181
|
+
# aborts; the collection renderer attributes it to the failed
|
|
182
|
+
# member, #586). The class+message line is also printed here in all
|
|
183
|
+
# cases, so it sits adjacent to its backtrace in the build log: a
|
|
184
|
+
# pooled message surfaces only at end of run, and a bare backtrace
|
|
185
|
+
# mid-log is undiagnosable. The exception class is retained because
|
|
186
|
+
# for errors like Encoding::UndefinedConversionError it carries
|
|
187
|
+
# half the diagnosis.
|
|
171
188
|
def isodoc_error_process(err, strict, must_abort)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
puts err.message
|
|
176
|
-
end
|
|
189
|
+
msg = "#{err.class}: #{err.message}"
|
|
190
|
+
strict || err.message.include?("Fatal:") and @errors << msg
|
|
191
|
+
puts msg
|
|
177
192
|
puts err.backtrace.join("\n")
|
|
178
193
|
must_abort and 1
|
|
179
194
|
end
|
data/lib/metanorma/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: metanorma
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.5.
|
|
4
|
+
version: 2.5.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -217,7 +217,6 @@ extra_rdoc_files:
|
|
|
217
217
|
files:
|
|
218
218
|
- ".envrc"
|
|
219
219
|
- ".gitignore"
|
|
220
|
-
- ".hound.yml"
|
|
221
220
|
- ".rspec"
|
|
222
221
|
- ".rubocop.yml"
|
|
223
222
|
- CHANGELOG.adoc
|