Created
September 28, 2013 13:37
-
-
Save stevedonovan/6742163 to your computer and use it in GitHub Desktop.
A simple Lua install script for Lua modules, extensions and scripts. Tested on Windows and Linux.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env lua | |
--[[ -- installing LDoc | |
function install() | |
-- requires('pl','Penlight') | |
-- install_script 'ldoc' | |
end | |
--]] | |
-- --[[ | |
function install() | |
requires ('lfs','luafilesystem') | |
from 'lua' | |
install_lua_package 'mod' | |
end | |
--]] | |
function install_lua_package (dir) | |
copyd(join(dir),lua_lpath()) | |
end | |
function install_ext_package (dir) | |
copyd(join(dir),lua_cpath()) | |
end | |
function install_lua (mod) | |
local file = mod2file(mod)..'.lua' | |
copyf(join(file),lpath) | |
end | |
function install_ext (mod) | |
local file = mod2file(mod)..DEXT | |
copyf(join(file),cpath) | |
end | |
function install_script (file) | |
file = join(file) | |
local bindir = check_bin_dir() | |
local name = file | |
if not exists(file) then | |
file = exists(file..'.lua') | |
if not file then quit("cannot find script") end | |
end | |
local pwd = cwd() | |
local dest = bindir..DIRSEP..name..SEXT | |
local f,e = io.open(dest,'w') | |
if not f then quit("cannot create script "..e) end | |
print('writing',dest) | |
if WINDOWS then | |
f:write '@echo off\n' | |
f:write (LUA,' ',pwd,'\\',file,' %*\n') | |
else | |
f:write(LUA,' ',pwd,'/',file,' "$@"\n') | |
end | |
f:close() | |
if not WINDOWS then | |
run_command('chmod +x '..dest) | |
end | |
end | |
function cwd () | |
return result_run_command(CWD) | |
end | |
function result_run_command(cmd) | |
local f,e = io.popen(cmd..' 2>&1') | |
if e then quit(e) end | |
local res = f:read '*a':gsub('\n$','') | |
f:close() | |
return res | |
end | |
function mod2file (mod) | |
return (mod:gsub('%.','/')) | |
end | |
function copyf(src, dest) | |
if not exists(src) then quit("cannot find '"..src.."'") end | |
local dir = src:match('.-[/\\](.-)[%w_]+%.%a+$') | |
print ('dir',dir) | |
if WINDOWS then | |
run_command( 'xcopy /S /I /Y '..src..' '..quote(dest..dir)) | |
else | |
local target_dir = dest..dir | |
mkdir(target_dir) | |
run_command('cp -r '..src..' '..target_dir) | |
end | |
end | |
function copyd(src,dest) | |
local dirname = src:match '[%w_]+$' | |
if WINDOWS then | |
run_command('xcopy /S /I /Y '..src..' '..quote(dest..dirname)) | |
else | |
mkdir(dest) | |
run_command('cp -r '..src..' '..dest) | |
end | |
end | |
function run_command(cmd,dont_fail) | |
print(cmd) | |
local res,x1,x2 = os.execute(cmd) | |
-- Lua 5.1/5.2 compatible check | |
local ff | |
if res == nil or (type(res) == 'number' and res ~= 0) then | |
if not dont_fail then | |
quit 'command failed: were you running as an administrator?' | |
end | |
end | |
end | |
function exists(file) | |
local f = io.open(file) | |
if not f then return nil | |
else f:close(); return file | |
end | |
end | |
function err (msg) | |
io.stderr:write('install: ',msg,'\n') | |
end | |
function quit(msg) | |
err(msg) | |
os.exit(1) | |
end | |
function requires(mod,name,nofail) | |
local ok | |
if type(mod) == 'table' then | |
ok = true | |
for i = 1,#mod,2 do | |
ok = ok and requires(mod[i],mod[i+1],true) | |
end | |
if ok then return true end | |
else | |
ok = pcall(require,mod) | |
if not ok then | |
err('this package requires '..name) | |
end | |
end | |
if not ok and not nofail then | |
quit("unmet dependencies") | |
end | |
return ok | |
end | |
function check(mod) | |
requires(mod,'failed') | |
end | |
local created = {} | |
function mkdir(dest) | |
if not created[dest] then | |
run_command('mkdir -p '..dest) | |
created[dest] = true | |
end | |
end | |
function quote (f) | |
if WINDOWS and f:match '%s' then | |
f = '"'..f..'"' | |
end | |
return f | |
end | |
function isabs (f) | |
return f:match(ABSPAT) | |
end | |
function canonical (f) | |
if not WINDOWS then return f end | |
return f:gsub('/','\\'):lower() | |
end | |
local src_dir | |
function from (dir) | |
src_dir = dir | |
end | |
function join (p) | |
p = canonical(p) | |
if not src_dir then return p end | |
return src_dir..DIRSEP..p | |
end | |
DIRSEP = package.config:sub(1,1) | |
WINDOWS = DIRSEP == '\\' | |
if not WINDOWS then | |
DEXT = '.so' | |
ABSPAT = '^/' | |
SEXT = '' | |
CWD = 'pwd' | |
else | |
DEXT = '.dll' | |
ABSPAT = '^%a:\\' | |
SEXT = '.bat' | |
CWD = 'cd' | |
end | |
local opath = os.getenv 'PATH' | |
-- find all directories in a list which are writeable by current user | |
function user_writeable(paths) | |
local results, append = {}, table.insert | |
local me = os.getenv 'USER' | |
local f = io.popen('ls -ld '..paths..' 2>&1') | |
for line in f:lines() do | |
local type,id,user = line:match '(%S+)%s+(%S+)%s+(%S+)' | |
if user == me then | |
line = line:match '(%S+)$' | |
append(results,line) | |
end | |
end | |
f:close() | |
return results | |
end | |
-- are we sudo? | |
if not WINDOWS then | |
local f = io.popen 'id -u' | |
local res = f:read() | |
f:close() | |
SUDO = res == '0' | |
end | |
local bindir | |
function which(prog) | |
if not prog:match '%.exe$' then prog = prog..'.exe' end | |
for dir in opath:gmatch '[^;]+' do | |
local file = exists(dir..DIRSEP..prog) | |
if file then return file end | |
end | |
end | |
-- if we are God, then use /usr/local/bin; otherwise try to see if $HOME/bin | |
-- is on the path and actually exists. | |
-- For Windows, use the Lua binary directory for scripts. | |
function check_bin_dir() | |
if bindir then return bindir end | |
if WINDOWS then | |
if not isabs(LUA) then | |
LUA = which (LUA) | |
end | |
bindir = LUA:match '(.+)\\' | |
else | |
if SUDO then | |
bindir = '/usr/local/bin' | |
else -- let's go for a hunt | |
bindir = os.getenv 'HOME'..'/bin' | |
local paths = user_writeable(opath:gsub(':',' ')) | |
if not contains(paths,bindir) then | |
quit("sorry cannot install binary without superuser permissions") | |
end | |
end | |
end | |
return bindir | |
end | |
function contains(ls,value) | |
for _, v in ipairs(ls) do | |
if v == value then return true end | |
end | |
return false | |
end | |
-- On Unix, the idea here is to find a Lua module path that is user writeable. | |
-- find absolute Lua module paths | |
function find_lua_path(package_path) | |
local paths, append = {}, table.insert | |
for p in package_path:gmatch('[^;]+') do | |
if isabs(p) then | |
-- get the path with trailiing slash and nothing afterwards | |
append(paths, p:match ('[^?]+')) | |
end | |
end | |
if not WINDOWS then | |
paths = user_writeable(table.concat(paths,' ')) | |
if #paths == 0 then | |
quit("sorry cannot install Lua module without superuser permissions") | |
end | |
end | |
return paths[1] | |
end | |
local lpath,cpath | |
function lua_lpath() | |
if lpath then return lpath end | |
lpath = find_lua_path(package.path) | |
return lpath | |
end | |
function lua_cpath() | |
if cpath then return cpath end | |
cpath = find_lua_path(package.cpath) | |
return cpath | |
end | |
LUA = arg[-1] | |
install() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment