metanorma 1.2.8 → 1.3.4

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.
@@ -44,7 +44,8 @@ module Metanorma
44
44
  def parse_docref(mnf)
45
45
  mnf.xpath("xmlns:docref").map do |dr|
46
46
  h = { "identifier" => dr.at("identifier").text }
47
- h["fileref"] = dr[:fileref] if dr[:fileref]
47
+ dr[:fileref] and h["fileref"] = dr[:fileref]
48
+ h["attachment"] = dr[:attachment] if dr[:attachment]
48
49
  h
49
50
  end
50
51
  end
@@ -62,12 +63,13 @@ module Metanorma
62
63
  docs = @docref.each_with_object({}) do |dr, m|
63
64
  next m unless dr["fileref"]
64
65
 
65
- m[dr["identifier"]] = Document.parse_file File.join(dir, dr["fileref"])
66
+ m[dr["identifier"]] = Document.parse_file(
67
+ File.join(dir, dr["fileref"]),
68
+ dr["attachment"], dr["identifier"]
69
+ )
66
70
  m
67
71
  end
68
- @manifest.reduce(docs) do |mem, mnf|
69
- mem.merge mnf.documents(dir)
70
- end
72
+ @manifest.reduce(docs) { |mem, mnf| mem.merge mnf.documents(dir) }
71
73
  end
72
74
 
73
75
  # @param builder [Nokogiri::XML::Builder]
@@ -100,7 +102,8 @@ module Metanorma
100
102
  def docref_to_xml(builder)
101
103
  @docref.each do |dr|
102
104
  drf = builder.docref { |b| b.identifier dr["identifier"] }
103
- drf[:fileref] = dr["fileref"]
105
+ drf[:fileref] = Util::source2dest_filename(dr["fileref"])
106
+ drf[:attachment] = dr["attachment"] if dr["attachment"]
104
107
  if collection.directives.include?("documents-inline")
105
108
  id = collection.documents.find_index { |k, _| k == dr["identifier"] }
106
109
  drf[:id] = format("doc%<index>09d", index: id)
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "isodoc"
4
- require_relative "./collection_fileprocess"
4
+ require_relative "collection_fileprocess"
5
+ require_relative "fontist_utils"
5
6
 
6
7
  module Metanorma
7
8
  # XML collection renderer
@@ -20,9 +21,9 @@ module Metanorma
20
21
  # the collection, and that the flavour gem can sensibly process it. We may
21
22
  # need to enhance metadata in the flavour gems isodoc/metadata.rb with
22
23
  # collection metadata
23
- def initialize(xml, folder, options = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
24
+ def initialize(collection, folder, options = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
24
25
  check_options options
25
- @xml = Nokogiri::XML xml # @xml is the collection manifest
26
+ @xml = Nokogiri::XML collection.to_xml # @xml is the collection manifest
26
27
  @lang = @xml&.at(ns("//bibdata/language"))&.text || "en"
27
28
  @script = @xml&.at(ns("//bibdata/script"))&.text || "Latn"
28
29
  @doctype = doctype
@@ -36,6 +37,7 @@ module Metanorma
36
37
  @format = options[:format]
37
38
  @compile_options = options[:compile] || {}
38
39
  @log = options[:log]
40
+ @documents = collection.documents
39
41
 
40
42
  # list of files in the collection
41
43
  @files = read_files folder
@@ -50,7 +52,7 @@ module Metanorma
50
52
  # @option options [Strong] :ourput_folder output directory
51
53
  def self.render(col, options = {})
52
54
  folder = File.dirname col.file
53
- cr = new(col.to_xml, folder, options)
55
+ cr = new(col, folder, options)
54
56
  cr.files
55
57
  cr.concatenate(col, options)
56
58
  cr.coverpage if options[:format]&.include?(:html)
@@ -60,10 +62,13 @@ module Metanorma
60
62
  options[:format] << :presentation if options[:format].include?(:pdf)
61
63
  options[:format].uniq.each do |e|
62
64
  next unless %i(presentation xml).include?(e)
65
+
63
66
  ext = e == :presentation ? "presentation.xml" : e.to_s
64
67
  out = col.clone
65
68
  out.directives << "documents-inline"
66
69
  out.documents.keys.each do |id|
70
+ next if @files[id][:attachment]
71
+
67
72
  filename = @files[id][:outputs][e]
68
73
  out.documents[id] = Metanorma::Document.raw_file(filename)
69
74
  end
@@ -74,13 +79,27 @@ module Metanorma
74
79
  end
75
80
 
76
81
  def pdfconv
77
- x = Asciidoctor.load nil, backend: @doctype.to_sym
78
- x.converter.pdf_converter(Dummy.new)
82
+ doctype = @doctype.to_sym
83
+ x = Asciidoctor.load nil, backend: doctype
84
+ x.converter.pdf_converter(PdfOptionsNode.new(doctype, @compile_options))
85
+ end
86
+
87
+ class PdfOptionsNode
88
+ def initialize(doctype, options)
89
+ doc_proc = Metanorma::Registry.instance.find_processor(doctype)
90
+ @font_locations = FontistUtils.fontist_font_locations(doc_proc, options)
91
+ end
92
+
93
+ def attr(key)
94
+ if key == "mn2pdf-font-manifest-file" && @font_locations
95
+ @font_locations.path
96
+ end
97
+ end
79
98
  end
80
99
 
81
100
  # Dummy class
82
101
  class Dummy
83
- def attr(_xyz); end
102
+ def attr(_key); end
84
103
  end
85
104
 
86
105
  # The isodoc class for the metanorma flavour we are using
@@ -119,6 +138,8 @@ module Metanorma
119
138
  # populate liquid template of ARGV[1] with metadata extracted from
120
139
  # collection manifest
121
140
  def coverpage
141
+ return unless @coverpage
142
+
122
143
  File.open(File.join(@outdir, "index.html"), "w:UTF-8") do |f|
123
144
  f.write @isodoc.populate_template(File.read(@coverpage))
124
145
  end
@@ -183,8 +204,6 @@ module Metanorma
183
204
  unless options[:format].is_a?(Array) && (FORMATS & options[:format]).any?
184
205
  raise ArgumentError, "Need to specify formats (xml,html,pdf,doc)"
185
206
  end
186
- return if !options[:format].include?(:html) || options[:coverpage]
187
- raise ArgumentError, "Need to specify a coverpage to render HTML"
188
207
  end
189
208
  end
190
209
  end
@@ -2,9 +2,10 @@ require "fileutils"
2
2
  require "nokogiri"
3
3
  require "htmlentities"
4
4
  require "yaml"
5
-
6
5
  require "fontist"
7
6
  require "fontist/manifest/install"
7
+ require_relative "compile_validate"
8
+ require_relative "fontist_utils"
8
9
 
9
10
  module Metanorma
10
11
  class Compile
@@ -19,29 +20,25 @@ module Metanorma
19
20
  def compile(filename, options = {})
20
21
  require_libraries(options)
21
22
  options = options_extract(filename, options)
22
- validate_type(options) && validate_format(options) || (return nil)
23
+ validate_options(options)
23
24
  @processor = @registry.find_processor(options[:type].to_sym)
24
25
  extensions = get_extensions(options) or return nil
25
26
  (file, isodoc = process_input(filename, options)) or return nil
26
27
  relaton_export(isodoc, options)
27
28
  extract(isodoc, options[:extract], options[:extract_type])
28
- install_fonts(options)
29
+ FontistUtils.install_fonts(@processor, options)
29
30
  process_extensions(extensions, file, isodoc, options)
30
31
  end
31
32
 
32
33
  def require_libraries(options)
33
- if options[:require]
34
- options[:require].each do |r|
35
- require r
36
- end
37
- end
34
+ options&.dig(:require)&.each { |r| require r }
38
35
  end
39
36
 
40
37
  def xml_options_extract(file)
41
38
  xml = Nokogiri::XML(file)
42
39
  if xml.root
43
40
  @registry.root_tags.each do |k, v|
44
- return { type: k } if v == xml.root.name
41
+ return { type: k } if v == xml.root.name
45
42
  end
46
43
  end
47
44
  {}
@@ -63,48 +60,6 @@ module Metanorma
63
60
  options
64
61
  end
65
62
 
66
- def validate_type(options)
67
- unless options[:type]
68
- Util.log("[metanorma] Error: Please specify a standard type: #{@registry.supported_backends}.", :error)
69
- return nil
70
- end
71
-
72
- stdtype = options[:type].to_sym
73
- metanorma_flavor = "metanorma-#{stdtype}"
74
-
75
- unless @registry.supported_backends.include? stdtype
76
- Util.log("[metanorma] Info: Loading `#{metanorma_flavor}` gem for standard type `#{stdtype}`.", :info)
77
- end
78
-
79
- begin
80
- require "metanorma-#{stdtype}"
81
- Util.log("[metanorma] Info: gem `#{metanorma_flavor}` loaded.", :info)
82
-
83
- rescue Gem::ConflictError
84
- Util.log("[metanorma] Error: Couldn't resolve dependencies for `metanorma-#{stdtype}`, Please add it to your Gemfile and run bundle install first", :error)
85
- return false
86
-
87
- rescue LoadError
88
- Util.log("[metanorma] Error: loading gem `#{metanorma_flavor}` failed. Exiting.", :error)
89
- return false
90
- end
91
-
92
- unless @registry.supported_backends.include? stdtype
93
- Util.log("[metanorma] Error: The `#{metanorma_flavor}` gem still doesn't support `#{stdtype}`. Exiting.", :error)
94
- return false
95
- end
96
-
97
- true
98
- end
99
-
100
- def validate_format(options)
101
- unless options[:format] == :asciidoc
102
- Util.log("[metanorma] Error: Only source file format currently supported is 'asciidoc'.", :error)
103
- return false
104
- end
105
- true
106
- end
107
-
108
63
  def get_extensions(options)
109
64
  options[:extension_keys] ||= @processor.output_formats.reduce([]) do |memo, (k, _)|
110
65
  memo << k
@@ -121,7 +76,7 @@ module Metanorma
121
76
  end
122
77
  if !extensions.include?(:presentation) and extensions.any? { |e| @processor.use_presentation_xml(e) }
123
78
  extensions << :presentation
124
- end
79
+ end
125
80
  extensions
126
81
  end
127
82
 
@@ -187,7 +142,7 @@ module Metanorma
187
142
  xml.xpath("//sourcecode | //xmlns:sourcecode").each_with_index do |s, i|
188
143
  filename = s["filename"] || sprintf("sourcecode-%04d.txt", i)
189
144
  File.open("#{dirname}/sourcecode/#{filename}", "w:UTF-8") do |f|
190
- f.write clean_sourcecode(s.dup)
145
+ f.write clean_sourcecode(s.dup)
191
146
  end
192
147
  end
193
148
  end
@@ -197,6 +152,7 @@ module Metanorma
197
152
  FileUtils.mkdir_p "#{dirname}/image"
198
153
  xml.xpath("//image | //xmlns:image").each_with_index do |s, i|
199
154
  next unless /^data:image/.match s["src"]
155
+
200
156
  %r{^data:image/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ s["src"]
201
157
  filename = s["filename"] || sprintf("image-%04d.%s", i, imgtype)
202
158
  File.open("#{dirname}/image/#{filename}", "wb") do |f|
@@ -222,22 +178,22 @@ module Metanorma
222
178
 
223
179
  # dependency ordering
224
180
  def sort_extensions_execution(ext)
225
- case ext
226
- when :xml then 0
227
- when :rxl then 1
228
- when :presentation then 2
229
- else
230
- 99
231
- end
181
+ case ext
182
+ when :xml then 0
183
+ when :rxl then 1
184
+ when :presentation then 2
185
+ else
186
+ 99
187
+ end
232
188
  end
233
189
 
234
190
  def wrap_html(options, file_extension, outfilename)
235
- if options[:wrapper] and /html$/.match file_extension
236
- outfilename = outfilename.sub(/\.html$/, "")
237
- FileUtils.mkdir_p outfilename
238
- FileUtils.mv "#{outfilename}.html", outfilename
239
- FileUtils.mv "#{outfilename}_images", outfilename, force: true
240
- end
191
+ if options[:wrapper] && /html$/.match(file_extension)
192
+ outfilename = outfilename.sub(/\.html$/, "")
193
+ FileUtils.mkdir_p outfilename
194
+ FileUtils.mv "#{outfilename}.html", outfilename
195
+ FileUtils.mv "#{outfilename}_images", outfilename, force: true
196
+ end
241
197
  end
242
198
 
243
199
  # isodoc is Raw Metanorma XML
@@ -250,11 +206,13 @@ module Metanorma
250
206
  end.each do |ext|
251
207
  isodoc_options = @processor.extract_options(file)
252
208
  isodoc_options[:datauriimage] = true if options[:datauriimage]
209
+ isodoc_options[:sourcefilename] = options[:filename]
253
210
  file_extension = @processor.output_formats[ext]
254
211
  outfilename = f.sub(/\.[^.]+$/, ".#{file_extension}")
255
212
  if ext == :pdf
256
- font_locations = fontist_font_locations(options)
257
- isodoc_options[:mn2pdf] = { font_manifest_file: font_locations.path } if font_locations
213
+ font_locations = FontistUtils.fontist_font_locations(@processor, options)
214
+ font_locations and
215
+ isodoc_options[:mn2pdf] = { font_manifest_file: font_locations.path }
258
216
  end
259
217
  if ext == :rxl
260
218
  options[:relaton] = outfilename
@@ -265,104 +223,20 @@ module Metanorma
265
223
  @processor.output(nil, presentationxml_name, outfilename, ext, isodoc_options) :
266
224
  @processor.output(isodoc, xml_name, outfilename, ext, isodoc_options)
267
225
  rescue StandardError => e
268
- puts e.message
269
- puts e.backtrace.join("\n")
226
+ if e.message.include? "Fatal:"
227
+ @errors << e.message
228
+ else
229
+ puts e.message
230
+ puts e.backtrace.join("\n")
231
+ end
270
232
  end
271
233
  end
272
- if ext == :pdf
273
- # font_locations.unlink
274
- end
275
234
  wrap_html(options, file_extension, outfilename)
276
235
  end
277
236
  end
278
237
 
279
- def install_fonts(options)
280
- if options[:no_install_fonts]
281
- Util.log("[fontist] Skip font installation because" \
282
- " --no-install-fonts argument passed", :debug)
283
- return
284
- end
285
-
286
- if missing_fontist_manifest?
287
- Util.log("[fontist] Skip font installation because font_manifest is missing", :debug)
288
- return
289
- end
290
-
291
- @updated_formulas_repo = false
292
-
293
- manifest = @processor.fonts_manifest
294
- agree_to_terms = options[:agree_to_terms] || false
295
- continue_without_fonts = options[:continue_without_fonts] || false
296
- no_progress = options[:no_progress] || false
297
-
298
- install_fonts_safe(manifest, agree_to_terms, continue_without_fonts, no_progress)
299
- end
300
-
301
238
  private
302
239
 
303
- def install_fonts_safe(manifest, agree, continue, no_progress)
304
- fontist_install(manifest, agree, no_progress)
305
- rescue Fontist::Errors::LicensingError
306
- if continue
307
- Util.log(
308
- "[fontist] Processing will continue without fonts installed",
309
- :debug
310
- )
311
- else
312
- Util.log("[fontist] Aborting without proper fonts installed," \
313
- " make sure that you have set option --agree-to-terms", :fatal)
314
- end
315
- rescue Fontist::Errors::FontError => e
316
- log_level = continue ? :warning : :fatal
317
- Util.log("[fontist] '#{e.font}' font is not supported. " \
318
- "Please report this issue at github.com/metanorma/metanorma-"\
319
- "#{@processor.short}/issues to report this issue.", log_level)
320
- rescue Fontist::Errors::FormulaIndexNotFoundError
321
- if @updated_formulas_repo
322
- Util.log(
323
- "[fontist] Bug: formula index not found after 'fontist update'",
324
- :fatal
325
- )
326
- end
327
- Util.log("[fontist] Missing formula index. Fetching it...", :debug)
328
- Fontist::Formula.update_formulas_repo
329
- @updated_formulas_repo = true
330
- install_fonts_safe(manifest, agree, continue, no_progress)
331
- end
332
-
333
- def fontist_install(manifest, agree, no_progress)
334
- Fontist::Manifest::Install.from_hash(
335
- manifest,
336
- confirmation: agree ? "yes" : "no",
337
- no_progress: no_progress
338
- )
339
- end
340
-
341
- def fontist_font_locations(options)
342
- return nil if missing_fontist_manifest? || options[:no_install_fonts]
343
-
344
- dump_fontist_manifest_locations(@processor.fonts_manifest)
345
- rescue Fontist::Errors::FormulaIndexNotFoundError
346
- raise unless options[:continue_without_fonts]
347
-
348
- nil
349
- end
350
-
351
- def dump_fontist_manifest_locations(manifest)
352
- location_manifest = Fontist::Manifest::Locations.from_hash(
353
- manifest
354
- )
355
- location_manifest_file = Tempfile.new(["fontist_locations", ".yml"])
356
- location_manifest_file.write location_manifest.to_yaml
357
- location_manifest_file.flush
358
-
359
- location_manifest_file
360
- end
361
-
362
- def missing_fontist_manifest?
363
- !@processor.respond_to?(:fonts_manifest) || @processor.fonts_manifest.nil?
364
- end
365
-
366
240
  # @param options [Hash]
367
241
  # @return [String]
368
242
  def change_output_dir(options)
@@ -0,0 +1,51 @@
1
+ module Metanorma
2
+ class Compile
3
+ def validate_options(options)
4
+ validate_type(options)
5
+ validate_format(options)
6
+ end
7
+
8
+ def validate_type(options)
9
+ unless options[:type]
10
+ Util.log("[metanorma] Error: Please specify a standard type: "\
11
+ "#{@registry.supported_backends}.", :fatal)
12
+ end
13
+ stdtype = options[:type].to_sym
14
+ load_flavor(stdtype)
15
+ end
16
+
17
+ def validate_format(options)
18
+ unless options[:format] == :asciidoc
19
+ Util.log("[metanorma] Error: Only source file format currently "\
20
+ "supported is 'asciidoc'.", :fatal)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def load_flavor(stdtype)
27
+ flavor = "metanorma-#{stdtype}"
28
+ unless @registry.supported_backends.include? stdtype
29
+ Util.log("[metanorma] Info: Loading `#{flavor}` gem "\
30
+ "for standard type `#{stdtype}`.", :info)
31
+ end
32
+ require_flavor(flavor, stdtype)
33
+ unless @registry.supported_backends.include? stdtype
34
+ Util.log("[metanorma] Error: The `#{flavor}` gem "\
35
+ "still doesn't support `#{stdtype}`. Exiting.", :fatal)
36
+ end
37
+ end
38
+
39
+ def require_flavor(flavor, stdtype)
40
+ require flavor
41
+ Util.log("[metanorma] Info: gem `#{flavor}` loaded.", :info)
42
+ rescue Gem::ConflictError
43
+ Util.log("[metanorma] Error: Couldn't resolve dependencies for "\
44
+ "`metanorma-#{stdtype}`, Please add it to your Gemfile "\
45
+ "and run bundle install first", :fatal)
46
+ rescue LoadError
47
+ Util.log("[metanorma] Error: loading gem `#{flavor}` "\
48
+ "failed. Exiting.", :fatal)
49
+ end
50
+ end
51
+ end