PageRenderTime 24ms CodeModel.GetById 12ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/src/luarocks/fs/unix.lua

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