#!/usr/bin/lua --------------------------------------------------------- ----------------Auto generated code block---------------- --------------------------------------------------------- do local origin_loader = package.loaders[2] package.loaders[2] = function(path) local files = { ------------------------ -- Modules part begin -- ------------------------ ["helpers"] = function() -------------------- -- Module: 'helpers' -------------------- local helpers = {} function helpers.read_file(filename) local file, err = io.open(filename, "r") if file then local data = file:read("*a") file:close() return data else error(err) end end function helpers.write_file(filename, data) local file, err = io.open(filename, "w") if file then file:write(data) else error(err) end end function helpers.find_in_includes(includes, modulename) local function check_path(p) local f = io.open(p) if f then f:close() return true end return false end local path = string.gsub(modulename, "%.", '/') table.insert(includes, 1, '.') for _, include in pairs(includes) do local abs_path = include .. '/' .. path .. '.lua' if check_path(abs_path) then return abs_path end end error("Unable to find file: " .. '"' .. modulename .. '"') end return helpers end, ["argparse"] = function() -------------------- -- Module: 'argparse' -------------------- -- The MIT License (MIT) -- Copyright (c) 2013 - 2015 Peter Melnichenko -- Permission is hereby granted, free of charge, to any person obtaining a copy of -- this software and associated documentation files (the "Software"), to deal in -- the Software without restriction, including without limitation the rights to -- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -- the Software, and to permit persons to whom the Software is furnished to do so, -- subject to the following conditions: -- The above copyright notice and this permission notice shall be included in all -- copies or substantial portions of the Software. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. local function deep_update(t1, t2) for k, v in pairs(t2) do if type(v) == "table" then v = deep_update({}, v) end t1[k] = v end return t1 end -- A property is a tuple {name, callback}. -- properties.args is number of properties that can be set as arguments -- when calling an object. local function class(prototype, properties, parent) -- Class is the metatable of its instances. local cl = {} cl.__index = cl if parent then cl.__prototype = deep_update(deep_update({}, parent.__prototype), prototype) else cl.__prototype = prototype end if properties then local names = {} -- Create setter methods and fill set of property names. for _, property in ipairs(properties) do local name, callback = property[1], property[2] cl[name] = function(self, value) if not callback(self, value) then self["_" .. name] = value end return self end names[name] = true end function cl.__call(self, ...) -- When calling an object, if the first argument is a table, -- interpret keys as property names, else delegate arguments -- to corresponding setters in order. if type((...)) == "table" then for name, value in pairs((...)) do if names[name] then self[name](self, value) end end else local nargs = select("#", ...) for i, property in ipairs(properties) do if i > nargs or i > properties.args then break end local arg = select(i, ...) if arg ~= nil then self[property[1]](self, arg) end end end return self end end -- If indexing class fails, fallback to its parent. local class_metatable = {} class_metatable.__index = parent function class_metatable.__call(self, ...) -- Calling a class returns its instance. -- Arguments are delegated to the instance. local object = deep_update({}, self.__prototype) setmetatable(object, self) return object(...) end return setmetatable(cl, class_metatable) end local function typecheck(name, types, value) for _, type_ in ipairs(types) do if type(value) == type_ then return true end end error(("bad property '%s' (%s expected, got %s)"):format(name, table.concat(types, " or "), type(value))) end local function typechecked(name, ...) local types = {...} return {name, function(_, value) typecheck(name, types, value) end} end local multiname = {"name", function(self, value) typecheck("name", {"string"}, value) for alias in value:gmatch("%S+") do self._name = self._name or alias table.insert(self._aliases, alias) end -- Do not set _name as with other properties. return true end} local function parse_boundaries(str) if tonumber(str) then return tonumber(str), tonumber(str) end if str == "*" then return 0, math.huge end if str == "+" then return 1, math.huge end if str == "?" then return 0, 1 end if str:match "^%d+%-%d+$" then local min, max = str:match "^(%d+)%-(%d+)$" return tonumber(min), tonumber(max) end if str:match "^%d+%+$" then local min = str:match "^(%d+)%+$" return tonumber(min), math.huge end end local function boundaries(name) return {name, function(self, value) typecheck(name, {"number", "string"}, value) local min, max = parse_boundaries(value) if not min then error(("bad property '%s'"):format(name)) end self["_min" .. name], self["_max" .. name] = min, max end} end local actions = {} local option_action = {"action", function(_, value) typecheck("action", {"function", "string"}, value) if type(value) == "string" and not actions[value] then error(("unknown action '%s'"):format(value)) end end} local option_init = {"init", function(self) self._has_init = true end} local option_default = {"default", function(self, value) if type(value) ~= "string" then self._init = value self._has_init = true return true end end} local add_help = {"add_help", function(self, value) typecheck("add_help", {"boolean", "string", "table"}, value) if self._has_help then table.remove(self._options) self._has_help = false end if value then local help = self:flag() :description "Show this help message and exit." :action(function() print(self:get_help()) os.exit(0) end) if value ~= true then help = help(value) end if not help._name then help "-h" "--help" end self._has_help = true end end} local Parser = class({ _arguments = {}, _options = {}, _commands = {}, _mutexes = {}, _require_command = true, _handle_options = true }, { args = 3, typechecked("name", "string"), typechecked("description", "string"), typechecked("epilog", "string"), typechecked("usage", "string"), typechecked("help", "string"), typechecked("require_command", "boolean"), typechecked("handle_options", "boolean"), typechecked("action", "function"), typechecked("command_target", "string"), add_help }) local Command = class({ _aliases = {} }, { args = 3, multiname, typechecked("description", "string"), typechecked("epilog", "string"), typechecked("target", "string"), typechecked("usage", "string"), typechecked("help", "string"), typechecked("require_command", "boolean"), typechecked("handle_options", "boolean"), typechecked("action", "function"), typechecked("command_target", "string"), add_help }, Parser) local Argument = class({ _minargs = 1, _maxargs = 1, _mincount = 1, _maxcount = 1, _defmode = "unused", _show_default = true }, { args = 5, typechecked("name", "string"), typechecked("description", "string"), option_default, typechecked("convert", "function", "table"), boundaries("args"), typechecked("target", "string"), typechecked("defmode", "string"), typechecked("show_default", "boolean"), typechecked("argname", "string", "table"), option_action, option_init }) local Option = class({ _aliases = {}, _mincount = 0, _overwrite = true }, { args = 6, multiname, typechecked("description", "string"), option_default, typechecked("convert", "function", "table"), boundaries("args"), boundaries("count"), typechecked("target", "string"), typechecked("defmode", "string"), typechecked("show_default", "boolean"), typechecked("overwrite", "boolean"), typechecked("argname", "string", "table"), option_action, option_init }, Argument) function Argument:_get_argument_list() local buf = {} local i = 1 while i <= math.min(self._minargs, 3) do local argname = self:_get_argname(i) if self._default and self._defmode:find "a" then argname = "[" .. argname .. "]" end table.insert(buf, argname) i = i+1 end while i <= math.min(self._maxargs, 3) do table.insert(buf, "[" .. self:_get_argname(i) .. "]") i = i+1 if self._maxargs == math.huge then break end end if i < self._maxargs then table.insert(buf, "...") end return buf end function Argument:_get_usage() local usage = table.concat(self:_get_argument_list(), " ") if self._default and self._defmode:find "u" then if self._maxargs > 1 or (self._minargs == 1 and not self._defmode:find "a") then usage = "[" .. usage .. "]" end end return usage end function actions.store_true(result, target) result[target] = true end function actions.store_false(result, target) result[target] = false end function actions.store(result, target, argument) result[target] = argument end function actions.count(result, target, _, overwrite) if not overwrite then result[target] = result[target] + 1 end end function actions.append(result, target, argument, overwrite) result[target] = result[target] or {} table.insert(result[target], argument) if overwrite then table.remove(result[target], 1) end end function actions.concat(result, target, arguments, overwrite) if overwrite then error("'concat' action can't handle too many invocations") end result[target] = result[target] or {} for _, argument in ipairs(arguments) do table.insert(result[target], argument) end end function Argument:_get_action() local action, init if self._maxcount == 1 then if self._maxargs == 0 then action, init = "store_true", nil else action, init = "store", nil end else if self._maxargs == 0 then action, init = "count", 0 else action, init = "append", {} end end if self._action then action = self._action end if self._has_init then init = self._init end if type(action) == "string" then action = actions[action] end return action, init end -- Returns placeholder for `narg`-th argument. function Argument:_get_argname(narg) local argname = self._argname or self:_get_default_argname() if type(argname) == "table" then return argname[narg] else return argname end end function Argument:_get_default_argname() return "<" .. self._name .. ">" end function Option:_get_default_argname() return "<" .. self:_get_default_target() .. ">" end -- Returns label to be shown in the help message. function Argument:_get_label() return self._name end function Option:_get_label() local variants = {} local argument_list = self:_get_argument_list() table.insert(argument_list, 1, nil) for _, alias in ipairs(self._aliases) do argument_list[1] = alias table.insert(variants, table.concat(argument_list, " ")) end return table.concat(variants, ", ") end function Command:_get_label() return table.concat(self._aliases, ", ") end function Argument:_get_description() if self._default and self._show_default then if self._description then return ("%s (default: %s)"):format(self._description, self._default) else return ("default: %s"):format(self._default) end else return self._description or "" end end function Command:_get_description() return self._description or "" end function Option:_get_usage() local usage = self:_get_argument_list() table.insert(usage, 1, self._name) usage = table.concat(usage, " ") if self._mincount == 0 or self._default then usage = "[" .. usage .. "]" end return usage end function Argument:_get_default_target() return self._name end function Option:_get_default_target() local res for _, alias in ipairs(self._aliases) do if alias:sub(1, 1) == alias:sub(2, 2) then res = alias:sub(3) break end end res = res or self._name:sub(2) return (res:gsub("-", "_")) end function Option:_is_vararg() return self._maxargs ~= self._minargs end function Parser:_get_fullname() local parent = self._parent local buf = {self._name} while parent do table.insert(buf, 1, parent._name) parent = parent._parent end return table.concat(buf, " ") end function Parser:_update_charset(charset) charset = charset or {} for _, command in ipairs(self._commands) do command:_update_charset(charset) end for _, option in ipairs(self._options) do for _, alias in ipairs(option._aliases) do charset[alias:sub(1, 1)] = true end end return charset end function Parser:argument(...) local argument = Argument(...) table.insert(self._arguments, argument) return argument end function Parser:option(...) local option = Option(...) if self._has_help then table.insert(self._options, #self._options, option) else table.insert(self._options, option) end return option end function Parser:flag(...) return self:option():args(0)(...) end function Parser:command(...) local command = Command():add_help(true)(...) command._parent = self table.insert(self._commands, command) return command end function Parser:mutex(...) local options = {...} for i, option in ipairs(options) do assert(getmetatable(option) == Option, ("bad argument #%d to 'mutex' (Option expected)"):format(i)) end table.insert(self._mutexes, options) return self end local max_usage_width = 70 local usage_welcome = "Usage: " function Parser:get_usage() if self._usage then return self._usage end local lines = {usage_welcome .. self:_get_fullname()} local function add(s) if #lines[#lines]+1+#s <= max_usage_width then lines[#lines] = lines[#lines] .. " " .. s else lines[#lines+1] = (" "):rep(#usage_welcome) .. s end end -- This can definitely be refactored into something cleaner local mutex_options = {} local vararg_mutexes = {} -- First, put mutexes which do not contain vararg options and remember those which do for _, mutex in ipairs(self._mutexes) do local buf = {} local is_vararg = false for _, option in ipairs(mutex) do if option:_is_vararg() then is_vararg = true end table.insert(buf, option:_get_usage()) mutex_options[option] = true end local repr = "(" .. table.concat(buf, " | ") .. ")" if is_vararg then table.insert(vararg_mutexes, repr) else add(repr) end end -- Second, put regular options for _, option in ipairs(self._options) do if not mutex_options[option] and not option:_is_vararg() then add(option:_get_usage()) end end -- Put positional arguments for _, argument in ipairs(self._arguments) do add(argument:_get_usage()) end -- Put mutexes containing vararg options for _, mutex_repr in ipairs(vararg_mutexes) do add(mutex_repr) end for _, option in ipairs(self._options) do if not mutex_options[option] and option:_is_vararg() then add(option:_get_usage()) end end if #self._commands > 0 then if self._require_command then add("") else add("[]") end add("...") end return table.concat(lines, "\n") end local margin_len = 3 local margin_len2 = 25 local margin = (" "):rep(margin_len) local margin2 = (" "):rep(margin_len2) local function make_two_columns(s1, s2) if s2 == "" then return margin .. s1 end s2 = s2:gsub("\n", "\n" .. margin2) if #s1 < (margin_len2-margin_len) then return margin .. s1 .. (" "):rep(margin_len2-margin_len-#s1) .. s2 else return margin .. s1 .. "\n" .. margin2 .. s2 end end function Parser:get_help() if self._help then return self._help end local blocks = {self:get_usage()} if self._description then table.insert(blocks, self._description) end local labels = {"Arguments:", "Options:", "Commands:"} for i, elements in ipairs{self._arguments, self._options, self._commands} do if #elements > 0 then local buf = {labels[i]} for _, element in ipairs(elements) do table.insert(buf, make_two_columns(element:_get_label(), element:_get_description())) end table.insert(blocks, table.concat(buf, "\n")) end end if self._epilog then table.insert(blocks, self._epilog) end return table.concat(blocks, "\n\n") end local function get_tip(context, wrong_name) local context_pool = {} local possible_name local possible_names = {} for name in pairs(context) do if type(name) == "string" then for i = 1, #name do possible_name = name:sub(1, i - 1) .. name:sub(i + 1) if not context_pool[possible_name] then context_pool[possible_name] = {} end table.insert(context_pool[possible_name], name) end end end for i = 1, #wrong_name + 1 do possible_name = wrong_name:sub(1, i - 1) .. wrong_name:sub(i + 1) if context[possible_name] then possible_names[possible_name] = true elseif context_pool[possible_name] then for _, name in ipairs(context_pool[possible_name]) do possible_names[name] = true end end end local first = next(possible_names) if first then if next(possible_names, first) then local possible_names_arr = {} for name in pairs(possible_names) do table.insert(possible_names_arr, "'" .. name .. "'") end table.sort(possible_names_arr) return "\nDid you mean one of these: " .. table.concat(possible_names_arr, " ") .. "?" else return "\nDid you mean '" .. first .. "'?" end else return "" end end local ElementState = class({ invocations = 0 }) function ElementState:__call(state, element) self.state = state self.result = state.result self.element = element self.target = element._target or element:_get_default_target() self.action, self.result[self.target] = element:_get_action() return self end function ElementState:error(fmt, ...) self.state:error(fmt, ...) end function ElementState:convert(argument) local converter = self.element._convert if converter then local ok, err if type(converter) == "function" then ok, err = converter(argument) else ok = converter[argument] end if ok == nil then self:error(err and "%s" or "malformed argument '%s'", err or argument) end argument = ok end return argument end function ElementState:default(mode) return self.element._defmode:find(mode) and self.element._default end local function bound(noun, min, max, is_max) local res = "" if min ~= max then res = "at " .. (is_max and "most" or "least") .. " " end local number = is_max and max or min return res .. tostring(number) .. " " .. noun .. (number == 1 and "" or "s") end function ElementState:invoke(alias) self.open = true self.name = ("%s '%s'"):format(alias and "option" or "argument", alias or self.element._name) self.overwrite = false if self.invocations >= self.element._maxcount then if self.element._overwrite then self.overwrite = true else self:error("%s must be used %s", self.name, bound("time", self.element._mincount, self.element._maxcount, true)) end else self.invocations = self.invocations + 1 end self.args = {} if self.element._maxargs <= 0 then self:close() end return self.open end function ElementState:pass(argument) argument = self:convert(argument) table.insert(self.args, argument) if #self.args >= self.element._maxargs then self:close() end return self.open end function ElementState:complete_invocation() while #self.args < self.element._minargs do self:pass(self.element._default) end end function ElementState:close() if self.open then self.open = false if #self.args < self.element._minargs then if self:default("a") then self:complete_invocation() else if #self.args == 0 then if getmetatable(self.element) == Argument then self:error("missing %s", self.name) elseif self.element._maxargs == 1 then self:error("%s requires an argument", self.name) end end self:error("%s requires %s", self.name, bound("argument", self.element._minargs, self.element._maxargs)) end end local args = self.args if self.element._maxargs <= 1 then args = args[1] end if self.element._maxargs == 1 and self.element._minargs == 0 and self.element._mincount ~= self.element._maxcount then args = self.args end self.action(self.result, self.target, args, self.overwrite) end end local ParseState = class({ result = {}, options = {}, arguments = {}, argument_i = 1, element_to_mutexes = {}, mutex_to_used_option = {}, command_actions = {} }) function ParseState:__call(parser, error_handler) self.parser = parser self.error_handler = error_handler self.charset = parser:_update_charset() self:switch(parser) return self end function ParseState:error(fmt, ...) self.error_handler(self.parser, fmt:format(...)) end function ParseState:switch(parser) self.parser = parser if parser._action then table.insert(self.command_actions, {action = parser._action, name = parser._name}) end for _, option in ipairs(parser._options) do option = ElementState(self, option) table.insert(self.options, option) for _, alias in ipairs(option.element._aliases) do self.options[alias] = option end end for _, mutex in ipairs(parser._mutexes) do for _, option in ipairs(mutex) do if not self.element_to_mutexes[option] then self.element_to_mutexes[option] = {} end table.insert(self.element_to_mutexes[option], mutex) end end for _, argument in ipairs(parser._arguments) do argument = ElementState(self, argument) table.insert(self.arguments, argument) argument:invoke() end self.handle_options = parser._handle_options self.argument = self.arguments[self.argument_i] self.commands = parser._commands for _, command in ipairs(self.commands) do for _, alias in ipairs(command._aliases) do self.commands[alias] = command end end end function ParseState:get_option(name) local option = self.options[name] if not option then self:error("unknown option '%s'%s", name, get_tip(self.options, name)) else return option end end function ParseState:get_command(name) local command = self.commands[name] if not command then if #self.commands > 0 then self:error("unknown command '%s'%s", name, get_tip(self.commands, name)) else self:error("too many arguments") end else return command end end function ParseState:invoke(option, name) self:close() if self.element_to_mutexes[option.element] then for _, mutex in ipairs(self.element_to_mutexes[option.element]) do local used_option = self.mutex_to_used_option[mutex] if used_option and used_option ~= option then self:error("option '%s' can not be used together with %s", name, used_option.name) else self.mutex_to_used_option[mutex] = option end end end if option:invoke(name) then self.option = option end end function ParseState:pass(arg) if self.option then if not self.option:pass(arg) then self.option = nil end elseif self.argument then if not self.argument:pass(arg) then self.argument_i = self.argument_i + 1 self.argument = self.arguments[self.argument_i] end else local command = self:get_command(arg) self.result[command._target or command._name] = true if self.parser._command_target then self.result[self.parser._command_target] = command._name end self:switch(command) end end function ParseState:close() if self.option then self.option:close() self.option = nil end end function ParseState:finalize() self:close() for i = self.argument_i, #self.arguments do local argument = self.arguments[i] if #argument.args == 0 and argument:default("u") then argument:complete_invocation() else argument:close() end end if self.parser._require_command and #self.commands > 0 then self:error("a command is required") end for _, option in ipairs(self.options) do local name = option.name or ("option '%s'"):format(option.element._name) if option.invocations == 0 then if option:default("u") then option:invoke(name) option:complete_invocation() option:close() end end local mincount = option.element._mincount if option.invocations < mincount then if option:default("a") then while option.invocations < mincount do option:invoke(name) option:close() end elseif option.invocations == 0 then self:error("missing %s", name) else self:error("%s must be used %s", name, bound("time", mincount, option.element._maxcount)) end end end for i = #self.command_actions, 1, -1 do self.command_actions[i].action(self.result, self.command_actions[i].name) end end function ParseState:parse(args) for _, arg in ipairs(args) do local plain = true if self.handle_options then local first = arg:sub(1, 1) if self.charset[first] then if #arg > 1 then plain = false if arg:sub(2, 2) == first then if #arg == 2 then self:close() self.handle_options = false else local equals = arg:find "=" if equals then local name = arg:sub(1, equals - 1) local option = self:get_option(name) if option.element._maxargs <= 0 then self:error("option '%s' does not take arguments", name) end self:invoke(option, name) self:pass(arg:sub(equals + 1)) else local option = self:get_option(arg) self:invoke(option, arg) end end else for i = 2, #arg do local name = first .. arg:sub(i, i) local option = self:get_option(name) self:invoke(option, name) if i ~= #arg and option.element._maxargs > 0 then self:pass(arg:sub(i + 1)) break end end end end end end if plain then self:pass(arg) end end self:finalize() return self.result end function Parser:error(msg) io.stderr:write(("%s\n\nError: %s\n"):format(self:get_usage(), msg)) os.exit(1) end -- Compatibility with strict.lua and other checkers: local default_cmdline = rawget(_G, "arg") or {} function Parser:_parse(args, error_handler) return ParseState(self, error_handler):parse(args or default_cmdline) end function Parser:parse(args) return self:_parse(args, self.error) end local function xpcall_error_handler(err) return tostring(err) .. "\noriginal " .. debug.traceback("", 2):sub(2) end function Parser:pparse(args) local parse_error local ok, result = xpcall(function() return self:_parse(args, function(_, err) parse_error = err error(err, 0) end) end, xpcall_error_handler) if ok then return true, result elseif not parse_error then error(result, 0) else return false, parse_error end end return function(...) return Parser(default_cmdline[0]):add_help(true)(...) end end, ["template"] = function() -------------------- -- Module: 'template' -------------------- local setmetatable = setmetatable local loadstring = loadstring local loadchunk local tostring = tostring local setfenv = setfenv local require = require local capture local concat = table.concat local assert = assert local prefix local write = io.write local pcall = pcall local phase local open = io.open local load = load local type = type local dump = string.dump local find = string.find local gsub = string.gsub local byte = string.byte local null local sub = string.sub local ngx = ngx local jit = jit local var local _VERSION = _VERSION local _ENV = _ENV local _G = _G local HTML_ENTITIES = { ["&"] = "&", ["<"] = "<", [">"] = ">", ['"'] = """, ["'"] = "'", ["/"] = "/" } local CODE_ENTITIES = { ["{"] = "{", ["}"] = "}", ["&"] = "&", ["<"] = "<", [">"] = ">", ['"'] = """, ["'"] = "'", ["/"] = "/" } local VAR_PHASES local ok, newtab = pcall(require, "table.new") if not ok then newtab = function() return {} end end local caching = true local template = newtab(0, 12) template._VERSION = "1.9" template.cache = {} local function enabled(val) if val == nil then return true end return val == true or (val == "1" or val == "true" or val == "on") end local function trim(s) return gsub(gsub(s, "^%s+", ""), "%s+$", "") end local function rpos(view, s) while s > 0 do local c = sub(view, s, s) if c == " " or c == "\t" or c == "\0" or c == "\x0B" then s = s - 1 else break end end return s end local function escaped(view, s) if s > 1 and sub(view, s - 1, s - 1) == "\\" then if s > 2 and sub(view, s - 2, s - 2) == "\\" then return false, 1 else return true, 1 end end return false, 0 end local function readfile(path) local file = open(path, "rb") if not file then return nil end local content = file:read "*a" file:close() return content end local function loadlua(path) return readfile(path) or path end local function loadngx(path) local vars = VAR_PHASES[phase()] local file, location = path, vars and var.template_location if sub(file, 1) == "/" then file = sub(file, 2) end if location and location ~= "" then if sub(location, -1) == "/" then location = sub(location, 1, -2) end local res = capture(concat{ location, '/', file}) if res.status == 200 then return res.body end end local root = vars and (var.template_root or var.document_root) or prefix if sub(root, -1) == "/" then root = sub(root, 1, -2) end return readfile(concat{ root, "/", file }) or path end do if ngx then VAR_PHASES = { set = true, rewrite = true, access = true, content = true, header_filter = true, body_filter = true, log = true } template.print = ngx.print or write template.load = loadngx prefix, var, capture, null, phase = ngx.config.prefix(), ngx.var, ngx.location.capture, ngx.null, ngx.get_phase if VAR_PHASES[phase()] then caching = enabled(var.template_cache) end else template.print = write template.load = loadlua end if _VERSION == "Lua 5.1" then local context = { __index = function(t, k) return t.context[k] or t.template[k] or _G[k] end } if jit then loadchunk = function(view) return assert(load(view, nil, nil, setmetatable({ template = template }, context))) end else loadchunk = function(view) local func = assert(loadstring(view)) setfenv(func, setmetatable({ template = template }, context)) return func end end else local context = { __index = function(t, k) return t.context[k] or t.template[k] or _ENV[k] end } loadchunk = function(view) return assert(load(view, nil, nil, setmetatable({ template = template }, context))) end end end function template.caching(enable) if enable ~= nil then caching = enable == true end return caching end function template.output(s) if s == nil or s == null then return "" end if type(s) == "function" then return template.output(s()) end return tostring(s) end function template.escape(s, c) if type(s) == "string" then if c then return gsub(s, "[}{\">/<'&]", CODE_ENTITIES) end return gsub(s, "[\">/<'&]", HTML_ENTITIES) end return template.output(s) end function template.new(view, layout) assert(view, "view was not provided for template.new(view, layout).") local render, compile = template.render, template.compile if layout then if type(layout) == "table" then return setmetatable({ render = function(self, context) local context = context or self context.blocks = context.blocks or {} context.view = compile(view)(context) layout.blocks = context.blocks or {} layout.view = context.view or "" return layout:render() end }, { __tostring = function(self) local context = self context.blocks = context.blocks or {} context.view = compile(view)(context) layout.blocks = context.blocks or {} layout.view = context.view return tostring(layout) end }) else return setmetatable({ render = function(self, context) local context = context or self context.blocks = context.blocks or {} context.view = compile(view)(context) return render(layout, context) end }, { __tostring = function(self) local context = self context.blocks = context.blocks or {} context.view = compile(view)(context) return compile(layout)(context) end }) end end return setmetatable({ render = function(self, context) return render(view, context or self) end }, { __tostring = function(self) return compile(view)(self) end }) end function template.precompile(view, path, strip) local chunk = dump(template.compile(view), strip ~= false) if path then local file = open(path, "wb") file:write(chunk) file:close() end return chunk end function template.compile(view, key, plain) assert(view, "view was not provided for template.compile(view, key, plain).") if key == "no-cache" then return loadchunk(template.parse(view, plain)), false end key = key or view local cache = template.cache if cache[key] then return cache[key], true end local func = loadchunk(template.parse(view, plain)) if caching then cache[key] = func end return func, false end function template.parse(view, plain) assert(view, "view was not provided for template.parse(view, plain).") if not plain then view = template.load(view) if byte(view, 1, 1) == 27 then return view end end local j = 2 local c = {[[ context=... or {} local function include(v, c) return template.compile(v)(c or context) end local ___,blocks,layout={},blocks or {} ]] } local i, s = 1, find(view, "{", 1, true) while s do local t, p = sub(view, s + 1, s + 1), s + 2 if t == "{" then local e = find(view, "}}", p, true) if e then local z, w = escaped(view, s) if i < s - w then c[j] = "___[#___+1]=[=[\n" c[j+1] = sub(view, i, s - 1 - w) c[j+2] = "]=]\n" j=j+3 end if z then i = s else c[j] = "___[#___+1]=template.escape(" c[j+1] = trim(sub(view, p, e - 1)) c[j+2] = ")\n" j=j+3 s, i = e + 1, e + 2 end end elseif t == "*" then local e = find(view, "*}", p, true) if e then local z, w = escaped(view, s) if i < s - w then c[j] = "___[#___+1]=[=[\n" c[j+1] = sub(view, i, s - 1 - w) c[j+2] = "]=]\n" j=j+3 end if z then i = s else c[j] = "___[#___+1]=template.output(" c[j+1] = trim(sub(view, p, e - 1)) c[j+2] = ")\n" j=j+3 s, i = e + 1, e + 2 end end elseif t == "%" then local e = find(view, "%}", p, true) if e then local z, w = escaped(view, s) if z then if i < s - w then c[j] = "___[#___+1]=[=[\n" c[j+1] = sub(view, i, s - 1 - w) c[j+2] = "]=]\n" j=j+3 end i = s else local n = e + 2 if sub(view, n, n) == "\n" then n = n + 1 end local r = rpos(view, s - 1) if i <= r then c[j] = "___[#___+1]=[=[\n" c[j+1] = sub(view, i, r) c[j+2] = "]=]\n" j=j+3 end c[j] = trim(sub(view, p, e - 1)) c[j+1] = "\n" j=j+2 s, i = n - 1, n end end elseif t == "(" then local e = find(view, ")}", p, true) if e then local z, w = escaped(view, s) if i < s - w then c[j] = "___[#___+1]=[=[\n" c[j+1] = sub(view, i, s - 1 - w) c[j+2] = "]=]\n" j=j+3 end if z then i = s else local f = sub(view, p, e - 1) local x = find(f, ",", 2, true) if x then c[j] = "___[#___+1]=include([=[" c[j+1] = trim(sub(f, 1, x - 1)) c[j+2] = "]=]," c[j+3] = trim(sub(f, x + 1)) c[j+4] = ")\n" j=j+5 else c[j] = "___[#___+1]=include([=[" c[j+1] = trim(f) c[j+2] = "]=])\n" j=j+3 end s, i = e + 1, e + 2 end end elseif t == "[" then local e = find(view, "]}", p, true) if e then local z, w = escaped(view, s) if i < s - w then c[j] = "___[#___+1]=[=[\n" c[j+1] = sub(view, i, s - 1 - w) c[j+2] = "]=]\n" j=j+3 end if z then i = s else c[j] = "___[#___+1]=include(" c[j+1] = trim(sub(view, p, e - 1)) c[j+2] = ")\n" j=j+3 s, i = e + 1, e + 2 end end elseif t == "-" then local e = find(view, "-}", p, true) if e then local x, y = find(view, sub(view, s, e + 1), e + 2, true) if x then local z, w = escaped(view, s) if z then if i < s - w then c[j] = "___[#___+1]=[=[\n" c[j+1] = sub(view, i, s - 1 - w) c[j+2] = "]=]\n" j=j+3 end i = s else y = y + 1 x = x - 1 if sub(view, y, y) == "\n" then y = y + 1 end local b = trim(sub(view, p, e - 1)) if b == "verbatim" or b == "raw" then if i < s - w then c[j] = "___[#___+1]=[=[\n" c[j+1] = sub(view, i, s - 1 - w) c[j+2] = "]=]\n" j=j+3 end c[j] = "___[#___+1]=[=[" c[j+1] = sub(view, e + 2, x) c[j+2] = "]=]\n" j=j+3 else if sub(view, x, x) == "\n" then x = x - 1 end local r = rpos(view, s - 1) if i <= r then c[j] = "___[#___+1]=[=[\n" c[j+1] = sub(view, i, r) c[j+2] = "]=]\n" j=j+3 end c[j] = 'blocks["' c[j+1] = b c[j+2] = '"]=include[=[' c[j+3] = sub(view, e + 2, x) c[j+4] = "]=]\n" j=j+5 end s, i = y - 1, y end end end elseif t == "#" then local e = find(view, "#}", p, true) if e then local z, w = escaped(view, s) if i < s - w then c[j] = "___[#___+1]=[=[\n" c[j+1] = sub(view, i, s - 1 - w) c[j+2] = "]=]\n" j=j+3 end if z then i = s else e = e + 2 if sub(view, e, e) == "\n" then e = e + 1 end s, i = e - 1, e end end end s = find(view, "{", s + 1, true) end s = sub(view, i) if s and s ~= "" then c[j] = "___[#___+1]=[=[\n" c[j+1] = s c[j+2] = "]=]\n" j=j+3 end c[j] = "return layout and include(layout,setmetatable({view=table.concat(___),blocks=blocks},{__index=context})) or table.concat(___)" return concat(c) end function template.render(view, context, key, plain) assert(view, "view was not provided for template.render(view, context, key, plain).") return template.print(template.compile(view, key, plain)(context)) end return template end, ---------------------- -- Modules part end -- ---------------------- } if files[path] then return files[path] else return origin_loader(path) end end end --------------------------------------------------------- ----------------Auto generated code block---------------- --------------------------------------------------------- package.path = 'argparse/src/?.lua;templates/lib/resty/?.lua;' .. package.path argparse = require 'argparse' helpers = require 'helpers' templates = require 'template' local parser = argparse("luacc", "Lua Code Combine tool") parser:argument("main", "Main file of project") parser:argument("modules", "Secondary files of project"):args("*") parser:option("-o --output", "Output file"):count(1) parser:option("-i --include", "Include directory path"):count('*') parser:option("-p --position", "Amount of main file lines that should be left before generated code block") local args = parser:parse() local data_loader_temp = [[ --------------------------------------------------------- ----------------Auto generated code block---------------- --------------------------------------------------------- do local origin_loader = package.loaders[2] package.loaders[2] = function(path) local files = { ------------------------ -- Modules part begin -- ------------------------ {% for _, file in ipairs(files) do %} ["{*file.filename*}"] = function() -------------------- -- Module: '{*file.filename*}' -------------------- {*file.filedata*} end, {% end %} ---------------------- -- Modules part end -- ---------------------- } if files[path] then return files[path] else return origin_loader(path) end end end --------------------------------------------------------- ----------------Auto generated code block---------------- --------------------------------------------------------- ]] local main_file_body = {} for line in io.lines(helpers.find_in_includes(args.include, args.main)) do table.insert(main_file_body, line) end local length_of_head = 0 if not args.position then if string.sub(main_file_body[1], 1, 2) == '#!' then length_of_head = 1 end elseif tonumber(args.position) then length_of_head = tonumber(args.position) if length_of_head > #main_file_body then error("invalid value of 'position': number of lines less than value of paramenter") end else local pattern = '--' .. args.position for n, line in ipairs(main_file_body) do if line == pattern then length_of_head = n end end if length_of_head == 0 then error("invalid value of 'position': unable to find pattern " .. "'" .. pattern .. "'") end table.remove(main_file_body, length_of_head) length_of_head = length_of_head - 1 end local files_table = { files = {} } for _, filename in ipairs(args.modules) do local path = helpers.find_in_includes(args.include, filename) local data = helpers.read_file(path) table.insert( files_table.files, { filename = filename, filedata = data } ) end local render_res = "" templates.print = function(res) render_res = res end templates.render(data_loader_temp, files_table) local result_data = table.concat(main_file_body, "\n", 1, length_of_head) .. "\n" .. render_res .. table.concat(main_file_body, "\n", length_of_head + 1) helpers.write_file(args.output, result_data)