#!/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 , 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)