Mercurial > hg > Members > nobuyasu > Lua
comparison tools.lua @ 0:73146cb10aa5
add some files
author | Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 01 Feb 2013 03:07:15 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:73146cb10aa5 |
---|---|
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 local dir = require("luarocks.dir") | |
7 local cfg = require("luarocks.cfg") | |
8 | |
9 local dir_stack = {} | |
10 | |
11 local vars = cfg.variables | |
12 | |
13 local function command_at(directory, cmd) | |
14 return "cd " .. fs.Q(directory) .. " && " .. cmd | |
15 end | |
16 | |
17 --- Obtain current directory. | |
18 -- Uses the module's internal directory stack. | |
19 -- @return string: the absolute pathname of the current directory. | |
20 function current_dir() | |
21 local pipe = io.popen(vars.PWD) | |
22 local current = pipe:read("*l") | |
23 pipe:close() | |
24 for _, directory in ipairs(dir_stack) do | |
25 current = fs.absolute_name(directory, current) | |
26 end | |
27 return current | |
28 end | |
29 | |
30 --- Run the given command. | |
31 -- The command is executed in the current directory in the directory stack. | |
32 -- @param cmd string: No quoting/escaping is applied to the command. | |
33 -- @return boolean: true if command succeeds (status code 0), false | |
34 -- otherwise. | |
35 function execute_string(cmd) | |
36 local code = os.execute(command_at(fs.current_dir(), cmd)) | |
37 if code == 0 or code == true then | |
38 return true | |
39 else | |
40 return false | |
41 end | |
42 end | |
43 | |
44 --- Change the current directory. | |
45 -- Uses the module's internal directory stack. This does not have exact | |
46 -- semantics of chdir, as it does not handle errors the same way, | |
47 -- but works well for our purposes for now. | |
48 -- @param directory string: The directory to switch to. | |
49 function change_dir(directory) | |
50 assert(type(directory) == "string") | |
51 table.insert(dir_stack, directory) | |
52 end | |
53 | |
54 --- Change directory to root. | |
55 -- Allows leaving a directory (e.g. for deleting it) in | |
56 -- a crossplatform way. | |
57 function change_dir_to_root() | |
58 table.insert(dir_stack, "/") | |
59 end | |
60 | |
61 --- Change working directory to the previous in the directory stack. | |
62 function pop_dir() | |
63 local directory = table.remove(dir_stack) | |
64 return directory ~= nil | |
65 end | |
66 | |
67 --- Create a directory if it does not already exist. | |
68 -- If any of the higher levels in the path name does not exist | |
69 -- too, they are created as well. | |
70 -- @param directory string: pathname of directory to create. | |
71 -- @return boolean: true on success, false on failure. | |
72 function make_dir(directory) | |
73 assert(directory) | |
74 return fs.execute(vars.MKDIR.." -p", directory) | |
75 end | |
76 | |
77 --- Remove a directory if it is empty. | |
78 -- Does not return errors (for example, if directory is not empty or | |
79 -- if already does not exist) | |
80 -- @param directory string: pathname of directory to remove. | |
81 function remove_dir_if_empty(directory) | |
82 assert(directory) | |
83 fs.execute_string(fs.quiet(vars.RMDIR.." "..fs.Q(directory))) | |
84 end | |
85 | |
86 --- Remove a directory if it is empty. | |
87 -- Does not return errors (for example, if directory is not empty or | |
88 -- if already does not exist) | |
89 -- @param directory string: pathname of directory to remove. | |
90 function remove_dir_tree_if_empty(directory) | |
91 assert(directory) | |
92 fs.execute_string(fs.quiet(vars.RMDIR.." -p "..fs.Q(directory))) | |
93 end | |
94 | |
95 --- Copy a file. | |
96 -- @param src string: Pathname of source | |
97 -- @param dest string: Pathname of destination | |
98 -- @param perm string or nil: Permissions for destination file, | |
99 -- @return boolean or (boolean, string): true on success, false on failure, | |
100 -- plus an error message. | |
101 function copy(src, dest, perm) | |
102 assert(src and dest) | |
103 if fs.execute(vars.CP, src, dest) then | |
104 if perm then | |
105 if fs.is_dir(dest) then | |
106 dest = dir.path(dest, dir.base_name(src)) | |
107 end | |
108 if fs.chmod(dest, perm) then | |
109 return true | |
110 else | |
111 return false, "Failed setting permissions of "..dest | |
112 end | |
113 end | |
114 return true | |
115 else | |
116 return false, "Failed copying "..src.." to "..dest | |
117 end | |
118 end | |
119 | |
120 --- Recursively copy the contents of a directory. | |
121 -- @param src string: Pathname of source | |
122 -- @param dest string: Pathname of destination | |
123 -- @return boolean or (boolean, string): true on success, false on failure, | |
124 -- plus an error message. | |
125 function copy_contents(src, dest) | |
126 assert(src and dest) | |
127 if fs.execute_string(fs.quiet(vars.CP.." -pPR "..fs.Q(src).."/* "..fs.Q(dest))) then | |
128 return true | |
129 else | |
130 return false, "Failed copying "..src.." to "..dest | |
131 end | |
132 end | |
133 --- Delete a file or a directory and all its contents. | |
134 -- For safety, this only accepts absolute paths. | |
135 -- @param arg string: Pathname of source | |
136 -- @return boolean: true on success, false on failure. | |
137 function delete(arg) | |
138 assert(arg) | |
139 assert(arg:sub(1,1) == "/") | |
140 return fs.execute_string(fs.quiet(vars.RM.." -rf " .. fs.Q(arg))) | |
141 end | |
142 | |
143 --- List the contents of a directory. | |
144 -- @param at string or nil: directory to list (will be the current | |
145 -- directory if none is given). | |
146 -- @return table: an array of strings with the filenames representing | |
147 -- the contents of a directory. | |
148 function list_dir(at) | |
149 assert(type(at) == "string" or not at) | |
150 if not at then | |
151 at = fs.current_dir() | |
152 end | |
153 if not fs.is_dir(at) then | |
154 return {} | |
155 end | |
156 local result = {} | |
157 local pipe = io.popen(command_at(at, vars.LS)) | |
158 for file in pipe:lines() do | |
159 table.insert(result, file) | |
160 end | |
161 pipe:close() | |
162 return result | |
163 end | |
164 | |
165 --- Recursively scan the contents of a directory. | |
166 -- @param at string or nil: directory to scan (will be the current | |
167 -- directory if none is given). | |
168 -- @return table: an array of strings with the filenames representing | |
169 -- the contents of a directory. | |
170 function find(at) | |
171 assert(type(at) == "string" or not at) | |
172 if not at then | |
173 at = fs.current_dir() | |
174 end | |
175 if not fs.is_dir(at) then | |
176 return {} | |
177 end | |
178 local result = {} | |
179 local pipe = io.popen(command_at(at, vars.FIND.." * 2>/dev/null")) | |
180 for file in pipe:lines() do | |
181 table.insert(result, file) | |
182 end | |
183 pipe:close() | |
184 return result | |
185 end | |
186 | |
187 --- Compress files in a .zip archive. | |
188 -- @param zipfile string: pathname of .zip archive to be created. | |
189 -- @param ... Filenames to be stored in the archive are given as | |
190 -- additional arguments. | |
191 -- @return boolean: true on success, false on failure. | |
192 function zip(zipfile, ...) | |
193 return fs.execute(vars.ZIP.." -r", zipfile, ...) | |
194 end | |
195 | |
196 --- Uncompress files from a .zip archive. | |
197 -- @param zipfile string: pathname of .zip archive to be extracted. | |
198 -- @return boolean: true on success, false on failure. | |
199 function unzip(zipfile) | |
200 assert(zipfile) | |
201 return fs.execute(vars.UNZIP, zipfile) | |
202 end | |
203 | |
204 --- Test is file/directory exists | |
205 -- @param file string: filename to test | |
206 -- @return boolean: true if file exists, false otherwise. | |
207 function exists(file) | |
208 assert(file) | |
209 return fs.execute(vars.TEST, "-e", file) | |
210 end | |
211 | |
212 --- Test is pathname is a directory. | |
213 -- @param file string: pathname to test | |
214 -- @return boolean: true if it is a directory, false otherwise. | |
215 function is_dir(file) | |
216 assert(file) | |
217 return fs.execute(vars.TEST, "-d", file) | |
218 end | |
219 | |
220 --- Test is pathname is a regular file. | |
221 -- @param file string: pathname to test | |
222 -- @return boolean: true if it is a regular file, false otherwise. | |
223 function is_file(file) | |
224 assert(file) | |
225 return fs.execute(vars.TEST, "-f", file) | |
226 end | |
227 | |
228 --- Download a remote file. | |
229 -- @param url string: URL to be fetched. | |
230 -- @param filename string or nil: this function attempts to detect the | |
231 -- resulting local filename of the remote file as the basename of the URL; | |
232 -- if that is not correct (due to a redirection, for example), the local | |
233 -- filename can be given explicitly as this second argument. | |
234 -- @return boolean: true on success, false on failure. | |
235 function download(url, filename) | |
236 assert(type(url) == "string") | |
237 assert(type(filename) == "string" or not filename) | |
238 | |
239 if cfg.downloader == "wget" then | |
240 local wget_cmd = vars.WGET.." --no-check-certificate --no-cache --user-agent='"..cfg.user_agent.." via wget' --quiet --continue " | |
241 if filename then | |
242 return fs.execute(wget_cmd.." --output-document ", filename, url) | |
243 else | |
244 return fs.execute(wget_cmd, url) | |
245 end | |
246 elseif cfg.downloader == "curl" then | |
247 filename = filename or dir.base_name(url) | |
248 return fs.execute_string(vars.CURL.." -L --user-agent '"..cfg.user_agent.." via curl' "..fs.Q(url).." 2> /dev/null 1> "..fs.Q(filename)) | |
249 end | |
250 end | |
251 | |
252 function chmod(pathname, mode) | |
253 if mode then | |
254 return fs.execute(vars.CHMOD, mode, pathname) | |
255 else | |
256 return false | |
257 end | |
258 end | |
259 | |
260 --- Apply a patch. | |
261 -- @param patchname string: The filename of the patch. | |
262 function apply_patch(patchname) | |
263 return fs.execute(vars.PATCH.." -p1 -f -i ", patchname) | |
264 end | |
265 | |
266 --- Unpack an archive. | |
267 -- Extract the contents of an archive, detecting its format by | |
268 -- filename extension. | |
269 -- @param archive string: Filename of archive. | |
270 -- @return boolean or (boolean, string): true on success, false and an error message on failure. | |
271 function unpack_archive(archive) | |
272 assert(type(archive) == "string") | |
273 | |
274 local ok | |
275 if archive:match("%.tar%.gz$") or archive:match("%.tgz$") then | |
276 ok = fs.execute_string(vars.GUNZIP.." -c "..archive.."|"..vars.TAR.." -xf -") | |
277 elseif archive:match("%.tar%.bz2$") then | |
278 ok = fs.execute_string(vars.BUNZIP2.." -c "..archive.."|tar -xf -") | |
279 elseif archive:match("%.zip$") then | |
280 ok = fs.execute(vars.UNZIP, archive) | |
281 elseif archive:match("%.lua$") or archive:match("%.c$") then | |
282 -- Ignore .lua and .c files; they don't need to be extracted. | |
283 return true | |
284 else | |
285 local ext = archive:match(".*(%..*)") | |
286 return false, "Unrecognized filename extension "..(ext or "") | |
287 end | |
288 if not ok then | |
289 return false, "Failed extracting "..archive | |
290 end | |
291 return true | |
292 end | |
293 | |
294 local md5_cmd = { | |
295 md5sum = vars.MD5SUM, | |
296 openssl = vars.OPENSSL.." md5", | |
297 md5 = vars.MD5, | |
298 } | |
299 | |
300 --- Get the MD5 checksum for a file. | |
301 -- @param file string: The file to be computed. | |
302 -- @return string: The MD5 checksum | |
303 function get_md5(file) | |
304 local cmd = md5_cmd[cfg.md5checker] | |
305 if not cmd then return nil end | |
306 local pipe = io.popen(cmd.." "..fs.absolute_name(file)) | |
307 local computed = pipe:read("*a") | |
308 pipe:close() | |
309 if not computed then return nil end | |
310 return computed:match("("..("%x"):rep(32)..")") | |
311 end | |
312 | |
313 function get_permissions(filename) | |
314 local pipe = io.popen(vars.STAT.." "..vars.STATFLAG.." "..fs.Q(filename)) | |
315 local ret = pipe:read("*l") | |
316 pipe:close() | |
317 return ret | |
318 end |