#!/bin/sh
SH=--[[ # -*- mode: lua; -*-
## Slingshot rockspec generator.
##
## This file is distributed with Slingshot, and licensed under the
## terms of the MIT license reproduced below.
## ====================================================================
## Copyright (C) 2013-2015 Gary V. Vaughan
##
## Permission is hereby granted, free of charge, to any person
## obtaining a copy of this software and associated documentation
## files (the "Software"), to deal in the Software without restriction,
## including without limitation the rights to use, copy, modify, merge,
## publish, distribute, sublicense, and/or sell copies of the Software,
## and to permit persons to whom the Software is furnished to do so,
## subject to the following conditions:
##
## The above copyright notice and this permission notice shall be
## included in all copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGE-
## MENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
## FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
## CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
## WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## ====================================================================
_lua_version_re='"Lua 5."[123]*'
_lua_binaries='lua lua5.3 lua53 lua5.2 lua52 luajit lua5.1 lua51'
export LUA
export LUA_INIT
export LUA_INIT_5_2
export LUA_INIT_5_3
export LUA_PATH
export LUA_CPATH
# Be Bourne compatible
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
emulate sh
NULLCMD=:
# Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
setopt NO_GLOB_SUBST
else
case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
fi
# If LUA is not set, search PATH for something suitable.
test -n "$LUA" || {
# Check that the supplied binary is executable and returns a compatible
# Lua version number.
func_vercheck ()
{
test -x "$1" && {
eval 'case `'$1' -e "print (_VERSION)" 2>/dev/null` in
'"$_lua_version_re"') LUA='$1' ;;
esac'
}
}
progname=`echo "$0" |${SED-sed} 's|.*/||'`
save_IFS="$IFS"
LUA=
for x in $_lua_binaries; do
IFS=:
for dir in $PATH; do
IFS="$save_IFS"
func_vercheck "$dir/$x"
test -n "$LUA" && break
done
IFS="$save_IFS"
test -n "$LUA" && break
e="${e+$e\n}$progname: command not found on PATH: $x"
done
}
test -n "$LUA" || {
printf "${e+$e\n}$progname: retry after 'export LUA=/path/to/lua'\n" >&2
exit 1
}
LUA_INIT=
LUA_INIT_5_2=
LUA_INIT_5_3=
# Reexecute using the interpreter suppiled in LUA, or found above.
exec "$LUA" "$0" "$@"
]]SH
--[[ ============== ]]--
--[[ Parse options. ]]--
--[[ ============== ]]--
local usage = 'Usage: mkrockspecs [OPTIONS] PACKAGE VERSION [REVISION] [FILE]\n'
prog = {
name = arg[0] and arg[0]:gsub (".*/", "") or "mkrockspecs",
opts = {},
}
-- Print an argument processing error message, and return non-zero exit
-- status.
local function opterr (msg)
io.stderr:write (usage)
io.stderr:write (prog.name .. ": error: " .. msg .. ".\n")
io.stderr:write (prog.name .. ": Try '" .. prog.name .. " --help' for help,\n")
os.exit (2)
end
local function setopt (optname, arglist, i)
local opt = arglist[i]
if i + 1 > #arglist then
opterr ("option '" .. opt .. "' requires an argument")
end
prog.opts[optname] = arglist[i + 1]
return i + 1
end
local function die (msg)
msg:gsub ("([^\n]+)\n?",
function ()
io.stderr:write (prog.name .. ": error: " .. msg.. "\n")
end)
os.exit (1)
end
prog["--help"] = function ()
print (usage .. [[
Convert a YAML configuration file into a full rockspec.
If FILE is provided, load it as the base configuration, otherwise if
there is a 'rockspec.conf' in the current directory use that, or else
wait for input on stdin. If FILE is '-', force reading base config-
uration from stdin.
PACKAGE and VERSION are the package name and version number as defined
by 'configure.ac' or similar. REVISION is only required for a revised
rockspec if the default "-1" revision was released with errors.
-b, --branch=BRANCH make git rockspec use BRANCH
-m, --module-dir=ROOT directory of lua-files for builtin build type
-r, --repository=REPO set the repository name (default=PACKAGE)
--help print this help, then exit
--version print version number, then exit
Report bugs to http://github.com/gvvaughan/slingshot/issues.]])
os.exit (0)
end
prog["--version"] = function ()
print [[mkrockspecs (slingshot) 8.0.0
Written by Gary V. Vaughan <gary@gnu.org>, 2013
Copyright (C) 2013, Gary V. Vaughan
Slingshot comes with ABSOLUTELY NO WARRANTY.
See source files for individual license conditions.]]
os.exit (0)
end
prog["-b"] = function (argl, i) return setopt ("branch", argl, i) end
prog["--branch"] = prog["-b"]
prog["-m"] = function (argl, i) return setopt ("module_root", argl, i) end
prog["--module-dir"] = prog["-m"]
prog["-r"] = function (argl, i) return setopt ("repository", argl, i) end
prog["--repository"] = prog["-r"]
local nonopts
local i = 0
while i < #arg do
i = i + 1
local opt = arg[i]
-- Collect remaining arguments not nonopts to save back into _G.arg later.
if type (nonopts) == "table" then
table.insert (nonopts, opt)
-- Run prog.option handler.
elseif opt:sub (1,1) == "-" and type (prog[opt]) == "function" then
i = prog[opt] (arg, i)
-- End of option arguments.
elseif opt == "--" then
nonopts = {}
-- Diagnose unknown command line options.
elseif opt:sub (1, 1) == "-" then
opterr ("unrecognized option '" .. opt .. "'")
-- First non-option argument marks the end of options.
else
nonopts = { opt }
end
end
-- put non-option args back into global arg table.
nonopts = nonopts or {}
nonopts[0] = arg[0]
_G.arg = nonopts
if select ("#", ...) < 2 then
opterr ("only " .. select ("#", ...) .. " arguments provided")
end
local package = arg[1]
local version = arg[2]
local revision = arg[3] or "1"
local conf = arg[4] or "rockspec.conf"
-- Unless set explicity, assume the repo is named after the package.
if prog.opts.repository == nil then
prog.opts.repository = package
end
--[[ ================= ]]--
--[[ Helper functions. ]]--
--[[ ================= ]]--
local ok, posix = pcall (require, "posix")
files = {}
if ok then
-- faster version if luaposix is available
function tree (root)
for f in posix.files (root) do
local path = root .. "/" .. f
if f:match ("%.lua$") then
table.insert (files, path)
elseif f == "." or f == ".." then
-- don't go into a loop
elseif posix.stat (path, "type") == "directory" then
tree (path)
end
end
end
else
-- fallback version that executes ls in subshells
function tree (root)
local p = io.popen ("ls -1 " .. root .. " 2>/dev/null")
if p ~= nil then
local f = p:read "*l"
while f ~= nil do
if f:match ("%.lua$") then
table.insert (files, root .. "/" .. f)
else
tree (root .. "/" .. f)
end
f = p:read "*l"
end
end
end
end
local function escape_pattern (s)
return (string.gsub (s, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0"))
end
local function loadmap (root)
local map = {}
tree (root)
for _, f in ipairs (files) do
local m = f:match ("^" .. escape_pattern (root) .. "/(.*)%.lua")
map [m:gsub ("/", "."):gsub ("%.init$", "")] = f:gsub ("^%./", "")
end
return map
end
--[[ =================== ]]--
--[[ Load configuration. ]]--
--[[ =================== ]]--
local yaml = require "lyaml"
-- Slurp io.input ().
local function slurp ()
h = io.input ()
if h then
local s = h:read "*a"
h:close ()
return s
end
end
if conf == "-" then
io.input (io.stdin)
else
local h = io.open (conf)
if h then
io.input (conf)
h:close ()
else
io.input (io.stdin)
end
end
local spec = yaml.load (slurp ())
local default = { source = {} }
-- url needn't be given if it is identical to homepage.
local url
if spec.source ~= nil then
url = spec.source.url
elseif spec.description ~= nil then
url = spec.description.homepage
else
die (conf .. ": could not find source.url or description.homepage")
end
url = url:gsub ("^[a-z]*://", ""):gsub ("%.git$", "")
-- Interpolate default values.
default.package = package
default.version = version .. "-" .. revision
configure_flags = ""
if type (spec.external_dependencies) == "table" then
CPPFLAGS, LDFLAGS = "", ""
for name, vars in pairs (spec.external_dependencies) do
if vars.library then
CPPFLAGS = CPPFLAGS .. " -I$(" .. name .. "_INCDIR)"
LDFLAGS = LDFLAGS .. " -L$(" .. name .. "_LIBDIR)"
end
end
if string.len (CPPFLAGS) > 0 then
configure_flags = configure_flags ..
"CPPFLAGS='" .. CPPFLAGS:gsub ("^%s", "") .. "'" ..
" LDFLAGS='" .. LDFLAGS:gsub ("^%s", "") .. "'" ..
" "
end
end
-- If we have a module root, use the luarocks "builtin" type.
if version ~= "scm" and version ~= "git" then
if prog.opts.module_root ~= nil then
default.build = {
type = "builtin",
modules = loadmap (prog.opts.module_root),
}
elseif spec.build ~= nil and spec.build.modules ~= nil then
default.build = { type = "builtin" }
end
end
default.build = default.build or {
type = "command",
build_command = "./configure " ..
"LUA='$(LUA)' LUA_INCLUDE='-I$(LUA_INCDIR)' " .. configure_flags ..
"--prefix='$(PREFIX)' --libdir='$(LIBDIR)' --datadir='$(LUADIR)' " ..
"--datarootdir='$(PREFIX)' && make clean all",
install_command = "make install luadir='$(LUADIR)' luaexecdir='$(LIBDIR)'",
copy_directories = {},
}
-- Additional spec-type dependent values.
spec.source = spec.source or {}
spec.build = spec.build or {}
if version ~= "scm" and version ~= "git" then
spec.source.url = "http://" .. url .. "/archive/release-v" .. version .. ".zip"
spec.source.dir = prog.opts.repository .. "-release-v" .. version
else
spec.source.url = "git://" .. url .. ".git"
spec.source.branch = prog.opts.branch
spec.build.modules = nil
default.build.build_command = "./bootstrap && " .. default.build.build_command
end
-- Recursive merge, settings from spec take precedence. Elements of src
-- overwrite equivalent keys in dest.
local function merge (dest, src)
for k, v in pairs (src) do
if type (v) == "table" then
dest[k] = merge (dest[k] or {}, src[k])
else
dest[k] = src[k]
end
end
return dest
end
spec = merge (default, spec)
--[[ ======= ]]--
--[[ Output. ]]--
--[[ ======= ]]--
-- Recursively format X, with pretty printing.
local function format (x, indent)
indent = indent or ""
if type (x) == "table" then
if next (x) == nil then
return "{}"
else
local s = "{\n"
-- Collect and sort non-numeric keys first.
keys = {}
for k in pairs (x) do
if type (k) ~= "number" then table.insert (keys, k) end
end
table.sort (keys, function (a, b) return tostring (a) < tostring (b) end)
-- Display non-numeric key pairs in sort order.
for _, k in ipairs (keys) do
s = s .. indent
if k:match ("[^_%w]") then
-- wrap keys with non-%w chars in square brackets
s = s .. '["' .. k .. '"]'
else
s = s .. k
end
s = s .. " = " .. format (x[k], indent .. " ") .. ",\n"
end
-- And numeric key pairs last.
for i, v in ipairs (x) do
s = s .. indent .. format (v, indent .. " ") .. ",\n"
end
return s..indent:sub (1, -3).."}"
end
elseif type (x) == "string" then
return string.format ("%q", x)
else
return tostring (x)
end
end
-- Use the standard order for known keys.
for _, k in ipairs {
"package",
"version",
"description",
"source",
"dependencies",
"external_dependencies",
"build",
} do
print (k .. " = " .. format (spec[k], " "))
spec[k] = nil
end
-- Output anything left in the table at the end.
for i, v in pairs (spec) do
print (i .. " = " .. format (v, " "))
end
os.exit (0)