core-ctx.lua /size: 13 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
core-ctx
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to core-ctx.mkiv
"
,
4
author
=
"
Hans Hagen, PRAGMA-ADE, Hasselt NL
"
,
5
copyright
=
"
PRAGMA ADE / ConTeXt Development Team
"
,
6
license
=
"
see context related readme files
"
7
}
8 9
--[[ 10Job control files aka ctx files are rather old and date from the mkii times. 11They were handled in texexec and mtx-context and deals with modes, modules, 12environments and preprocessing in projects where one such file drives the 13processing of lots of files without the need to provide command line 14arguments. 15 16In mkiv this concept was of course supported as well. The first implementation 17of mtx-context took much of the approach of texexec, but by now we have gotten 18rid of the option file (for passing modes, modules and environments), the stubs 19(for directly processing cld and xml) as well as the preprocessing component 20of the ctx files. Special helper features, like typesetting listings, were 21already moved to the extras (a direct side effect of the ability to pass along 22command line arguments.) All this made mtx-context more simple than its ancestor 23texexec. 24 25Because some of the modes might affect the mtx-context end, the ctx file is 26still loaded there but only for getting the modes. The file is loaded again 27during the run but as loading and basic processing takes less than a 28millisecond it's not that much of a burden. 29--]]
30 31
-- the ctxrunner tabel might either become private or move to the job namespace
32
-- which also affects the loading order
33 34
local
trace_prepfiles
=
false
trackers
.
register
(
"
system.prepfiles
"
,
function
(
v
)
trace_prepfiles
=
v
end
)
35 36
local
tostring
=
tostring
37
local
gsub
,
find
,
match
,
validstring
=
string
.
gsub
,
string
.
find
,
string
.
match
,
string
.
valid
38
local
concat
=
table
.
concat
39
local
xmltext
=
xml
.
text
40 41
local
report_jobfile
=
logs
.
reporter
(
"
system
"
,
"
jobfile
"
)
42
local
report_prepfiles
=
logs
.
reporter
(
"
system
"
,
"
prepfiles
"
)
43 44
local
commands
=
commands
45
local
implement
=
interfaces
.
implement
46 47
ctxrunner
=
ctxrunner
or
{
}
48 49
ctxrunner
.
prepfiles
=
utilities
.
storage
.
allocate
(
)
50 51
local
function
dontpreparefile
(
t
,
k
)
52
return
k
-- we only store when we have a prepper
53
end
54 55
table
.
setmetatableindex
(
ctxrunner
.
prepfiles
,
dontpreparefile
)
56 57
local
function
filtered
(
str
,
method
)
-- in resolvers?
58
str
=
tostring
(
str
)
59
if
method
=
=
'
name
'
then
str
=
file
.
nameonly
(
str
)
60
elseif
method
=
=
'
path
'
then
str
=
file
.
dirname
(
str
)
61
elseif
method
=
=
'
suffix
'
then
str
=
file
.
suffix
(
str
)
62
elseif
method
=
=
'
nosuffix
'
then
str
=
file
.
removesuffix
(
str
)
63
elseif
method
=
=
'
nopath
'
then
str
=
file
.
basename
(
str
)
64
elseif
method
=
=
'
base
'
then
str
=
file
.
basename
(
str
)
65
-- elseif method == 'full' then
66
-- elseif method == 'complete' then
67
-- elseif method == 'expand' then -- str = file.expandpath(str)
68
end
69
return
(
gsub
(
str
,
"
\\
"
,
"
/
"
)
)
70
end
71 72
-- local function substitute(e,str)
73
-- local attributes = e.at
74
-- if str and attributes then
75
-- if attributes['method'] then
76
-- str = filtered(str,attributes['method'])
77
-- end
78
-- if str == "" and attributes['default'] then
79
-- str = attributes['default']
80
-- end
81
-- end
82
-- return str
83
-- end
84 85
local
function
substitute
(
str
)
86
return
str
87
end
88 89
local
function
justtext
(
str
)
90
str
=
xml
.
unescaped
(
tostring
(
str
)
)
91
str
=
xml
.
cleansed
(
str
)
92
str
=
gsub
(
str
,
"
\\+
"
,
'
/
'
)
93
str
=
gsub
(
str
,
"
%s+
"
,
'
'
)
94
return
str
95
end
96 97
function
ctxrunner
.
load
(
ctxname
)
98 99
report_jobfile
(
"
processing %a
"
,
ctxname
)
100 101
local
xmldata
=
xml
.
load
(
ctxname
)
102 103
local
jobname
=
tex
.
jobname
-- todo
104 105
local
variables
=
{
job
=
jobname
}
106
local
commands
=
{
}
107
local
flags
=
{
}
108
local
paths
=
{
}
-- todo
109
local
treatments
=
{
}
110
local
suffix
=
"
prep
"
111 112
xml
.
include
(
xmldata
,
'
ctx:include
'
,
'
name
'
,
{
'
.
'
,
file
.
dirname
(
ctxname
)
,
"
..
"
,
"
../..
"
}
)
113 114
for
e
in
xml
.
collected
(
xmldata
,
"
/ctx:job/ctx:flags/ctx:flag
"
)
do
115
local
flag
=
xmltext
(
e
)
116
local
key
,
value
=
match
(
flag
,
"
^(.-)=(.+)$
"
)
117
if
key
and
value
then
118
environment
.
setargument
(
key
,
value
)
119
else
120
environment
.
setargument
(
flag
,
true
)
121
end
122
end
123 124
-- add to document.options.ctxfile[...]
125 126
local
ctxfile
=
document
.
options
.
ctxfile
127 128
local
modes
=
ctxfile
.
modes
129
local
modules
=
ctxfile
.
modules
130
local
environments
=
ctxfile
.
environments
131 132
for
e
in
xml
.
collected
(
xmldata
,
"
/ctx:job/ctx:process/ctx:resources/ctx:mode
"
)
do
133
modes
[
#
modes
+
1
]
=
xmltext
(
e
)
134
end
135 136
for
e
in
xml
.
collected
(
xmldata
,
"
/ctx:job/ctx:process/ctx:resources/ctx:module
"
)
do
137
modules
[
#
modules
+
1
]
=
xmltext
(
e
)
138
end
139 140
for
e
in
xml
.
collected
(
xmldata
,
"
/ctx:job/ctx:process/ctx:resources/ctx:environment
"
)
do
141
environments
[
#
environments
+
1
]
=
xmltext
(
e
)
142
end
143 144
for
e
in
xml
.
collected
(
xmldata
,
"
ctx:message
"
)
do
145
report_jobfile
(
"
ctx comment: %s
"
,
xmltext
(
e
)
)
146
end
147 148
for
r
,
d
,
k
in
xml
.
elements
(
xmldata
,
"
ctx:value[@name='job']
"
)
do
149
d
[
k
]
=
variables
[
'
job
'
]
or
"
"
150
end
151 152
for
e
in
xml
.
collected
(
xmldata
,
"
/ctx:job/ctx:preprocess/ctx:processors/ctx:processor
"
)
do
153
local
name
=
e
.
at
and
e
.
at
[
'
name
'
]
or
"
unknown
"
154
local
suffix
=
e
.
at
and
e
.
at
[
'
suffix
'
]
or
"
prep
"
155
for
r
,
d
,
k
in
xml
.
elements
(
command
,
"
ctx:old
"
)
do
156
d
[
k
]
=
"
%old%
"
157
end
158
for
r
,
d
,
k
in
xml
.
elements
(
e
,
"
ctx:new
"
)
do
159
d
[
k
]
=
"
%new%
"
160
end
161
for
r
,
d
,
k
in
xml
.
elements
(
e
,
"
ctx:value
"
)
do
162
local
tag
=
d
[
k
]
.
at
[
'
name
'
]
163
if
tag
then
164
d
[
k
]
=
"
%
"
.
.
tag
.
.
"
%
"
165
end
166
end
167
local
runner
=
xml
.
textonly
(
e
)
168
if
runner
and
runner
~
=
"
"
then
169
commands
[
name
]
=
{
170
suffix
=
suffix
,
171
runner
=
runner
,
172
}
173
end
174
end
175 176
local
suffix
=
xml
.
filter
(
xmldata
,
"
xml:///ctx:job/ctx:preprocess/attribute('suffix')
"
)
or
suffix
177
local
runlocal
=
xml
.
filter
(
xmldata
,
"
xml:///ctx:job/ctx:preprocess/ctx:processors/attribute('local')
"
)
178 179
runlocal
=
toboolean
(
runlocal
)
180 181
-- todo: only collect, then plug into file handler
182 183
local
inputfile
=
validstring
(
environment
.
arguments
.
input
)
or
jobname
184 185
variables
.
old
=
inputfile
186 187
for
files
in
xml
.
collected
(
xmldata
,
"
/ctx:job/ctx:preprocess/ctx:files
"
)
do
188
for
pattern
in
xml
.
collected
(
files
,
"
ctx:file
"
)
do
189
local
preprocessor
=
pattern
.
at
[
'
processor
'
]
or
"
"
190
for
r
,
d
,
k
in
xml
.
elements
(
pattern
,
"
/ctx:old
"
)
do
191
d
[
k
]
=
jobname
192
end
193
for
r
,
d
,
k
in
xml
.
elements
(
pattern
,
"
/ctx:value[@name='old'
"
)
do
194
d
[
k
]
=
jobname
195
end
196
pattern
=
justtext
(
xml
.
tostring
(
pattern
)
)
197
if
preprocessor
and
preprocessor
~
=
"
"
and
pattern
and
pattern
~
=
"
"
then
198
local
noftreatments
=
#
treatments
+
1
199
local
findpattern
=
string
.
topattern
(
pattern
)
200
local
preprocessors
=
utilities
.
parsers
.
settings_to_array
(
preprocessor
)
201
treatments
[
noftreatments
]
=
{
202
pattern
=
findpattern
,
203
preprocessors
=
preprocessors
,
204
}
205
report_jobfile
(
"
step %s, pattern %a, preprocessor: %a
"
,
noftreatments
,
findpattern
,
preprocessors
)
206
end
207
end
208
end
209 210
if
#
treatments
=
=
0
then
211
report_jobfile
(
"
no treatments needed
"
)
212
end
213 214
local
function
needstreatment
(
oldfile
)
215
for
i
=
1
,
#
treatments
do
216
local
treatment
=
treatments
[
i
]
217
local
pattern
=
treatment
.
pattern
218
if
find
(
oldfile
,
pattern
)
then
219
return
treatment
220
end
221
end
222
end
223 224
local
preparefile
=
#
treatments
>
0
and
function
(
prepfiles
,
filename
)
225 226
filename
=
file
.
collapsepath
(
filename
)
227 228
local
treatment
=
needstreatment
(
filename
)
229
local
oldfile
=
filename
230
local
newfile
=
false
231
if
treatment
then
232
local
preprocessors
=
treatment
.
preprocessors
233
local
runners
=
{
}
234
for
i
=
1
,
#
preprocessors
do
235
local
preprocessor
=
preprocessors
[
i
]
236
local
command
=
commands
[
preprocessor
]
237
if
command
then
238
local
runner
=
command
.
runner
239
local
suffix
=
command
.
suffix
240
local
result
=
filename
.
.
"
.
"
.
.
suffix
241
if
runlocal
then
242
result
=
file
.
basename
(
result
)
243
end
244
variables
.
old
=
oldfile
245
variables
.
new
=
result
246
runner
=
utilities
.
templates
.
replace
(
runner
,
variables
)
247
if
runner
and
runner
~
=
"
"
then
248
runners
[
#
runners
+
1
]
=
runner
249
oldfile
=
result
250
if
runlocal
then
251
oldfile
=
file
.
basename
(
oldfile
)
252
end
253
newfile
=
oldfile
254
end
255
end
256
end
257
oldname
=
file
.
collapsepath
(
oldname
)
258
newname
=
file
.
collapsepath
(
newname
)
259
if
not
newfile
then
260
newfile
=
filename
261
report_prepfiles
(
"
%a is not converted to %a
"
,
filename
,
newfile
)
262
elseif
not
lfs
.
isfile
(
newfile
)
or
file
.
needsupdating
(
filename
,
newfile
)
then
263
for
i
=
1
,
#
runners
do
264
report_prepfiles
(
"
step %i: %s
"
,
i
,
runners
[
i
]
)
265
end
266
--
267
for
i
=
1
,
#
runners
do
268
local
command
=
runners
[
i
]
269
report_prepfiles
(
"
command: %s
"
,
command
)
270
--
271
-- remark: we don't use sandbox.registerrunner here as we cannot predict what
272
-- gets done here, so just:
273
--
274
local
result
=
os
.
execute
(
command
)
or
0
275
--
276
-- if result > 0 then
277
-- report_prepfiles("error, return code: %s",result)
278
-- end
279
logs
.
newline
(
)
280
logs
.
newline
(
)
281
end
282
if
lfs
.
isfile
(
newfile
)
then
283
file
.
syncmtimes
(
filename
,
newfile
)
284
report_prepfiles
(
"
%a is converted to %a
"
,
filename
,
newfile
)
285
else
286
report_prepfiles
(
"
%a is not converted to %a
"
,
filename
,
newfile
)
287
newfile
=
filename
288
end
289
elseif
lfs
.
isfile
(
newfile
)
then
290
report_prepfiles
(
"
%a is already converted to %a
"
,
filename
,
newfile
)
291
else
292
report_prepfiles
(
"
unknown error when converting %a to %a
"
,
filename
,
newfile
)
293
end
294
else
295
newfile
=
filename
296
end
297
prepfiles
[
filename
]
=
newfile
298
-- in case we ask twice (with the prepped name) ... todo: avoid this mess
299
prepfiles
[
newfile
]
=
newfile
300
return
newfile
301
end
302 303
table
.
setmetatableindex
(
ctxrunner
.
prepfiles
,
preparefile
or
dontpreparefile
)
304 305
-- we need to deal with the input filename as it has already be resolved
306 307
end
308 309
-- print("\n")
310
-- document = {
311
-- options = {
312
-- ctxfile = {
313
-- modes = { },
314
-- modules = { },
315
-- environments = { },
316
-- }
317
-- }
318
-- }
319
-- environment.arguments.input = "test.tex"
320
-- ctxrunner.load("x-ldx.ctx")
321 322
local
function
resolve
(
name
)
-- used a few times later on
323
return
ctxrunner
.
prepfiles
[
file
.
collapsepath
(
name
)
]
or
false
324
end
325 326
function
ctxrunner
.
preparedfile
(
name
)
327
return
resolve
(
name
)
or
name
328
end
329 330
local
processfile
=
commands
.
processfile
331
local
doifelseinputfile
=
commands
.
doifelseinputfile
332 333
implement
{
334
name
=
"
processfile
"
,
335
overload
=
true
,
336
arguments
=
{
"
string
"
,
"
integer
"
}
,
337
actions
=
function
(
name
,
maxreadlevel
)
-- overloaded
338
local
prepname
=
resolve
(
name
)
339
if
prepname
then
340
return
processfile
(
prepname
,
0
)
341
end
342
return
processfile
(
name
,
maxreadlevel
)
343
end
344
}
345 346
implement
{
347
name
=
"
doifelseinputfile
"
,
348
overload
=
true
,
349
arguments
=
{
"
string
"
,
"
integer
"
}
,
350
actions
=
function
(
name
,
depth
)
351
local
prepname
=
resolve
(
name
)
352
if
prepname
then
353
return
doifelseinputfile
(
prepname
,
0
)
354
end
355
return
doifelseinputfile
(
name
,
depth
)
356
end
357
}
358 359
-- implement {
360
-- name = "preparedfile", -- not used
361
-- arguments = "string",
362
-- actions = { ctxrunner.preparedfile, context }
363
-- }
364 365
implement
{
366
name
=
"
setdocumentctxfile
"
,
367
onlyonce
=
true
,
368
actions
=
function
(
)
369
local
ctxfile
=
document
.
arguments
.
ctx
or
"
"
370
if
ctxfile
~
=
"
"
then
371
ctxrunner
.
load
(
ctxfile
)
-- do we need to locate it?
372
end
373
end
374
}
375 376
function
ctxrunner
.
resolve
(
name
)
-- used a few times later on
377
local
collapsedname
=
file
.
collapsepath
(
name
,
"
.
"
)
378
return
ctxrunner
.
prepfiles
[
collapsedname
]
or
collapsedname
379
end
380 381
-- ctxrunner.load("t:/sources/core-ctx.ctx")
382 383
-- context(ctxrunner.prepfiles["one-a.xml"]) context.par()
384
-- context(ctxrunner.prepfiles["one-b.xml"]) context.par()
385
-- context(ctxrunner.prepfiles["two-c.xml"]) context.par()
386
-- context(ctxrunner.prepfiles["two-d.xml"]) context.par()
387
-- context(ctxrunner.prepfiles["all-x.xml"]) context.par()
388 389
-- inspect(ctxrunner.prepfiles)
390