data-tar.lua /size: 7128 b    last modification: 2023-12-21 09:44
1if not modules then modules = { } end modules ['data-tar'] = {
2    version   = 1.001,
3    comment   = "companion to luat-lib.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
9local format, find, match = string.format, string.find, string.match
10
11local trace_locating = false  trackers.register("resolvers.locating", function(v) trace_locating = v end)
12
13local report_tar = logs.reporter("resolvers","tar")
14
15-- We use a url syntax for accessing the tar file itself and file in it:
16--
17--   tar:///oeps.tar?name=bla/bla.tex
18--   tar:///oeps.tar?tree=tex/texmf-local
19
20local resolvers    = resolvers
21local findfile     = resolvers.findfile
22local registerfile = resolvers.registerfile
23local splitmethod  = resolvers.splitmethod
24local starttiming  = resolvers.starttiming
25local stoptiming   = resolvers.stoptiming
26
27local urlquery     = url.query
28
29--- hm, zip sits in the global namespace, but tar doesn't
30
31local tar          = utilities.tar or { }
32utilities.tar      = tar -- not needed
33
34local archives     = tar.archives or { }
35tar.archives       = archives
36
37local registeredfiles = tar.registeredfiles or { }
38tar.registeredfiles   = registeredfiles
39
40-- foo.tar.xz : done
41-- foo.tar.gz : todo
42-- foo.tar    : done
43
44local hashtar, fetchtar, wipetar  do
45
46    local suffix = file.suffix -- hassuffix .. no need to split
47
48    local tarfiles       = utilities.tar.file
49    local tarstrings     = utilities.tar.string
50
51    local hashtarfile    = tar.files.hash
52    local fetchtarfile   = tar.files.fetch
53
54    local hashtarstring  = tar.strings.hash
55    local fetchtarstring = tar.strings.fetch
56
57    local register       = resolvers.decompressors.register
58
59    hashtar = function(archive,strip)
60        local a = register(archive)
61        if a then
62            return hashtarstring(a,archive)
63        else
64            return hashtarfile(archive,archive)
65        end
66    end
67
68    fetchtar = function(archive,filename,list)
69        local a = register(archive)
70        if a then
71            return fetchtarstring(a,filename,list)
72        else
73            return fetchtarfile(archive,filename,list)
74        end
75    end
76
77    wipetar = resolvers.decompressors.unregister
78
79end
80
81local function validfile(archive,name)
82    return archive[name]
83end
84
85local function openarchive(name)
86    if not name or name == "" then
87        return nil
88    else
89        local arch = archives[name]
90        if not arch then
91           local full = findfile(name) or ""
92           arch = full ~= "" and hashtar(full,name) or false
93           archives[name] = arch
94        end
95        return arch
96    end
97end
98
99local function closearchive(name)
100    if not name or (name == "" and archives[name]) then
101        archives[name] = nil
102        wipetar(name)
103    end
104end
105
106tar.openarchive  = openarchive
107tar.closearchive = closearchive
108
109function resolvers.locators.tar(specification)
110    local archive = specification.filename
111    local tarfile = archive and archive ~= "" and openarchive(archive)
112    if trace_locating then
113        if tarfile then
114            report_tar("locator: archive %a found",archive)
115        else
116            report_tar("locator: archive %a not found",archive)
117        end
118    end
119end
120
121function resolvers.concatinators.tar(tarfile,path,name) -- ok ?
122    if not path or path == "" then
123        return format('%s?name=%s',tarfile,name)
124    else
125        return format('%s?name=%s/%s',tarfile,path,name)
126    end
127end
128
129local finders  = resolvers.finders
130local notfound = finders.notfound
131
132function finders.tar(specification)
133    local original = specification.original
134    local archive  = specification.filename
135    if archive then
136        local query     = urlquery(specification.query)
137        local queryname = query.name
138        if queryname then
139            local tfile = openarchive(archive)
140            if tfile then
141                if trace_locating then
142                    report_tar("finder: archive %a found",archive)
143                end
144                if validfile(tfile,queryname) then
145                    if trace_locating then
146                        report_tar("finder: file %a found",queryname)
147                    end
148                    return specification.original
149                elseif trace_locating then
150                    report_tar("finder: file %a not found",queryname)
151                end
152            elseif trace_locating then
153                report_tar("finder: unknown archive %a",archive)
154            end
155        end
156    end
157    if trace_locating then
158        report_tar("finder: %a not found",original)
159    end
160    return notfound()
161end
162
163local openers    = resolvers.openers
164local notfound   = openers.notfound
165local textopener = openers.helpers.textopener
166
167function openers.tar(specification)
168    local original = specification.original
169    local archive  = specification.filename
170    if archive then
171        local query     = urlquery(specification.query)
172        local queryname = query.name
173        if queryname then
174            local tfile = openarchive(archive)
175            if tfile then
176                if trace_locating then
177                    report_tar("opener; archive %a opened",archive)
178                end
179                local data = fetchtar(archive,queryname,tfile)
180                if data then
181                    if trace_locating then
182                        report_tar("opener: file %a found",queryname)
183                    end
184                    return textopener('tar',original,data) -- a string handle
185                elseif trace_locating then
186                    report_tar("opener: file %a not found",queryname)
187                end
188            elseif trace_locating then
189                report_tar("opener: unknown archive %a",archive)
190            end
191        end
192    end
193    if trace_locating then
194        report_tar("opener: %a not found",original)
195    end
196    return notfound()
197end
198
199loaders  = resolvers.loaders
200local notfound = loaders.notfound
201
202function loaders.tar(specification)
203    local original = specification.original
204    local archive  = specification.filename
205    if archive then
206        local query     = urlquery(specification.query)
207        local queryname = query.name
208        if queryname then
209            local tfile = openarchive(archive)
210            if tfile then
211                if trace_locating then
212                    report_tar("loader: archive %a opened",archive)
213                end
214                local data = fetchtar(archive,queryname,tfile)
215                if data then
216                    if trace_locating then
217                        report_tar("loader; file %a loaded",original)
218                    end
219                    return true, data, #data
220                elseif trace_locating then
221                    report_tar("loader: file %a not found",queryname)
222                end
223            elseif trace_locating then
224                report_tar("loader; unknown archive %a",archive)
225            end
226        end
227    end
228    if trace_locating then
229        report_tar("loader: %a not found",original)
230    end
231    return notfound()
232end
233