metanorma 1.2.8 → 1.3.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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