do do local _ENV = _ENV package.preload[ "moonbuild.fsutil" ] = function( ... ) local arg = _G.arg; local dir, attributes do local _obj_0 = require('lfs') dir, attributes = _obj_0.dir, _obj_0.attributes 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 insert, concat do local _obj_0 = table insert, concat = _obj_0.insert, _obj_0.concat end local ls ls = function(d) local _accum_0 = { } local _len_0 = 1 for f in dir(d) do 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 for f in dir(d) do if f ~= '.' and f ~= '..' then _accum_0[_len_0] = d .. '/' .. f _len_0 = _len_0 + 1 end end return _accum_0 end local exists exists = function(f) return (attributes(f)) ~= nil end local isdir isdir = function(f) local a = attributes(f) return a and a.mode == 'directory' or false end local mtime mtime = function(f) local a = attributes(f) return a and a.modification end local matchglob matchglob = function(str, glob) local patt = '^' .. (gsub((gsub(glob, '%*%*', '.*')), '%*', '[^/]*')) .. '$' 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 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 = 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))) local files = lswithpath(prevpath) local results = { } for _index_0 = 1, #files do local file = files[_index_0] if matchglob(file, currpath) then if i == #parts then insert(results, file) 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] insert(results, result) 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] insert(results, result) end end end return results end if match(part, '%*') then local files = lswithpath(prevpath) if i == #parts then return matchglob(files, glob) end local results = { } 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] insert(results, result) end end end return results end end if exists(glob) then return { glob } else return { } end end return { wildcard = wildcard, exists = exists, isdir = isdir, mtime = mtime } end end do local _ENV = _ENV package.preload[ "moonbuild.stringutil" ] = function( ... ) local arg = _G.arg; local match, gmatch, sub do local _obj_0 = string match, gmatch, sub = _obj_0.match, _obj_0.gmatch, _obj_0.sub end local upper, lower do local _obj_0 = string upper, lower = _obj_0.upper, _obj_0.lower end local GLOB_PATT = '^([^%%]*)%%([^%%]*)$' local patsubst patsubst = function(str, pattern, replacement) if (type(str)) == 'table' then local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #str do local s = str[_index_0] _accum_0[_len_0] = patsubst(s, pattern, replacement) _len_0 = _len_0 + 1 end return _accum_0 end local prefix, suffix = match(pattern, GLOB_PATT) if not (prefix) then return str end local reprefix, resuffix = match(replacement, GLOB_PATT) if not (reprefix) then return replacement end if (sub(str, 1, #prefix)) == prefix and (sub(str, -#suffix)) == suffix then return reprefix .. (sub(str, #prefix + 1, -#suffix - 1)) .. resuffix end return str end local splitsp splitsp = function(str) local _accum_0 = { } local _len_0 = 1 for elem in gmatch(str, '%S+') do _accum_0[_len_0] = elem _len_0 = _len_0 + 1 end return _accum_0 end return { patsubst = patsubst, splitsp = splitsp, upper = upper, lower = lower } end end do local _ENV = _ENV package.preload[ "moonbuild.tableutil" ] = function( ... ) local arg = _G.arg; local insert, remove, concat, sort do local _obj_0 = table insert, remove, concat, sort = _obj_0.insert, _obj_0.remove, _obj_0.concat, _obj_0.sort end local unpack = unpack or table.unpack local sortedpairs sortedpairs = function(table, cmp) local keys do local _accum_0 = { } local _len_0 = 1 for k in pairs(table) do _accum_0[_len_0] = k _len_0 = _len_0 + 1 end keys = _accum_0 end sort(keys, cmp) return coroutine.wrap(function() for _index_0 = 1, #keys do local key = keys[_index_0] coroutine.yield(key, table[key]) end end) end local min min = function(table, cmp) if cmp == nil then cmp = function(a, b) return a < b end end local val = table[1] for i = 2, #table do local elem = table[i] if cmp(val, elem) then val = elem end end return val end local max max = function(table, cmp) if cmp == nil then cmp = function(a, b) return a < b end end local val = table[1] for i = 2, #table do local elem = table[i] if not cmp(val, elem) then val = elem end end return val end local foreach foreach = function(tab, fn) local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #tab do local e = tab[_index_0] _accum_0[_len_0] = fn(e) _len_0 = _len_0 + 1 end return _accum_0 end local first first = function(tab, fn) for _index_0 = 1, #tab do local e = tab[_index_0] if fn(e) then return e end end end local exclude exclude = function(tab, ...) local i = 1 while i <= #tab do local removed = false for j = 1, select('#', ...) do if tab[i] == select(j, ...) then remove(tab, i) removed = true break end end if not (removed) then i = i + 1 end end return tab end local flatten flatten = function(tab) if (type(tab)) ~= 'table' then return { tab } end local out = { } for _index_0 = 1, #tab do local e = tab[_index_0] if (type(e)) == 'table' then local _list_0 = flatten(e) for _index_1 = 1, #_list_0 do local v = _list_0[_index_1] insert(out, v) end else insert(out, e) end end return out end return { min = min, max = max, foreach = foreach, first = first, exclude = exclude, flatten = flatten, sortedpairs = sortedpairs, insert = insert, remove = remove, concat = concat, sort = sort, unpack = unpack } end end do local _ENV = _ENV package.preload[ "moonbuild.util" ] = function( ... ) local arg = _G.arg; local wildcard, exists, isdir, mtime do local _obj_0 = require('moonbuild.fsutil') wildcard, exists, isdir, mtime = _obj_0.wildcard, _obj_0.exists, _obj_0.isdir, _obj_0.mtime end local foreach, first, flatten, exclude, sortedpairs, min, max do local _obj_0 = require('moonbuild.tableutil') foreach, first, flatten, exclude, sortedpairs, min, max = _obj_0.foreach, _obj_0.first, _obj_0.flatten, _obj_0.exclude, _obj_0.sortedpairs, _obj_0.min, _obj_0.max end local patsubst, splitsp do local _obj_0 = require('moonbuild.stringutil') patsubst, splitsp = _obj_0.patsubst, _obj_0.splitsp end local insert, concat, sort, pairs do local _obj_0 = require('moonbuild.tableutil') insert, concat, sort, pairs = _obj_0.insert, _obj_0.concat, _obj_0.sort, _obj_0.pairs end local upper, lower do local _obj_0 = require('moonbuild.stringutil') upper, lower = _obj_0.upper, _obj_0.lower end local GLOB_PATT = '^([^%%]*)%%([^%%]*)$' local escapecmdpart escapecmdpart = function(p) if (type(p)) == 'table' then if p.raw then return p.raw end return concat((function() local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #p do local part = p[_index_0] _accum_0[_len_0] = escapecmdpart(part) _len_0 = _len_0 + 1 end return _accum_0 end)(), ' ') end if p:match('^[a-zA-Z0-9_./-]+$') then return p end return '"' .. p:gsub('\\', '\\\\'):gsub('"', '\\"') .. '"' end local escapecmd escapecmd = function(c, args) if args == nil then args = { } end c = escapecmdpart(c) local _list_0 = flatten(args) for _index_0 = 1, #_list_0 do local a = _list_0[_index_0] if a then c = c .. (' ' .. escapecmdpart(a)) end end return c end local run run = function(c, args, params) if params == nil then params = { } end local escaped = escapecmd(c, args) if params.print then print(escaped) end local ret, _, code = os.execute(escaped) if (type(ret)) == 'number' then ret, code = ret == 0, ret end if params.error and not ret then error(tostring(c) .. " failed with code " .. tostring(code)) end return ret, code end local popen popen = function(c, args, mode, params) if mode == nil then mode = 'r' end if params == nil then params = { } end local escaped = escapecmd(c, args) if params.print then print(escaped) end return io.popen(escaped, mode) end local calccdeps calccdeps = function(infile, includesys) if includesys == nil then includesys = false end local data = (popen('cc', { includesys and '-M' or '-MM', infile })):read('*a') local rawdeps = data:gsub('\\\n', ''):match(':(.+)') local _accum_0 = { } local _len_0 = 1 for dep in rawdeps:gmatch('%S+') do if dep ~= infile then _accum_0[_len_0] = dep _len_0 = _len_0 + 1 end end return _accum_0 end local findclib findclib = function(name, mode) if mode == nil then mode = 'all' end local args = { name } if mode == 'all' or mode == 'cc' then insert(args, '--cflags') end if mode == 'all' or mode == 'ld' then insert(args, '--libs') end local _accum_0 = { } local _len_0 = 1 for arg in (popen('pkg-config', args)):read('*a'):gmatch('%S+') do _accum_0[_len_0] = arg _len_0 = _len_0 + 1 end return _accum_0 end local match match = function(str, glob) local prefix, suffix = glob:match(GLOB_PATT) if not (prefix) then return str == glob end if (str:sub(1, #prefix)) == prefix and (str:sub(-#suffix)) == suffix then return str:sub(#prefix + 1, -#suffix - 1) end return false end local isglob isglob = function(glob) if glob:match(GLOB_PATT) then return true else return false end end local env env = function(key, def) return (os.getenv(key)) or def end return { min = min, max = max, foreach = foreach, first = first, exclude = exclude, flatten = flatten, sortedpairs = sortedpairs, insert = insert, remove = remove, concat = concat, sort = sort, unpack = unpack, wildcard = wildcard, mtime = mtime, exists = exists, isdir = isdir, run = run, popen = popen, calccdeps = calccdeps, findclib = findclib, patsubst = patsubst, splitsp = splitsp, upper = upper, lower = lower, match = match, isglob = isglob, env = env } end end end local argparse = require('argparse') require('moonscript') local loadfile loadfile = require('moonscript.base').loadfile local truncate_traceback, rewrite_traceback do local _obj_0 = require('moonscript.errors') truncate_traceback, rewrite_traceback = _obj_0.truncate_traceback, _obj_0.rewrite_traceback end local trim trim = require('moonscript.util').trim local util = require('moonbuild.util') local exists, mtime, run, min, max, first, flatten, match, patsubst, sortedpairs exists, mtime, run, min, max, first, flatten, match, patsubst, sortedpairs = util.exists, util.mtime, util.run, util.min, util.max, util.first, util.flatten, util.match, util.patsubst, util.sortedpairs local insert, concat do local _obj_0 = table insert, concat = _obj_0.insert, _obj_0.concat end local parser = argparse('moonbuild') parser:argument('targets', "Targets to run"):args('*') parser:flag('-a --noskip', "Always run targets") parser:flag('-l --list', "List available targets") parser:flag('-d --deps', "List targets and their dependancies") local args = parser:parse() local loadwithscope loadwithscope = function(file, scope) local fn, err = loadfile(file) if not (fn) then error(err or "failed to load code") end local dumped dumped, err = string.dump(fn) if not (dumped) then error(err or "failed to dump function") end return load(dumped, file, 'b', scope) end local pcall pcall = function(fn, ...) local rewrite rewrite = function(err) local trace = debug.traceback('', 2) local trunc = truncate_traceback(trim(trace)) return rewrite_traceback(trunc, err) end return xpcall(fn, rewrite, ...) end local Command do local _class_0 local _base_0 = { __unm = function(self) return self:run({ error = true, print = true }) end, __len = function(self) return self:run({ error = true }) end, __tostring = function(self) return self.cmd end, run = function(self, params) return run(self.cmd, self.args, params) end } _base_0.__index = _base_0 _class_0 = setmetatable({ __init = function(self, cmd, ...) self.cmd = cmd self.args = { ... } end, __base = _base_0, __name = "Command" }, { __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.run = function(self, ...) return -self(...) end Command = _class_0 end local BuildObject do local _class_0 local all, skip local _base_0 = { __tostring = function(self) return "Target " .. tostring(self.name) .. " (" .. tostring(concat(self.deps, ', ')) .. ")" end, build = function(self, name, upper) if upper == nil then upper = { } end if skip[name] then return end if upper[self] then error("Cycle detected on " .. tostring(self.name)) end upper = setmetatable({ [self] = true }, { __index = upper }) if self.name ~= name then local _list_0 = self.deps for _index_0 = 1, #_list_0 do local dep = _list_0[_index_0] self.__class:build((patsubst(name, self.name, dep)), upper) end else local _list_0 = self.deps for _index_0 = 1, #_list_0 do local dep = _list_0[_index_0] self.__class:build(dep, upper) end end if not (self:shouldbuild(name)) then return end local ins = self.ins local outs = self.outs if self.name ~= name then do local _accum_0 = { } local _len_0 = 1 local _list_0 = self.ins for _index_0 = 1, #_list_0 do local elem = _list_0[_index_0] _accum_0[_len_0] = patsubst(name, self.name, elem) _len_0 = _len_0 + 1 end ins = _accum_0 end do local _accum_0 = { } local _len_0 = 1 local _list_0 = self.outs for _index_0 = 1, #_list_0 do local elem = _list_0[_index_0] _accum_0[_len_0] = patsubst(name, self.name, elem) _len_0 = _len_0 + 1 end outs = _accum_0 end print("Building " .. tostring(self.name) .. " as " .. tostring(name)) else print("Building " .. tostring(name)) end local ok, err = pcall(function() return self.fn({ ins = ins, outs = outs, infile = ins[1], outfile = outs[1], name = name }) end) if not (ok) then error("Can't build " .. tostring(self.name) .. ": lua error\n" .. tostring(err)) end for _index_0 = 1, #outs do local f = outs[_index_0] if not (exists(f)) then error("Can't build " .. tostring(self.name) .. ": output file " .. tostring(f) .. " not created") end end skip[name] = true end, shouldbuild = function(self, name) if args.noskip then return true end if #self.ins == 0 or #self.outs == 0 then return true end local ins if self.name ~= name then do local _accum_0 = { } local _len_0 = 1 local _list_0 = self.ins for _index_0 = 1, #_list_0 do local elem = _list_0[_index_0] _accum_0[_len_0] = patsubst(name, self.name, elem) _len_0 = _len_0 + 1 end ins = _accum_0 end else ins = self.ins end local itimes do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #ins do local f = ins[_index_0] _accum_0[_len_0] = mtime(f) _len_0 = _len_0 + 1 end itimes = _accum_0 end for i = 1, #self.ins do if not (itimes[i]) then error("Can't build " .. tostring(self.name) .. ": missing inputs") end end local outs if self.name ~= name then do local _accum_0 = { } local _len_0 = 1 local _list_0 = self.outs for _index_0 = 1, #_list_0 do local elem = _list_0[_index_0] _accum_0[_len_0] = patsubst(name, self.name, elem) _len_0 = _len_0 + 1 end outs = _accum_0 end else outs = self.outs end local otimes do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #outs do local f = outs[_index_0] _accum_0[_len_0] = mtime(f) _len_0 = _len_0 + 1 end otimes = _accum_0 end for i = 1, #self.outs do if not otimes[i] then return true end end return (max(itimes)) >= (min(otimes)) end } _base_0.__index = _base_0 _class_0 = setmetatable({ __init = function(self, name, outs, ins, deps, fn) if outs == nil then outs = { } end if ins == nil then ins = { } end if deps == nil then deps = { } end if fn == nil then fn = function(self) end end self.name, self.outs, self.ins, self.deps, self.fn = name, outs, ins, deps, fn self.skip = false if all[self.name] then error("Duplicate build name " .. tostring(self.name)) end all[self.name] = self end, __base = _base_0, __name = "BuildObject" }, { __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 all = { } skip = { } self.find = function(self, name) local target = all[name] if target then return target end for glob, tgt in pairs(all) do if match(name, glob) then return tgt end end return nil end self.list = function(self) local _tbl_0 = { } for name, target in pairs(all) do do local _tbl_1 = { } local _list_0 = target.deps for _index_0 = 1, #_list_0 do local dep = _list_0[_index_0] _tbl_1[dep] = self:find(dep) end _tbl_0[target] = _tbl_1 end end return _tbl_0 end self.build = function(self, name, upper) local target = (self:find(name)) or error("No such target: " .. tostring(name)) return target:build(name, upper) end BuildObject = _class_0 end if setfenv then error("Need Lua >=5.2") end local targets = { } local defaulttarget = 'all' local buildscope = { default = function(target) defaulttarget = target.name return target end, public = function(target) insert(targets, target.name) return target end, target = function(name, params) local tout = flatten(params.out) local tin = flatten(params["in"]) local tdeps = flatten(params.deps) local _list_0 = flatten(params.from) for _index_0 = 1, #_list_0 do local f = _list_0[_index_0] insert(tin, f) insert(tdeps, f) end return BuildObject(name, tout, tin, tdeps, params.fn) end, Command = Command } for k, fn in pairs(util) do buildscope[k] = fn end setmetatable(buildscope, { __index = function(self, k) local global = rawget(_G, k) if global then return global end return function(...) return Command(k, ...) end end }) local file = first({ 'Build.moon', 'Buildfile.moon', 'Build', 'Buildfile' }, exists) if not (file) then error("No Build.moon or Buildfile found") end local buildfn = loadwithscope(file, buildscope) if not (buildfn) then error("Failed to load build function") end local ok, err = pcall(buildfn) if not (ok) then if err then io.stderr:write(err, '\n') else io.stderr:write("Unknown error\n") end os.exit(1) end if args.list then io.write("Available targets:\n") io.write("\t" .. tostring(concat(targets, ', ')) .. "\n") os.exit(0) end if args.deps then io.write("Targets:\n") for target, deps in sortedpairs(BuildObject:list(), function(a, b) return a.name < b.name end) do io.write("\t" .. tostring(target.name) .. " ") if #target.ins == 0 then if #target.outs == 0 then io.write("[no in/out]") else io.write("[spontaneous generation]") end else if #target.outs == 0 then io.write("[consumer]") else io.write("(" .. tostring(concat(target.ins, ', ')) .. " -> " .. tostring(concat(target.outs, ', ')) .. ")") end end io.write("\n") for name, dep in sortedpairs(deps) do io.write("\t\t" .. tostring(name) .. " (" .. tostring(dep.name) .. ")\n") end end os.exit(0) end if #args.targets == 0 then BuildObject:build(defaulttarget) end local _list_0 = args.targets for _index_0 = 1, #_list_0 do local target = _list_0[_index_0] BuildObject:build(target) end