metanorma 1.2.6 → 1.3.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.
@@ -45,6 +45,7 @@ module Metanorma
45
45
  mnf.xpath("xmlns:docref").map do |dr|
46
46
  h = { "identifier" => dr.at("identifier").text }
47
47
  h["fileref"] = dr[:fileref] if 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]
@@ -101,6 +103,7 @@ module Metanorma
101
103
  @docref.each do |dr|
102
104
  drf = builder.docref { |b| b.identifier dr["identifier"] }
103
105
  drf[:fileref] = 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
@@ -64,6 +65,7 @@ module Metanorma
64
65
  out = col.clone
65
66
  out.directives << "documents-inline"
66
67
  out.documents.keys.each do |id|
68
+ next if @files[id][:attachment]
67
69
  filename = @files[id][:outputs][e]
68
70
  out.documents[id] = Metanorma::Document.raw_file(filename)
69
71
  end
@@ -74,13 +76,27 @@ module Metanorma
74
76
  end
75
77
 
76
78
  def pdfconv
77
- x = Asciidoctor.load nil, backend: @doctype.to_sym
78
- x.converter.pdf_converter(Dummy.new)
79
+ doctype = @doctype.to_sym
80
+ x = Asciidoctor.load nil, backend: doctype
81
+ x.converter.pdf_converter(PdfOptionsNode.new(doctype, @compile_options))
82
+ end
83
+
84
+ class PdfOptionsNode
85
+ def initialize(doctype, options)
86
+ doc_proc = Metanorma::Registry.instance.find_processor(doctype)
87
+ @font_locations = FontistUtils.fontist_font_locations(doc_proc, options)
88
+ end
89
+
90
+ def attr(key)
91
+ if key == "mn2pdf-font-manifest-file" && @font_locations
92
+ @font_locations.path
93
+ end
94
+ end
79
95
  end
80
96
 
81
97
  # Dummy class
82
98
  class Dummy
83
- def attr(_xyz); end
99
+ def attr(_key); end
84
100
  end
85
101
 
86
102
  # The isodoc class for the metanorma flavour we are using
@@ -1,9 +1,11 @@
1
1
  require "fileutils"
2
2
  require "nokogiri"
3
3
  require "htmlentities"
4
-
4
+ require "yaml"
5
5
  require "fontist"
6
6
  require "fontist/manifest/install"
7
+ require_relative "compile_validate"
8
+ require_relative "fontist_utils"
7
9
 
8
10
  module Metanorma
9
11
  class Compile
@@ -24,23 +26,19 @@ module Metanorma
24
26
  (file, isodoc = process_input(filename, options)) or return nil
25
27
  relaton_export(isodoc, options)
26
28
  extract(isodoc, options[:extract], options[:extract_type])
27
- install_fonts(options)
29
+ FontistUtils.install_fonts(@processor, options)
28
30
  process_extensions(extensions, file, isodoc, options)
29
31
  end
30
32
 
31
33
  def require_libraries(options)
32
- if options[:require]
33
- options[:require].each do |r|
34
- require r
35
- end
36
- end
34
+ options&.dig(:require)&.each { |r| require r }
37
35
  end
38
36
 
39
37
  def xml_options_extract(file)
40
38
  xml = Nokogiri::XML(file)
41
39
  if xml.root
42
40
  @registry.root_tags.each do |k, v|
43
- return { type: k } if v == xml.root.name
41
+ return { type: k } if v == xml.root.name
44
42
  end
45
43
  end
46
44
  {}
@@ -62,48 +60,6 @@ module Metanorma
62
60
  options
63
61
  end
64
62
 
