mirror of https://github.com/natnat-mc/moonbuild
				
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							429 lines
						
					
					
						
							11 KiB
						
					
					
				
			
		
		
	
	
							429 lines
						
					
					
						
							11 KiB
						
					
					
				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
 | 
						|
 |