diff --git a/.gitignore b/.gitignore index 35a954f..47307da 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/*/**.lua +/moonbuild/*.lua +/bin/*.lua diff --git a/Alfons.moon b/Alfons.moon index bf4520c..db0a766 100644 --- a/Alfons.moon +++ b/Alfons.moon @@ -1,6 +1,8 @@ tasks: build: => sh "moon bin/moonbuild.moon compile" + install: => + sh "moon bin/moonbuild.moon install" release: => error "no version provided" unless @v tasks.build! diff --git a/Build.moon b/Build.moon index 50b23e6..39f3881 100644 --- a/Build.moon +++ b/Build.moon @@ -5,15 +5,27 @@ BINARY_LUA = patsubst BINARY, '%.moon', '%.lua' OUT_AMALG = 'moonbuild.lua' public target 'clean', fn: => - -rm '-f', OUT_LUA + -rm '-f', OUT_LUA, BINARY_LUA public target 'info', fn: => #echo "Moonscript sources:", SOURCES_MOON #echo "Compiled lua:", OUT_LUA -default target 'compile', from: OUT_AMALG +public target 'compile', deps: OUT_AMALG -target OUT_AMALG, from: {BINARY_LUA, OUT_LUA}, out: OUT_AMALG, fn: => +public target 'install', from: OUT_AMALG, out: '/usr/local/bin/moonbuild', fn: => + dfd, err = io.open @outfile, 'w' + error err unless dfd + ifd, err = io.open @infile, 'r' + error err unless ifd + dfd\write '#!/usr/bin/env lua5.3\n' + for line in ifd\lines! + dfd\write line, '\n' + ifd\close! + dfd\close! + #echo "Installed at:", @outfile + +default target OUT_AMALG, from: {BINARY_LUA, OUT_LUA}, out: OUT_AMALG, fn: => modules = foreach (patsubst OUT_LUA, '%.lua', '%'), => @gsub '/', '.' -Command 'amalg.lua', '-o', @outfile, '-s', 'bin/moonbuild.lua', modules diff --git a/README.md b/README.md index a4c47fd..aeee5cb 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,10 @@ Basically like `make`, but in [Moonscript](https://moonscript.org) and with expl It's fast, based on lua, and it's easy to write DSLs with it, so the build instructions can be readable. Also, it's a full programming language, so there are no arbitrary restrictions. ## How do I install it? +Any of these will work - `luarocks install moonbuild` (probably as root) +- `moon bin/moonbuild.moon install` (probably as root, in the cloned repo) +- `alfons install` (probably as root, in the cloned repo, requires alfons) ## Now, how do I use it? First, you'll need a `Build.moon`, `Buildfile.moon`, `Build` or `Buildfile` in the root of your project. diff --git a/bin/moonbuild.lua b/bin/moonbuild.lua deleted file mode 100644 index 6bb558a..0000000 --- a/bin/moonbuild.lua +++ /dev/null @@ -1,429 +0,0 @@ -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 diff --git a/bin/moonbuild.moon b/bin/moonbuild.moon index e265acc..0e70ef9 100755 --- a/bin/moonbuild.moon +++ b/bin/moonbuild.moon @@ -124,7 +124,7 @@ class BuildObject for i=1, #@outs return true if not otimes[i] - (max itimes)>(min otimes) + (max itimes)>=(min otimes) error "Need Lua >=5.2" if setfenv diff --git a/moonbuild.lua b/moonbuild.lua index f2d09ca..684b536 100644 --- a/moonbuild.lua +++ b/moonbuild.lua @@ -812,7 +812,7 @@ do return true end end - return (max(itimes)) > (min(otimes)) + return (max(itimes)) >= (min(otimes)) end } _base_0.__index = _base_0