1if 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
30
31
32
33
34local trace_prepfiles = false trackers.register("system.prepfiles", function(v) trace_prepfiles = v end)
35
36local tostring = tostring
37local gsub, find, match, validstring = string.gsub, string.find, string.match, string.valid
38local concat = table.concat
39local xmltext = xml.text
40
41local report_jobfile = logs.reporter("system","jobfile")
42local report_prepfiles = logs.reporter("system","prepfiles")
43
44local commands = commands
45local implement = interfaces.implement
46
47ctxrunner = ctxrunner or { }
48
49ctxrunner.prepfiles = utilities.storage.allocate()
50
51local function dontpreparefile(t,k)
52 return k
53end
54
55table.setmetatableindex(ctxrunner.prepfiles,dontpreparefile)
56
57local function filtered(str,method)
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
66
67
68 end
69 return (gsub(str,"\\","/"))
70end
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85local function substitute(str)
86 return str
87end
88
89local 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
95end
96
97function ctxrunner.load(ctxname)
98
99 report_jobfile("processing %a",ctxname)
100
101 local xmldata = xml.load(ctxname)
102
103 local jobname = tex.jobname
104
105 local variables = { job = jobname }
106 local commands = { }
107 local flags = { }
108 local paths = { }
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
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
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
272
273
274 local result = os.execute(command) or 0
275
276
277
278
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
299 prepfiles[newfile] = newfile
300 return newfile
301 end
302
303 table.setmetatableindex(ctxrunner.prepfiles,preparefile or dontpreparefile)
304
305
306
307end
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322local function resolve(name)
323 return ctxrunner.prepfiles[file.collapsepath(name)] or false
324end
325
326function ctxrunner.preparedfile(name)
327 return resolve(name) or name
328end
329
330local ctx_processfile = commands.processfile
331local ctx_doifelseinputfile = commands.doifelseinputfile
332
333implement {
334 name = "processfile",
335 overload = true,
336 arguments = { "string", "integer" },
337 actions = function(name,maxreadlevel)
338 local prepname = resolve(name)
339 if prepname then
340 return ctx_processfile(prepname,0)
341 else
342 return ctx_processfile(name,maxreadlevel)
343 end
344 end
345}
346
347implement {
348 name = "doifelseinputfile",
349 overload = true,
350 arguments = { "string", "integer" },
351 actions = function(name,depth)
352 local prepname = resolve(name)
353 if prepname then
354 return ctx_doifelseinputfile(prepname,0)
355 else
356 return ctx_doifelseinputfile(name,depth)
357 end
358 end
359}
360
361
362
363
364
365
366
367implement {
368 name = "setdocumentctxfile",
369 onlyonce = true,
370 actions = function()
371 local ctxfile = document.arguments.ctx or ""
372 if ctxfile ~= "" then
373 ctxrunner.load(ctxfile)
374 end
375 end
376}
377
378function ctxrunner.resolve(name)
379 local collapsedname = file.collapsepath(name,".")
380 return ctxrunner.prepfiles[collapsedname] or collapsedname
381end
382
383
384
385
386
387
388
389
390
391
392 |