/src/luarocks/fs/unix.lua

http://github.com/keplerproject/luarocks · Lua · 232 lines · 207 code · 8 blank · 17 comment · 4 complexity · f91ada838ea5c0cf1f0b72d735d74596 MD5 · raw file

  1. --- Unix implementation of filesystem and platform abstractions.
  2. local unix = {}
  3. local fs = require("luarocks.fs")
  4. local cfg = require("luarocks.core.cfg")
  5. local dir = require("luarocks.dir")
  6. local path = require("luarocks.path")
  7. local util = require("luarocks.util")
  8. --- Annotate command string for quiet execution.
  9. -- @param cmd string: A command-line string.
  10. -- @return string: The command-line, with silencing annotation.
  11. function unix.quiet(cmd)
  12. return cmd.." 1> /dev/null 2> /dev/null"
  13. end
  14. --- Annotate command string for execution with quiet stderr.
  15. -- @param cmd string: A command-line string.
  16. -- @return string: The command-line, with stderr silencing annotation.
  17. function unix.quiet_stderr(cmd)
  18. return cmd.." 2> /dev/null"
  19. end
  20. --- Quote argument for shell processing.
  21. -- Adds single quotes and escapes.
  22. -- @param arg string: Unquoted argument.
  23. -- @return string: Quoted argument.
  24. function unix.Q(arg)
  25. assert(type(arg) == "string")
  26. return "'" .. arg:gsub("'", "'\\''") .. "'"
  27. end
  28. --- Return an absolute pathname from a potentially relative one.
  29. -- @param pathname string: pathname to convert.
  30. -- @param relative_to string or nil: path to prepend when making
  31. -- pathname absolute, or the current dir in the dir stack if
  32. -- not given.
  33. -- @return string: The pathname converted to absolute.
  34. function unix.absolute_name(pathname, relative_to)
  35. assert(type(pathname) == "string")
  36. assert(type(relative_to) == "string" or not relative_to)
  37. local unquoted = pathname:match("^['\"](.*)['\"]$")
  38. if unquoted then
  39. pathname = unquoted
  40. end
  41. relative_to = (relative_to or fs.current_dir()):gsub("/*$", "")
  42. if pathname:sub(1,1) == "/" then
  43. return pathname
  44. else
  45. return relative_to .. "/" .. pathname
  46. end
  47. end
  48. --- Return the root directory for the given path.
  49. -- In Unix, root is always "/".
  50. -- @param pathname string: pathname to use.
  51. -- @return string: The root of the given pathname.
  52. function unix.root_of(_)
  53. return "/"
  54. end
  55. --- Create a wrapper to make a script executable from the command-line.
  56. -- @param script string: Pathname of script to be made executable.
  57. -- @param target string: wrapper target pathname (without wrapper suffix).
  58. -- @param name string: rock name to be used in loader context.
  59. -- @param version string: rock version to be used in loader context.
  60. -- @return boolean or (nil, string): True if succeeded, or nil and
  61. -- an error message.
  62. function unix.wrap_script(script, target, deps_mode, name, version, ...)
  63. assert(type(script) == "string" or not script)
  64. assert(type(target) == "string")
  65. assert(type(deps_mode) == "string")
  66. assert(type(name) == "string" or not name)
  67. assert(type(version) == "string" or not version)
  68. local wrapper = io.open(target, "w")
  69. if not wrapper then
  70. return nil, "Could not open "..target.." for writing."
  71. end
  72. local lpath, lcpath = path.package_paths(deps_mode)
  73. local luainit = {
  74. "package.path="..util.LQ(lpath..";").."..package.path",
  75. "package.cpath="..util.LQ(lcpath..";").."..package.cpath",
  76. }
  77. local remove_interpreter = false
  78. if target == "luarocks" or target == "luarocks-admin" then
  79. if cfg.is_binary then
  80. remove_interpreter = true
  81. end
  82. luainit = {
  83. "package.path="..util.LQ(package.path),
  84. "package.cpath="..util.LQ(package.cpath),
  85. }
  86. end
  87. if name and version then
  88. local addctx = "local k,l,_=pcall(require,"..util.LQ("luarocks.loader")..") _=k " ..
  89. "and l.add_context("..util.LQ(name)..","..util.LQ(version)..")"
  90. table.insert(luainit, addctx)
  91. end
  92. local argv = {
  93. fs.Q(dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)),
  94. "-e",
  95. fs.Q(table.concat(luainit, ";")),
  96. script and fs.Q(script) or [[$([ "$*" ] || echo -i)]],
  97. ...
  98. }
  99. if remove_interpreter then
  100. table.remove(argv, 1)
  101. table.remove(argv, 1)
  102. table.remove(argv, 1)
  103. end
  104. wrapper:write("#!/bin/sh\n\n")
  105. wrapper:write("LUAROCKS_SYSCONFDIR="..fs.Q(cfg.sysconfdir) .. " ")
  106. wrapper:write("exec "..table.concat(argv, " ")..' "$@"\n')
  107. wrapper:close()
  108. if fs.set_permissions(target, "exec", "all") then
  109. return true
  110. else
  111. return nil, "Could not make "..target.." executable."
  112. end
  113. end
  114. --- Check if a file (typically inside path.bin_dir) is an actual binary
  115. -- or a Lua wrapper.
  116. -- @param filename string: the file name with full path.
  117. -- @return boolean: returns true if file is an actual binary
  118. -- (or if it couldn't check) or false if it is a Lua wrapper.
  119. function unix.is_actual_binary(filename)
  120. if filename:match("%.lua$") then
  121. return false
  122. end
  123. local file = io.open(filename)
  124. if not file then
  125. return true
  126. end
  127. local first = file:read(2)
  128. file:close()
  129. if not first then
  130. util.warning("could not read "..filename)
  131. return true
  132. end
  133. return first ~= "#!"
  134. end
  135. function unix.copy_binary(filename, dest)
  136. return fs.copy(filename, dest, "exec")
  137. end
  138. --- Move a file on top of the other.
  139. -- The new file ceases to exist under its original name,
  140. -- and takes over the name of the old file.
  141. -- On Unix this is done through a single rename operation.
  142. -- @param old_file The name of the original file,
  143. -- which will be the new name of new_file.
  144. -- @param new_file The name of the new file,
  145. -- which will replace old_file.
  146. -- @return boolean or (nil, string): True if succeeded, or nil and
  147. -- an error message.
  148. function unix.replace_file(old_file, new_file)
  149. return os.rename(new_file, old_file)
  150. end
  151. function unix.tmpname()
  152. return os.tmpname()
  153. end
  154. function unix.current_user()
  155. return os.getenv("USER")
  156. end
  157. function unix.export_cmd(var, val)
  158. return ("export %s='%s'"):format(var, val)
  159. end
  160. local octal_to_rwx = {
  161. ["0"] = "---",
  162. ["1"] = "--x",
  163. ["2"] = "-w-",
  164. ["3"] = "-wx",
  165. ["4"] = "r--",
  166. ["5"] = "r-x",
  167. ["6"] = "rw-",
  168. ["7"] = "rwx",
  169. }
  170. local rwx_to_octal = {}
  171. for octal, rwx in pairs(octal_to_rwx) do
  172. rwx_to_octal[rwx] = octal
  173. end
  174. --- Moderate the given permissions based on the local umask
  175. -- @param perms string: permissions to moderate
  176. -- @return string: the moderated permissions
  177. function unix._unix_moderate_permissions(perms)
  178. local umask = fs._unix_umask()
  179. local moderated_perms = ""
  180. for i = 1, 3 do
  181. local p_rwx = octal_to_rwx[perms:sub(i, i)]
  182. local u_rwx = octal_to_rwx[umask:sub(i, i)]
  183. local new_perm = ""
  184. for j = 1, 3 do
  185. local p_val = p_rwx:sub(j, j)
  186. local u_val = u_rwx:sub(j, j)
  187. if p_val == u_val then
  188. new_perm = new_perm .. "-"
  189. else
  190. new_perm = new_perm .. p_val
  191. end
  192. end
  193. moderated_perms = moderated_perms .. rwx_to_octal[new_perm]
  194. end
  195. return moderated_perms
  196. end
  197. function unix.system_cache_dir()
  198. if fs.is_dir("/var/cache") then
  199. return "/var/cache"
  200. end
  201. return dir.path(fs.system_temp_dir(), "cache")
  202. end
  203. return unix