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