/src/luarocks/fs/lua.lua

http://github.com/keplerproject/luarocks · Lua · 1208 lines · 865 code · 123 blank · 220 comment · 290 complexity · 1ff33c7e5b69c7ffa72e5ad132a4068f MD5 · raw file

  1. --- Native Lua implementation of filesystem and platform abstractions,
  2. -- using LuaFileSystem, LuaSocket, LuaSec, lua-zlib, LuaPosix, MD5.
  3. -- module("luarocks.fs.lua")
  4. local fs_lua = {}
  5. local fs = require("luarocks.fs")
  6. local cfg = require("luarocks.core.cfg")
  7. local dir = require("luarocks.dir")
  8. local util = require("luarocks.util")
  9. local socket_ok, zip_ok, lfs_ok, md5_ok, posix_ok, bz2_ok, _
  10. local http, ftp, zip, lfs, md5, posix, bz2
  11. if cfg.fs_use_modules then
  12. socket_ok, http = pcall(require, "socket.http")
  13. _, ftp = pcall(require, "socket.ftp")
  14. zip_ok, zip = pcall(require, "luarocks.tools.zip")
  15. bz2_ok, bz2 = pcall(require, "bz2")
  16. lfs_ok, lfs = pcall(require, "lfs")
  17. md5_ok, md5 = pcall(require, "md5")
  18. posix_ok, posix = pcall(require, "posix")
  19. end
  20. local patch = require("luarocks.tools.patch")
  21. local tar = require("luarocks.tools.tar")
  22. local dir_stack = {}
  23. --- Test is file/dir is writable.
  24. -- Warning: testing if a file/dir is writable does not guarantee
  25. -- that it will remain writable and therefore it is no replacement
  26. -- for checking the result of subsequent operations.
  27. -- @param file string: filename to test
  28. -- @return boolean: true if file exists, false otherwise.
  29. function fs_lua.is_writable(file)
  30. assert(file)
  31. file = dir.normalize(file)
  32. local result
  33. if fs.is_dir(file) then
  34. local file2 = dir.path(file, '.tmpluarockstestwritable')
  35. local fh = io.open(file2, 'wb')
  36. result = fh ~= nil
  37. if fh then fh:close() end
  38. os.remove(file2)
  39. else
  40. local fh = io.open(file, 'r+b')
  41. result = fh ~= nil
  42. if fh then fh:close() end
  43. end
  44. return result
  45. end
  46. local function quote_args(command, ...)
  47. local out = { command }
  48. for _, arg in ipairs({...}) do
  49. assert(type(arg) == "string")
  50. out[#out+1] = fs.Q(arg)
  51. end
  52. return table.concat(out, " ")
  53. end
  54. --- Run the given command, quoting its arguments.
  55. -- The command is executed in the current directory in the dir stack.
  56. -- @param command string: The command to be executed. No quoting/escaping
  57. -- is applied.
  58. -- @param ... Strings containing additional arguments, which are quoted.
  59. -- @return boolean: true if command succeeds (status code 0), false
  60. -- otherwise.
  61. function fs_lua.execute(command, ...)
  62. assert(type(command) == "string")
  63. return fs.execute_string(quote_args(command, ...))
  64. end
  65. --- Run the given command, quoting its arguments, silencing its output.
  66. -- The command is executed in the current directory in the dir stack.
  67. -- Silencing is omitted if 'verbose' mode is enabled.
  68. -- @param command string: The command to be executed. No quoting/escaping
  69. -- is applied.
  70. -- @param ... Strings containing additional arguments, which will be quoted.
  71. -- @return boolean: true if command succeeds (status code 0), false
  72. -- otherwise.
  73. function fs_lua.execute_quiet(command, ...)
  74. assert(type(command) == "string")
  75. if cfg.verbose then -- omit silencing output
  76. return fs.execute_string(quote_args(command, ...))
  77. else
  78. return fs.execute_string(fs.quiet(quote_args(command, ...)))
  79. end
  80. end
  81. function fs.execute_env(env, command, ...)
  82. assert(type(command) == "string")
  83. local envstr = {}
  84. for var, val in pairs(env) do
  85. table.insert(envstr, fs.export_cmd(var, val))
  86. end
  87. return fs.execute_string(table.concat(envstr, "\n") .. "\n" .. quote_args(command, ...))
  88. end
  89. local tool_available_cache = {}
  90. function fs_lua.set_tool_available(tool_name, value)
  91. assert(type(value) == "boolean")
  92. tool_available_cache[tool_name] = value
  93. end
  94. --- Checks if the given tool is available.
  95. -- The tool is executed using a flag, usually just to ask its version.
  96. -- @param tool_cmd string: The command to be used to check the tool's presence (e.g. hg in case of Mercurial)
  97. -- @param tool_name string: The actual name of the tool (e.g. Mercurial)
  98. -- @param arg string: The flag to pass to the tool. '--version' by default.
  99. function fs_lua.is_tool_available(tool_cmd, tool_name, arg)
  100. assert(type(tool_cmd) == "string")
  101. assert(type(tool_name) == "string")
  102. arg = arg or "--version"
  103. assert(type(arg) == "string")
  104. local ok
  105. if tool_available_cache[tool_name] ~= nil then
  106. ok = tool_available_cache[tool_name]
  107. else
  108. ok = fs.execute_quiet(tool_cmd, arg)
  109. tool_available_cache[tool_name] = (ok == true)
  110. end
  111. if ok then
  112. return true
  113. else
  114. local msg = "'%s' program not found. Make sure %s is installed and is available in your PATH " ..
  115. "(or you may want to edit the 'variables.%s' value in file '%s')"
  116. return nil, msg:format(tool_cmd, tool_name, tool_name:upper(), cfg.config_files.nearest)
  117. end
  118. end
  119. --- Check the MD5 checksum for a file.
  120. -- @param file string: The file to be checked.
  121. -- @param md5sum string: The string with the expected MD5 checksum.
  122. -- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false + msg if not
  123. -- or if it could not perform the check for any reason.
  124. function fs_lua.check_md5(file, md5sum)
  125. file = dir.normalize(file)
  126. local computed, msg = fs.get_md5(file)
  127. if not computed then
  128. return false, msg
  129. end
  130. if computed:match("^"..md5sum) then
  131. return true
  132. else
  133. return false, "Mismatch MD5 hash for file "..file
  134. end
  135. end
  136. --- List the contents of a directory.
  137. -- @param at string or nil: directory to list (will be the current
  138. -- directory if none is given).
  139. -- @return table: an array of strings with the filenames representing
  140. -- the contents of a directory.
  141. function fs_lua.list_dir(at)
  142. local result = {}
  143. for file in fs.dir(at) do
  144. result[#result+1] = file
  145. end
  146. return result
  147. end
  148. --- Iterate over the contents of a directory.
  149. -- @param at string or nil: directory to list (will be the current
  150. -- directory if none is given).
  151. -- @return function: an iterator function suitable for use with
  152. -- the for statement.
  153. function fs_lua.dir(at)
  154. if not at then
  155. at = fs.current_dir()
  156. end
  157. at = dir.normalize(at)
  158. if not fs.is_dir(at) then
  159. return function() end
  160. end
  161. return coroutine.wrap(function() fs.dir_iterator(at) end)
  162. end
  163. --- List the Lua modules at a specific require path.
  164. -- eg. `modules("luarocks.cmd")` would return a list of all LuaRocks command
  165. -- modules, in the current Lua path.
  166. function fs_lua.modules(at)
  167. at = at or ""
  168. if #at > 0 then
  169. -- turn require path into file path
  170. at = at:gsub("%.", package.config:sub(1,1)) .. package.config:sub(1,1)
  171. end
  172. local path = package.path:sub(-1, -1) == ";" and package.path or package.path .. ";"
  173. local paths = {}
  174. for location in path:gmatch("(.-);") do
  175. if location:lower() == "?.lua" then
  176. location = "./?.lua"
  177. end
  178. local _, q_count = location:gsub("%?", "") -- only use the ones with a single '?'
  179. if location:match("%?%.[lL][uU][aA]$") and q_count == 1 then -- only use when ending with "?.lua"
  180. location = location:gsub("%?%.[lL][uU][aA]$", at)
  181. table.insert(paths, location)
  182. end
  183. end
  184. if #paths == 0 then
  185. return {}
  186. end
  187. local modules = {}
  188. local is_duplicate = {}
  189. for _, path in ipairs(paths) do
  190. local files = fs.list_dir(path)
  191. for _, filename in ipairs(files or {}) do
  192. if filename:match("%.[lL][uU][aA]$") then
  193. filename = filename:sub(1,-5) -- drop the extension
  194. if not is_duplicate[filename] then
  195. is_duplicate[filename] = true
  196. table.insert(modules, filename)
  197. end
  198. end
  199. end
  200. end
  201. return modules
  202. end
  203. function fs_lua.filter_file(fn, input_filename, output_filename)
  204. local fd, err = io.open(input_filename, "rb")
  205. if not fd then
  206. return nil, err
  207. end
  208. local input, err = fd:read("*a")
  209. fd:close()
  210. if not input then
  211. return nil, err
  212. end
  213. local output, err = fn(input)
  214. if not output then
  215. return nil, err
  216. end
  217. fd, err = io.open(output_filename, "wb")
  218. if not fd then
  219. return nil, err
  220. end
  221. local ok, err = fd:write(output)
  222. fd:close()
  223. if not ok then
  224. return nil, err
  225. end
  226. return true
  227. end
  228. function fs_lua.system_temp_dir()
  229. return os.getenv("TMPDIR") or os.getenv("TEMP") or "/tmp"
  230. end
  231. ---------------------------------------------------------------------
  232. -- LuaFileSystem functions
  233. ---------------------------------------------------------------------
  234. if lfs_ok then
  235. --- Run the given command.
  236. -- The command is executed in the current directory in the dir stack.
  237. -- @param cmd string: No quoting/escaping is applied to the command.
  238. -- @return boolean: true if command succeeds (status code 0), false
  239. -- otherwise.
  240. function fs_lua.execute_string(cmd)
  241. local code = os.execute(cmd)
  242. return (code == 0 or code == true)
  243. end
  244. --- Obtain current directory.
  245. -- Uses the module's internal dir stack.
  246. -- @return string: the absolute pathname of the current directory.
  247. function fs_lua.current_dir()
  248. return lfs.currentdir()
  249. end
  250. --- Change the current directory.
  251. -- Uses the module's internal dir stack. This does not have exact
  252. -- semantics of chdir, as it does not handle errors the same way,
  253. -- but works well for our purposes for now.
  254. -- @param d string: The directory to switch to.
  255. function fs_lua.change_dir(d)
  256. table.insert(dir_stack, lfs.currentdir())
  257. d = dir.normalize(d)
  258. return lfs.chdir(d)
  259. end
  260. --- Change directory to root.
  261. -- Allows leaving a directory (e.g. for deleting it) in
  262. -- a crossplatform way.
  263. function fs_lua.change_dir_to_root()
  264. local current = lfs.currentdir()
  265. if not current or current == "" then
  266. return false
  267. end
  268. table.insert(dir_stack, current)
  269. lfs.chdir("/") -- works on Windows too
  270. return true
  271. end
  272. --- Change working directory to the previous in the dir stack.
  273. -- @return true if a pop occurred, false if the stack was empty.
  274. function fs_lua.pop_dir()
  275. local d = table.remove(dir_stack)
  276. if d then
  277. lfs.chdir(d)
  278. return true
  279. else
  280. return false
  281. end
  282. end
  283. --- Create a directory if it does not already exist.
  284. -- If any of the higher levels in the path name do not exist
  285. -- too, they are created as well.
  286. -- @param directory string: pathname of directory to create.
  287. -- @return boolean or (boolean, string): true on success or (false, error message) on failure.
  288. function fs_lua.make_dir(directory)
  289. assert(type(directory) == "string")
  290. directory = dir.normalize(directory)
  291. local path = nil
  292. if directory:sub(2, 2) == ":" then
  293. path = directory:sub(1, 2)
  294. directory = directory:sub(4)
  295. else
  296. if directory:match("^/") then
  297. path = ""
  298. end
  299. end
  300. for d in directory:gmatch("([^/]+)/*") do
  301. path = path and path .. "/" .. d or d
  302. local mode = lfs.attributes(path, "mode")
  303. if not mode then
  304. local ok, err = lfs.mkdir(path)
  305. if not ok then
  306. return false, err
  307. end
  308. ok, err = fs.set_permissions(path, "exec", "all")
  309. if not ok then
  310. return false, err
  311. end
  312. elseif mode ~= "directory" then
  313. return false, path.." is not a directory"
  314. end
  315. end
  316. return true
  317. end
  318. --- Remove a directory if it is empty.
  319. -- Does not return errors (for example, if directory is not empty or
  320. -- if already does not exist)
  321. -- @param d string: pathname of directory to remove.
  322. function fs_lua.remove_dir_if_empty(d)
  323. assert(d)
  324. d = dir.normalize(d)
  325. lfs.rmdir(d)
  326. end
  327. --- Remove a directory if it is empty.
  328. -- Does not return errors (for example, if directory is not empty or
  329. -- if already does not exist)
  330. -- @param d string: pathname of directory to remove.
  331. function fs_lua.remove_dir_tree_if_empty(d)
  332. assert(d)
  333. d = dir.normalize(d)
  334. for i=1,10 do
  335. lfs.rmdir(d)
  336. d = dir.dir_name(d)
  337. end
  338. end
  339. local function are_the_same_file(f1, f2)
  340. if f1 == f2 then
  341. return true
  342. end
  343. if cfg.is_platform("unix") then
  344. local i1 = lfs.attributes(f1, "ino")
  345. local i2 = lfs.attributes(f2, "ino")
  346. if i1 ~= nil and i1 == i2 then
  347. return true
  348. end
  349. end
  350. return false
  351. end
  352. --- Copy a file.
  353. -- @param src string: Pathname of source
  354. -- @param dest string: Pathname of destination
  355. -- @param perms string ("read" or "exec") or nil: Permissions for destination
  356. -- file or nil to use the source file permissions
  357. -- @return boolean or (boolean, string): true on success, false on failure,
  358. -- plus an error message.
  359. function fs_lua.copy(src, dest, perms)
  360. assert(src and dest)
  361. src = dir.normalize(src)
  362. dest = dir.normalize(dest)
  363. local destmode = lfs.attributes(dest, "mode")
  364. if destmode == "directory" then
  365. dest = dir.path(dest, dir.base_name(src))
  366. end
  367. if are_the_same_file(src, dest) then
  368. return nil, "The source and destination are the same files"
  369. end
  370. local src_h, err = io.open(src, "rb")
  371. if not src_h then return nil, err end
  372. local dest_h, err = io.open(dest, "w+b")
  373. if not dest_h then src_h:close() return nil, err end
  374. while true do
  375. local block = src_h:read(8192)
  376. if not block then break end
  377. dest_h:write(block)
  378. end
  379. src_h:close()
  380. dest_h:close()
  381. local fullattrs
  382. if not perms then
  383. fullattrs = lfs.attributes(src, "permissions")
  384. end
  385. if fullattrs and posix_ok then
  386. return posix.chmod(dest, fullattrs)
  387. else
  388. if not perms then
  389. perms = fullattrs:match("x") and "exec" or "read"
  390. end
  391. return fs.set_permissions(dest, perms, "all")
  392. end
  393. end
  394. --- Implementation function for recursive copy of directory contents.
  395. -- Assumes paths are normalized.
  396. -- @param src string: Pathname of source
  397. -- @param dest string: Pathname of destination
  398. -- @param perms string ("read" or "exec") or nil: Optional permissions.
  399. -- If not given, permissions of the source are copied over to the destination.
  400. -- @return boolean or (boolean, string): true on success, false on failure
  401. local function recursive_copy(src, dest, perms)
  402. local srcmode = lfs.attributes(src, "mode")
  403. if srcmode == "file" then
  404. local ok = fs.copy(src, dest, perms)
  405. if not ok then return false end
  406. elseif srcmode == "directory" then
  407. local subdir = dir.path(dest, dir.base_name(src))
  408. local ok, err = fs.make_dir(subdir)
  409. if not ok then return nil, err end
  410. if pcall(lfs.dir, src) == false then
  411. return false
  412. end
  413. for file in lfs.dir(src) do
  414. if file ~= "." and file ~= ".." then
  415. local ok = recursive_copy(dir.path(src, file), subdir, perms)
  416. if not ok then return false end
  417. end
  418. end
  419. end
  420. return true
  421. end
  422. --- Recursively copy the contents of a directory.
  423. -- @param src string: Pathname of source
  424. -- @param dest string: Pathname of destination
  425. -- @param perms string ("read" or "exec") or nil: Optional permissions.
  426. -- @return boolean or (boolean, string): true on success, false on failure,
  427. -- plus an error message.
  428. function fs_lua.copy_contents(src, dest, perms)
  429. assert(src and dest)
  430. src = dir.normalize(src)
  431. dest = dir.normalize(dest)
  432. if not fs.is_dir(src) then
  433. return false, src .. " is not a directory"
  434. end
  435. if pcall(lfs.dir, src) == false then
  436. return false, "Permission denied"
  437. end
  438. for file in lfs.dir(src) do
  439. if file ~= "." and file ~= ".." then
  440. local ok = recursive_copy(dir.path(src, file), dest, perms)
  441. if not ok then
  442. return false, "Failed copying "..src.." to "..dest
  443. end
  444. end
  445. end
  446. return true
  447. end
  448. --- Implementation function for recursive removal of directories.
  449. -- Assumes paths are normalized.
  450. -- @param name string: Pathname of file
  451. -- @return boolean or (boolean, string): true on success,
  452. -- or nil and an error message on failure.
  453. local function recursive_delete(name)
  454. local ok = os.remove(name)
  455. if ok then return true end
  456. local pok, ok, err = pcall(function()
  457. for file in lfs.dir(name) do
  458. if file ~= "." and file ~= ".." then
  459. local ok, err = recursive_delete(dir.path(name, file))
  460. if not ok then return nil, err end
  461. end
  462. end
  463. local ok, err = lfs.rmdir(name)
  464. return ok, (not ok) and err
  465. end)
  466. if pok then
  467. return ok, err
  468. else
  469. return pok, ok
  470. end
  471. end
  472. --- Delete a file or a directory and all its contents.
  473. -- @param name string: Pathname of source
  474. -- @return nil
  475. function fs_lua.delete(name)
  476. name = dir.normalize(name)
  477. recursive_delete(name)
  478. end
  479. --- Internal implementation function for fs.dir.
  480. -- Yields a filename on each iteration.
  481. -- @param at string: directory to list
  482. -- @return nil or (nil and string): an error message on failure
  483. function fs_lua.dir_iterator(at)
  484. local pok, iter, arg = pcall(lfs.dir, at)
  485. if not pok then
  486. return nil, iter
  487. end
  488. for file in iter, arg do
  489. if file ~= "." and file ~= ".." then
  490. coroutine.yield(file)
  491. end
  492. end
  493. end
  494. --- Implementation function for recursive find.
  495. -- Assumes paths are normalized.
  496. -- @param cwd string: Current working directory in recursion.
  497. -- @param prefix string: Auxiliary prefix string to form pathname.
  498. -- @param result table: Array of strings where results are collected.
  499. local function recursive_find(cwd, prefix, result)
  500. local pok, iter, arg = pcall(lfs.dir, cwd)
  501. if not pok then
  502. return nil
  503. end
  504. for file in iter, arg do
  505. if file ~= "." and file ~= ".." then
  506. local item = prefix .. file
  507. table.insert(result, item)
  508. local pathname = dir.path(cwd, file)
  509. if lfs.attributes(pathname, "mode") == "directory" then
  510. recursive_find(pathname, item.."/", result)
  511. end
  512. end
  513. end
  514. end
  515. --- Recursively scan the contents of a directory.
  516. -- @param at string or nil: directory to scan (will be the current
  517. -- directory if none is given).
  518. -- @return table: an array of strings with the filenames representing
  519. -- the contents of a directory.
  520. function fs_lua.find(at)
  521. assert(type(at) == "string" or not at)
  522. if not at then
  523. at = fs.current_dir()
  524. end
  525. at = dir.normalize(at)
  526. local result = {}
  527. recursive_find(at, "", result)
  528. return result
  529. end
  530. --- Test for existence of a file.
  531. -- @param file string: filename to test
  532. -- @return boolean: true if file exists, false otherwise.
  533. function fs_lua.exists(file)
  534. assert(file)
  535. file = dir.normalize(file)
  536. return type(lfs.attributes(file)) == "table"
  537. end
  538. --- Test is pathname is a directory.
  539. -- @param file string: pathname to test
  540. -- @return boolean: true if it is a directory, false otherwise.
  541. function fs_lua.is_dir(file)
  542. assert(file)
  543. file = dir.normalize(file)
  544. return lfs.attributes(file, "mode") == "directory"
  545. end
  546. --- Test is pathname is a regular file.
  547. -- @param file string: pathname to test
  548. -- @return boolean: true if it is a file, false otherwise.
  549. function fs_lua.is_file(file)
  550. assert(file)
  551. file = dir.normalize(file)
  552. return lfs.attributes(file, "mode") == "file"
  553. end
  554. -- Set access and modification times for a file.
  555. -- @param filename File to set access and modification times for.
  556. -- @param time may be a number containing the format returned
  557. -- by os.time, or a table ready to be processed via os.time; if
  558. -- nil, current time is assumed.
  559. function fs_lua.set_time(file, time)
  560. assert(time == nil or type(time) == "table" or type(time) == "number")
  561. file = dir.normalize(file)
  562. if type(time) == "table" then
  563. time = os.time(time)
  564. end
  565. return lfs.touch(file, time)
  566. end
  567. else -- if not lfs_ok
  568. function fs_lua.exists(file)
  569. assert(file)
  570. file = dir.normalize(fs.absolute_name(file))
  571. -- check if file exists by attempting to open it
  572. return util.exists(file)
  573. end
  574. end
  575. ---------------------------------------------------------------------
  576. -- lua-bz2 functions
  577. ---------------------------------------------------------------------
  578. if bz2_ok then
  579. local function bunzip2_string(data)
  580. local decompressor = bz2.initDecompress()
  581. local output, err = decompressor:update(data)
  582. if not output then
  583. return nil, err
  584. end
  585. decompressor:close()
  586. return output
  587. end
  588. --- Uncompresses a .bz2 file.
  589. -- @param infile string: pathname of .bz2 file to be extracted.
  590. -- @param outfile string or nil: pathname of output file to be produced.
  591. -- If not given, name is derived from input file.
  592. -- @return boolean: true on success; nil and error message on failure.
  593. function fs_lua.bunzip2(infile, outfile)
  594. assert(type(infile) == "string")
  595. assert(outfile == nil or type(outfile) == "string")
  596. if not outfile then
  597. outfile = infile:gsub("%.bz2$", "")
  598. end
  599. return fs.filter_file(bunzip2_string, infile, outfile)
  600. end
  601. end
  602. ---------------------------------------------------------------------
  603. -- luarocks.tools.zip functions
  604. ---------------------------------------------------------------------
  605. if zip_ok then
  606. function fs_lua.zip(zipfile, ...)
  607. return zip.zip(zipfile, ...)
  608. end
  609. function fs_lua.unzip(zipfile)
  610. return zip.unzip(zipfile)
  611. end
  612. function fs_lua.gunzip(infile, outfile)
  613. return zip.gunzip(infile, outfile)
  614. end
  615. end
  616. ---------------------------------------------------------------------
  617. -- LuaSocket functions
  618. ---------------------------------------------------------------------
  619. if socket_ok then
  620. local ltn12 = require("ltn12")
  621. local luasec_ok, https = pcall(require, "ssl.https")
  622. local redirect_protocols = {
  623. http = http,
  624. https = luasec_ok and https,
  625. }
  626. local function request(url, method, http, loop_control)
  627. local result = {}
  628. if cfg.verbose then
  629. print(method, url)
  630. end
  631. local proxy = os.getenv("http_proxy")
  632. if type(proxy) ~= "string" then proxy = nil end
  633. -- LuaSocket's http.request crashes when given URLs missing the scheme part.
  634. if proxy and not proxy:find("://") then
  635. proxy = "http://" .. proxy
  636. end
  637. if cfg.show_downloads then
  638. io.write(method.." "..url.." ...\n")
  639. end
  640. local dots = 0
  641. if cfg.connection_timeout and cfg.connection_timeout > 0 then
  642. http.TIMEOUT = cfg.connection_timeout
  643. end
  644. local res, status, headers, err = http.request {
  645. url = url,
  646. proxy = proxy,
  647. method = method,
  648. redirect = false,
  649. sink = ltn12.sink.table(result),
  650. step = cfg.show_downloads and function(...)
  651. io.write(".")
  652. io.flush()
  653. dots = dots + 1
  654. if dots == 70 then
  655. io.write("\n")
  656. dots = 0
  657. end
  658. return ltn12.pump.step(...)
  659. end,
  660. headers = {
  661. ["user-agent"] = cfg.user_agent.." via LuaSocket"
  662. },
  663. }
  664. if cfg.show_downloads then
  665. io.write("\n")
  666. end
  667. if not res then
  668. return nil, status
  669. elseif status == 301 or status == 302 then
  670. local location = headers.location
  671. if location then
  672. local protocol, rest = dir.split_url(location)
  673. if redirect_protocols[protocol] then
  674. if not loop_control then
  675. loop_control = {}
  676. elseif loop_control[location] then
  677. return nil, "Redirection loop -- broken URL?"
  678. end
  679. loop_control[url] = true
  680. return request(location, method, redirect_protocols[protocol], loop_control)
  681. else
  682. return nil, "URL redirected to unsupported protocol - install luasec to get HTTPS support.", "https"
  683. end
  684. end
  685. return nil, err
  686. elseif status ~= 200 then
  687. return nil, err
  688. else
  689. return result, status, headers, err
  690. end
  691. end
  692. local function write_timestamp(filename, data)
  693. local fd = io.open(filename, "w")
  694. if fd then
  695. fd:write(data)
  696. fd:close()
  697. end
  698. end
  699. local function read_timestamp(filename)
  700. local fd = io.open(filename, "r")
  701. if fd then
  702. local data = fd:read("*a")
  703. fd:close()
  704. return data
  705. end
  706. end
  707. local function fail_with_status(filename, status, headers)
  708. write_timestamp(filename .. ".unixtime", os.time())
  709. write_timestamp(filename .. ".status", status)
  710. return nil, status, headers
  711. end
  712. -- @param url string: URL to fetch.
  713. -- @param filename string: local filename of the file to fetch.
  714. -- @param http table: The library to use (http from LuaSocket or LuaSec)
  715. -- @param cache boolean: Whether to use a `.timestamp` file to check
  716. -- via the HTTP Last-Modified header if the full download is needed.
  717. -- @return (boolean | (nil, string, string?)): True if successful, or
  718. -- nil, error message and optionally HTTPS error in case of errors.
  719. local function http_request(url, filename, http, cache)
  720. if cache then
  721. local status = read_timestamp(filename..".status")
  722. local timestamp = read_timestamp(filename..".timestamp")
  723. if status or timestamp then
  724. local unixtime = read_timestamp(filename..".unixtime")
  725. if tonumber(unixtime) then
  726. local diff = os.time() - tonumber(unixtime)
  727. if status then
  728. if diff < cfg.cache_fail_timeout then
  729. return nil, status, {}
  730. end
  731. else
  732. if diff < cfg.cache_timeout then
  733. return true, nil, nil, true
  734. end
  735. end
  736. end
  737. local result, status, headers, err = request(url, "HEAD", http)
  738. if not result then
  739. return fail_with_status(filename, status, headers)
  740. end
  741. if status == 200 and headers["last-modified"] == timestamp then
  742. write_timestamp(filename .. ".unixtime", os.time())
  743. return true, nil, nil, true
  744. end
  745. end
  746. end
  747. local result, status, headers, err = request(url, "GET", http)
  748. if not result then
  749. if status then
  750. return fail_with_status(filename, status, headers)
  751. end
  752. end
  753. if cache and headers["last-modified"] then
  754. write_timestamp(filename .. ".timestamp", headers["last-modified"])
  755. write_timestamp(filename .. ".unixtime", os.time())
  756. end
  757. local file = io.open(filename, "wb")
  758. if not file then return nil, 0, {} end
  759. for _, data in ipairs(result) do
  760. file:write(data)
  761. end
  762. file:close()
  763. return true
  764. end
  765. local function ftp_request(url, filename)
  766. local content, err = ftp.get(url)
  767. if not content then
  768. return false, err
  769. end
  770. local file = io.open(filename, "wb")
  771. if not file then return false, err end
  772. file:write(content)
  773. file:close()
  774. return true
  775. end
  776. local downloader_warning = false
  777. --- Download a remote file.
  778. -- @param url string: URL to be fetched.
  779. -- @param filename string or nil: this function attempts to detect the
  780. -- resulting local filename of the remote file as the basename of the URL;
  781. -- if that is not correct (due to a redirection, for example), the local
  782. -- filename can be given explicitly as this second argument.
  783. -- @return (boolean, string, boolean):
  784. -- In case of success:
  785. -- * true
  786. -- * a string with the filename
  787. -- * true if the file was retrieved from local cache
  788. -- In case of failure:
  789. -- * false
  790. -- * error message
  791. function fs_lua.download(url, filename, cache)
  792. assert(type(url) == "string")
  793. assert(type(filename) == "string" or not filename)
  794. filename = fs.absolute_name(filename or dir.base_name(url))
  795. -- delegate to the configured downloader so we don't have to deal with whitelists
  796. if os.getenv("no_proxy") then
  797. return fs.use_downloader(url, filename, cache)
  798. end
  799. local ok, err, https_err, from_cache
  800. if util.starts_with(url, "http:") then
  801. ok, err, https_err, from_cache = http_request(url, filename, http, cache)
  802. elseif util.starts_with(url, "ftp:") then
  803. ok, err = ftp_request(url, filename)
  804. elseif util.starts_with(url, "https:") then
  805. -- skip LuaSec when proxy is enabled since it is not supported
  806. if luasec_ok and not os.getenv("https_proxy") then
  807. local _
  808. ok, err, _, from_cache = http_request(url, filename, https, cache)
  809. else
  810. https_err = true
  811. end
  812. else
  813. err = "Unsupported protocol"
  814. end
  815. if https_err then
  816. local downloader, err = fs.which_tool("downloader")
  817. if not downloader then
  818. return nil, err
  819. end
  820. if not downloader_warning then
  821. util.warning("falling back to "..downloader.." - install luasec to get native HTTPS support")
  822. downloader_warning = true
  823. end
  824. return fs.use_downloader(url, filename, cache)
  825. elseif not ok then
  826. return nil, err
  827. end
  828. return true, filename, from_cache
  829. end
  830. else --...if socket_ok == false then
  831. function fs_lua.download(url, filename, cache)
  832. return fs.use_downloader(url, filename, cache)
  833. end
  834. end
  835. ---------------------------------------------------------------------
  836. -- MD5 functions
  837. ---------------------------------------------------------------------
  838. if md5_ok then
  839. -- Support the interface of lmd5 by lhf in addition to md5 by Roberto
  840. -- and the keplerproject.
  841. if not md5.sumhexa and md5.digest then
  842. md5.sumhexa = function(msg)
  843. return md5.digest(msg)
  844. end
  845. end
  846. if md5.sumhexa then
  847. --- Get the MD5 checksum for a file.
  848. -- @param file string: The file to be computed.
  849. -- @return string: The MD5 checksum or nil + error
  850. function fs_lua.get_md5(file)
  851. file = fs.absolute_name(file)
  852. local file_handler = io.open(file, "rb")
  853. if not file_handler then return nil, "Failed to open file for reading: "..file end
  854. local computed = md5.sumhexa(file_handler:read("*a"))
  855. file_handler:close()
  856. if computed then return computed end
  857. return nil, "Failed to compute MD5 hash for file "..file
  858. end
  859. end
  860. end
  861. ---------------------------------------------------------------------
  862. -- POSIX functions
  863. ---------------------------------------------------------------------
  864. function fs_lua._unix_rwx_to_number(rwx, neg)
  865. local num = 0
  866. neg = neg or false
  867. for i = 1, 9 do
  868. local c = rwx:sub(10 - i, 10 - i) == "-"
  869. if neg == c then
  870. num = num + 2^(i-1)
  871. end
  872. end
  873. return math.floor(num)
  874. end
  875. if posix_ok then
  876. local octal_to_rwx = {
  877. ["0"] = "---",
  878. ["1"] = "--x",
  879. ["2"] = "-w-",
  880. ["3"] = "-wx",
  881. ["4"] = "r--",
  882. ["5"] = "r-x",
  883. ["6"] = "rw-",
  884. ["7"] = "rwx",
  885. }
  886. do
  887. local umask_cache
  888. function fs_lua._unix_umask()
  889. if umask_cache then
  890. return umask_cache
  891. end
  892. -- LuaPosix (as of 34.0.4) only returns the umask as rwx
  893. local rwx = posix.umask()
  894. local num = fs_lua._unix_rwx_to_number(rwx, true)
  895. umask_cache = ("%03o"):format(num)
  896. return umask_cache
  897. end
  898. end
  899. function fs_lua.set_permissions(filename, mode, scope)
  900. local perms
  901. if mode == "read" and scope == "user" then
  902. perms = fs._unix_moderate_permissions("600")
  903. elseif mode == "exec" and scope == "user" then
  904. perms = fs._unix_moderate_permissions("700")
  905. elseif mode == "read" and scope == "all" then
  906. perms = fs._unix_moderate_permissions("644")
  907. elseif mode == "exec" and scope == "all" then
  908. perms = fs._unix_moderate_permissions("755")
  909. else
  910. return false, "Invalid permission " .. mode .. " for " .. scope
  911. end
  912. -- LuaPosix (as of 5.1.15) does not support octal notation...
  913. local new_perms = {}
  914. for c in perms:sub(-3):gmatch(".") do
  915. table.insert(new_perms, octal_to_rwx[c])
  916. end
  917. perms = table.concat(new_perms)
  918. local err = posix.chmod(filename, perms)
  919. return err == 0
  920. end
  921. function fs_lua.current_user()
  922. return posix.getpwuid(posix.geteuid()).pw_name
  923. end
  924. -- This call is not available on all systems, see #677
  925. if posix.mkdtemp then
  926. --- Create a temporary directory.
  927. -- @param name_pattern string: name pattern to use for avoiding conflicts
  928. -- when creating temporary directory.
  929. -- @return string or (nil, string): name of temporary directory or (nil, error message) on failure.
  930. function fs_lua.make_temp_dir(name_pattern)
  931. assert(type(name_pattern) == "string")
  932. name_pattern = dir.normalize(name_pattern)
  933. return posix.mkdtemp(fs.system_temp_dir() .. "/luarocks_" .. name_pattern:gsub("/", "_") .. "-XXXXXX")
  934. end
  935. end -- if posix.mkdtemp
  936. end
  937. ---------------------------------------------------------------------
  938. -- Other functions
  939. ---------------------------------------------------------------------
  940. if lfs_ok and not fs_lua.make_temp_dir then
  941. function fs_lua.make_temp_dir(name_pattern)
  942. assert(type(name_pattern) == "string")
  943. name_pattern = dir.normalize(name_pattern)
  944. local pattern = fs.system_temp_dir() .. "/luarocks_" .. name_pattern:gsub("/", "_") .. "-"
  945. while true do
  946. local name = pattern .. tostring(math.random(10000000))
  947. if lfs.mkdir(name) then
  948. return name
  949. end
  950. end
  951. end
  952. end
  953. --- Apply a patch.
  954. -- @param patchname string: The filename of the patch.
  955. -- @param patchdata string or nil: The actual patch as a string.
  956. -- @param create_delete boolean: Support creating and deleting files in a patch.
  957. function fs_lua.apply_patch(patchname, patchdata, create_delete)
  958. local p, all_ok = patch.read_patch(patchname, patchdata)
  959. if not all_ok then
  960. return nil, "Failed reading patch "..patchname
  961. end
  962. if p then
  963. return patch.apply_patch(p, 1, create_delete)
  964. end
  965. end
  966. --- Move a file.
  967. -- @param src string: Pathname of source
  968. -- @param dest string: Pathname of destination
  969. -- @param perms string ("read" or "exec") or nil: Permissions for destination
  970. -- file or nil to use the source file permissions.
  971. -- @return boolean or (boolean, string): true on success, false on failure,
  972. -- plus an error message.
  973. function fs_lua.move(src, dest, perms)
  974. assert(src and dest)
  975. if fs.exists(dest) and not fs.is_dir(dest) then
  976. return false, "File already exists: "..dest
  977. end
  978. local ok, err = fs.copy(src, dest, perms)
  979. if not ok then
  980. return false, err
  981. end
  982. fs.delete(src)
  983. if fs.exists(src) then
  984. return false, "Failed move: could not delete "..src.." after copy."
  985. end
  986. return true
  987. end
  988. --- Check if user has write permissions for the command.
  989. -- Assumes the configuration variables under cfg have been previously set up.
  990. -- @param args table: the args table passed to run() drivers.
  991. -- @return boolean or (boolean, string): true on success, false on failure,
  992. -- plus an error message.
  993. function fs_lua.check_command_permissions(args)
  994. local ok = true
  995. local err = ""
  996. for _, directory in ipairs { cfg.rocks_dir, cfg.deploy_lua_dir, cfg.deploy_bin_dir, cfg.deploy_lua_dir } do
  997. if fs.exists(directory) then
  998. if not fs.is_writable(directory) then
  999. ok = false
  1000. err = "Your user does not have write permissions in " .. directory
  1001. break
  1002. end
  1003. else
  1004. local root = fs.root_of(directory)
  1005. local parent = directory
  1006. repeat
  1007. parent = dir.dir_name(parent)
  1008. if parent == "" then
  1009. parent = root
  1010. end
  1011. until parent == root or fs.exists(parent)
  1012. if not fs.is_writable(parent) then
  1013. ok = false
  1014. err = directory.." does not exist and your user does not have write permissions in " .. parent
  1015. break
  1016. end
  1017. end
  1018. end
  1019. if ok then
  1020. return true
  1021. else
  1022. if args["local"] or cfg.local_by_default then
  1023. err = err .. " \n-- please check your permissions."
  1024. else
  1025. err = err .. " \n-- you may want to run as a privileged user or use your local tree with --local."
  1026. end
  1027. return nil, err
  1028. end
  1029. end
  1030. --- Check whether a file is a Lua script
  1031. -- When the file can be successfully compiled by the configured
  1032. -- Lua interpreter, it's considered to be a valid Lua file.
  1033. -- @param filename filename of file to check
  1034. -- @return boolean true, if it is a Lua script, false otherwise
  1035. function fs_lua.is_lua(filename)
  1036. filename = filename:gsub([[%\]],"/") -- normalize on fw slash to prevent escaping issues
  1037. local lua = fs.Q(dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)) -- get lua interpreter configured
  1038. -- execute on configured interpreter, might not be the same as the interpreter LR is run on
  1039. local result = fs.execute_string(lua..[[ -e "if loadfile(']]..filename..[[') then os.exit(0) else os.exit(1) end"]])
  1040. return (result == true)
  1041. end
  1042. --- Unpack an archive.
  1043. -- Extract the contents of an archive, detecting its format by
  1044. -- filename extension.
  1045. -- @param archive string: Filename of archive.
  1046. -- @return boolean or (boolean, string): true on success, false and an error message on failure.
  1047. function fs_lua.unpack_archive(archive)
  1048. assert(type(archive) == "string")
  1049. local ok, err
  1050. archive = fs.absolute_name(archive)
  1051. if archive:match("%.tar%.gz$") then
  1052. local tar_filename = archive:gsub("%.gz$", "")
  1053. ok, err = fs.gunzip(archive, tar_filename)
  1054. if ok then
  1055. ok, err = tar.untar(tar_filename, ".")
  1056. end
  1057. elseif archive:match("%.tgz$") then
  1058. local tar_filename = archive:gsub("%.tgz$", ".tar")
  1059. ok, err = fs.gunzip(archive, tar_filename)
  1060. if ok then
  1061. ok, err = tar.untar(tar_filename, ".")
  1062. end
  1063. elseif archive:match("%.tar%.bz2$") then
  1064. local tar_filename = archive:gsub("%.bz2$", "")
  1065. ok, err = fs.bunzip2(archive, tar_filename)
  1066. if ok then
  1067. ok, err = tar.untar(tar_filename, ".")
  1068. end
  1069. elseif archive:match("%.zip$") then
  1070. ok, err = fs.unzip(archive)
  1071. elseif archive:match("%.lua$") or archive:match("%.c$") then
  1072. -- Ignore .lua and .c files; they don't need to be extracted.
  1073. return true
  1074. else
  1075. return false, "Couldn't extract archive "..archive..": unrecognized filename extension"
  1076. end
  1077. if not ok then
  1078. return false, "Failed extracting "..archive..": "..err
  1079. end
  1080. return true
  1081. end
  1082. return fs_lua