#!/usr/bin/env lua -- -- Yoink -- This script is a predictable alternative to the system install program. -- function show_help() print([[ Install files, optionally changing the mode of the installed files. Usage: install.lua [-m MODE] SOURCE... DEST If DEST is a directory, the source(s) will be copied into DEST with their same names. ]]) end -- Get the next argument passed to the script. function shift() var = arg[1] table.remove(arg, 1) return var end -- Execute a command and return its output or nil if the command failed to -- run. function backtick_run(command) local fd = io.popen(command.." 2>/dev/null") if fd then local stdout = fd:read("*l") fd:close() return stdout end return nil end -- Return true if a filespec is a directory, false otherwise. function is_directory(path) return os.execute(string.format("test -d %q", path)) == 0 end -- Get the basename of a path. function basename(path, ext) if not ext then ext = "" end return backtick_run(string.format("basename %q %s", path, ext)) end -- Get the directory part of a path. function dirname(path) if path:sub(-1) == "/" then path = path .. "." end return backtick_run(string.format("dirname %q", path)) end -- Like mkdir -p except portable. function mkdir(path) if path:sub(1,1) ~= "/" then path = os.getenv("PWD") .. "/" .. path end path = path:gsub("/$", "") path = path:gsub("/+", "/") path = path:gsub("/[^/]+/%.%.", "") path = path:gsub("%./", "") path = path:gsub("/%.", "") local compound = "" for component in path:gmatch("(/[^/]*)") do compound = compound .. component if not is_directory(compound) then local result = os.execute(string.format("mkdir %q", compound)) if result ~= 0 then os.exit(1) end end end end -- Change the mode of a file or directory. function chmod(mode, filespec) if not mode or mode == "" then return end local result = os.execute(string.format("chmod %s %q", mode, filespec)) if result ~= 0 then os.exit(1) end end -- Install a file. If destination is a directory, the source will be -- installed into the directory with the same name. function install(mode, source, dest) if is_directory(dest) then dest = dest .. "/" .. basename(source) end local result = os.execute(string.format("cp %q %q", source, dest)) if result == 0 then chmod(mode, dest) else os.exit(1) end end files = {} -- Consume and parse each argument. while 0 < #arg do local v = shift() if v == "-h" or v == "--help" then show_help() os.exit(0) end if v == "-m" then mode = shift() else table.insert(files, v) end end -- Check the arguments and determine the target. if #files < 2 then show_help() os.exit(1) else target = table.remove(files) end -- Perform the installation. if 1 < #files then mkdir(target) for i,file in ipairs(files) do install(mode, file, target) end else mkdir(dirname(target)) install(mode, files[1], target) end