65
- def validate_type(options)
66
- unless options[:type]
67
- Util.log("[metanorma] Error: Please specify a standard type: #{@registry.supported_backends}.", :error)
68
- return nil
69
- end
70
-
71
- stdtype = options[:type].to_sym
72
- metanorma_flavor = "metanorma-#{stdtype}"
73
-
74
- unless @registry.supported_backends.include? stdtype
75
- Util.log("[metanorma] Info: Loading `#{metanorma_flavor}` gem for standard type `#{stdtype}`.", :info)
76
- end
77
-
78
- begin
79
- require "metanorma-#{stdtype}"
80
- Util.log("[metanorma] Info: gem `#{metanorma_flavor}` loaded.", :info)
81
-
82
- rescue Gem::ConflictError
83
- Util.log("[metanorma] Error: Couldn't resolve dependencies for `metanorma-#{stdtype}`, Please add it to your Gemfile and run bundle install first", :error)
84
- return false
85
-
86
- rescue LoadError
87
- Util.log("[metanorma] Error: loading gem `#{metanorma_flavor}` failed. Exiting.", :error)
88
- return false
89
- end
90
-
91
- unless @registry.supported_backends.include? stdtype
92
- Util.log("[metanorma] Error: The `#{metanorma_flavor}` gem still doesn't support `#{stdtype}`. Exiting.", :error)
93
- return false
94
- end
95
-
96
- true
97
- end
98
-
99
- def validate_format(options)
100
- unless options[:format] == :asciidoc
101
- Util.log("[metanorma] Error: Only source file format currently supported is 'asciidoc'.", :error)
102
- return false
103
- end
104
- true
105
- end
106
-
107
63
  def get_extensions(options)
108
64
  options[:extension_keys] ||= @processor.output_formats.reduce([]) do |memo, (k, _)|
109
65
  memo << k
@@ -120,7 +76,7 @@ module Metanorma
120
76
  end
121
77
  if !extensions.include?(:presentation) and extensions.any? { |e| @processor.use_presentation_xml(e) }
122
78
  extensions << :presentation
123
- end
79
+ end
124
80
  extensions
125
81
  end
126
82
 
@@ -186,7 +142,7 @@ module Metanorma
186
142
  xml.xpath("//sourcecode | //xmlns:sourcecode").each_with_index do |s, i|
187
143
  filename = s["filename"] || sprintf("sourcecode-%04d.txt", i)
188
144
  File.open("#{dirname}/sourcecode/#{filename}", "w:UTF-8") do |f|
189
- f.write clean_sourcecode(s.dup)
145
+ f.write clean_sourcecode(s.dup)
190
146
  end
191
147
  end
192
148
  end
@@ -196,6 +152,7 @@ module Metanorma
196
152
  FileUtils.mkdir_p "#{dirname}/image"
197
153
  xml.xpath("//image | //xmlns:image").each_with_index do |s, i|
198
154
  next unless /^data:image/.match s["src"]
