mirror of
https://github.com/smogon/sprites.git
synced 2026-03-22 01:45:27 -05:00
163 lines
3.9 KiB
Lua
163 lines
3.9 KiB
Lua
|
|
--
|
|
-- Configuration
|
|
--
|
|
|
|
-- getconfig returning an empty string on absence is inconvenient
|
|
function getconfig(str)
|
|
local v = tup.getconfig(str)
|
|
if v == "" then
|
|
return nil
|
|
else
|
|
return v
|
|
end
|
|
end
|
|
|
|
--
|
|
-- Globs
|
|
--
|
|
|
|
-- A glob pattern is either an interpolated string, or a table of glob patterns
|
|
--
|
|
-- A normalized glob pattern is a table of strings, with interpolation resolved.
|
|
-- globpat_normalize("foo/*") --> {"foo/*"}
|
|
-- globpat_normalize({"foo/*"}) --> {"foo/*"}
|
|
-- globpat_normalize({"foo/*", {"{bar}/*"}}) --> {"foo/*", "baz_value/*"}
|
|
local function globpat_normalize(pat)
|
|
if type(pat) == "string" then
|
|
return {expand(pat)}
|
|
elseif type(pat) == 'table' then
|
|
local result = {}
|
|
for x in iter(pat) do
|
|
result += globpat_normalize(x)
|
|
end
|
|
return result
|
|
else
|
|
error("bad globpat")
|
|
end
|
|
end
|
|
|
|
function glob(pat, opts)
|
|
local results = {}
|
|
local filter = opts and opts.filter
|
|
local key = opts and opts.key
|
|
local seen = {}
|
|
for pat in iter(globpat_normalize(pat)) do
|
|
local frame = {}
|
|
push_frame(frame)
|
|
for file in iter(tup.glob(pat)) do
|
|
-- Workaround a weird issue pre reported
|
|
file = file:gsub("//", "/")
|
|
frame.input = file
|
|
|
|
if key then
|
|
local k = expand(key)
|
|
if seen[k] then
|
|
goto continue
|
|
end
|
|
seen[k] = true
|
|
end
|
|
|
|
if filter then
|
|
if not filter() then
|
|
goto continue
|
|
end
|
|
end
|
|
|
|
table.insert(results, file)
|
|
::continue::
|
|
end
|
|
pop_frame()
|
|
end
|
|
return results
|
|
end
|
|
|
|
-- Convenience iterator so you can do
|
|
-- `for path in iglob{...}` instead of `for path in iter(glob{...})`
|
|
function iglob(pat, opts)
|
|
return iter(glob(pat, opts))
|
|
end
|
|
|
|
|
|
function glob_matches(pat, opts)
|
|
local matched = glob(pat, opts)
|
|
return #matched > 0
|
|
end
|
|
|
|
-- Commands
|
|
|
|
local function cspec2cmd(cmdSpec)
|
|
local cmd = ""
|
|
for newcmd in iter(flatten(astable(cmdSpec))) do
|
|
newcmd = trim(newcmd)
|
|
if cmd ~= "" then
|
|
cmd = cmd .. " &&\n"
|
|
end
|
|
cmd = cmd .. newcmd
|
|
end
|
|
return cmd
|
|
end
|
|
|
|
-- Abstract over tup's arcane display override
|
|
local function display_cmd(display, cmd)
|
|
if display == nil then
|
|
return cmd
|
|
else
|
|
return rep{"^ ${display}^ ${cmd}", display=display, cmd=cmd}
|
|
end
|
|
end
|
|
|
|
local function do_rule_frame(opts, foreach)
|
|
local cspec = opts.command
|
|
local cmd = display_cmd(opts.display, cspec2cmd(cspec))
|
|
if foreach then
|
|
local input = glob(opts.input, opts)
|
|
for i in iter(input) do
|
|
local frame = {}
|
|
push_frame(frame)
|
|
frame.input = i
|
|
local output = {}
|
|
for v in iter(astable(opts.output)) do
|
|
table.insert(output, expand(v))
|
|
end
|
|
frame.output = tostring(output)
|
|
tup.rule(i, expand(cmd), output)
|
|
pop_frame()
|
|
end
|
|
else
|
|
local frame = {}
|
|
push_frame(frame)
|
|
local input = glob(opts.input)
|
|
frame.input = tostring(input)
|
|
local output = {}
|
|
for v in iter(astable(opts.output)) do
|
|
table.insert(output, expand(v))
|
|
end
|
|
frame.output = tostring(output)
|
|
tup.rule(input, expand(cmd), output)
|
|
pop_frame()
|
|
end
|
|
end
|
|
|
|
local function do_rule(opts, foreach)
|
|
local dimensions = opts.dimensions or {}
|
|
local ret = {}
|
|
iter_rep(dimensions,
|
|
function()
|
|
for v in iter{do_rule_frame(opts, foreach, ret)} do
|
|
table.insert(ret, v)
|
|
end
|
|
end
|
|
)
|
|
return ret
|
|
end
|
|
|
|
function rule(opts)
|
|
return do_rule(opts, false)
|
|
end
|
|
|
|
function foreach_rule(opts)
|
|
return do_rule(opts, true)
|
|
end
|
|
|