diff --git a/.gitignore b/.gitignore index 7c99134..d907c43 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ *.lua -/out/* diff --git a/Alfons.moon b/Alfons.moon new file mode 100644 index 0000000..c271a7c --- /dev/null +++ b/Alfons.moon @@ -0,0 +1,7 @@ +tasks: + build: => + sh "moon bin/moonbuild.moon -jy" + release: => + error "no version provided" unless @v + tasks.build! + sh "rockbuild -m -t #{@v} upload" diff --git a/out/moonbuild b/out/moonbuild new file mode 100755 index 0000000..bab000d --- /dev/null +++ b/out/moonbuild @@ -0,0 +1,2601 @@ +#!/usr/bin/env lua5.3 +do + +do +local _ENV = _ENV +package.preload[ "moonbuild._" ] = function( ... ) local arg = _G.arg; +local gmatch, match, gsub +do + local _obj_0 = string + gmatch, match, gsub = _obj_0.gmatch, _obj_0.match, _obj_0.gsub +end +local insert, remove, concat, sub, sort +do + local _obj_0 = table + insert, remove, concat, sub, sort = _obj_0.insert, _obj_0.remove, _obj_0.concat, _obj_0.sub, _obj_0.sort +end +local _fs = require('moonbuild._fs') +local _cmd = require('moonbuild._cmd') +local _util = require('moonbuild._util') +local _common = require('moonbuild._common') +local _ = { } +for k, lib in pairs({ + _fs = _fs, + _cmd = _cmd, + _util = _util, + _common = _common +}) do + _[k] = lib + local _list_0 = lib() + for _index_0 = 1, #_list_0 do + local n = _list_0[_index_0] + _[n] = lib[n] + end +end +return _ +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild._cmd" ] = function( ... ) local arg = _G.arg; +local parseargs, escape +do + local _obj_0 = require('moonbuild._cmd.common') + parseargs, escape = _obj_0.parseargs, _obj_0.escape +end +local ok, cmd, backend = false, nil, nil +if not (ok) then + ok, cmd = pcall(function() + return require('moonbuild._cmd.posix') + end) + backend = 'posix' +end +if not (ok) then + ok, cmd = pcall(function() + return require('moonbuild._cmd.lua') + end) + backend = 'lua' +end +if not (ok) then + error("unable to load any cmd library, tried luaposix and posix commands") +end +do + local _tbl_0 = { } + for k, v in pairs(cmd) do + _tbl_0[k] = v + end + cmd = _tbl_0 +end +cmd.backend = backend +cmd.parseargs = parseargs +cmd.escape = escape +return setmetatable(cmd, { + __call = function(self) + return { + 'cmd', + 'cmdrst', + 'sh' + } + end +}) +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild._cmd.common" ] = function( ... ) local arg = _G.arg; +local gsub, sub, match +do + local _obj_0 = string + gsub, sub, match = _obj_0.gsub, _obj_0.sub, _obj_0.match +end +local concat +concat = table.concat +local specialchars = { + ['\"'] = '\\\"', + ['\\'] = '\\\\', + ['\''] = '\\\'', + ['\n'] = '\\n', + ['\r'] = '\\r', + ['\t'] = '\\t' +} +local replacespecialchar +replacespecialchar = function(c) + return specialchars[c] or c +end +local escape +escape = function(arg) + if match(arg, "^[a-zA-Z0-9_.-]+$") then + return arg + end + return '"' .. (gsub(arg, "([\"\\\n\r\t])", replacespecialchar)) .. '"' +end +local parseargs +parseargs = function(argstr) + local state = 'normal' + local current, ci = { }, 1 + local args, ai = { }, 1 + local c = nil + local i = 0 + local running = true + local add + add = function() + current[ci], ci = c, ci + 1 + end + local push + push = function() + if ci ~= 1 then + args[ai], ai, current, ci = (concat(current)), ai + 1, { }, 1 + end + end + local addv + addv = function(v) + current[ci], ci = v, ci + 1 + end + local fail + fail = function(msg) + return error("failed to parse: " .. tostring(msg) .. " in state " .. tostring(state) .. " at pos " .. tostring(i), 2) + end + local finish + finish = function() + running = false + end + local EOF = '' + while running do + i = i + 1 + c = sub(argstr, i, i) + local _exp_0 = state + if 'normal' == _exp_0 then + local _exp_1 = c + if '\"' == _exp_1 then + state = 'doublequote' + elseif '\'' == _exp_1 then + state = 'singlequote' + elseif ' ' == _exp_1 then + push() + elseif '\n' == _exp_1 then + push() + elseif '\t' == _exp_1 then + push() + elseif '\\' == _exp_1 then + state = 'backslashnormal' + elseif EOF == _exp_1 then + push() + finish() + else + add() + end + elseif 'doublequote' == _exp_0 then + local _exp_1 = c + if '\"' == _exp_1 then + state = 'normal' + elseif '\\' == _exp_1 then + state = 'backslashdoublequote' + elseif EOF == _exp_1 then + fail("unexpected EOF") + else + add() + end + elseif 'singlequote' == _exp_0 then + local _exp_1 = c + if '\'' == _exp_1 then + state = 'normal' + elseif EOF == _exp_1 then + fail("unexpected EOF") + else + add() + end + elseif 'backslashnormal' == _exp_0 then + local _exp_1 = c + if '\n' == _exp_1 then + state = 'normal' + elseif EOF == _exp_1 then + fail("unexpected EOF") + else + add() + state = 'normal' + end + elseif 'backslashdoublequote' == _exp_0 then + local _exp_1 = c + if '$' == _exp_1 then + add() + state = 'doublequote' + elseif '`' == _exp_1 then + add() + state = 'doublequote' + elseif '\"' == _exp_1 then + add() + state = 'doublequote' + elseif '\\' == _exp_1 then + add() + state = 'doublequote' + elseif '\n' == _exp_1 then + state = 'doublequote' + elseif EOF == _exp_1 then + fail("unexpected EOF") + else + addv('\\') + add() + state = 'doublequote' + end + end + end + return args +end +return { + escape = escape, + parseargs = parseargs +} +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild._cmd.lua" ] = function( ... ) local arg = _G.arg; +local escape +escape = require('moonbuild._cmd.common').escape +local flatten +flatten = require('moonbuild._common').flatten +local execute +execute = require('moonbuild.compat.execute').execute +local popen +popen = io.popen +local concat +concat = table.concat +local cmdline +cmdline = function(...) + return concat((function(...) + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = flatten(...) + for _index_0 = 1, #_list_0 do + local arg = _list_0[_index_0] + _accum_0[_len_0] = escape(arg) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(...), ' ') +end +local cmd +cmd = function(...) + local ok, ret, code = execute(cmdline(...)) + if not (ok) then + return error("command " .. tostring(first(...)) .. " exited with " .. tostring(code) .. " (" .. tostring(ret) .. ")") + end +end +local cmdrst +cmdrst = function(...) + local fd, err = popen(cmdline(...)) + if not (fd) then + error(err) + end + local data = fd:read('*a') + fd:close() + return data +end +local sh +sh = function(cli) + local ok, ret, code = execute(cli) + if not (ok) then + return error("command '" .. tostring(cli) .. "' exited with " .. tostring(code) .. " (" .. tostring(ret) .. ")") + end +end +return { + cmd = cmd, + cmdrst = cmdrst, + sh = sh +} +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild._cmd.posix" ] = function( ... ) local arg = _G.arg; +local spawn +spawn = require('posix').spawn +local fork, execp, pipe, dup2, _exit, close +do + local _obj_0 = require('posix.unistd') + fork, execp, pipe, dup2, _exit, close = _obj_0.fork, _obj_0.execp, _obj_0.pipe, _obj_0.dup2, _obj_0._exit, _obj_0.close +end +local fdopen +fdopen = require('posix.stdio').fdopen +local wait +wait = require('posix.sys.wait').wait +local flatten, first +do + local _obj_0 = require('moonbuild._common') + flatten, first = _obj_0.flatten, _obj_0.first +end +local remove +remove = table.remove +local cmd +cmd = function(...) + local code, ty = spawn(flatten(...)) + if ty ~= 'exited' or code ~= 0 then + return error("command " .. tostring(first(...)) .. " " .. tostring(ty) .. " with code " .. tostring(code)) + end +end +local cmdrst +cmdrst = function(...) + local rd, wr = pipe() + local pid, err = fork() + if pid == 0 then + dup2(wr, 1) + close(rd) + local args = flatten(...) + local c = remove(args, 1) + execp(c, args) + return _exit(1) + end + if pid == nil then + close(rd) + close(wr) + error("command " .. tostring(first(...)) .. " failed to start: couldn't fork(): " .. tostring(err)) + end + close(wr) + local fd = fdopen(rd, 'r') + local data = fd:read('*a') + fd:close() + close(rd) + local _, ty, code = wait(pid) + if ty ~= 'exited' or code ~= 0 then + error("command " .. tostring(first(...)) .. " " .. tostring(ty) .. " with code " .. tostring(code)) + end + return data +end +local sh +sh = function(cli) + return cmd('sh', '-c', cli) +end +return { + cmd = cmd, + cmdrst = cmdrst, + sh = sh +} +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild._common" ] = function( ... ) local arg = _G.arg; +local sort, concat +do + local _obj_0 = table + sort, concat = _obj_0.sort, _obj_0.concat +end +local huge +huge = math.huge +local match, sub +do + local _obj_0 = string + match, sub = _obj_0.match, _obj_0.sub +end +local common = { } +local flatten +flatten = function(list, ...) + if (select('#', ...)) ~= 0 then + return flatten({ + list, + ... + }) + end + local t = type(list) + local _exp_0 = t + if 'nil' == _exp_0 then + return { } + elseif 'string' == _exp_0 then + return { + list + } + elseif 'number' == _exp_0 then + return { + tostring(list) + } + elseif 'boolean' == _exp_0 then + return { + list + } + elseif 'table' == _exp_0 then + local keys + do + local _accum_0 = { } + local _len_0 = 1 + for k in pairs(list) do + _accum_0[_len_0] = k + _len_0 = _len_0 + 1 + end + keys = _accum_0 + end + sort(keys) + local elements, i = { }, 1 + for _index_0 = 1, #keys do + local k = keys[_index_0] + if (type(k)) == 'number' then + local _list_0 = (flatten(list[k])) + for _index_1 = 1, #_list_0 do + local e = _list_0[_index_1] + elements[i], i = e, i + 1 + end + else + return { + list + } + end + end + return setmetatable(elements, { + __tostring = function(self) + return concat(self, ' ') + end + }) + else + return error("can't flatten elements of type " .. tostring(t)) + end +end +local first +first = function(list, ...) + local t = type(list) + local _exp_0 = t + if 'nil' == _exp_0 then + if (select('#', ...)) == 0 then + return nil + else + return first(...) + end + elseif 'string' == _exp_0 then + return list + elseif 'number' == _exp_0 then + return tostring(list) + elseif 'boolean' == _exp_0 then + return list + elseif 'table' == _exp_0 then + local min = huge + for k in pairs(list) do + if (type(k)) == 'number' then + if k < min then + min = k + end + else + return list + end + end + return first(list[min]) + else + return error("can't find first of type " .. tostring(t)) + end +end +local foreach +foreach = function(list, fn) + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = flatten(list) + for _index_0 = 1, #_list_0 do + local v = _list_0[_index_0] + _accum_0[_len_0] = fn(v) + _len_0 = _len_0 + 1 + end + return _accum_0 +end +local filter +filter = function(list, fn) + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = flatten(list) + for _index_0 = 1, #_list_0 do + local v = _list_0[_index_0] + if fn(v) then + _accum_0[_len_0] = v + _len_0 = _len_0 + 1 + end + end + return _accum_0 +end +local includes +includes = function(list, v) + if list == v then + return true + end + if (type(list)) == 'table' then + for k, e in pairs(list) do + if (type(k)) == 'number' then + if includes(e, v) then + return true + end + end + end + end + if (type(list)) == 'number' then + return (tostring(list)) == (tostring(v)) + end + return false +end +local patget +patget = function(s, pat) + local prefix, suffix = match(pat, '^(.*)%%(.*)$') + if not (prefix) then + return s == pat and s or nil + end + if (sub(s, 1, #prefix)) == prefix and (suffix == '' or (sub(s, -#suffix)) == suffix) then + return sub(s, #prefix + 1, -#suffix - 1) + else + return nil + end +end +local patset +patset = function(s, rep) + local prefix, suffix = match(rep, '^(.*)%%(.*)$') + if prefix then + return prefix .. s .. suffix + else + return rep + end +end +local patsubst +patsubst = function(s, pat, rep) + local prefix, suffix = match(pat, '^(.*)%%(.*)$') + local rprefix, rsuffix = match(rep, '^(.*)%%(.*)$') + local t = type(s) + local f = false + if t == 'nil' then + return nil + end + if t == 'number' then + t = 'string' + s = tostring(s) + end + if t == 'string' then + t = 'table' + s = { + s + } + f = true + end + if t ~= 'table' then + error("can't substitute patterns on type " .. tostring(t)) + end + local r, i = { }, 1 + local _list_0 = flatten(s) + for _index_0 = 1, #_list_0 do + local s = _list_0[_index_0] + if not prefix then + if s == pat then + if rprefix then + r[i], i = rprefix .. s .. rsuffix, i + 1 + else + r[i], i = rep, i + 1 + end + end + elseif (sub(s, 1, #prefix)) == prefix and (suffix == '' or (sub(s, -#suffix)) == suffix) then + if rprefix then + r[i], i = rprefix .. (sub(s, #prefix + 1, -#suffix - 1)) .. rsuffix, i + 1 + else + r[i], i = rep, i + 1 + end + end + end + return f and r[1] or r +end +local exclude +exclude = function(list, ...) + local exclusions = flatten(...) + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = flatten(list) + for _index_0 = 1, #_list_0 do + local v = _list_0[_index_0] + if not includes(exclusions, v) then + _accum_0[_len_0] = v + _len_0 = _len_0 + 1 + end + end + return _accum_0 +end +local min +min = function(list) + local m = list[1] + for i = 2, #list do + local e = list[i] + if e < m then + m = e + end + end + return m +end +local max +max = function(list) + local m = list[1] + for i = 2, #list do + local e = list[i] + if e > m then + m = e + end + end + return m +end +local minmax +minmax = function(list) + local m = list[1] + local M = list[1] + for i = 2, #list do + local e = list[i] + if e < m then + m = e + end + if e > M then + M = e + end + end + return m, M +end +common.flatten = flatten +common.first = first +common.foreach = foreach +common.filter = filter +common.includes = includes +common.patget = patget +common.patset = patset +common.patsubst = patsubst +common.min = min +common.max = max +common.minmax = minmax +return setmetatable(common, { + __call = function(self) + local _accum_0 = { } + local _len_0 = 1 + for k in pairs(common) do + _accum_0[_len_0] = k + _len_0 = _len_0 + 1 + end + return _accum_0 + end +}) +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild._fs" ] = function( ... ) local arg = _G.arg; +local remove, concat +do + local _obj_0 = table + remove, concat = _obj_0.remove, _obj_0.concat +end +local gmatch, match, gsub, sub +do + local _obj_0 = string + gmatch, match, gsub, sub = _obj_0.gmatch, _obj_0.match, _obj_0.gsub, _obj_0.sub +end +local ok, fs, backend = false, nil, nil +if not (ok) then + ok, fs = pcall(function() + return require('moonbuild._fs.posix') + end) + backend = 'posix' +end +if not (ok) then + ok, fs = pcall(function() + return require('moonbuild._fs.lfs') + end) + backend = 'lfs' +end +if not (ok) then + ok, fs = pcall(function() + return require('moonbuild._fs.cmd') + end) + backend = 'cmd' +end +if not (ok) then + error("unable to load any fs library, tried luaposix, luafilesystem and posix commands") +end +local DISABLED = (function() + return DISABLED +end) +local NIL = (function() + return NIL +end) +local cacheenabled = true +local caches = { } +local clearcache +clearcache = function() + for k, v in pairs(caches) do + v.clearcache() + end +end +local clearentry +clearentry = function(entry) + for k, v in pairs(caches) do + v.clearentry(entry) + end +end +local disableentry +disableentry = function(entry) + for k, v in pairs(caches) do + v.disableentry(entry) + end +end +local disablecache +disablecache = function() + cacheenabled = false +end +local enablecache +enablecache = function() + cacheenabled = true +end +local withcache +withcache = function(fn) + local opts = { } + opts.cache = { } + opts.clearcache = function() + opts.cache = { } + end + opts.clearentry = function(entry) + opts.cache[entry] = nil + end + opts.disableentry = function(entry) + opts.cache[entry] = DISABLED + end + caches[fn] = opts + return setmetatable(opts, { + __call = function(self, arg) + if not (cacheenabled) then + return fn(arg) + end + local cached = opts.cache[arg] + if cached == DISABLED then + return fn(arg) + end + if cached == NIL then + return nil + end + if cached ~= nil then + return cached + end + cached = fn(arg) + opts.cache[arg] = cached + if cached == nil then + opts.cache[arg] = NIL + end + return cached + end + }) +end +fs = { + dir = withcache(fs.dir), + attributes = withcache(fs.attributes), + mkdir = fs.mkdir +} +local attributes, dir, mkdir +attributes, dir, mkdir = fs.attributes, fs.dir, fs.mkdir +local normalizepath +normalizepath = function(file) + local parts + do + local _accum_0 = { } + local _len_0 = 1 + for part in gmatch(file, '[^/]+') do + _accum_0[_len_0] = part + _len_0 = _len_0 + 1 + end + parts = _accum_0 + end + local absolute = (sub(file, 1, 1)) == '/' + local i = 1 + while i <= #parts do + local _continue_0 = false + repeat + if parts[i] == '.' then + remove(parts, i) + _continue_0 = true + break + end + if parts[i] == '..' and i ~= 1 and parts[i - 1] ~= '..' then + remove(parts, i) + remove(parts, i - 1) + i = i - 1 + _continue_0 = true + break + end + i = i + 1 + _continue_0 = true + until true + if not _continue_0 then + break + end + end + if #parts == 0 then + return absolute and '/' or '.' + else + return (absolute and '/' or '') .. concat(parts, '/') + end +end +local ls +ls = function(d) + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = dir(normalizepath(d)) + for _index_0 = 1, #_list_0 do + local f = _list_0[_index_0] + if f ~= '.' and f ~= '..' then + _accum_0[_len_0] = f + _len_0 = _len_0 + 1 + end + end + return _accum_0 +end +local lswithpath +lswithpath = function(d) + if d == '' then + return ls('.') + end + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = dir(normalizepath(d)) + for _index_0 = 1, #_list_0 do + local f = _list_0[_index_0] + if f ~= '.' and f ~= '..' then + _accum_0[_len_0] = d .. '/' .. f + _len_0 = _len_0 + 1 + end + end + return _accum_0 +end +local matchglob +matchglob = function(str, glob) + glob = gsub(glob, '[%[%]%%+.?-]', function(self) + return '%' .. self + end) + local patt = '^' .. (gsub(glob, '%*%*?', function(self) + return self == '**' and '.*' or '[^/]*' + end)) .. '$' + local rst + if (type(str)) == 'table' then + local results, i = { }, 1 + for _index_0 = 1, #str do + local s = str[_index_0] + rst = (match(s, patt)) and s + if rst then + results[i], i = rst, i + 1 + end + end + rst = results + else + rst = (match(str, patt)) and str + end + return rst +end +local exists +exists = function(f) + return (attributes(normalizepath(f))) ~= nil +end +local isdir +isdir = function(f) + return ((attributes(normalizepath(f))) or { }).mode == 'directory' +end +local wildcard +wildcard = function(glob) + local parts + do + local _accum_0 = { } + local _len_0 = 1 + for part in gmatch(glob, '[^/]+') do + _accum_0[_len_0] = part + _len_0 = _len_0 + 1 + end + parts = _accum_0 + end + local absolute = (sub(glob, 1, 1)) == '/' + for i, part in ipairs(parts) do + local prevpath = (absolute and '/' or '') .. concat(parts, '/', 1, i - 1) + local currpath = (i == 1 and '' or (prevpath .. '/')) .. part + if match(part, '%*%*.*%*%*') then + error("Two '**' in the same path component in a wildcard") + end + if match(part, '%*%*') then + local prefix = match(currpath, '^(.*)%*%*') + local suffix = (match(part, '%*%*(.*)$')) .. (i == #parts and '' or ('/' .. concat(parts, '/', i + 1, #parts))) + if not (exists(prevpath)) then + return { } + end + local files = lswithpath(prevpath) + local results, ri = { }, 1 + for _index_0 = 1, #files do + local file = files[_index_0] + if matchglob(file, currpath) then + if i == #parts then + results[ri], ri = file, ri + 1 + elseif isdir(file) then + local _list_0 = wildcard(file .. '/' .. concat(parts, '/', i + 1, #parts)) + for _index_1 = 1, #_list_0 do + local result = _list_0[_index_1] + results[ri], ri = result, ri + 1 + end + end + end + if (matchglob(file, prefix .. '**')) and isdir(file) then + local _list_0 = wildcard(file .. '/**' .. suffix) + for _index_1 = 1, #_list_0 do + local result = _list_0[_index_1] + results[ri], ri = result, ri + 1 + end + end + end + return results + end + if match(part, '%*') then + if not (exists(prevpath)) then + return { } + end + local files = lswithpath(prevpath) + if i == #parts then + return matchglob(files, glob) + end + local results, ri = { }, 1 + for _index_0 = 1, #files do + local file = files[_index_0] + if (matchglob(file, currpath)) and isdir(file) then + local _list_0 = wildcard(file .. '/' .. concat(parts, '/', i + 1, #parts)) + for _index_1 = 1, #_list_0 do + local result = _list_0[_index_1] + results[ri], ri = result, ri + 1 + end + end + end + return results + end + end + if exists(glob) then + return { + glob + } + else + return { } + end +end +local parent +parent = function(file) + return normalizepath(file .. '/..') +end +local actualmkdir = mkdir +mkdir = function(dir) + actualmkdir(dir) + return clearentry(parent(dir)) +end +local mkdirs +mkdirs = function(dir) + if isdir(dir) then + return + end + if exists(dir) then + error("Can't mkdirs " .. tostring(dir) .. ": file exists") + end + mkdirs(parent(dir)) + return mkdir(dir) +end +do + local _tbl_0 = { } + for k, fn in pairs(fs) do + _tbl_0[k] = withcache(fn) + end + fs = _tbl_0 +end +fs.normalizepath = normalizepath +fs.ls = ls +fs.lswithpath = lswithpath +fs.matchglob = matchglob +fs.exists = exists +fs.isdir = isdir +fs.wildcard = wildcard +fs.parent = parent +fs.mkdir = mkdir +fs.mkdirs = mkdirs +fs.clearcache = clearcache +fs.clearentry = clearentry +fs.disableentry = disableentry +fs.disablecache = disablecache +fs.enablecache = enablecache +fs.backend = backend +return setmetatable(fs, { + __call = function(self) + return { + 'dir', + 'ls', + 'normalizepath', + 'exists', + 'isdir', + 'wildcard', + 'mkdir', + 'mkdirs' + } + end +}) +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild._fs.cmd" ] = function( ... ) local arg = _G.arg; +local escape +escape = require('moonbuild._cmd').escape +local execute +execute = require('moonbuild.compat.execute').execute +local popen +popen = io.popen +local gmatch, match, sub +do + local _obj_0 = string + gmatch, match, sub = _obj_0.gmatch, _obj_0.match, _obj_0.sub +end +if not ((execute("which ls >/dev/null 2>&1")) and (execute("which stat >/dev/null 2>&1"))) then + error("commands ls and stat aren't available") +end +return { + dir = function(path) + local _accum_0 = { } + local _len_0 = 1 + for file in (popen("ls -1 " .. tostring(escape(path)))):lines() do + _accum_0[_len_0] = file + _len_0 = _len_0 + 1 + end + return _accum_0 + end, + attributes = function(path) + local fd = popen("stat -c '%d %i %A %h %u %g %s %b %t %T %X %Y %Z' " .. tostring(escape(path))) + local stat + do + local _accum_0 = { } + local _len_0 = 1 + for part in gmatch((fd:read('*a')), "%S+") do + _accum_0[_len_0] = part + _len_0 = _len_0 + 1 + end + stat = _accum_0 + end + fd:close() + fd = popen("stat -f -c '%S' " .. tostring(escape(path))) + local blksize = match((fd:read('*a')), '%S+') + fd:close() + return { + dev = tonumber(stat[1]), + ino = tonumber(stat[2]), + nlink = tonumber(stat[4]), + uid = tonumber(stat[5]), + gid = tonumber(stat[6]), + size = tonumber(stat[7]), + blocks = tonumber(stat[8]), + blksize = tonumber(blksize), + access = tonumber(stat[11]), + modification = tonumber(stat[12]), + change = tonumber(stat[13]), + permissions = (function() + return sub(stat[3], 2) + end)(), + mode = (function() + local _exp_0 = sub(stat[3], 1, 1) + if '-' == _exp_0 then + return 'file' + elseif 'd' == _exp_0 then + return 'directory' + elseif 'l' == _exp_0 then + return 'link' + elseif 's' == _exp_0 then + return 'socket' + elseif 'p' == _exp_0 then + return 'named pipe' + elseif 'c' == _exp_0 then + return 'char device' + elseif 'b' == _exp_0 then + return 'block device' + else + return 'other' + end + end)(), + rdev = (function() + return (tonumber(stat[9])) * 256 + (tonumber(stat[10])) + end)() + } + end, + mkdir = function(path) + if not (execute("mkdir " .. tostring(escape(path)))) then + return error("Mkdir " .. tostring(path) .. " failed") + end + end +} +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild._fs.lfs" ] = function( ... ) local arg = _G.arg; +local dir, attributes, mkdir +do + local _obj_0 = require('lfs') + dir, attributes, mkdir = _obj_0.dir, _obj_0.attributes, _obj_0.mkdir +end +return { + dir = function(path) + local _accum_0 = { } + local _len_0 = 1 + for v in dir(path) do + _accum_0[_len_0] = v + _len_0 = _len_0 + 1 + end + return _accum_0 + end, + attributes = attributes, + mkdir = function(path) + local ok, err = mkdir(path) + if not (ok) then + return error("Failed to mkdir " .. tostring(path) .. ": " .. tostring(err)) + end + end +} +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild._fs.posix" ] = function( ... ) local arg = _G.arg; +local dir +dir = require('posix.dirent').dir +local stat, mkdir, S_IFMT, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLINK, S_IFREG, S_IFSOCK +do + local _obj_0 = require('posix.sys.stat') + stat, mkdir, S_IFMT, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLINK, S_IFREG, S_IFSOCK = _obj_0.stat, _obj_0.mkdir, _obj_0.S_IFMT, _obj_0.S_IFBLK, _obj_0.S_IFCHR, _obj_0.S_IFDIR, _obj_0.S_IFIFO, _obj_0.S_IFLINK, _obj_0.S_IFREG, _obj_0.S_IFSOCK +end +local band, btest +do + local _obj_0 = require('moonbuild.compat.bit') + band, btest = _obj_0.band, _obj_0.btest +end +local concat +concat = table.concat +return { + dir = dir, + attributes = function(path) + local st = stat(path) + if not (st) then + return nil + end + local mode = st.st_mode + return { + mode = (function() + local ty = band(mode, S_IFMT) + local _exp_0 = ty + if S_IFREG == _exp_0 then + return 'file' + elseif S_IFDIR == _exp_0 then + return 'directory' + elseif S_IFLINK == _exp_0 then + return 'link' + elseif S_IFSOCK == _exp_0 then + return 'socket' + elseif S_IFIFO == _exp_0 then + return 'named pipe' + elseif S_IFCHR == _exp_0 then + return 'char device' + elseif S_IFBLK == _exp_0 then + return 'block device' + else + return 'other' + end + end)(), + permissions = (function() + local _suid = btest(mode, 2048) + local _sgid = btest(mode, 1024) + local _stic = btest(mode, 512) + local _ur = btest(mode, 256) + local _uw = btest(mode, 128) + local _ux = btest(mode, 64) + local _gr = btest(mode, 32) + local _gw = btest(mode, 16) + local _gx = btest(mode, 8) + local _or = btest(mode, 4) + local _ow = btest(mode, 2) + local _ox = btest(mode, 1) + return concat({ + _ur and 'r' or '-', + _uw and 'w' or '-', + _suid and 's' or (_ux and 'x' or '-'), + _gr and 'r' or '-', + _gw and 'w' or '-', + _sgid and 's' or (_gx and 'x' or '-'), + _or and 'r' or '-', + _ow and 'w' or '-', + _stic and 't' or (_ox and 'x' or '-') + }) + end)(), + dev = st.st_dev, + ino = st.st_ino, + nlink = st.st_nlink, + uid = st.st_uid, + gid = st.st_gid, + rdev = st.st_rdev, + access = st.st_atime, + modification = st.st_mtime, + change = st.st_ctime, + size = st.st_size, + blocks = st.st_blocks, + blksize = st.st_blksize + } + end, + mkdir = function(path) + local ok, err = mkdir(path) + if not (ok) then + return error("Failed to mkdir " .. tostring(path) .. ": " .. tostring(err)) + end + end +} +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild._util" ] = function( ... ) local arg = _G.arg; +local to_lua +to_lua = require('moonscript.base').to_lua +local parseargs, cmdrst +do + local _obj_0 = require('moonbuild._cmd') + parseargs, cmdrst = _obj_0.parseargs, _obj_0.cmdrst +end +local gmatch, match, gsub +do + local _obj_0 = string + gmatch, match, gsub = _obj_0.gmatch, _obj_0.match, _obj_0.gsub +end +local open +open = io.open +local util = { } +local _pkgconfig +_pkgconfig = function(mode, ...) + return parseargs(cmdrst('pkg-config', "--" .. tostring(mode), ...)) +end +local pkgconfig = setmetatable({ }, { + __index = function(self, mode) + return function(...) + return _pkgconfig(mode, ...) + end + end +}) +local _cdeps +_cdeps = function(cc, cflags, path) + local raw = cmdrst(cc, cflags, '-M', path) + local rawlist = gsub((match(raw, ':(.+)')), '\\\n', ' ') + local _accum_0 = { } + local _len_0 = 1 + for v in gmatch(rawlist, '%S+') do + _accum_0[_len_0] = v + _len_0 = _len_0 + 1 + end + return _accum_0 +end +local cdeps = setmetatable({ }, { + __index = function(self, cc) + return function(cflags, path) + return _cdeps(cc, cflags, path) + end + end, + __call = function(self, cflags, path) + return _cdeps('cc', cflags, path) + end +}) +local readfile +readfile = function(filename) + local fd, err = open(filename, 'rb') + if not (fd) then + error(err) + end + local data + data, err = fd:read('*a') + if not (data) then + error(err) + end + fd:close() + return data +end +local writefile +writefile = function(filename, data) + local fd, err = open(filename, 'wb') + if not (fd) then + error(err) + end + local ok + ok, err = fd:write(data) + if not (ok) then + error(err) + end + fd:close() + return nil +end +local moonc +moonc = function(infile, outfile) + local code, err = to_lua(readfile(infile)) + if not (code) then + error("Failed to compile " .. tostring(self.infile) .. ": " .. tostring(err)) + end + return writefile(outfile, code) +end +util.pkgconfig = pkgconfig +util.cdeps = cdeps +util.readfile = readfile +util.writefile = writefile +util.moonc = moonc +return setmetatable(util, { + __call = function(self) + local _accum_0 = { } + local _len_0 = 1 + for k in pairs(util) do + _accum_0[_len_0] = k + _len_0 = _len_0 + 1 + end + return _accum_0 + end +}) +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.compat.bit" ] = function( ... ) local arg = _G.arg; +local loadstring = loadstring or load +local floor, ceil, pow +do + local _obj_0 = math + floor, ceil, pow = _obj_0.floor, _obj_0.ceil, _obj_0.pow +end +local band = loadstring([[local a, b = ...; return a & b ]]) +local bor = loadstring([[local a, b = ...; return a | b ]]) +local bxor = loadstring([[local a, b = ...; return a ~ b ]]) +local bnot = loadstring([[local a = ...; return ~a ]]) +local shl = loadstring([[local a, b = ...; return a << b]]) +local shr = loadstring([[local a, b = ...; return a >> b]]) +if not (band) then + local _checkint + _checkint = function(n) + if n % 1 == 0 then + return n + else + return error("not an int") + end + end + local _shl + _shl = function(a, b) + return a * pow(2, b) + end + local _shr + _shr = function(a, b) + local v = a / pow(2, b) + if v < 0 then + return ceil(v) + else + return floor(v) + end + end + local _shr1 + _shr1 = function(n) + n = n / 2 + if n < 0 then + return ceil(v) + else + return floor(v) + end + end + local _band + _band = function(a, b) + local v = 0 + local n = 1 + for i = 0, 63 do + if a % 2 == 1 and b % 2 == 1 then + v = v + n + end + if i ~= 63 then + a = _shr1(a) + b = _shr1(b) + n = n * 2 + end + end + return v + end + local _bor + _bor = function(a, b) + local v = 0 + local n = 1 + for i = 0, 63 do + if a % 2 == 1 or b % 2 == 1 then + v = v + n + end + if i ~= 63 then + a = _shr1(a) + b = _shr1(b) + n = n * 2 + end + end + return v + end + local _bxor + _bxor = function(a, b) + local v = 0 + local n = 1 + for i = 0, 63 do + if a % 2 ~= b % 2 then + v = v + n + end + if i ~= 63 then + a = _shr1(a) + b = _shr1(b) + n = n * 2 + end + end + return v + end + local _bnot + _bnot = function(a) + local v = 0 + local n = 1 + for i = 0, 63 do + if a % 2 == 0 then + v = v + n + end + if i ~= 63 then + a = _shr1(a) + n = n * 2 + end + end + return v + end + band = function(a, b) + return _band((_checkint(a)), (_checkint(b))) + end + bor = function(a, b) + return _bor((_checkint(a)), (_checkint(b))) + end + bxor = function(a, b) + return _bxor((_checkint(a)), (_checkint(b))) + end + bnot = function(a) + return _bnot((_checkint(a))) + end + shl = function(a, b) + return _shl((_checkint(a)), (_checkint(b))) + end + shr = function(a, b) + return _shr((_checkint(a)), (_checkint(b))) + end +end +local btest +btest = function(a, b) + return (band(a, b)) == b +end +return { + band = band, + bor = bor, + bxor = bxor, + bnot = bnot, + shl = shl, + shr = shr, + btest = btest +} +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.compat.ctx" ] = function( ... ) local arg = _G.arg; +local pcall = require('moonbuild.compat.pcall') +local runwithcontext +if setfenv then + runwithcontext = function(fn, ctx, ...) + local env = getfenv(fn) + setfenv(fn, ctx) + local data, ndata, ok + local acc + acc = function(succ, ...) + ok = succ + if succ then + data = { + ... + } + ndata = select('#', ...) + else + data = ... + end + end + acc(pcall(fn, ...)) + setfenv(fn, env) + if ok then + return unpack(data, 1, ndata) + else + return error(data) + end + end +else + local dump + dump = string.dump + runwithcontext = function(fn, ctx, ...) + local code = dump(fn, false) + fn = load(code, 'runwithcontext', 'b', ctx) + return fn(...) + end +end +return { + runwithcontext = runwithcontext +} +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.compat.execute" ] = function( ... ) local arg = _G.arg; +local execute +execute = os.execute +return { + execute = function(cmd) + local a, b, c = execute(cmd) + if (type(a)) == 'boolean' then + return a, b, c + else + return a == 0 or nil, 'exit', a + end + end +} +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.compat.pcall" ] = function( ... ) local arg = _G.arg; +local pcall = _G.pcall +local unpack = _G.unpack or table.unpack +local testfn +testfn = function(a, b) + return a == b and a == 1 and true or error() +end +local testok, testrst = pcall(testfn, 1, 1) +if not (testok and testrst) then + local realpcall = pcall + pcall = function(fn, ...) + local args = { + n = (select('#', ...)), + ... + } + return realpcall(function() + return fn(unpack(args, 1, args.n)) + end) + end +end +return pcall +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.context" ] = function( ... ) local arg = _G.arg; +local runwithcontext +runwithcontext = require('moonbuild.compat.ctx').runwithcontext +local topenv = require('moonbuild.env.top') +local initenv = require('moonbuild.env.init') +local includes +includes = require('moonbuild._common').includes +local insert +insert = table.insert +local Context +do + local _class_0 + local _base_0 = { + addvar = function(self, var) + self.variables[var.name] = var + end, + addinit = function(self, fn) + return insert(self.inits, fn) + end, + addtarget = function(self, target) + return insert(self.targets, target) + end, + resetexecuted = function(self) + self.executedtargets = { } + end, + adddefault = function(self, target) + if not (includes(self.targets, target)) then + error("not a target of the current context: " .. tostring(target)) + end + if not ((type(target.name)) == 'string') then + error("not a named target") + end + return insert(self.defaulttargets, target.name) + end, + load = function(self, code, overrides) + return runwithcontext(code, (topenv(self, overrides))) + end, + init = function(self) + if self.inits[1] then + local env = (initenv(self)) + local _list_0 = self.inits + for _index_0 = 1, #_list_0 do + local init = _list_0[_index_0] + runwithcontext(code, env) + end + end + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self) + self.targets = { } + self.defaulttargets = { } + self.variables = { } + self.inits = { } + end, + __base = _base_0, + __name = "Context" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Context = _class_0 + return _class_0 +end +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.core.DAG" ] = function( ... ) local arg = _G.arg; +local filter, foreach, flatten, patsubst +do + local _obj_0 = require('moonbuild._common') + filter, foreach, flatten, patsubst = _obj_0.filter, _obj_0.foreach, _obj_0.flatten, _obj_0.patsubst +end +local runwithcontext +runwithcontext = require('moonbuild.compat.ctx').runwithcontext +local globalenv = require('moonbuild.env.global') +local exists, parent, mkdirs, clearentry, disableentry, attributes +do + local _obj_0 = require('moonbuild._fs') + exists, parent, mkdirs, clearentry, disableentry, attributes = _obj_0.exists, _obj_0.parent, _obj_0.mkdirs, _obj_0.clearentry, _obj_0.disableentry, _obj_0.attributes +end +local sort +sort = table.sort +local huge +huge = math.huge +local DepNode, FileTarget +local nodepriority +nodepriority = function(a, b) + local ta = type(a.name) + local tb = type(b.name) + local da = #a.deps + local db = #b.deps + if ta == 'string' and tb ~= 'string' then + return true + elseif ta ~= 'string' and tb == 'string' then + return false + elseif a.priority > b.priority then + return true + elseif a.priority < b.priority then + return false + else + return da < db + end +end +local transclosure +transclosure = function(obj, prop) + local elems = { } + local i = 1 + local set = { } + local imp + imp = function(e) + local _list_0 = e[prop] + for _index_0 = 1, #_list_0 do + local v = _list_0[_index_0] + if not set[v] then + elems[i], i = v, i + 1 + set[v] = i + imp(v) + end + end + end + imp(obj) + return elems +end +local mtime +mtime = function(path) + local attr = attributes(path) + return attr and attr.modification +end +local DepGraph +do + local _class_0 + local _base_0 = { + addnode = function(self, name) + if self.nodes[name] then + return + end + local elected = self:resolvedeps(name) + self.nodes[name] = elected + local _list_0 = (transclosure(elected, 'deps')) + for _index_0 = 1, #_list_0 do + local dep = _list_0[_index_0] + self.nodes[dep.name] = dep + dep.deps = nil + end + elected.deps = nil + end, + resolvedeps = function(self, name) + do + local node = self.nodes[name] + if node then + return node, { } + end + end + local candidates = filter({ + self.ctx.targets, + FileTarget() + }, function(target) + return target:matches(name) + end) + local nodes = foreach(candidates, function(candidate) + return { + a = { + pcall(function() + return DepNode(self, candidate, name) + end) + } + } + end) + local resolved = foreach((filter(nodes, function(node) + return node.a[1] + end)), function(node) + return node.a[2] + end) + sort(resolved, nodepriority) + return resolved[1] or error("Cannot resolve target " .. tostring(name)) + end, + buildablenodes = function(self) + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.nodes) do + if v:canbuild() and not v.built then + _accum_0[_len_0] = v + _len_0 = _len_0 + 1 + end + end + return _accum_0 + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, ctx, names) + if names == nil then + names = { } + end + self.ctx = ctx + self.nodes = { } + self.env = globalenv(self.ctx) + for _index_0 = 1, #names do + local name = names[_index_0] + self:addnode(name) + end + end, + __base = _base_0, + __name = "DepGraph" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + DepGraph = _class_0 +end +do + local _class_0 + local _base_0 = { + canbuild = function(self) + local _list_0 = flatten({ + self.ins, + self.after + }) + for _index_0 = 1, #_list_0 do + local node = _list_0[_index_0] + if not self.dag.nodes[node].built then + return false + end + end + local _list_1 = self.ins + for _index_0 = 1, #_list_1 do + local file = _list_1[_index_0] + if not exists(file) then + error("Node " .. tostring(name) .. " has ran all of its parents, but can't run since " .. tostring(file) .. " doesn't exist") + end + end + return true + end, + build = function(self, opts) + if opts == nil then + opts = { } + end + local force = opts.force or false + local quiet = opts.quiet or false + if self.built then + return + end + if not (force or self:shouldbuild()) then + return + end + if not (quiet or #self.buildfunctions == 0) then + print(tostring(self.type == 'virtual' and "Running" or "Building") .. " " .. tostring(self.name)) + end + return self:actuallybuild() + end, + shouldbuild = function(self) + if #self.outs == 0 or #self.ins == 0 or self.type == 'virtual' then + return true + end + local minout = huge + local _list_0 = self.outs + for _index_0 = 1, #_list_0 do + local file = _list_0[_index_0] + local time = mtime(file) + if not time then + return true + end + if time < minout then + minout = time + end + end + local maxin = 0 + local _list_1 = self.ins + for _index_0 = 1, #_list_1 do + local file = _list_1[_index_0] + local time = mtime(file) + if time > maxin then + maxin = time + end + end + return maxin > minout + end, + actuallybuild = function(self) + if self.mkdirs then + local _list_0 = self.outs + for _index_0 = 1, #_list_0 do + local file = _list_0[_index_0] + mkdirs(parent(file)) + end + end + local _list_0 = self.outs + for _index_0 = 1, #_list_0 do + local file = _list_0[_index_0] + disableentry(file) + end + local ctx = setmetatable({ }, { + __index = function(_, k) + local _exp_0 = k + if 'infile' == _exp_0 then + return self.ins[1] + elseif 'infiles' == _exp_0 then + return self.ins + elseif 'outfile' == _exp_0 then + return self.outs[1] + elseif 'outfiles' == _exp_0 then + return self.outs + elseif 'name' == _exp_0 then + return self.name + else + return error("No such field in TargetContext: " .. tostring(k)) + end + end, + __newindex = function(self, k) + return error("Attempt to set field " .. tostring(k) .. " of TargetContext") + end + }) + local _list_1 = self.buildfunctions + for _index_0 = 1, #_list_1 do + local fn = _list_1[_index_0] + runwithcontext(fn, self.dag.env, ctx) + end + end, + updatecache = function(self) + local _list_0 = self.outs + for _index_0 = 1, #_list_0 do + local file = _list_0[_index_0] + clearentry(file) + end + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, dag, target, name) + self.dag, self.name = dag, name + self.priority = target.priority + self.buildfunctions = target.buildfunctions + self.mkdirs = target._mkdirs + self.sync = target._sync + self.type = target._type + self.outs = foreach(target.outfiles, function(name) + return patsubst(self.name, target.pattern, name) + end) + if #self.outs == 0 then + self.type = 'virtual' + end + self.built = false + local resolve + resolve = function(name) + return self.dag:resolvedeps(patsubst(self.name, target.pattern, name)) + end + local after = flatten(foreach(target.needtargets, resolve)) + local deps = flatten(foreach(target.infiles, resolve)) + if #target.depfunctions ~= 0 then + local ctx = setmetatable({ }, { + __index = function(_, k) + local _exp_0 = k + if 'infile' == _exp_0 then + return first(deps) + elseif 'infiles' == _exp_0 then + return flatten(deps) + elseif 'outfile' == _exp_0 then + return first(self.outs) + elseif 'outfiles' == _exp_0 then + return flatten(self.outs) + elseif 'name' == _exp_0 then + return self.name + else + return error("No such field in TargetDepsContext: " .. tostring(k)) + end + end, + __newindex = function(self, k) + return error("Attempt to set field " .. tostring(k) .. " of TargetDepsContext") + end + }) + local _list_0 = target.depfunctions + for _index_0 = 1, #_list_0 do + local depfn = _list_0[_index_0] + deps = flatten(deps, foreach(depfn, function(fn) + return resolve(runwithcontext(fn, self.dag.env, ctx)) + end)) + end + end + self.ins = foreach(deps, function(dep) + return dep.name + end) + self.after = foreach(after, function(dep) + return dep.name + end) + self.deps = flatten({ + deps, + after + }) + if #self.deps == 0 and #self.buildfunctions == 0 then + self.built = true + end + end, + __base = _base_0, + __name = "DepNode" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + DepNode = _class_0 +end +do + local _class_0 + local _base_0 = { + matches = function(self, name) + return exists(name) + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self) + self.priority = -huge + self.buildfunctions = { } + self._mkdirs = false + self._sync = false + self._type = 'file' + self.needtargets = { } + self.infiles = { } + self.depfunctions = { } + self.outfiles = { + '%' + } + self.pattern = '%' + end, + __base = _base_0, + __name = "FileTarget" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + FileTarget = _class_0 +end +return DepGraph +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.core.Target" ] = function( ... ) local arg = _G.arg; +local flatten, includes, patget +do + local _obj_0 = require('moonbuild._common') + flatten, includes, patget = _obj_0.flatten, _obj_0.includes, _obj_0.patget +end +local insert +insert = table.insert +local Target +do + local _class_0 + local _base_0 = { + matches = function(self, name) + if self.name == name then + return true + end + if (includes(self.name, name)) and patget(name, self.pattern) then + return true + end + return false + end, + produces = function(self, ...) + local n = #self.outfiles + 1 + local _list_0 = flatten(...) + for _index_0 = 1, #_list_0 do + local obj = _list_0[_index_0] + self.outfiles[n], n = obj, n + 1 + end + end, + depends = function(self, ...) + if (type(...)) == 'function' then + return insert(self.depfunctions, (...)) + else + local n = #self.infiles + 1 + local _list_0 = flatten(...) + for _index_0 = 1, #_list_0 do + local obj = _list_0[_index_0] + self.infiles[n], n = obj, n + 1 + end + end + end, + after = function(self, ...) + local n = #self.needtargets + 1 + local _list_0 = flatten(...) + for _index_0 = 1, #_list_0 do + local tgt = _list_0[_index_0] + self.needtargets[n], n = tgt, n + 1 + end + end, + fn = function(self, fn) + return insert(self.buildfunctions, fn) + end, + sync = function(self) + self._sync = true + end, + mkdirs = function(self) + self._mkdirs = true + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, ctx, name, opts) + if opts == nil then + opts = { } + end + self.ctx, self.name = ctx, name + if (type(self.name)) ~= 'string' then + self.name = flatten(self.name) + end + self.pattern = opts.pattern or ((type(self.name)) == 'string' and self.name or '%') + self.priority = opts.priority or 0 + if not ((type(self.pattern)) == 'string') then + error("pattern must be a string") + end + if not ((type(self.priority)) == 'number' and self.priority % 1 == 0) then + error("priority must be an int") + end + self.outfiles = { } + self.infiles = { } + self.needtargets = { } + self.depfunctions = { } + self.buildfunctions = { } + self._mkdirs = false + self._sync = false + self._type = 'normal' + self.public = false + end, + __base = _base_0, + __name = "Target" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Target = _class_0 + return _class_0 +end +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.core.Variable" ] = function( ... ) local arg = _G.arg; +local flatten +flatten = require('moonbuild._common').flatten +local Variable +do + local _class_0 + local _base_0 = { } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, name, ...) + self.name = name + self.public = false + if (select('#', ...)) ~= 1 or (type(...)) == 'table' then + self.value = flatten(...) + else + self.value = ... + end + end, + __base = _base_0, + __name = "Variable" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.NIL = function() end + Variable = _class_0 + return _class_0 +end +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.core.multiprocessexecutor" ] = function( ... ) local arg = _G.arg; +local fork, _exit +do + local _obj_0 = require('posix.unistd') + fork, _exit = _obj_0.fork, _obj_0._exit +end +local wait +wait = require('posix.sys.wait').wait +local open, stderr +do + local _obj_0 = io + open, stderr = _obj_0.open, _obj_0.stderr +end +local match +match = string.match +local Executor +do + local _class_0 + local _base_0 = { + execute = function(self, opts) + local block = self.dag:buildablenodes() + while #block ~= 0 do + for _index_0 = 1, #block do + local node = block[_index_0] + self:addprocess(node, opts) + if self.nprocesses == self.nparallel then + self:waitprocess() + end + end + do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = self.dag:buildablenodes() + for _index_0 = 1, #_list_0 do + local node = _list_0[_index_0] + if not self.building[node] then + _accum_0[_len_0] = node + _len_0 = _len_0 + 1 + end + end + block = _accum_0 + end + while #block == 0 and self.nprocesses ~= 0 do + self:waitprocess() + do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = self.dag:buildablenodes() + for _index_0 = 1, #_list_0 do + local node = _list_0[_index_0] + if not self.building[node] then + _accum_0[_len_0] = node + _len_0 = _len_0 + 1 + end + end + block = _accum_0 + end + end + end + while self.nprocesses ~= 0 do + self:waitprocess() + end + for name, node in pairs(self.dag.nodes) do + if not (node.built) then + error("Node " .. tostring(name) .. " wasn't built") + end + end + end, + addprocess = function(self, node, opts) + local pid = fork() + if not (pid) then + error("Failed to fork") + end + if pid ~= 0 then + self.processes[pid] = node + self.nprocesses = self.nprocesses + 1 + self.building[node] = true + else + local ok, err = pcall(function() + return node:build(opts) + end) + if ok then + return _exit(0) + else + stderr:write(err) + return _exit(1) + end + end + end, + waitprocess = function(self) + local pid, ty, status = wait() + if not (pid) then + error("Failed to wait") + end + if ty ~= 'exited' or status ~= 0 then + error("Failed to build " .. tostring(self.processes[pid].name)) + end + self.processes[pid].built = true + self.processes[pid]:updatecache() + self.processes[pid] = nil + self.nprocesses = self.nprocesses - 1 + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, dag, nparallel) + self.dag, self.nparallel = dag, nparallel + self.processes = { } + self.nprocesses = 0 + self.building = { } + end, + __base = _base_0, + __name = "Executor" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.getmaxparallel = function(self) + local fd = open('/proc/cpuinfo', 'r') + if not (fd) then + return 1 + end + local ncpu = 0 + for line in fd:lines() do + if match(line, '^processor%s*:') then + ncpu = ncpu + 1 + end + end + fd:close() + return ncpu == 0 and 1 or ncpu + end + Executor = _class_0 + return _class_0 +end +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.core.singleprocessexecutor" ] = function( ... ) local arg = _G.arg; +local Executor +do + local _class_0 + local _base_0 = { + execute = function(self, opts) + local block = self.dag:buildablenodes() + while #block ~= 0 do + for _index_0 = 1, #block do + local node = block[_index_0] + node:build(opts) + node:updatecache() + node.built = true + end + block = self.dag:buildablenodes() + end + for name, node in pairs(self.dag.nodes) do + if not (node.built) then + error("Node " .. tostring(name) .. " wasn't built") + end + end + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, dag, nparallel) + self.dag, self.nparallel = dag, nparallel + end, + __base = _base_0, + __name = "Executor" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.getmaxparallel = function(self) + return 1 + end + Executor = _class_0 + return _class_0 +end +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.env.global" ] = function( ... ) local arg = _G.arg; +local _ = require('moonbuild._') +return function(ctx) + local varlayer = setmetatable({ }, { + __index = _G + }) + for name, var in pairs(ctx.variables) do + rawset(varlayer, name, var.value) + end + local env = setmetatable({ }, { + __index = varlayer, + __newindex = function(self, k) + return error("attempt to assign to global variable '" .. tostring(k) .. "', which is disabled in the global env") + end + }) + rawset(env, '_', _) + rawset(env, '_G', env) + rawset(env, '_ENV', env) + return env, varlayer +end +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.env.init" ] = function( ... ) local arg = _G.arg; +local Target = require('moonbuild.core.Target') +local Variable = require('moonbuild.core.Variable') +local _ = require('moonbuild._') +local flatten +flatten = _.flatten +return function(ctx) + local varlayer = setmetatable({ }, { + __index = _G + }) + for name, var in pairs(ctx.variables) do + rawset(varlayer, name, var.value) + end + local env = setmetatable({ }, { + __index = varlayer, + __newindex = function(self, k) + return error("attempt to assign to global variable '" .. tostring(k) .. "', use the function 'var' instead") + end + }) + rawset(env, '_', _) + rawset(env, '_G', env) + rawset(env, '_ENV', env) + rawset(env, 'var', function(name, ...) + local var = Variable(name, ...) + ctx:addvar(var) + rawset(varlayer, name, var.value) + return var + end) + rawset(env, 'target', function(name, opts) + local target = Target(ctx, name, opts) + ctx:addtarget(target) + return target + end) + return env, varlayer +end +end +end + +do +local _ENV = _ENV +package.preload[ "moonbuild.env.top" ] = function( ... ) local arg = _G.arg; +local initenv = require('moonbuild.env.init') +local Target = require('moonbuild.core.Target') +local Variable = require('moonbuild.core.Variable') +return function(ctx, overrides) + local env, varlayer = initenv(ctx) + rawset(env, 'default', function(target) + ctx:adddefault(target) + return target + end) + rawset(env, 'public', function(e) + local clazz = ((getmetatable(e)) or { }).__class + if clazz == Target then + e.public = true + elseif clazz == Variable then + e.public = true + local override = overrides[e.name] + if override then + if override == Variable.NIL then + override = nil + end + e.value = override + rawset(varlayer, e.name, override) + end + else + error("cannot set an object of type " .. tostring(clazz and clazz.__name or type(e)) .. " public") + end + return e + end) + rawset(env, 'init', function(fn) + if not ((type(fn)) == 'function') then + error("you can only add functions to init") + end + return ctx:addinit(fn) + end) + return env, varlayer +end +end +end + +end + +local loadfile +loadfile = require('moonscript.base').loadfile +local Context = require('moonbuild.context') +local Variable = require('moonbuild.core.Variable') +local DepGraph = require('moonbuild.core.DAG') +local parseargs +parseargs = require('moonbuild._cmd.common').parseargs +local sort, concat +do + local _obj_0 = table + sort, concat = _obj_0.sort, _obj_0.concat +end +local exit +exit = os.exit +local argparse = require('argparse') +local parser +do + local _with_0 = argparse("moonbuild", "A build system in moonscript") + _with_0:option('-b --buildfile', "Build file to use", 'Build.moon') + _with_0:option('-j --parallel', "Sets the number of parallel tasks, 'y' to run as many as we have cores", '1') + _with_0:flag('-l --list', "List the targets", false) + _with_0:flag('-V --list-variables', "List the variables", false) + _with_0:flag('-q --quiet', "Don't print targets as they are being built", false) + _with_0:flag('-f --force', "Always rebuild every target", false) + _with_0:flag('-v --verbose', "Be verbose", false); + (_with_0:option('-u --unset', "Unsets a variable")):count('*'); + (_with_0:option('-s --set', "Sets a variable")):args(2):count('*'); + (_with_0:option('-S --set-list', "Sets a variable to a list")):args(2):count('*'); + (_with_0:argument('targets', "Targets to build")):args('*') + _with_0:add_complete() + parser = _with_0 +end +local args = parser:parse() +local overrides = { } +local _list_0 = args.unset +for _index_0 = 1, #_list_0 do + local unset = _list_0[_index_0] + overrides[unset] = Variable.NIL +end +local _list_1 = args.set +for _index_0 = 1, #_list_1 do + local set = _list_1[_index_0] + overrides[set[1]] = set[2] +end +local _list_2 = args.set_list +for _index_0 = 1, #_list_2 do + local set = _list_2[_index_0] + overrides[set[1]] = parseargs(set[2]) +end +args.parallel = args.parallel == 'y' and 'y' or ((tonumber(args.parallel)) or error("Invalid argument for -j: " .. tostring(args.parallel))) +if args.parallel ~= 'y' and (args.parallel < 1 or args.parallel % 1 ~= 0) then + error("Invalid argument for -j: " .. tostring(args.parallel)) +end +if args.verbose then + print("Parsed CLI args") +end +local ctx = Context() +ctx:load((loadfile(args.buildfile)), overrides) +if args.verbose then + print("Loaded buildfile") +end +if args.list then + print("Public targets") + local targets, n = { }, 1 + local _list_3 = ctx.targets + for _index_0 = 1, #_list_3 do + local t = _list_3[_index_0] + if t.public then + targets[n], n = t.name, n + 1 + end + end + sort(targets) + print(concat(targets, ", ")) + print() + if not (args.list_variables) then + exit(0) + end +end +if args.list_variables then + print("Public variables") + local vars, n = { }, 1 + for k, v in pairs(ctx.variables) do + if v.public then + vars[n], n = k, n + 1 + end + end + sort(vars) + print(concat(vars, ", ")) + print() + exit(0) +end +ctx:init() +if args.verbose then + print("Initialized buildfile") +end +local targets = #args.targets == 0 and ctx.defaulttargets or args.targets +local dag = DepGraph(ctx, targets) +if args.verbose then + print("Created dependancy graph") +end +if args.parallel == 1 then + local Executor = require('moonbuild.core.singleprocessexecutor') + local executor = Executor(dag, args.parallel) + executor:execute(args) +else + local ok, Executor = pcall(function() + return require('moonbuild.core.multiprocessexecutor') + end) + if not (ok) then + Executor = require('moonbuild.core.singleprocessexecutor') + end + local nparallel = args.parallel == 'y' and Executor:getmaxparallel() or args.parallel + if args.verbose then + print("Building with " .. tostring(nparallel) .. " max parallel process" .. tostring(nparallel > 1 and "es" or "")) + end + local executor = Executor(dag, nparallel) + executor:execute(args) +end +if args.verbose then + return print("Finished") +end \ No newline at end of file diff --git a/rock.yml b/rock.yml new file mode 100644 index 0000000..3dc5b0c --- /dev/null +++ b/rock.yml @@ -0,0 +1,24 @@ +package: moonbuild +source: + url: git://github.com/natnat-mc/moonbuild +description: + summary: Small build system in between make and a build.sh + detailed: > + moonbuild is a small build system that simplifies your + build definitions by allowing you to use declarative as + well as imperative rules. + It represents the build as a DAG with explicit ordering, + and doesn't give you any default confusing rules (unlike + make). + If you can, installing luaposix and/or luafilesystem + will speed up builds and increase stability. +homepage: https://github.com/natnat-mc/moonbuild +dependencies: + - lua >= 5.1 + - argparse >= 0.7.1-1 + - moonscript >= 0.5.0-1 +build: + type: builtin + install: + bin: + moonbuild: out/moonbuild diff --git a/rockspecs/moonbuild-2.0.0-1.rockspec b/rockspecs/moonbuild-2.0.0-1.rockspec new file mode 100644 index 0000000..9c38d86 --- /dev/null +++ b/rockspecs/moonbuild-2.0.0-1.rockspec @@ -0,0 +1,24 @@ +build = { + install = { + bin = { + moonbuild = "out/moonbuild" + } + }, + type = "builtin" +} +dependencies = { + "lua >= 5.1", + "argparse >= 0.7.1-1", + "moonscript >= 0.5.0-1" +} +description = { + detailed = "moonbuild is a small build system that simplifies your build definitions by allowing you to use declarative as well as imperative rules. It represents the build as a DAG with explicit ordering, and doesn't give you any default confusing rules (unlike make). If you can, installing luaposix and/or luafilesystem will speed up builds and increase stability.\n", + summary = "Small build system in between make and a build.sh" +} +package = "moonbuild" +rockspec_format = "3.0" +source = { + tag = "v2.0.0", + url = "git://github.com/natnat-mc/moonbuild" +} +version = "2.0.0-1" diff --git a/test/Build.moon b/test/Build.moon new file mode 100644 index 0000000..cb14049 --- /dev/null +++ b/test/Build.moon @@ -0,0 +1,168 @@ +-- project name +var 'NAME', 'raytrace' + +-- tools to use +public var 'CPP', 'g++' +public var 'LD', 'g++' +public var 'MOC', 'moc' + +-- compile flags +var 'CFLAGS', {'-fPIC', '-fopenmp', '-Wall', '-Wextra', '-Isrc', '--std=c++1', '-O3'} +var 'LDFLAGS', {'-fPIC', '-fopenmp'} +var 'PKGS', {'Qt5Widgets'} + +-- extra cli flags +public var 'XCFLAGS' +public var 'XLDFLAGS' +public var 'XPKGS' +public var 'XLIBS' + +-- find all files for project +var 'SOURCES', _.wildcard 'src/**.cpp' +var 'HEADERS', _.wildcard 'src/**.h' +var 'QT_HEADERS', _.wildcard 'src/**.hh' + +-- complete our flags +var 'PKGS', {PKGS, XPKGS} +var 'CFLAGS', {CFLAGS, XCFLAGS, _.pkgconfig.cflags PKGS} +var 'LDFLAGS', {LDFLAGS, LDCFLAGS} +var 'LIBS', {XLIBS, _.pkgconfig.libs PKGS} + +-- determine our subtargets +var 'BINARY', "out/#{NAME}" +var 'OBJECTS', _.patsubst SOURCES, 'src/%.cpp', 'build/%.o' +var 'MOC_SOURCES', _.patsubst QT_HEADERS, 'src/%.hh', 'build/%.moc.cpp' +var 'MOC_OBJECTS', _.patsubst MOC_SOURCES, '%.cpp', '%.o' +var 'OBJECTS', {OBJECTS, MOC_OBJECTS} + + +-- build everything +with public default target 'all' + \depends BINARY + +-- clean build objects +with public target 'clean' + \fn => _.cmd 'rm', '-f', ALL_OBJECTS, MOC_SOURCES + +-- clean everything +with public target 'mrproper' + \after 'clean' + \fn => _.cmd 'rm', '-f', BINARY + +-- build and run +with public target 'run' + \depends BINARY + \fn => _.cmd "./#{BINARY}" + +-- produce the binary from all objects +with target BINARY + \produces BINARY + \depends OBJECTS + \fn => _.cmd LD, LDFLAGS, '-o', @outfile, @infiles, LIBS + \mkdirs! + +-- produce the objects from the sources +with target OBJECTS, pattern: 'build/%.o' + \produces 'build/%.o' + \depends 'src/%.cpp' + \depends => _.cdeps[CPP] @infile, CFLAGS + \fn => _.cmd CPP, CFLAGS, '-o', @outfile, '-c', @infile + \mkdirs! + +-- produce the objects from the moc-generated sources +with target MOC_OBJECTS, pattern: 'build/%.moc.o' + \produces 'build/%.moc.o' + \depends 'build/%.moc.cpp' + \fn => _.cmd CPP, CFLAGS, '-o', @outfile, '-c', @infile + +-- generate moc sources from the qt headers +with target MOC_SOURCES, pattern: 'build/%.moc.cpp' + \produces 'build/%.moc.cpp' + \depends 'src/%.hh' + \fn => _.cmd MOC, '-o', @outfile, @infile + \mkdirs! + +[[ +var: string, Serializable -> Variable + creates a variable in the global shared state + +public: Variable -> Variable + makes a variable overwritable with a CLI flag or through environment variables + +target: string|array, TargetOptions? -> Target + creates a target matching the given name or names, with the given options + +public: Target -> Target + makes a target listable on the CLI + +default: Target -> Target + makes a target run automatically if no target is specified + +init: (nil -> nil) -> nil + adds a function to run in the init environment after the CLI options are processed + +typedef Serializable +| string +| boolean +| number +| nil +| array +| map + a value that can be flattened and passed to another environment + +typedef List +| nil +| string +| array + a list of strings that can get flattened to array unambiguously + +typedef TargetOptions: table +- pattern: string? [@name or '%'] + a pattern that is matched when trying the target, it is also used to fill in '%' in the target +- priority: int? [0] + higher values make moonbuild try the target before lower-priority targets + +class Target +- produces: List -> Target + adds objects to the list of productions +- depends: List -> Target + adds objects to the list of dependencies +- depends: (TargetContext -> List) -> Target + adds objects to the list of dependencies when the target is first tried +- after: List -> Target + adds targets to the ordering list +- fn: (TargetContext -> nil) -> Target + adds a function to run to build the target +- sync: nil -> Target + forces the target to run synchronously and sequentially +- mkdirs: nil -> Target + always ensures the parent directories of the productions exist, creating them if they don't + +class TargetContext +- name: string + the name the target is running as +- infiles: List + the list of input files +- infile: string? + the first input file +- outfiles: List + the list of output files +- outfile: string? + the first output file + +environment Global +- _ library +- VARIABLES +- standard Lua library + +environment Top: Global +- target +- var +- init +- public +- default + +environment Init: Global +- target +- var +]]