155
+
199
156
  %r{^data:image/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ s["src"]
200
157
  filename = s["filename"] || sprintf("image-%04d.%s", i, imgtype)
201
158
  File.open("#{dirname}/image/#{filename}", "wb") do |f|
@@ -221,22 +178,22 @@ module Metanorma
221
178
 
222
179
  # dependency ordering
223
180
  def sort_extensions_execution(ext)
224
- case ext
225
- when :xml then 0
226
- when :rxl then 1
227
- when :presentation then 2
228
- else
229
- 99
230
- 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
231
188
  end
232
189
 
233
190
  def wrap_html(options, file_extension, outfilename)
234
- if options[:wrapper] and /html$/.match file_extension
235
- outfilename = outfilename.sub(/\.html$/, "")
236
- FileUtils.mkdir_p outfilename
237
- FileUtils.mv "#{outfilename}.html", outfilename
238
- FileUtils.mv "#{outfilename}_images", outfilename, force: true
239
- 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
240
197
  end
241
198
 
242
199
  # isodoc is Raw Metanorma XML
@@ -249,8 +206,14 @@ module Metanorma
249
206
  end.each do |ext|
250
207
  isodoc_options = @processor.extract_options(file)
251
208
  isodoc_options[:datauriimage] = true if options[:datauriimage]
209
+ isodoc_options[:sourcefilename] = options[:filename]
252
210
  file_extension = @processor.output_formats[ext]
253
211
  outfilename = f.sub(/\.[^.]+$/, ".#{file_extension}")
212
+ if ext == :pdf
213
+ font_locations = FontistUtils.fontist_font_locations(@processor, options)
214
+ font_locations and
215
+ isodoc_options[:mn2pdf] = { font_manifest_file: font_locations.path }
216
+ end
254
217
  if ext == :rxl
255
218
  options[:relaton] = outfilename
256
219
  relaton_export(isodoc, options)
@@ -260,66 +223,20 @@ module Metanorma
260
223
  @processor.output(nil, presentationxml_name, outfilename, ext, isodoc_options) :
261
224
  @processor.output(isodoc, xml_name, outfilename, ext, isodoc_options)
262
225
  rescue StandardError => e
263
- puts e.message
264
- 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
265
232
  end
266
233
  end
267
234
  wrap_html(options, file_extension, outfilename)
268
235
  end
269
236
  end
270
237
 
271
- def install_fonts(options)
272
- if options[:no_install_fonts]
273
- Util.log("[fontist] Skip font installation because" \
274
- " --no-install-fonts argument passed", :debug)
275
- return
276
- end
277
-
278
- if !@processor.respond_to?(:fonts_manifest) || @processor.fonts_manifest.nil?
279
- Util.log("[fontist] Skip font installation because font_manifest is missing", :debug)
280
- return
281
- end
282
-
283
- @updated_formulas_repo = false
284
-
285
- manifest = @processor.fonts_manifest
286
- agree_to_terms = options[:agree_to_terms] || false
287
- continue_without_fonts = options[:continue_without_fonts] || false
288
-
289
- install_fonts_safe(manifest, agree_to_terms, continue_without_fonts)
290
- end
291
-
292
238
  private
293
239
 
294
- def install_fonts_safe(manifest, agree, continue)
295
- fontist_install(manifest, agree)
296
- rescue Fontist::Errors::LicensingError
297
- if continue
298
- Util.log("[fontist] Processing will continue without fonts installed", :debug)
299
- else
300
- Util.log("[fontist] Aborting without proper fonts installed," \
301
- " make sure that you have set option --agree-to-terms", :fatal)
302
- end
303
- rescue Fontist::Errors::FontError => e
304
- log_level = continue ? :warning : :fatal
305
- Util.log("[fontist] '#{e.font}' font is not supported. " \
306
- "Please report this issue at github.com/metanorma/metanorma-#{@processor.short}/issues" \
307
- " to report this issue.", log_level)
308
- rescue Fontist::Errors::FormulaIndexNotFoundError
309
- Util.log("[fontist] Bug: formula index not found after 'fontist update'", :fatal) if @updated_formulas_repo
310
- Util.log("[fontist] Missing formula index. Fetching it...", :debug)
311
- Fontist::Formula.update_formulas_repo
312
- @updated_formulas_repo = true
313
- install_fonts_safe(manifest, agree, continue)
314
- end
315
-
316
- def fontist_install(manifest, agree)
317
- Fontist::Manifest::Install.from_hash(
318
- manifest,
319
- confirmation: agree ? "yes" : "no"
320
- )
321
- end
322
-
323
240
  # @param options [Hash]
324
241
  # @return [String]
325
242
  def change_output_dir(options)
@@ -0,0 +1,45 @@
1
+ module Metanorma
2
+ class Compile
3
+ def validate_type(options)
4
+ unless options[:type]
5
+ Util.log("[metanorma] Error: Please specify a standard type: "\
6
+ "#{@registry.supported_backends}.", :error)
7
+ return nil
8
+ end
9
+ stdtype = options[:type].to_sym
10
+ metanorma_flavor = "metanorma-#{stdtype}"
11
+ unless @registry.supported_backends.include? stdtype
12
+ Util.log("[metanorma] Info: Loading `#{metanorma_flavor}` gem "\
13
+ "for standard type `#{stdtype}`.", :info)
14
+ end
15
+ begin
16
+ require "metanorma-#{stdtype}"
17
+ Util.log("[metanorma] Info: gem `#{metanorma_flavor}` loaded.", :info)
18
+ rescue Gem::ConflictError
19
+ Util.log("[metanorma] Error: Couldn't resolve dependencies for "\
20
+ "`metanorma-#{stdtype}`, Please add it to your Gemfile "\
21
+ "and run bundle install first", :error)
22
+ return false
23
+ rescue LoadError
24
+ Util.log("[metanorma] Error: loading gem `#{metanorma_flavor}` "\
25
+ "failed. Exiting.", :error)
26
+ return false
27
+ end
28
+ unless @registry.supported_backends.include? stdtype
29
+ Util.log("[metanorma] Error: The `#{metanorma_flavor}` gem "\
30
+ "still doesn't support `#{stdtype}`. Exiting.", :error)
31
+ return false
32
+ end
33
+ true
34
+ end
35
+
36
+ def validate_format(options)
37
+ unless options[:format] == :asciidoc
38
+ Util.log("[metanorma] Error: Only source file format currently "\
39
+ "supported is 'asciidoc'.", :error)
40
+ return false
41
+ end
42
+ true
43
+ end
44
+ end
45
+ end
@@ -15,7 +15,7 @@ module Metanorma
15
15
  attr_accessor :logs
16
16
 
17
17
  def initialize
18
- @logs ||= [:warning, :error, :fatal]
18
+ @logs ||= %i[warning error fatal]
19
19
  end
20
20
  end
21
21
 
@@ -1,20 +1,25 @@
1
1
  module Metanorma
2
2
  class Document
3
3
  # @return [Strin]
4
- attr_reader :file
4
+ attr_reader :file, :attachment, :bibitem
5
5
 
6
6
  # @param bibitem [RelatonBib::BibliographicItem]
7
7
  def initialize(bibitem, file, options = {})
8
8
  @bibitem = bibitem
9
9
  @file = file
10
+ @attachment = options[:attachment]
10
11
  @raw = options[:raw]
11
12
  end
12
13
 
13
14
  class << self
14
15
  # @param file [String] file path
16
+ # @param attachment [Bool] is an attachment
17
+ # @param identifier [String] is the identifier assigned the file
18
+ # in the collection file
15
19
  # @return [Metanorma::Document]
16
- def parse_file(file)
17
- new bibitem(file), file
20
+ def parse_file(file, attachment, identifier = nil)
21
+ new(bibitem(file, attachment, identifier), file,
22
+ { attachment: attachment })
18
23
  end
19
24
 
20
25
  # #param xml [Nokogiri::XML::Document, Nokogiri::XML::Element]
@@ -29,6 +34,12 @@ module Metanorma
29
34
  new(doc, filename, raw: true)
30
35
  end
31
36
 
37
+ def attachment_bibitem(identifier)
38
+ Nokogiri::XML(
39
+ "<bibdata><docidentifier>#{identifier}</docidentifier></bibdata>",
40
+ )
41
+ end
42
+
32
43
  private
33
44
 
34
45
  # #param xml [Nokogiri::XML::Document, Nokogiri::XML::Element]
@@ -49,13 +60,16 @@ module Metanorma
49
60
  # @param file [String]
50
61
  # @return [RelatonBib::BibliographicItem,
51
62
  # RelatonIso::IsoBibliographicItem]
52
- def bibitem(file)
53
- case format(file)
54
- when :xml
55
- from_xml Nokogiri::XML(File.read(file, encoding: "UTF-8"))
56
- when :yaml
57
- yaml = File.read(file, encoding: "UTF-8")
58
- Relaton::Cli::YAMLConvertor.convert_single_file(yaml)
63
+ def bibitem(file, attachment, identifier)
64
+ if attachment then attachment_bibitem(identifier)
65
+ else
66
+ case format(file)
67
+ when :xml
68
+ from_xml Nokogiri::XML(File.read(file, encoding: "UTF-8"))
69
+ when :yaml
70
+ yaml = File.read(file, encoding: "UTF-8")
71
+ Relaton::Cli::YAMLConvertor.convert_single_file(yaml)
72
+ end
59
73
  end
60
74
  end
61
75
  end
@@ -0,0 +1,108 @@
1
+ module Metanorma
2
+ class FontistUtils
3
+ class << self
4
+ private
5
+
6
+ def validate_options(options)
7
+ agree_to_terms = options[:agree_to_terms] || false
8
+ continue_without_fonts = options[:continue_without_fonts] || false
9
+ no_progress = options[:no_progress] || false
10
+
11
+ [agree_to_terms, continue_without_fonts, no_progress]
12
+ end
13
+
14
+ def validate_install_fonts(processor, options)
15
+ if options[:no_install_fonts]
16
+ Util.log("[fontist] Skip font installation because" \
17
+ " --no-install-fonts argument passed", :debug)
18
+ return false
19
+ elsif missing_fontist_manifest?(processor)
20
+ Util.log("[fontist] Skip font installation because "\
21
+ "font_manifest is missing", :debug)
22
+ return false
23
+ end
24
+ true
25
+ end
26
+
27
+ def install_fonts_safe(manifest, agree, continue, no_progress)
28
+ fontist_install(manifest, agree, no_progress)
29
+ rescue Fontist::Errors::LicensingError
30
+ if continue
31
+ Util.log(
32
+ "[fontist] Processing will continue without fonts installed",
33
+ :debug
34
+ )
35
+ else
36
+ Util.log("[fontist] Aborting without proper fonts installed," \
37
+ " make sure that you have set option --agree-to-terms",
38
+ :fatal)
39
+ end
40
+ rescue Fontist::Errors::FontError => e
41
+ log_level = continue ? :warning : :fatal
42
+ Util.log("[fontist] '#{e.font}' font is not supported. " \
43
+ "Please report this issue at github.com/metanorma/metanorma" \
44
+ "/issues to report this issue.", log_level)
45
+ rescue Fontist::Errors::FormulaIndexNotFoundError
46
+ if @@updated_formulas_repo
47
+ Util.log(
48
+ "[fontist] Bug: formula index not found after 'fontist update'",
49
+ :fatal
50
+ )
51
+ end
52
+ Util.log("[fontist] Missing formula index. Fetching it...", :debug)
53
+ Fontist::Formula.update_formulas_repo
54
+ @@updated_formulas_repo = true
55
+ install_fonts_safe(manifest, agree, continue, no_progress)
56
+ end
57
+
58
+ def fontist_install(manifest, agree, no_progress)
59
+ Fontist::Manifest::Install.from_hash(
60
+ manifest,
61
+ confirmation: agree ? "yes" : "no",
62
+ no_progress: no_progress
63
+ )
64
+ end
65
+
66
+ def dump_fontist_manifest_locations(manifest)
67
+ location_manifest = Fontist::Manifest::Locations.from_hash(
68
+ manifest
69
+ )
70
+ location_manifest_file = Tempfile.new(["fontist_locations", ".yml"])
71
+ location_manifest_file.write location_manifest.to_yaml
72
+ location_manifest_file.flush
73
+ location_manifest_file
74
+ end
75
+
76
+ def missing_fontist_manifest?(processor)
77
+ !processor.respond_to?(:fonts_manifest) || processor.fonts_manifest.nil?
78
+ end
79
+ end
80
+
81
+ def self.install_fonts(processor, options)
82
+ return unless validate_install_fonts(processor, options)
83
+
84
+ @@updated_formulas_repo = false
85
+ manifest = processor.fonts_manifest
86
+ agree_to_terms, can_without_fonts, no_progress = validate_options(options)
87
+
88
+ install_fonts_safe(
89
+ manifest,
90
+ agree_to_terms,
91
+ can_without_fonts,
92
+ no_progress
93
+ )
94
+ end
95
+
96
+ def self.fontist_font_locations(processor, options)
97
+ if missing_fontist_manifest?(processor) || options[:no_install_fonts]
98
+ return nil
99
+ end
100
+
101
+ dump_fontist_manifest_locations(processor.fonts_manifest)
102
+ rescue Fontist::Errors::FormulaIndexNotFoundError
103
+ raise unless options[:continue_without_fonts]
104
+
105
+ nil
106
+ end
107
+ end
108
+ end