diff options
author | hisham <hisham@9ca3f7c1-7366-0410-b1a3-b5c78f85698c> | 2009-04-16 22:20:49 +0000 |
---|---|---|
committer | hisham <hisham@9ca3f7c1-7366-0410-b1a3-b5c78f85698c> | 2009-04-16 22:20:49 +0000 |
commit | 6df8be18495cf4c09509bca3a38f44f6afe7ceec (patch) | |
tree | 441643b799bf66dd5660b5cdf0679f71fee8a448 /src | |
parent | 4f15619eabf3b47853406bbb5b52f5878121df44 (diff) | |
download | luarocks-6df8be18495cf4c09509bca3a38f44f6afe7ceec.tar.gz luarocks-6df8be18495cf4c09509bca3a38f44f6afe7ceec.tar.bz2 luarocks-6df8be18495cf4c09509bca3a38f44f6afe7ceec.zip |
Split 3rd-party-tool-dependant parts
git-svn-id: http://luarocks.org/svn/luarocks/trunk@9 9ca3f7c1-7366-0410-b1a3-b5c78f85698c
Diffstat (limited to 'src')
-rw-r--r-- | src/luarocks/fs/unix/tools.lua | 314 | ||||
-rw-r--r-- | src/luarocks/fs/win32/tools.lua | 230 |
2 files changed, 544 insertions, 0 deletions
diff --git a/src/luarocks/fs/unix/tools.lua b/src/luarocks/fs/unix/tools.lua new file mode 100644 index 00000000..fdec7869 --- /dev/null +++ b/src/luarocks/fs/unix/tools.lua | |||
@@ -0,0 +1,314 @@ | |||
1 | |||
2 | --- fs operations implemented with third-party tools for Unix platform abstractions. | ||
3 | module("luarocks.fs.unix.tools", package.seeall) | ||
4 | |||
5 | local fs = require("luarocks.fs") | ||
6 | |||
7 | local cfg = require("luarocks.cfg") | ||
8 | |||
9 | dir_stack = {} | ||
10 | |||
11 | --- Run the given command. | ||
12 | -- The command is executed in the current directory in the dir stack. | ||
13 | -- @param cmd string: No quoting/escaping is applied to the command. | ||
14 | -- @return boolean: true if command succeeds (status code 0), false | ||
15 | -- otherwise. | ||
16 | function execute_string(cmd) | ||
17 | if os.execute("cd " .. fs.Q(fs.current_dir()) .. " && " .. cmd) == 0 then | ||
18 | return true | ||
19 | else | ||
20 | return false | ||
21 | end | ||
22 | end | ||
23 | |||
24 | --- Obtain current directory. | ||
25 | -- Uses the module's internal dir stack. | ||
26 | -- @return string: the absolute pathname of the current directory. | ||
27 | function current_dir() | ||
28 | local current = os.getenv("PWD") | ||
29 | if not current then | ||
30 | local pipe = io.popen("pwd") | ||
31 | current = pipe:read("*l") | ||
32 | pipe:close() | ||
33 | end | ||
34 | for _, d in ipairs(fs.dir_stack) do | ||
35 | current = fs.absolute_name(d, current) | ||
36 | end | ||
37 | return current | ||
38 | end | ||
39 | |||
40 | --- Change the current directory. | ||
41 | -- Uses the module's internal dir stack. This does not have exact | ||
42 | -- semantics of chdir, as it does not handle errors the same way, | ||
43 | -- but works well for our purposes for now. | ||
44 | -- @param d string: The directory to switch to. | ||
45 | function change_dir(d) | ||
46 | assert(type(d) == "string") | ||
47 | table.insert(fs.dir_stack, d) | ||
48 | end | ||
49 | |||
50 | --- Change directory to root. | ||
51 | -- Allows leaving a directory (e.g. for deleting it) in | ||
52 | -- a crossplatform way. | ||
53 | function change_dir_to_root() | ||
54 | table.insert(fs.dir_stack, "/") | ||
55 | end | ||
56 | |||
57 | --- Change working directory to the previous in the dir stack. | ||
58 | function pop_dir() | ||
59 | local d = table.remove(fs.dir_stack) | ||
60 | return d ~= nil | ||
61 | end | ||
62 | |||
63 | --- Create a directory if it does not already exist. | ||
64 | -- If any of the higher levels in the path name does not exist | ||
65 | -- too, they are created as well. | ||
66 | -- @param d string: pathname of directory to create. | ||
67 | -- @return boolean: true on success, false on failure. | ||
68 | function make_dir(d) | ||
69 | assert(d) | ||
70 | return fs.execute("mkdir -p", d) | ||
71 | end | ||
72 | |||
73 | --- Remove a directory if it is empty. | ||
74 | -- Does not return errors (for example, if directory is not empty or | ||
75 | -- if already does not exist) | ||
76 | -- @param dir string: pathname of directory to remove. | ||
77 | function remove_dir_if_empty(d) | ||
78 | assert(d) | ||
79 | fs.execute_string("rmdir "..fs.Q(d).." 1> /dev/null 2> /dev/null") | ||
80 | end | ||
81 | |||
82 | --- Copy a file. | ||
83 | -- @param src string: Pathname of source | ||
84 | -- @param dest string: Pathname of destination | ||
85 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
86 | -- plus an error message. | ||
87 | function copy(src, dest) | ||
88 | assert(src and dest) | ||
89 | if fs.execute("cp", src, dest) then | ||
90 | return true | ||
91 | else | ||
92 | return false, "Failed copying "..src.." to "..dest | ||
93 | end | ||
94 | end | ||
95 | |||
96 | --- Recursively copy the contents of a directory. | ||
97 | -- @param src string: Pathname of source | ||
98 | -- @param dest string: Pathname of destination | ||
99 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
100 | -- plus an error message. | ||
101 | function copy_contents(src, dest) | ||
102 | assert(src and dest) | ||
103 | if fs.execute_string("cp -pPR "..fs.Q(src).."/* "..fs.Q(dest).." 1> /dev/null 2>/dev/null") then | ||
104 | return true | ||
105 | else | ||
106 | return false, "Failed copying "..src.." to "..dest | ||
107 | end | ||
108 | end | ||
109 | --- Delete a file or a directory and all its contents. | ||
110 | -- For safety, this only accepts absolute paths. | ||
111 | -- @param arg string: Pathname of source | ||
112 | -- @return boolean: true on success, false on failure. | ||
113 | function delete(arg) | ||
114 | assert(arg) | ||
115 | assert(arg:sub(1,1) == "/") | ||
116 | return fs.execute_string("rm -rf " .. fs.Q(arg) .. " 1> /dev/null 2>/dev/null") | ||
117 | end | ||
118 | |||
119 | --- List the contents of a directory. | ||
120 | -- @param at string or nil: directory to list (will be the current | ||
121 | -- directory if none is given). | ||
122 | -- @return table: an array of strings with the filenames representing | ||
123 | -- the contents of a directory. | ||
124 | function list_dir(at) | ||
125 | assert(type(at) == "string" or not at) | ||
126 | if not at then | ||
127 | at = fs.current_dir() | ||
128 | end | ||
129 | if not fs.is_dir(at) then | ||
130 | return {} | ||
131 | end | ||
132 | local result = {} | ||
133 | local pipe = io.popen("cd "..fs.Q(at).." && ls") | ||
134 | for file in pipe:lines() do | ||
135 | table.insert(result, file) | ||
136 | end | ||
137 | pipe:close() | ||
138 | return result | ||
139 | end | ||
140 | |||
141 | --- Recursively scan the contents of a directory. | ||
142 | -- @param at string or nil: directory to scan (will be the current | ||
143 | -- directory if none is given). | ||
144 | -- @return table: an array of strings with the filenames representing | ||
145 | -- the contents of a directory. | ||
146 | function find(at) | ||
147 | assert(type(at) == "string" or not at) | ||
148 | if not at then | ||
149 | at = fs.current_dir() | ||
150 | end | ||
151 | if not fs.is_dir(at) then | ||
152 | return {} | ||
153 | end | ||
154 | local result = {} | ||
155 | local pipe = io.popen("cd "..fs.Q(at).." && find * 2>/dev/null") | ||
156 | for file in pipe:lines() do | ||
157 | table.insert(result, file) | ||
158 | end | ||
159 | pipe:close() | ||
160 | return result | ||
161 | end | ||
162 | |||
163 | --- Compress files in a .zip archive. | ||
164 | -- @param zipfile string: pathname of .zip archive to be created. | ||
165 | -- @param ... Filenames to be stored in the archive are given as | ||
166 | -- additional arguments. | ||
167 | -- @return boolean: true on success, false on failure. | ||
168 | function zip(zipfile, ...) | ||
169 | return fs.execute("zip -r", zipfile, ...) | ||
170 | end | ||
171 | |||
172 | --- Uncompress files from a .zip archive. | ||
173 | -- @param zipfile string: pathname of .zip archive to be extracted. | ||
174 | -- @return boolean: true on success, false on failure. | ||
175 | function unzip(zipfile) | ||
176 | assert(zipfile) | ||
177 | return fs.execute("unzip", zipfile) | ||
178 | end | ||
179 | |||
180 | --- Test for existance of a file. | ||
181 | -- @param file string: filename to test | ||
182 | -- @return boolean: true if file exists, false otherwise. | ||
183 | function exists(file) | ||
184 | assert(file) | ||
185 | return fs.execute("test -r", file) | ||
186 | end | ||
187 | |||
188 | --- Test is file/dir is writable. | ||
189 | -- @param file string: filename to test | ||
190 | -- @return boolean: true if file exists, false otherwise. | ||
191 | function is_writable(file) | ||
192 | assert(file) | ||
193 | return fs.execute("test -w", file) | ||
194 | end | ||
195 | |||
196 | --- Test is pathname is a directory. | ||
197 | -- @param file string: pathname to test | ||
198 | -- @return boolean: true if it is a directory, false otherwise. | ||
199 | function is_dir(file) | ||
200 | assert(file) | ||
201 | return fs.execute("test -d", file) | ||
202 | end | ||
203 | |||
204 | --- Test is pathname is a regular file. | ||
205 | -- @param file string: pathname to test | ||
206 | -- @return boolean: true if it is a regular file, false otherwise. | ||
207 | function is_file(file) | ||
208 | assert(file) | ||
209 | return fs.execute("test -f", file) | ||
210 | end | ||
211 | |||
212 | --- Download a remote file. | ||
213 | -- @param url string: URL to be fetched. | ||
214 | -- @param filename string or nil: this function attempts to detect the | ||
215 | -- resulting local filename of the remote file as the basename of the URL; | ||
216 | -- if that is not correct (due to a redirection, for example), the local | ||
217 | -- filename can be given explicitly as this second argument. | ||
218 | -- @return boolean: true on success, false on failure. | ||
219 | function download(url, filename) | ||
220 | assert(type(url) == "string") | ||
221 | assert(type(filename) == "string" or not filename) | ||
222 | |||
223 | if cfg.downloader == "wget" then | ||
224 | local wget_cmd = "wget --user-agent="..cfg.user_agent.." --quiet --continue " | ||
225 | if filename then | ||
226 | return fs.execute(wget_cmd.." --output-document ", filename, url) | ||
227 | else | ||
228 | return fs.execute(wget_cmd, url) | ||
229 | end | ||
230 | elseif cfg.downloader == "curl" then | ||
231 | filename = filename or dir.base_name(url) | ||
232 | return fs.execute_string("curl --user-agent "..cfg.user_agent.." "..fs.Q(url).." 2> /dev/null 1> "..fs.Q(filename)) | ||
233 | end | ||
234 | end | ||
235 | |||
236 | function chmod(pathname, mode) | ||
237 | return fs.execute("chmod "..mode, pathname) | ||
238 | end | ||
239 | |||
240 | --- Apply a patch. | ||
241 | -- @param patchname string: The filename of the patch. | ||
242 | function apply_patch(patchname) | ||
243 | return fs.execute("patch -p1 -f -i ", patchname) | ||
244 | end | ||
245 | |||
246 | --- Unpack an archive. | ||
247 | -- Extract the contents of an archive, detecting its format by | ||
248 | -- filename extension. | ||
249 | -- @param archive string: Filename of archive. | ||
250 | -- @return boolean or (boolean, string): true on success, false and an error message on failure. | ||
251 | function unpack_archive(archive) | ||
252 | assert(type(archive) == "string") | ||
253 | |||
254 | local ok | ||
255 | if archive:match("%.tar%.gz$") or archive:match("%.tgz$") then | ||
256 | -- ok = fs.execute("tar zxvpf ", archive) | ||
257 | ok = fs.execute_string("gunzip -c "..archive.."|tar -xf -") | ||
258 | elseif archive:match("%.tar%.bz2$") then | ||
259 | -- ok = fs.execute("tar jxvpf ", archive) | ||
260 | ok = fs.execute_string("bunzip2 -c "..archive.."|tar -xf -") | ||
261 | elseif archive:match("%.zip$") then | ||
262 | ok = fs.execute("unzip ", archive) | ||
263 | elseif archive:match("%.lua$") or archive:match("%.c$") then | ||
264 | -- Ignore .lua and .c files; they don't need to be extracted. | ||
265 | return true | ||
266 | else | ||
267 | local ext = archive:match(".*(%..*)") | ||
268 | return false, "Unrecognized filename extension "..(ext or "") | ||
269 | end | ||
270 | if not ok then | ||
271 | return false, "Failed extracting "..archive | ||
272 | end | ||
273 | return true | ||
274 | end | ||
275 | |||
276 | --- Check the MD5 checksum for a file. | ||
277 | -- @param file string: The file to be checked. | ||
278 | -- @param md5sum string: The string with the expected MD5 checksum. | ||
279 | -- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false if not | ||
280 | -- or if it could not perform the check for any reason. | ||
281 | function check_md5(file, md5sum) | ||
282 | file = fs.absolute_name(file) | ||
283 | local computed | ||
284 | if cfg.md5checker == "md5sum" then | ||
285 | local pipe = io.popen("md5sum "..file) | ||
286 | computed = pipe:read("*l"):gsub("[^%x]+", "") | ||
287 | pipe:close() | ||
288 | if computed then | ||
289 | computed = computed:sub(1,32) | ||
290 | end | ||
291 | elseif cfg.md5checker == "openssl" then | ||
292 | local pipe = io.popen("openssl md5 "..file) | ||
293 | computed = pipe:read("*l") | ||
294 | pipe:close() | ||
295 | if computed then | ||
296 | computed = computed:sub(-32) | ||
297 | end | ||
298 | elseif cfg.md5checker == "md5" then | ||
299 | local pipe = io.popen("md5 "..file) | ||
300 | computed = pipe:read("*l") | ||
301 | pipe:close() | ||
302 | if computed then | ||
303 | computed = computed:sub(-32) | ||
304 | end | ||
305 | end | ||
306 | if not computed then | ||
307 | return false | ||
308 | end | ||
309 | if computed:match("^"..md5sum) then | ||
310 | return true | ||
311 | else | ||
312 | return false | ||
313 | end | ||
314 | end | ||
diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua new file mode 100644 index 00000000..9f7b829b --- /dev/null +++ b/src/luarocks/fs/win32/tools.lua | |||
@@ -0,0 +1,230 @@ | |||
1 | |||
2 | --- fs operations implemented with third-party tools for Windows platform abstractions. | ||
3 | -- Download http://unxutils.sourceforge.net/ for Windows GNU utilities | ||
4 | -- used by this module. | ||
5 | module("luarocks.fs.win32.tools", package.seeall) | ||
6 | |||
7 | local fs = require("luarocks.fs") | ||
8 | |||
9 | local function command_at(directory, cmd) | ||
10 | local drive = directory:match("^([A-Za-z]:)") | ||
11 | cmd = "cd " .. fs.Q(directory) .. " & " .. cmd | ||
12 | if drive then | ||
13 | cmd = drive .. " & " .. cmd | ||
14 | end | ||
15 | return cmd | ||
16 | end | ||
17 | |||
18 | --- Test for existance of a file. | ||
19 | -- @param file string: filename to test | ||
20 | -- @return boolean: true if file exists, false otherwise. | ||
21 | function exists(file) | ||
22 | assert(file) | ||
23 | return fs.execute("if not exist " .. fs.Q(file) .. | ||
24 | " invalidcommandname 2>NUL 1>NUL") | ||
25 | end | ||
26 | |||
27 | --- Test is pathname is a directory. | ||
28 | -- @param file string: pathname to test | ||
29 | -- @return boolean: true if it is a directory, false otherwise. | ||
30 | function is_dir(file) | ||
31 | assert(file) | ||
32 | return fs.execute("chdir /D " .. fs.Q(file) .. " 2>NUL 1>NUL") | ||
33 | end | ||
34 | |||
35 | --- Run the given command. | ||
36 | -- The command is executed in the current directory in the dir stack. | ||
37 | -- @param cmd string: No quoting/escaping is applied to the command. | ||
38 | -- @return boolean: true if command succeeds (status code 0), false | ||
39 | -- otherwise. | ||
40 | function execute_string(cmd) | ||
41 | if os.execute(command_at(fs.current_dir(), cmd)) == 0 then | ||
42 | return true | ||
43 | else | ||
44 | return false | ||
45 | end | ||
46 | end | ||
47 | |||
48 | --- Test is pathname is a regular file. | ||
49 | -- @param file string: pathname to test | ||
50 | -- @return boolean: true if it is a regular file, false otherwise. | ||
51 | function is_dir(file) | ||
52 | assert(file) | ||
53 | return fs.execute("test -d" .. fs.Q(file) .. " 2>NUL 1>NUL") | ||
54 | end | ||
55 | |||
56 | --- Create a directory if it does not already exist. | ||
57 | -- If any of the higher levels in the path name does not exist | ||
58 | -- too, they are created as well. | ||
59 | -- @param d string: pathname of directory to create. | ||
60 | -- @return boolean: true on success, false on failure. | ||
61 | function make_dir(d) | ||
62 | assert(d) | ||
63 | fs.execute("mkdir "..fs.Q(d).." 1> NUL 2> NUL") | ||
64 | return 1 | ||
65 | end | ||
66 | |||
67 | --- Remove a directory if it is empty. | ||
68 | -- Does not return errors (for example, if directory is not empty or | ||
69 | -- if already does not exist) | ||
70 | -- @param d string: pathname of directory to remove. | ||
71 | function remove_dir_if_empty(d) | ||
72 | assert(d) | ||
73 | fs.execute_string("rmdir "..fs.Q(d).." 1> NUL 2> NUL") | ||
74 | end | ||
75 | |||
76 | --- Copy a file. | ||
77 | -- @param src string: Pathname of source | ||
78 | -- @param dest string: Pathname of destination | ||
79 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
80 | -- plus an error message. | ||
81 | function copy(src, dest) | ||
82 | assert(src and dest) | ||
83 | if dest:match("[/\\]$") then dest = dest:sub(1, -2) end | ||
84 | if fs.execute("cp", src, dest) then | ||
85 | return true | ||
86 | else | ||
87 | return false, "Failed copying "..src.." to "..dest | ||
88 | end | ||
89 | end | ||
90 | |||
91 | --- Recursively copy the contents of a directory. | ||
92 | -- @param src string: Pathname of source | ||
93 | -- @param dest string: Pathname of destination | ||
94 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
95 | -- plus an error message. | ||
96 | function copy_contents(src, dest) | ||
97 | assert(src and dest) | ||
98 | if fs.execute_string("cp -a "..src.."\\*.* "..fs.Q(dest).." 1> NUL 2> NUL") then | ||
99 | return true | ||
100 | else | ||
101 | return false, "Failed copying "..src.." to "..dest | ||
102 | end | ||
103 | end | ||
104 | |||
105 | --- Delete a file or a directory and all its contents. | ||
106 | -- For safety, this only accepts absolute paths. | ||
107 | -- @param arg string: Pathname of source | ||
108 | -- @return boolean: true on success, false on failure. | ||
109 | function delete(arg) | ||
110 | assert(arg) | ||
111 | assert(arg:match("^[\a-zA-Z]?:?[\\/]")) | ||
112 | fs.execute("chmod a+rw -R ", arg) | ||
113 | return fs.execute_string("rm -rf " .. fs.Q(arg) .. " 1> NUL 2> NUL") | ||
114 | end | ||
115 | |||
116 | --- List the contents of a directory. | ||
117 | -- @param at string or nil: directory to list (will be the current | ||
118 | -- directory if none is given). | ||
119 | -- @return table: an array of strings with the filenames representing | ||
120 | -- the contents of a directory. | ||
121 | function list_dir(at) | ||
122 | assert(type(at) == "string" or not at) | ||
123 | if not at then | ||
124 | at = fs.current_dir() | ||
125 | end | ||
126 | if not fs.is_dir(at) then | ||
127 | return {} | ||
128 | end | ||
129 | local result = {} | ||
130 | local pipe = io.popen(command_at(at, "ls")) | ||
131 | for file in pipe:lines() do | ||
132 | table.insert(result, file) | ||
133 | end | ||
134 | pipe:close() | ||
135 | |||
136 | return result | ||
137 | end | ||
138 | |||
139 | --- Recursively scan the contents of a directory. | ||
140 | -- @param at string or nil: directory to scan (will be the current | ||
141 | -- directory if none is given). | ||
142 | -- @return table: an array of strings with the filenames representing | ||
143 | -- the contents of a directory. Paths are returned with forward slashes. | ||
144 | function find(at) | ||
145 | assert(type(at) == "string" or not at) | ||
146 | if not at then | ||
147 | at = fs.current_dir() | ||
148 | end | ||
149 | if not fs.is_dir(at) then | ||
150 | return {} | ||
151 | end | ||
152 | local result = {} | ||
153 | local pipe = io.popen(command_at(at, "find 2> NUL")) | ||
154 | for file in pipe:lines() do | ||
155 | -- Windows find is a bit different | ||
156 | if file:sub(1,2)==".\\" then file=file:sub(3) end | ||
157 | if file ~= "." then | ||
158 | table.insert(result, (file:gsub("\\", "/"))) | ||
159 | end | ||
160 | end | ||
161 | return result | ||
162 | end | ||
163 | |||
164 | --- Download a remote file. | ||
165 | -- @param url string: URL to be fetched. | ||
166 | -- @param filename string or nil: this function attempts to detect the | ||
167 | -- resulting local filename of the remote file as the basename of the URL; | ||
168 | -- if that is not correct (due to a redirection, for example), the local | ||
169 | -- filename can be given explicitly as this second argument. | ||
170 | -- @return boolean: true on success, false on failure. | ||
171 | function download(url, filename) | ||
172 | assert(type(url) == "string") | ||
173 | assert(type(filename) == "string" or not filename) | ||
174 | local wget_cmd = "wget --user-agent="..cfg.user_agent.." --quiet --continue " | ||
175 | |||
176 | if filename then | ||
177 | return fs.execute(wget_cmd.." --output-document ", filename, url) | ||
178 | else | ||
179 | return fs.execute(wget_cmd, url) | ||
180 | end | ||
181 | end | ||
182 | |||
183 | --- Uncompress gzip file. | ||
184 | -- @param archive string: Filename of archive. | ||
185 | -- @return boolean : success status | ||
186 | local function gunzip(archive) | ||
187 | local cmd = fs.execute("gunzip -h 1>NUL 2>NUL") and 'gunzip' or | ||
188 | fs.execute("gzip -h 1>NUL 2>NUL") and 'gzip -d' | ||
189 | local ok = fs.execute(cmd, archive) | ||
190 | return ok | ||
191 | end | ||
192 | |||
193 | --- Unpack an archive. | ||
194 | -- Extract the contents of an archive, detecting its format by | ||
195 | -- filename extension. | ||
196 | -- @param archive string: Filename of archive. | ||
197 | -- @return boolean or (boolean, string): true on success, false and an error message on failure. | ||
198 | function unpack_archive(archive) | ||
199 | assert(type(archive) == "string") | ||
200 | |||
201 | local ok | ||
202 | if archive:match("%.tar%.gz$") then | ||
203 | ok = gunzip(archive) | ||
204 | if ok then | ||
205 | ok = fs.execute("tar -xf ", strip_extension(archive)) | ||
206 | end | ||
207 | elseif archive:match("%.tgz$") then | ||
208 | ok = gunzip(archive) | ||
209 | if ok then | ||
210 | ok = fs.execute("tar -xf ", strip_extension(archive)..".tar") | ||
211 | end | ||
212 | elseif archive:match("%.tar%.bz2$") then | ||
213 | ok = fs.execute("bunzip2 ", archive) | ||
214 | if ok then | ||
215 | ok = fs.execute("tar -xf ", strip_extension(archive)) | ||
216 | end | ||
217 | elseif archive:match("%.zip$") then | ||
218 | ok = fs.execute("unzip ", archive) | ||
219 | elseif archive:match("%.lua$") or archive:match("%.c$") then | ||
220 | -- Ignore .lua and .c files; they don't need to be extracted. | ||
221 | return true | ||
222 | else | ||
223 | local ext = archive:match(".*(%..*)") | ||
224 | return false, "Unrecognized filename extension "..(ext or "") | ||
225 | end | ||
226 | if not ok then | ||
227 | return false, "Failed extracting "..archive | ||
228 | end | ||
229 | return true | ||
230 | end | ||