1if not modules then modules = { } end modules ['mtx-ctan'] = {
2 version = 1.00,
3 comment = "companion to mtxrun.lua",
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
10
11
12
13
14
15
16
17
18
19
20
21
22local lower, find, gsub = string.lower, string.find, string.gsub
23local write_nl = (logs and logs.writer) or (texio and texio.write_nl) or print
24local xmlconvert, xmltext, xmlattr, xmlcollected = xml.convert, xml.text, xml.attribute, xml.collected
25
26local helpinfo = [[
27<?xml version="1.0"?>
28<application>
29 <metadata>
30 <entry name="name">mtx-ctan</entry>
31 <entry name="detail">Dealing with CTAN</entry>
32 <entry name="version">1.00</entry>
33 </metadata>
34 <flags>
35 <category name="basic">
36 <subcategory>
37 <flag name="packages"><short>list available packages [--field=key|name|caption]</short></flag>
38 <flag name="topics"><short>list available topics [--field=key|name|details]</short></flag>
39 <flag name="details"><short>show details about package</short></flag>
40 <flag name="pattern" value="string"><short>use this pattern, otherwise first argument</short></flag>
41 </subcategory>
42 </category>
43 </flags>
44</application>
45]]
46
47local application = logs.application {
48 name = "mtx-ctan",
49 banner = "Dealing with CTAN",
50 helpinfo = helpinfo,
51}
52
53local report = application.report
54
55scripts = scripts or { }
56scripts.ctan = scripts.ctan or { }
57
58local okay, json = pcall(require,"util-jsn")
59local okay, curl = pcall(require,"libs-imp-curl")
60 pcall(require,"char-ini")
61
62local jsontolua = json and json.tolua
63local shaped = characters and characters.shaped or lower
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81local ctanurl = "https://www.ctan.org/" .. (json and "json" or "xml") .. "/2.0/"
82
83local fetched = curl and
84
85 function(str)
86 local data, message = curl.fetch {
87 url = ctanurl .. str,
88 sslverifyhost = false,
89 sslverifypeer = false,
90 }
91 if not data then
92 report("some error: %s",message)
93 end
94 return data
95 end
96
97or
98
99 function(str)
100
101
102 local data = os.resultof("curl -sS " .. ctanurl .. str)
103
104 return data
105 end
106
107
108
109
110
111
112
113local function strfound(pattern,str)
114 if not pattern then
115 return true
116 else
117 local str = lower(shaped(str))
118 if find(str,pattern) then
119 return true
120 else
121 str = gsub(str,"[^a-zA-Z0-9]","")
122 if find(str,pattern) then
123 return true
124 else
125 return false
126 end
127 end
128 end
129end
130
131local function showresult(found)
132 if #found > 2 then
133 utilities.formatters.formatcolumns(found)
134 report("")
135 for k=1,#found do
136 report(found[k])
137 end
138 report("")
139 end
140end
141
142local function checkedpattern(pattern)
143 if pattern then
144 pattern = string.topattern(pattern,true)
145 return lower(shaped(pattern))
146 end
147end
148
149local validdata = json and
150
151 function(data)
152 if data then
153 data = jsontolua(data)
154 if type(data) == "table" then
155 return data
156 else
157 report("unable to handle this json data")
158 end
159 else
160 report("unable to fetch packages")
161 end
162 end
163
164or
165
166 function(data)
167 if data then
168 data = xmlconvert(data)
169 if data.error then
170 report("unable to handle this json data")
171 else
172 return data
173 end
174 else
175 report("unable to fetch packages")
176 end
177 end
178
179scripts.ctan.details = json and
180
181 function(name)
182 if name then
183 local data = validdata(fetched("pkg/" .. name))
184 if data then
185 report("")
186
187 report("name : %s",data.name or "-")
188 report("caption : %s",data.caption or "-")
189 report("path : %s",data.ctan and data.ctan.path or "-")
190 report("")
191 end
192 end
193 end
194
195or
196
197 function (name)
198 if name then
199 local data = validdata(fetched("pkg/" .. name))
200 report("")
201
202 report("name : %s",xmltext(data,"/entry/name"))
203 report("caption : %s",xmltext(data,"/entry/caption"))
204 report("path : %s",xmlattr(data,"/entry/ctan","path"))
205 report("")
206 end
207 end
208
209scripts.ctan.packages = json and
210
211 function(pattern,field)
212 local data = validdata(fetched("packages"))
213 if data then
214 local found = {
215 { "key", "name", "caption" },
216 { "", "", "" },
217 }
218 pattern = checkedpattern(pattern)
219 for i=1,#data do
220 local entry = data[i]
221 local key = entry.key
222 local name = entry.name
223 local caption = entry.caption
224 local where
225 if field == "name" then
226 where = name
227 elseif field == "caption" then
228 where = caption
229 elseif field == "key" then
230 where = key
231 end
232 if where then
233 if strfound(pattern,where) then
234 found[#found+1] = { key, name, caption }
235 end
236 else
237 if strfound(pattern,name) or strfound(pattern,caption) then
238 found[#found+1] = { key, name, caption }
239 end
240 end
241 end
242 showresult(found)
243 end
244 end
245
246or
247
248 function(pattern)
249 local data = validdata(fetched("packages"))
250 if data then
251 local found = {
252 { "key", "name", "caption" },
253 { "", "", "" },
254 }
255 pattern = checkedpattern(pattern)
256 for c in xmlcollected(data,"/packages/package") do
257 local at = c.at
258 if strfound(pattern,at.caption) then
259 found[#found+1] = { at.key, at.name, at.caption }
260 end
261 end
262 showresult(found)
263 end
264 end
265
266scripts.ctan.topics = json and
267
268 function (pattern)
269 local data = validdata(fetched("topics"))
270 if data then
271 local found = {
272 { "key", "details" },
273 { "", "" },
274 }
275 pattern = checkedpattern(pattern)
276 for i=1,#data do
277
278 local entry = data[i]
279 local key = entry.key
280 local name = entry.name
281 local details = entry.details
282 local where
283 if field == "name" then
284 where = name or key
285 elseif field == "details" then
286 where = details
287 elseif field == "key" then
288 where = key or name
289 end
290 if where then
291 if strfound(pattern,where) then
292 found[#found+1] = { key or name, details }
293 end
294 else
295 if strfound(pattern,key or name) or strfound(pattern,details) then
296 found[#found+1] = { key or name, details }
297 end
298 end
299 end
300 showresult(found)
301 end
302 end
303
304or
305
306 function(pattern)
307 local data = validdata(fetched("topics"))
308 if data then
309 local found = {
310 { "name", "details" },
311 { "", "" },
312 }
313 pattern = checkedpattern(pattern)
314 for c in xmlcollected(data,"/topics/topic") do
315 local at = c.at
316 if strfound(pattern,at.caption) then
317 found[#found+1] = { at.key or at.name, at.details }
318 end
319 end
320 showresult(found)
321 end
322 end
323
324local function whatever()
325 report("")
326 report("using %s interface", json and "json" or "xml")
327 report("using curl %s", curl and "library" or "binary")
328 report("")
329end
330
331
332
333
334
335
336
337
338
339
340
341
342if environment.argument("packages") then
343 whatever()
344 scripts.ctan.packages(environment.argument("pattern") or environment.files[1], environment.argument("field"))
345elseif environment.argument("topics") then
346 whatever()
347 scripts.ctan.topics(environment.argument("pattern") or environment.files[1])
348elseif environment.argument("details") then
349 whatever()
350 scripts.ctan.details(environment.files[1])
351elseif environment.argument("exporthelp") then
352 application.export(environment.argument("exporthelp"),environment.files[1])
353else
354 application.help()
355end
356 |