metanorma 1.2.1 → 1.2.6pre
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/.github/workflows/notify.yml +7 -7
- data/.github/workflows/rake.yml +18 -17
- data/lib/metanorma/collection.rb +8 -1
- data/lib/metanorma/collection_fileprocess.rb +270 -0
- data/lib/metanorma/collection_renderer.rb +3 -155
- data/lib/metanorma/compile.rb +72 -6
- data/lib/metanorma/input/asciidoc.rb +1 -1
- data/lib/metanorma/version.rb +1 -1
- data/metanorma.gemspec +6 -4
- metadata +35 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f44605746ed08329b51fabc943ab3e0587e7e4cf07645fcd20505121a1f7544
|
4
|
+
data.tar.gz: 7531752fd6c7b2d1c3f7e13deee84d54276a2dc7ed7bd2e05cab02ce83ce6b9b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1d8fc5ab61a03b0b2600bbf75f9d9945fefc463e0003f41b7534887c9c88826ed7dfa6cf264e852ac40493d4ced15fb639b3ee304bf0286328543ca119de296
|
7
|
+
data.tar.gz: 4ce326412a2248432450bd9fbe08c431bc5369bffa623e02895f8ce7d814ff000c50344bf7fa6653a55ac19deacebe31b9d07887ada84436a940db14a412712d
|
@@ -3,16 +3,16 @@
|
|
3
3
|
name: notify
|
4
4
|
|
5
5
|
on:
|
6
|
-
|
7
|
-
|
8
|
-
tags:
|
9
|
-
- '*'
|
6
|
+
repository_dispatch:
|
7
|
+
types: [ notify ]
|
10
8
|
|
11
9
|
jobs:
|
12
10
|
notify:
|
13
11
|
name: Notify dependent repos
|
14
12
|
runs-on: ubuntu-latest
|
15
13
|
steps:
|
14
|
+
- uses: actions/checkout@v2
|
15
|
+
|
16
16
|
- name: Trigger repositories
|
17
17
|
env:
|
18
18
|
GH_USERNAME: metanorma-ci
|
@@ -21,7 +21,7 @@ jobs:
|
|
21
21
|
curl -LO --retry 3 https://raw.githubusercontent.com/metanorma/metanorma-build-scripts/master/trigger-gh-actions.sh
|
22
22
|
[[ -f ".github/workflows/dependent_repos.env" ]] && source .github/workflows/dependent_repos.env
|
23
23
|
CLIENT_PAYLOAD=$(cat <<EOF
|
24
|
-
"{ "ref": "${
|
24
|
+
"{ "ref": "${{ github.event.client_payload.ref }}", "repo": "${GITHUB_REPOSITORY}" }"
|
25
25
|
EOF
|
26
26
|
)
|
27
27
|
for repo in $TEMPLATE_REPOS" $SAMPLES_REPOS"
|
@@ -30,7 +30,7 @@ jobs:
|
|
30
30
|
done
|
31
31
|
|
32
32
|
- name: Trigger release repositories
|
33
|
-
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v')
|
33
|
+
if: github.event.client_payload.ref == 'refs/heads/master' || startsWith(github.event.client_payload.ref, 'refs/tags/v')
|
34
34
|
env:
|
35
35
|
GH_USERNAME: metanorma-ci
|
36
36
|
GH_ACCESS_TOKEN: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
|
@@ -38,7 +38,7 @@ jobs:
|
|
38
38
|
curl -LO --retry 3 https://raw.githubusercontent.com/metanorma/metanorma-build-scripts/master/trigger-gh-actions.sh
|
39
39
|
[[ -f ".github/workflows/dependent_repos.env" ]] && source .github/workflows/dependent_repos.env
|
40
40
|
CLIENT_PAYLOAD=$(cat <<EOF
|
41
|
-
"{ "ref": "${
|
41
|
+
"{ "ref": "${{ github.event.client_payload.ref }}", "repo": "${GITHUB_REPOSITORY}" }"
|
42
42
|
EOF
|
43
43
|
)
|
44
44
|
for repo in $DEPENDENT_REPOS
|
data/.github/workflows/rake.yml
CHANGED
@@ -4,7 +4,7 @@ name: rake
|
|
4
4
|
|
5
5
|
on:
|
6
6
|
push:
|
7
|
-
branches: [ master ]
|
7
|
+
branches: [ master, main ]
|
8
8
|
tags: [ v* ]
|
9
9
|
pull_request:
|
10
10
|
|
@@ -32,28 +32,29 @@ jobs:
|
|
32
32
|
steps:
|
33
33
|
- uses: actions/checkout@master
|
34
34
|
|
35
|
-
-
|
36
|
-
uses: ruby/setup-ruby@v1
|
35
|
+
- uses: ruby/setup-ruby@v1
|
37
36
|
with:
|
38
37
|
ruby-version: ${{ matrix.ruby }}
|
39
|
-
bundler-cache: true
|
40
38
|
|
41
|
-
-
|
42
|
-
|
39
|
+
- uses: actions/cache@v2
|
40
|
+
with:
|
41
|
+
path: vendor/bundle
|
42
|
+
key: bundle-${{ matrix.os }}-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}
|
43
|
+
restore-keys: bundle-${{ matrix.os }}-${{ matrix.ruby }}
|
44
|
+
|
45
|
+
- run: bundle config set path 'vendor/bundle'
|
46
|
+
|
47
|
+
- run: bundle install --jobs 4 --retry 3
|
43
48
|
|
44
|
-
-
|
45
|
-
run: bundle exec rake
|
49
|
+
- run: bundle exec rake
|
46
50
|
|
47
|
-
|
48
|
-
name: Trigger notify workflow
|
51
|
+
tests-passed:
|
49
52
|
needs: rake
|
50
53
|
runs-on: ubuntu-latest
|
51
54
|
steps:
|
52
|
-
-
|
53
|
-
uses: Sibz/github-status-action@v1
|
55
|
+
- uses: peter-evans/repository-dispatch@v1
|
54
56
|
with:
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
sha: ${{ github.event.pull_request.head.sha || github.sha }}
|
57
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
58
|
+
repository: ${{ github.repository }}
|
59
|
+
event-type: notify
|
60
|
+
client-payload: '{"ref": "${{ github.ref }}"}'
|
data/lib/metanorma/collection.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "relaton"
|
4
4
|
require "relaton/cli"
|
5
5
|
require "metanorma/collection_manifest"
|
6
|
+
require "metanorma-utils"
|
6
7
|
|
7
8
|
module Metanorma
|
8
9
|
# Metanorma collection of documents
|
@@ -39,8 +40,13 @@ module Metanorma
|
|
39
40
|
@documents.merge! @manifest.documents(File.dirname(@file))
|
40
41
|
@prefatory = args[:prefatory]
|
41
42
|
@final = args[:final]
|
43
|
+
@log = Metanorma::Utils::Log.new
|
42
44
|
end
|
45
|
+
|
43
46
|
# rubocop:enable Metrics/AbcSize,Metrics/MethodLength
|
47
|
+
def clean_exit
|
48
|
+
@log.write(File.join(File.dirname(@file), File.basename(@file, ".*") + ".err"))
|
49
|
+
end
|
44
50
|
|
45
51
|
# @return [String] XML
|
46
52
|
def to_xml
|
@@ -57,7 +63,8 @@ module Metanorma
|
|
57
63
|
end
|
58
64
|
|
59
65
|
def render(opts)
|
60
|
-
CollectionRenderer.render self, opts
|
66
|
+
CollectionRenderer.render self, opts.merge(log: @log)
|
67
|
+
clean_exit
|
61
68
|
end
|
62
69
|
|
63
70
|
class << self
|
@@ -0,0 +1,270 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "isodoc"
|
4
|
+
|
5
|
+
module Metanorma
|
6
|
+
# XML collection renderer
|
7
|
+
class CollectionRenderer
|
8
|
+
# hash for each document in collection of document identifier to:
|
9
|
+
# document reference (fileref or id), type of document reference,
|
10
|
+
# and bibdata entry for that file
|
11
|
+
# @param path [String] path to collection
|
12
|
+
# @return [Hash{String=>Hash}]
|
13
|
+
def read_files(path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
14
|
+
files = {}
|
15
|
+
@xml.xpath(ns("//docref")).each do |d|
|
16
|
+
identifier = d.at(ns("./identifier")).text
|
17
|
+
files[identifier] = if d["fileref"]
|
18
|
+
{ type: "fileref",
|
19
|
+
ref: File.join(path, d["fileref"]) }
|
20
|
+
else { type: "id", ref: d["id"] }
|
21
|
+
end
|
22
|
+
file, _filename = targetfile(files[identifier], true)
|
23
|
+
xml = Nokogiri::XML(file)
|
24
|
+
add_document_suffix(identifier, xml)
|
25
|
+
files[identifier][:anchors] = read_anchors(xml)
|
26
|
+
files[identifier][:bibdata] = xml.at(ns("//bibdata"))
|
27
|
+
end
|
28
|
+
files
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_suffix_to_attributes(doc, suffix, tag_name, attribute_name)
|
32
|
+
doc.xpath(ns("//#{tag_name}[@#{attribute_name}]")).each do |elem|
|
33
|
+
elem.attributes[attribute_name].value =
|
34
|
+
"#{elem.attributes[attribute_name].value}_#{suffix}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_document_suffix(identifier, doc)
|
39
|
+
document_suffix = Metanorma::Utils::to_ncname(identifier)
|
40
|
+
[%w[* id],
|
41
|
+
%w[* bibitemid],
|
42
|
+
%w[review from],
|
43
|
+
%w[review to],
|
44
|
+
%w[index to],
|
45
|
+
%w[xref target],
|
46
|
+
%w[callout target]]
|
47
|
+
.each do |(tag_name, attribute_name)|
|
48
|
+
add_suffix_to_attributes(doc, document_suffix, tag_name, attribute_name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# map locality type and label (e.g. "clause" "1") to id = anchor for
|
53
|
+
# a document
|
54
|
+
def read_anchors(xml)
|
55
|
+
ret = {}
|
56
|
+
xrefs = @isodoc.xref_init(@lang, @script, @isodoc, @isodoc.i18n, {})
|
57
|
+
xrefs.parse xml
|
58
|
+
xrefs.get.each do |k, v|
|
59
|
+
ret[v[:type]] ||= {}
|
60
|
+
index = v[:container] || v[:label].nil? || v[:label].empty? ?
|
61
|
+
UUIDTools::UUID.random_create.to_s : v[:label]
|
62
|
+
# Note: will only key clauses, which have unambiguous reference label in locality.
|
63
|
+
# Notes, examples etc with containers are just plunked agaisnt UUIDs, so that their
|
64
|
+
# IDs can at least be registered to be tracked as existing.
|
65
|
+
ret[v[:type]][index] = k
|
66
|
+
end
|
67
|
+
ret
|
68
|
+
end
|
69
|
+
|
70
|
+
# return file contents + output filename for each file in the collection,
|
71
|
+
# given a docref entry
|
72
|
+
# @param data [Hash]
|
73
|
+
# @param read [Boolean]
|
74
|
+
# @return [Array<String, nil>]
|
75
|
+
def targetfile(data, read = false)
|
76
|
+
if data[:type] == "fileref" then ref_file data[:ref], read
|
77
|
+
else xml_file data[:id], read
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# @param ref [String]
|
82
|
+
# @param read [Boolean]
|
83
|
+
# @return [Array<String, nil>]
|
84
|
+
def ref_file(ref, read)
|
85
|
+
file = File.read(ref, encoding: "utf-8") if read
|
86
|
+
filename = ref.sub(/\.xml$/, ".html")
|
87
|
+
[file, filename]
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param id [String]
|
91
|
+
# @param read [Boolean]
|
92
|
+
# @return [Array<String, nil>]
|
93
|
+
def xml_file(id, read)
|
94
|
+
file = @xml.at(ns("//doc-container[@id = '#{id}']")).to_xml if read
|
95
|
+
filename = id + ".html"
|
96
|
+
[file, filename]
|
97
|
+
end
|
98
|
+
|
99
|
+
# @param bib [Nokogiri::XML::Element]
|
100
|
+
# @param identifier [String]
|
101
|
+
def update_bibitem(bib, identifier) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
102
|
+
docid = bib&.at(ns("./docidentifier"))&.text
|
103
|
+
unless @files[docid]
|
104
|
+
error = "[metanorma] Cannot find crossreference to document #{docid} in document #{identifier}."
|
105
|
+
@log.add("Cross-References", nil, error)
|
106
|
+
Util.log(error, :warning)
|
107
|
+
return
|
108
|
+
end
|
109
|
+
id = bib["id"]
|
110
|
+
newbib = bib.replace(@files[docid][:bibdata])
|
111
|
+
newbib.name = "bibitem"
|
112
|
+
newbib["id"] = id
|
113
|
+
newbib["hidden"] = "true"
|
114
|
+
newbib&.at(ns("./ext"))&.remove
|
115
|
+
_file, url = targetfile(@files[docid], false)
|
116
|
+
uri_node = Nokogiri::XML::Node.new "uri", newbib
|
117
|
+
uri_node[:type] = "citation"
|
118
|
+
uri_node.content = url
|
119
|
+
newbib.at(ns("./docidentifier")).previous = uri_node
|
120
|
+
end
|
121
|
+
|
122
|
+
# Resolves direct links to other files in collection (repo(current-metanorma-collection/x),
|
123
|
+
# and indirect links to other files in collection (bibitem[@type = 'internal'] pointing to a file anchor
|
124
|
+
# in another file in the collection)
|
125
|
+
# @param file [String] XML content
|
126
|
+
# @param identifier [String] docid
|
127
|
+
# @param internal_refs [Hash{String=>Hash{String=>String}] schema name to anchor to filename
|
128
|
+
# @return [String] XML content
|
129
|
+
def update_xrefs(file, identifier, internal_refs)
|
130
|
+
docxml = Nokogiri::XML(file)
|
131
|
+
update_indirect_refs_to_docs(docxml, internal_refs)
|
132
|
+
add_document_suffix(identifier, docxml)
|
133
|
+
update_direct_refs_to_docs(docxml, identifier)
|
134
|
+
docxml.xpath(ns("//references[not(./bibitem[not(@hidden) or @hidden = 'false'])]")).each do |f|
|
135
|
+
f["hidden"] = "true"
|
136
|
+
end
|
137
|
+
docxml.to_xml
|
138
|
+
end
|
139
|
+
|
140
|
+
# repo(current-metanorma-collection/ISO 17301-1:2016)
|
141
|
+
# replaced by bibdata of "ISO 17301-1:2016" in situ as bibitem.
|
142
|
+
# Any erefs to that bibitem id are replaced with relative URL
|
143
|
+
# Preferably with anchor, and is a job to realise dynamic lookup of localities.
|
144
|
+
def update_direct_refs_to_docs(docxml, identifier)
|
145
|
+
docxml.xpath(ns("//bibitem[not(ancestor::bibitem)]")).each do |b|
|
146
|
+
docid = b&.at(ns("./docidentifier[@type = 'repository']"))&.text
|
147
|
+
next unless docid && %r{^current-metanorma-collection/}.match(docid)
|
148
|
+
update_bibitem(b, identifier)
|
149
|
+
update_anchors(b, docxml, docid)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Resolve erefs to a container of ids in another doc, to an anchor eref (direct link)
|
154
|
+
def update_indirect_refs_to_docs(docxml, internal_refs)
|
155
|
+
internal_refs.each do |schema, ids|
|
156
|
+
ids.each do |id, file|
|
157
|
+
update_indirect_refs_to_docs1(docxml, schema, id, file)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def update_indirect_refs_to_docs1(docxml, schema, id, file)
|
163
|
+
docxml.xpath(ns("//eref[@bibitemid = '#{schema}_#{id}']")).each do |e|
|
164
|
+
e["citeas"] = file
|
165
|
+
end
|
166
|
+
docid = docxml.at(ns("//bibitem[@id = '#{schema}_#{id}']/docidentifier[@type = 'repository']")) or return
|
167
|
+
docid.children = "current-metanorma-collection/#{file}"
|
168
|
+
docid.previous = "<docidentifier type='X'>#{file}</docidentifier>"
|
169
|
+
end
|
170
|
+
|
171
|
+
# update crossrefences to other documents, to include disambiguating document suffix on id
|
172
|
+
def update_anchors(bib, docxml, _id) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
173
|
+
docid = bib&.at(ns("./docidentifier"))&.text
|
174
|
+
docxml.xpath("//xmlns:eref[@citeas = '#{docid}']").each do |e|
|
175
|
+
if @files[docid]
|
176
|
+
update_anchor_loc(bib, e, docid)
|
177
|
+
else
|
178
|
+
e << "<strong>** Unresolved reference to document #{docid}, id #{e['bibitemid']}</strong>"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def update_anchor_loc(bib, e, docid)
|
184
|
+
loc = e.at(ns(".//locality[@type = 'anchor']")) or return update_anchor_create_loc(bib, e, docid)
|
185
|
+
document_suffix = Metanorma::Utils::to_ncname(docid)
|
186
|
+
ref = loc.at(ns("./referenceFrom")) || return
|
187
|
+
anchor = "#{ref.text}_#{document_suffix}"
|
188
|
+
return unless @files[docid][:anchors].inject([]) { |m, (_, x)| m+= x.values }.include?(anchor)
|
189
|
+
ref.content = anchor
|
190
|
+
end
|
191
|
+
|
192
|
+
# if there is a crossref to another document, with no anchor, retrieve the
|
193
|
+
# anchor given the locality, and insert it into the crossref
|
194
|
+
def update_anchor_create_loc(bib, e, docid)
|
195
|
+
ins = e.at(ns("./localityStack")) || return
|
196
|
+
type = ins&.at(ns("./locality/@type"))&.text
|
197
|
+
ref = ins&.at(ns("./locality/referenceFrom"))&.text
|
198
|
+
(anchor = @files[docid][:anchors][type][ref]) || return
|
199
|
+
ref_from = Nokogiri::XML::Node.new "referenceFrom", bib
|
200
|
+
ref_from.content = anchor.sub(/^_/, "")
|
201
|
+
locality = Nokogiri::XML::Node.new "locality", bib
|
202
|
+
locality[:type] = "anchor"
|
203
|
+
locality.add_child ref_from
|
204
|
+
ins << locality
|
205
|
+
end
|
206
|
+
|
207
|
+
# compile and output individual file in collection
|
208
|
+
def file_compile(f, filename, identifier)
|
209
|
+
# warn "metanorma compile -x html #{f.path}"
|
210
|
+
c = Compile.new
|
211
|
+
c.compile f.path, { format: :asciidoc, extension_keys: @format }.merge(@compile_options)
|
212
|
+
@files[identifier][:outputs] = {}
|
213
|
+
@format.each do |e|
|
214
|
+
ext = c.processor.output_formats[e]
|
215
|
+
fn = File.basename(filename).sub(/(?<=\.)[^\.]+$/, ext.to_s)
|
216
|
+
FileUtils.mv f.path.sub(/\.xml$/, ".#{ext}"), File.join(@outdir, fn)
|
217
|
+
@files[identifier][:outputs][e] = File.join(@outdir, fn)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# gather internal bibitem references
|
222
|
+
def gather_internal_refs
|
223
|
+
@files.each_with_object({}) do |(identifier, x), refs|
|
224
|
+
file, _ = targetfile(x, true)
|
225
|
+
Nokogiri::XML(file).xpath(ns("//bibitem[@type = 'internal']/docidentifier[@type = 'repository']")).each do |d|
|
226
|
+
a = d.text.split(%r{/}, 2)
|
227
|
+
a.size > 1 or next
|
228
|
+
refs[a[0]] ||= {}
|
229
|
+
refs[a[0]][a[1]] = true
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# resolve file location for the target of each internal reference
|
235
|
+
def locate_internal_refs
|
236
|
+
refs = gather_internal_refs
|
237
|
+
@files.each do |identifier, x|
|
238
|
+
file, filename = targetfile(x, true)
|
239
|
+
docxml = Nokogiri::XML(file)
|
240
|
+
refs.each do |schema, ids|
|
241
|
+
ids.keys.each do |id|
|
242
|
+
docxml.at(ns("//*[@id = '#{id}'][@type = '#{schema}']")) and
|
243
|
+
refs[schema][id] = identifier
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
refs.each do |schema, ids|
|
248
|
+
ids.each do |id, key|
|
249
|
+
key == true and refs[schema][id] = "Missing:#{schema}:#{id}"
|
250
|
+
end
|
251
|
+
end
|
252
|
+
refs
|
253
|
+
end
|
254
|
+
|
255
|
+
# process each file in the collection
|
256
|
+
# files are held in memory, and altered as postprocessing
|
257
|
+
def files # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
258
|
+
internal_refs = locate_internal_refs
|
259
|
+
@files.each do |identifier, x|
|
260
|
+
file, filename = targetfile(x, true)
|
261
|
+
file = update_xrefs(file, identifier, internal_refs)
|
262
|
+
Tempfile.open(["collection", ".xml"], encoding: "utf-8") do |f|
|
263
|
+
f.write(file)
|
264
|
+
f.close
|
265
|
+
file_compile(f, filename, identifier)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "isodoc"
|
4
|
+
require_relative "./collection_fileprocess"
|
4
5
|
|
5
6
|
module Metanorma
|
6
7
|
# XML collection renderer
|
@@ -33,6 +34,8 @@ module Metanorma
|
|
33
34
|
@outdir = options[:output_folder]
|
34
35
|
@coverpage = options[:coverpage]
|
35
36
|
@format = options[:format]
|
37
|
+
@compile_options = options[:compile] || {}
|
38
|
+
@log = options[:log]
|
36
39
|
|
37
40
|
# list of files in the collection
|
38
41
|
@files = read_files folder
|
@@ -113,42 +116,6 @@ module Metanorma
|
|
113
116
|
IsoDoc::Convert.new({}).ns(xpath)
|
114
117
|
end
|
115
118
|
|
116
|
-
# hash for each document in collection of document identifier to:
|
117
|
-
# document reference (fileref or id), type of document reference,
|
118
|
-
# and bibdata entry for that file
|
119
|
-
# @param path [String] path to collection
|
120
|
-
# @return [Hash{String=>Hash}]
|
121
|
-
def read_files(path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
122
|
-
files = {}
|
123
|
-
@xml.xpath(ns("//docref")).each do |d|
|
124
|
-
identifier = d.at(ns("./identifier")).text
|
125
|
-
files[identifier] = if d["fileref"]
|
126
|
-
{ type: "fileref",
|
127
|
-
ref: File.join(path, d["fileref"]) }
|
128
|
-
else { type: "id", ref: d["id"] }
|
129
|
-
end
|
130
|
-
file, _filename = targetfile(files[identifier], true)
|
131
|
-
xml = Nokogiri::XML(file)
|
132
|
-
files[identifier][:anchors] = read_anchors(xml)
|
133
|
-
files[identifier][:bibdata] = xml.at(ns("//bibdata"))
|
134
|
-
end
|
135
|
-
files
|
136
|
-
end
|
137
|
-
|
138
|
-
# map locality type and label (e.g. "clause" "1") to id = anchor for
|
139
|
-
# a document
|
140
|
-
def read_anchors(xml)
|
141
|
-
ret = {}
|
142
|
-
xrefs = @isodoc.xref_init(@lang, @script, @isodoc, @isodoc.i18n, {})
|
143
|
-
xrefs.parse xml
|
144
|
-
xrefs.get.each do |k, v|
|
145
|
-
v[:label] && v[:type] || next
|
146
|
-
ret[v[:type]] ||= {}
|
147
|
-
ret[v[:type]][v[:label]] = k
|
148
|
-
end
|
149
|
-
ret
|
150
|
-
end
|
151
|
-
|
152
119
|
# populate liquid template of ARGV[1] with metadata extracted from
|
153
120
|
# collection manifest
|
154
121
|
def coverpage
|
@@ -208,124 +175,6 @@ module Metanorma
|
|
208
175
|
end.doc.root.to_html
|
209
176
|
end
|
210
177
|
|
211
|
-
# return file contents + output filename for each file in the collection,
|
212
|
-
# given a docref entry
|
213
|
-
# @param data [Hash]
|
214
|
-
# @param read [Boolean]
|
215
|
-
# @return [Array<String, nil>]
|
216
|
-
def targetfile(data, read = false)
|
217
|
-
if data[:type] == "fileref" then ref_file data[:ref], read
|
218
|
-
else xml_file data[:id], read
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
# @param ref [String]
|
223
|
-
# @param read [Boolean]
|
224
|
-
# @return [Array<String, nil>]
|
225
|
-
def ref_file(ref, read)
|
226
|
-
file = File.read(ref, encoding: "utf-8") if read
|
227
|
-
filename = ref.sub(/\.xml$/, ".html")
|
228
|
-
[file, filename]
|
229
|
-
end
|
230
|
-
|
231
|
-
# @param id [String]
|
232
|
-
# @param read [Boolean]
|
233
|
-
# @return [Array<String, nil>]
|
234
|
-
def xml_file(id, read)
|
235
|
-
file = @xml.at(ns("//doc-container[@id = '#{id}']")).to_xml if read
|
236
|
-
filename = id + ".html"
|
237
|
-
[file, filename]
|
238
|
-
end
|
239
|
-
|
240
|
-
# @param bib [Nokogiri::XML::Element]
|
241
|
-
# @param identifier [String]
|
242
|
-
def update_bibitem(bib, identifier) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
243
|
-
docid = bib&.at(ns("./docidentifier"))&.text
|
244
|
-
unless @files[docid]
|
245
|
-
warn "Cannot find crossreference to document #{docid} in document "\
|
246
|
-
"#{identifier}!"
|
247
|
-
abort
|
248
|
-
end
|
249
|
-
id = bib["id"]
|
250
|
-
newbib = bib.replace(@files[docid][:bibdata])
|
251
|
-
newbib.name = "bibitem"
|
252
|
-
newbib["id"] = id
|
253
|
-
newbib["hidden"] = "true"
|
254
|
-
newbib&.at(ns("./ext"))&.remove
|
255
|
-
_file, url = targetfile(@files[docid], false)
|
256
|
-
uri_node = Nokogiri::XML::Node.new "uri", newbib
|
257
|
-
uri_node[:type] = "citation"
|
258
|
-
uri_node.content = url
|
259
|
-
newbib.at(ns("./docidentifier")).previous = uri_node
|
260
|
-
end
|
261
|
-
|
262
|
-
# TODO: update crossreferences to other files in the selection
|
263
|
-
# repo(current-metanorma-collection/ISO 17301-1:2016)
|
264
|
-
# replaced by
|
265
|
-
# bibdata of "ISO 17301-1:2016" in situ as bibitem
|
266
|
-
# Any erefs to that bibitem id are replaced with relative URL
|
267
|
-
# Preferably with anchor, and is a job to realise dynamic lookup of
|
268
|
-
# localities
|
269
|
-
# @param file [String] XML content
|
270
|
-
# @param identifier [String] docid
|
271
|
-
# @return [String] XML content
|
272
|
-
def update_xrefs(file, identifier)
|
273
|
-
docxml = Nokogiri::XML(file)
|
274
|
-
docxml.xpath(ns("//bibitem[not(ancestor::bibitem)]")).each do |b|
|
275
|
-
docid = b&.at(ns("./docidentifier[@type = 'repository']"))&.text
|
276
|
-
next unless docid && %r{^current-metanorma-collection/}.match(docid)
|
277
|
-
|
278
|
-
update_bibitem(b, identifier)
|
279
|
-
update_anchors(b, docxml, docid)
|
280
|
-
end
|
281
|
-
docxml.xpath(ns("//references[not(./bibitem[not(@hidden) or @hidden = 'false'])]")).each do |f|
|
282
|
-
f["hidden"] = "true"
|
283
|
-
end
|
284
|
-
docxml.to_xml
|
285
|
-
end
|
286
|
-
|
287
|
-
# if there is a crossref to another document, with no anchor, retrieve the
|
288
|
-
# anchor given the locality, and insert it into the crossref
|
289
|
-
def update_anchors(bib, docxml, _id) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
290
|
-
docid = bib&.at(ns("./docidentifier"))&.text
|
291
|
-
docxml.xpath("//xmlns:eref[@citeas = '#{docid}']").each do |e|
|
292
|
-
e.at(ns(".//locality[@type = 'anchor']")).nil? || next
|
293
|
-
ins = e.at(ns("./localityStack")) || next
|
294
|
-
type = ins&.at(ns("./locality/@type"))&.text
|
295
|
-
ref = ins&.at(ns("./locality/referenceFrom"))&.text
|
296
|
-
(anchor = @files[docid][:anchors][type][ref]) || next
|
297
|
-
ref_from = Nokogiri::XML::Node.new "referenceFrom", bib
|
298
|
-
ref_from.content = anchor.sub(/^_/, "")
|
299
|
-
locality = Nokogiri::XML::Node.new "locality", bib
|
300
|
-
locality[:type] = "anchor"
|
301
|
-
locality.add_child ref_from
|
302
|
-
ins << locality
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
# process each file in the collection
|
307
|
-
# files are held in memory, and altered as postprocessing
|
308
|
-
def files # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
309
|
-
@files.each do |identifier, x|
|
310
|
-
file, filename = targetfile(x, true)
|
311
|
-
file = update_xrefs(file, identifier)
|
312
|
-
Tempfile.open(["collection", ".xml"], encoding: "utf-8") do |f|
|
313
|
-
f.write(file)
|
314
|
-
f.close
|
315
|
-
# warn "metanorma compile -x html #{f.path}"
|
316
|
-
c = Compile.new
|
317
|
-
c.compile f.path, format: :asciidoc, extension_keys: @format
|
318
|
-
@files[identifier][:outputs] = {}
|
319
|
-
@format.each do |e|
|
320
|
-
ext = c.processor.output_formats[e]
|
321
|
-
fn = File.basename(filename).sub(/(?<=\.)[^\.]+$/, ext.to_s)
|
322
|
-
FileUtils.mv f.path.sub(/\.xml$/, ".#{ext}"), File.join(@outdir, fn)
|
323
|
-
@files[identifier][:outputs][e] = File.join(@outdir, fn)
|
324
|
-
end
|
325
|
-
end
|
326
|
-
end
|
327
|
-
end
|
328
|
-
|
329
178
|
private
|
330
179
|
|
331
180
|
# @param options [Hash]
|
@@ -335,7 +184,6 @@ module Metanorma
|
|
335
184
|
raise ArgumentError, "Need to specify formats (xml,html,pdf,doc)"
|
336
185
|
end
|
337
186
|
return if !options[:format].include?(:html) || options[:coverpage]
|
338
|
-
|
339
187
|
raise ArgumentError, "Need to specify a coverpage to render HTML"
|
340
188
|
end
|
341
189
|
end
|
data/lib/metanorma/compile.rb
CHANGED
@@ -2,6 +2,9 @@ require "fileutils"
|
|
2
2
|
require "nokogiri"
|
3
3
|
require "htmlentities"
|
4
4
|
|
5
|
+
require "fontist"
|
6
|
+
require "fontist/manifest/install"
|
7
|
+
|
5
8
|
module Metanorma
|
6
9
|
class Compile
|
7
10
|
# @return [Array<String>]
|
@@ -21,6 +24,7 @@ module Metanorma
|
|
21
24
|
(file, isodoc = process_input(filename, options)) or return nil
|
22
25
|
relaton_export(isodoc, options)
|
23
26
|
extract(isodoc, options[:extract], options[:extract_type])
|
27
|
+
install_fonts(options)
|
24
28
|
process_extensions(extensions, file, isodoc, options)
|
25
29
|
end
|
26
30
|
|
@@ -63,21 +67,32 @@ module Metanorma
|
|
63
67
|
Util.log("[metanorma] Error: Please specify a standard type: #{@registry.supported_backends}.", :error)
|
64
68
|
return nil
|
65
69
|
end
|
70
|
+
|
66
71
|
stdtype = options[:type].to_sym
|
72
|
+
metanorma_flavor = "metanorma-#{stdtype}"
|
73
|
+
|
67
74
|
unless @registry.supported_backends.include? stdtype
|
68
|
-
Util.log("[metanorma] Info: Loading
|
75
|
+
Util.log("[metanorma] Info: Loading `#{metanorma_flavor}` gem for standard type `#{stdtype}`.", :info)
|
69
76
|
end
|
77
|
+
|
70
78
|
begin
|
71
79
|
require "metanorma-#{stdtype}"
|
72
|
-
Util.log("[metanorma] Info: gem
|
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
|
+
|
73
86
|
rescue LoadError
|
74
|
-
Util.log("[metanorma] Error: loading gem
|
87
|
+
Util.log("[metanorma] Error: loading gem `#{metanorma_flavor}` failed. Exiting.", :error)
|
75
88
|
return false
|
76
89
|
end
|
90
|
+
|
77
91
|
unless @registry.supported_backends.include? stdtype
|
78
|
-
Util.log("[metanorma] Error: The
|
92
|
+
Util.log("[metanorma] Error: The `#{metanorma_flavor}` gem still doesn't support `#{stdtype}`. Exiting.", :error)
|
79
93
|
return false
|
80
94
|
end
|
95
|
+
|
81
96
|
true
|
82
97
|
end
|
83
98
|
|
@@ -246,19 +261,70 @@ module Metanorma
|
|
246
261
|
@processor.output(isodoc, xml_name, outfilename, ext, isodoc_options)
|
247
262
|
rescue StandardError => e
|
248
263
|
puts e.message
|
264
|
+
puts e.backtrace.join("\n")
|
249
265
|
end
|
250
266
|
end
|
251
267
|
wrap_html(options, file_extension, outfilename)
|
252
268
|
end
|
253
269
|
end
|
254
270
|
|
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
|
+
|
255
292
|
private
|
256
293
|
|
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
|
+
|
257
323
|
# @param options [Hash]
|
258
324
|
# @return [String]
|
259
325
|
def change_output_dir(options)
|
260
|
-
if options[:
|
261
|
-
File.join options[:
|
326
|
+
if options[:output_dir]
|
327
|
+
File.join options[:output_dir], File.basename(options[:filename])
|
262
328
|
else options[:filename]
|
263
329
|
end
|
264
330
|
end
|
@@ -14,7 +14,7 @@ module Metanorma
|
|
14
14
|
header_footer: true,
|
15
15
|
attributes: [
|
16
16
|
"nodoc", "stem", "xrefstyle=short", "docfile=#{filename}",
|
17
|
-
"output_dir=#{options[:
|
17
|
+
"output_dir=#{options[:output_dir]}"
|
18
18
|
]
|
19
19
|
}
|
20
20
|
unless asciidoctor_validate(file, filename, out_opts)
|
data/lib/metanorma/version.rb
CHANGED
data/metanorma.gemspec
CHANGED
@@ -27,17 +27,19 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_runtime_dependency 'htmlentities'
|
28
28
|
spec.add_runtime_dependency 'nokogiri'
|
29
29
|
spec.add_runtime_dependency 'mn2pdf', "~> 1"
|
30
|
+
spec.add_runtime_dependency 'metanorma-utils', "~> 1"
|
30
31
|
spec.add_runtime_dependency 'pry'
|
31
|
-
|
32
|
+
spec.add_runtime_dependency 'fontist', '~> 1.8'
|
33
|
+
|
34
|
+
# get relaton-cli to avoid circular reference with metanorma-standoc
|
32
35
|
#spec.add_dependency "relaton-cli"
|
33
|
-
#spec.add_dependency "metanorma-standoc"
|
36
|
+
#spec.add_dependency "metanorma-standoc"
|
34
37
|
|
35
38
|
spec.add_development_dependency "rake", "~> 12.0"
|
36
39
|
spec.add_development_dependency "rspec", "~> 3.0"
|
37
40
|
spec.add_development_dependency "byebug", "~> 10.0"
|
38
41
|
spec.add_development_dependency "rspec-command", "~> 1.0"
|
39
42
|
spec.add_development_dependency "equivalent-xml", "~> 0.6"
|
40
|
-
spec.add_development_dependency "metanorma-iso", "~> 1.
|
43
|
+
spec.add_development_dependency "metanorma-iso", "~> 1.7.0"
|
41
44
|
spec.add_development_dependency "sassc", "~> 2.4.0"
|
42
|
-
#spec.add_development_dependency "isodoc", "~> 1.2.1"
|
43
45
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metanorma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.6pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciidoctor
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: metanorma-utils
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: pry
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +94,20 @@ dependencies:
|
|
80
94
|
- - ">="
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: fontist
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.8'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.8'
|
83
111
|
- !ruby/object:Gem::Dependency
|
84
112
|
name: rake
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,14 +184,14 @@ dependencies:
|
|
156
184
|
requirements:
|
157
185
|
- - "~>"
|
158
186
|
- !ruby/object:Gem::Version
|
159
|
-
version: 1.
|
187
|
+
version: 1.7.0
|
160
188
|
type: :development
|
161
189
|
prerelease: false
|
162
190
|
version_requirements: !ruby/object:Gem::Requirement
|
163
191
|
requirements:
|
164
192
|
- - "~>"
|
165
193
|
- !ruby/object:Gem::Version
|
166
|
-
version: 1.
|
194
|
+
version: 1.7.0
|
167
195
|
- !ruby/object:Gem::Dependency
|
168
196
|
name: sassc
|
169
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -210,6 +238,7 @@ files:
|
|
210
238
|
- lib/metanorma/asciidoctor_extensions.rb
|
211
239
|
- lib/metanorma/asciidoctor_extensions/glob_include_processor.rb
|
212
240
|
- lib/metanorma/collection.rb
|
241
|
+
- lib/metanorma/collection_fileprocess.rb
|
213
242
|
- lib/metanorma/collection_manifest.rb
|
214
243
|
- lib/metanorma/collection_renderer.rb
|
215
244
|
- lib/metanorma/compile.rb
|
@@ -243,9 +272,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
243
272
|
version: 2.4.0
|
244
273
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
245
274
|
requirements:
|
246
|
-
- - "
|
275
|
+
- - ">"
|
247
276
|
- !ruby/object:Gem::Version
|
248
|
-
version:
|
277
|
+
version: 1.3.1
|
249
278
|
requirements: []
|
250
279
|
rubygems_version: 3.0.3
|
251
280
|
signing_key:
|