From cb4f641884ae6104f44967949f9b52a9a72f7baf Mon Sep 17 00:00:00 2001 From: sanine Date: Tue, 4 Jan 2022 00:28:38 -0600 Subject: write first-pass main lua script --- src/argent.c | 37 +++++--- src/lua-script/cify.lua | 13 +++ src/lua-script/script.h | 209 ++++++++++++++++++++++++++++++++++++++++++++++ src/lua-script/script.lua | 207 +++++++++++++++++++++++++++++++++++++++++++++ src/options.c | 9 +- src/options.h | 1 - 6 files changed, 457 insertions(+), 19 deletions(-) create mode 100644 src/lua-script/cify.lua create mode 100644 src/lua-script/script.h create mode 100644 src/lua-script/script.lua diff --git a/src/argent.c b/src/argent.c index ae3a717..0d0dca2 100644 --- a/src/argent.c +++ b/src/argent.c @@ -7,6 +7,7 @@ #include "options.h" #include "bindings.h" #include "logging.h" +#include "lua-script/script.h" struct settings { @@ -14,6 +15,16 @@ struct settings { }; +#define CHECK_LUA_ERROR() \ + do { \ + if (error != 0) { \ + argent_log(FATAL, "lua_error: %s", lua_tostring(L, -1)); \ + lua_close(L); \ + return error; \ + } \ + } while(0) + + int main(int argc, char **argv) { argent_log(DEBUG, "parse command-line options"); @@ -24,7 +35,6 @@ int main(int argc, char **argv) argent_log(INFO, "log level: %s", level_string(argent_log_level)); argent_log(INFO, "configuration file: %s", opts.conf_filename); - argent_log(INFO, "output directory: %s", opts.output_dir); argent_log(DEBUG, "create lua state"); lua_State *L = luaL_newstate(); @@ -40,20 +50,25 @@ int main(int argc, char **argv) ); lua_setglobal(L, "argent"); + // load argent lua script + argent_log(DEBUG, "load main lua script"); + error = luaL_dostring(L, argent_script); + CHECK_LUA_ERROR(); + + // load configuration file argent_log(DEBUG, "load configuration file"); error = luaL_loadfile(L, opts.conf_filename); - if (error != 0) { - argent_log(FATAL, "lua error: %s", lua_tostring(L, -1)); - lua_close(L); - return error; - } + CHECK_LUA_ERROR(); + + // push config table to stack argent_log(DEBUG, "run configuration file"); error = hs_call(L, 0, 1); - if (error != 0) { - argent_log(FATAL, "lua error: %s", lua_tostring(L, -1)); - lua_close(L); - return error; - } + CHECK_LUA_ERROR(); + + // run argent script + argent_log(DEBUG, "run main lua script"); + error = hs_call(L, 1, 0); + CHECK_LUA_ERROR(); argent_log(DEBUG, "close lua state"); lua_close(L); diff --git a/src/lua-script/cify.lua b/src/lua-script/cify.lua new file mode 100644 index 0000000..153feb3 --- /dev/null +++ b/src/lua-script/cify.lua @@ -0,0 +1,13 @@ +-- "C"-ify a lua program + +output_file = io.open(arg[2], 'w') + + +output_file:write('const char *argent_script =\n') + +for line in io.lines(arg[1]) do + output_file:write(' "'..line..'\\n"\n') +end + +output_file:write(';') +output_file:close() diff --git a/src/lua-script/script.h b/src/lua-script/script.h new file mode 100644 index 0000000..e419923 --- /dev/null +++ b/src/lua-script/script.h @@ -0,0 +1,209 @@ +const char *argent_script = + "return function(config)\n" + "\n" + " --------------------------------\n" + " --\n" + " -- basics\n" + " --\n" + " --------------------------------\n" + "\n" + " function Set(array, transform)\n" + " if type(array) ~= 'table' then return nil end\n" + "\n" + " local transform = transform or function(x) return x end\n" + " \n" + " local set = {}\n" + " for _, element in ipairs(array) do\n" + " set[transform(element)] = true\n" + " end\n" + " return set\n" + " end\n" + "\n" + "\n" + " function add_end_slash(str)\n" + " if type(str) ~= 'string' then return nil end\n" + " if string.match(str, '/$') then return str end\n" + " return str .. '/'\n" + " end\n" + "\n" + "\n" + " function strip_end_slash(str)\n" + " if string.match(str, '/$') then return string.sub(str, 1, #str-1) end\n" + " return str\n" + " end\n" + "\n" + "\n" + " function setup(config)\n" + " argent.config = {\n" + " site_directory = add_end_slash(config.site_directory) or 'site/',\n" + " output_directory = add_end_slash(config.output_directory) or 'public/',\n" + " layout_directory = add_end_slash(config.layout_directory) or 'layouts/',\n" + " plugin_directory = add_end_slash(config.layout_directory) or 'plugins/',\n" + " exclude = Set(config.exclude, strip_end_slash) or {},\n" + " include = Set(config.include, strip_end_slash) or {},\n" + " keep = Set(config.keep, strip_end_slash) or {},\n" + " noprocess = Set(config.noprocess, strip_end_slash) or {},\n" + " rss_include = Set(config.rss_include, strip_end_slash) or {},\n" + " }\n" + "\n" + " package.path = argent.config.plugin_directory..'?.lua;'..package.path\n" + " end\n" + "\n" + "\n" + " function is_dotfile(filename)\n" + " if string.match(filename, '^%.') then return true end\n" + " return false\n" + " end\n" + "\n" + "\n" + " function directory_exists(directory, parent)\n" + " local directory = directory or ''\n" + " local parent = parent or ''\n" + " local dirs = argent.scanDirectory(argent.config.output_directory..parent)\n" + " for _, dir in ipairs(dirs) do\n" + " if strip_end_slash(directory) == dir then return true end\n" + " end\n" + " return false\n" + " end\n" + "\n" + "\n" + " function output_directory_exists()\n" + " local dirs = argent.scanDirectory('./')\n" + " for _, dir in ipairs(dirs) do\n" + " if add_end_slash(dir) == argent.config.output_directory then\n" + " return true\n" + " end\n" + " end\n" + " return false\n" + " end\n" + "\n" + "\n" + " --------------------------------\n" + " --\n" + " -- obliterating\n" + " --\n" + " --------------------------------\n" + "\n" + " function obliterate_file(file, parent)\n" + " if argent.config.keep[file] then\n" + " return true\n" + " end\n" + "\n" + " os.remove(argent.config.output_directory..parent..file)\n" + " return false\n" + " end\n" + "\n" + "\n" + " function obliterate_dir(dir, parent)\n" + " if argent.config.keep[strip_end_slash(dir)] then\n" + " return true\n" + " end\n" + "\n" + " return obliterate_directory(dir, parent)\n" + " end\n" + "\n" + "\n" + " function obliterate_directory(dirname, parent)\n" + " local dirname = add_end_slash(dirname) or ''\n" + " local parent = parent or ''\n" + " \n" + " if argent.config.keep[dirname] then return true end\n" + "\n" + " local keep_self = (dirname == '')\n" + "\n" + " local dirs, files = argent.scanDirectory(argent.config.output_directory..parent..dirname)\n" + " for _, file in ipairs(files) do\n" + " keep_self = obliterate_file(file, parent..dirname) or keep_self\n" + " end\n" + " for _, dir in ipairs(dirs) do\n" + " if dir ~= '.' and dir ~= '..' then\n" + " keep_self = obliterate_dir(dir, parent..dirname) or keep_self\n" + " end\n" + " end\n" + "\n" + " if not keep_self then\n" + " os.remove(argent.config.output_directory..parent..dirname)\n" + " return false\n" + " else\n" + " return true\n" + " end\n" + " end\n" + "\n" + "\n" + " --------------------------------\n" + " --\n" + " -- processing\n" + " --\n" + " --------------------------------\n" + "\n" + " function process_file(filename, parent)\n" + " if (is_dotfile(filename) and not argent.config.include[filename])\n" + " or argent.config.exclude[filename]\n" + " then return end\n" + "\n" + " if string.match(filename, '%.lua$') and not argent.config.noprocess[filename] then\n" + " process_lua_file(filename, parent)\n" + " else\n" + " argent.copyFile(\n" + " argent.config.site_directory..parent..filename,\n" + " argent.config.output_directory..parent..filename\n" + " )\n" + " end\n" + " end\n" + "\n" + "\n" + " function process_lua_file(filename, parent)\n" + " local success, result = pcall(loadfile(argent.config.site_directory..parent..filename))\n" + " if not success then\n" + " print('WARNING: '..result)\n" + " return\n" + " end\n" + "\n" + " print(filename, result)\n" + " end\n" + "\n" + "\n" + " function process_dir(directory, parent)\n" + " if (is_dotfile(directory) and not argent.config.include[strip_end_slash(directory)])\n" + " or argent.config.exclude[strip_end_slash(directory)]\n" + " then return end\n" + "\n" + " if not directory_exists(directory, parent) then\n" + " argent.createDirectory(argent.config.output_directory..parent..directory)\n" + " end\n" + " process_directory(directory, parent)\n" + " end\n" + "\n" + "\n" + " function process_directory(directory, parent)\n" + " local directory = add_end_slash(directory) or ''\n" + " local parent = add_end_slash(parent) or ''\n" + " local dirs, files = argent.scanDirectory(argent.config.site_directory..parent..directory)\n" + " for _, file in ipairs(files) do\n" + " process_file(file, parent..directory)\n" + " end\n" + "\n" + " for _, dir in ipairs(dirs) do\n" + " if dir ~= '.' and dir ~= '..' then\n" + " process_dir(dir, parent..directory)\n" + " end\n" + " end\n" + " end\n" + "\n" + "\n" + " --------------------------------\n" + " --\n" + " -- putting it all together\n" + " --\n" + " --------------------------------\n" + "\n" + " setup(config)\n" + " if not output_directory_exists() then\n" + " argent.createDirectory(argent.config.output_directory)\n" + " else\n" + " obliterate_directory()\n" + " end\n" + " process_directory()\n" + "end\n" + "\n" +; \ No newline at end of file diff --git a/src/lua-script/script.lua b/src/lua-script/script.lua new file mode 100644 index 0000000..733c494 --- /dev/null +++ b/src/lua-script/script.lua @@ -0,0 +1,207 @@ +return function(config) + + -------------------------------- + -- + -- basics + -- + -------------------------------- + + function Set(array, transform) + if type(array) ~= 'table' then return nil end + + local transform = transform or function(x) return x end + + local set = {} + for _, element in ipairs(array) do + set[transform(element)] = true + end + return set + end + + + function add_end_slash(str) + if type(str) ~= 'string' then return nil end + if string.match(str, '/$') then return str end + return str .. '/' + end + + + function strip_end_slash(str) + if string.match(str, '/$') then return string.sub(str, 1, #str-1) end + return str + end + + + function setup(config) + argent.config = { + site_directory = add_end_slash(config.site_directory) or 'site/', + output_directory = add_end_slash(config.output_directory) or 'public/', + layout_directory = add_end_slash(config.layout_directory) or 'layouts/', + plugin_directory = add_end_slash(config.layout_directory) or 'plugins/', + exclude = Set(config.exclude, strip_end_slash) or {}, + include = Set(config.include, strip_end_slash) or {}, + keep = Set(config.keep, strip_end_slash) or {}, + noprocess = Set(config.noprocess, strip_end_slash) or {}, + rss_include = Set(config.rss_include, strip_end_slash) or {}, + } + + package.path = argent.config.plugin_directory..'?.lua;'..package.path + end + + + function is_dotfile(filename) + if string.match(filename, '^%.') then return true end + return false + end + + + function directory_exists(directory, parent) + local directory = directory or '' + local parent = parent or '' + local dirs = argent.scanDirectory(argent.config.output_directory..parent) + for _, dir in ipairs(dirs) do + if strip_end_slash(directory) == dir then return true end + end + return false + end + + + function output_directory_exists() + local dirs = argent.scanDirectory('./') + for _, dir in ipairs(dirs) do + if add_end_slash(dir) == argent.config.output_directory then + return true + end + end + return false + end + + + -------------------------------- + -- + -- obliterating + -- + -------------------------------- + + function obliterate_file(file, parent) + if argent.config.keep[file] then + return true + end + + os.remove(argent.config.output_directory..parent..file) + return false + end + + + function obliterate_dir(dir, parent) + if argent.config.keep[strip_end_slash(dir)] then + return true + end + + return obliterate_directory(dir, parent) + end + + + function obliterate_directory(dirname, parent) + local dirname = add_end_slash(dirname) or '' + local parent = parent or '' + + if argent.config.keep[dirname] then return true end + + local keep_self = (dirname == '') + + local dirs, files = argent.scanDirectory(argent.config.output_directory..parent..dirname) + for _, file in ipairs(files) do + keep_self = obliterate_file(file, parent..dirname) or keep_self + end + for _, dir in ipairs(dirs) do + if dir ~= '.' and dir ~= '..' then + keep_self = obliterate_dir(dir, parent..dirname) or keep_self + end + end + + if not keep_self then + os.remove(argent.config.output_directory..parent..dirname) + return false + else + return true + end + end + + + -------------------------------- + -- + -- processing + -- + -------------------------------- + + function process_file(filename, parent) + if (is_dotfile(filename) and not argent.config.include[filename]) + or argent.config.exclude[filename] + then return end + + if string.match(filename, '%.lua$') and not argent.config.noprocess[filename] then + process_lua_file(filename, parent) + else + argent.copyFile( + argent.config.site_directory..parent..filename, + argent.config.output_directory..parent..filename + ) + end + end + + + function process_lua_file(filename, parent) + local success, result = pcall(loadfile(argent.config.site_directory..parent..filename)) + if not success then + print('WARNING: '..result) + return + end + + print(filename, result) + end + + + function process_dir(directory, parent) + if (is_dotfile(directory) and not argent.config.include[strip_end_slash(directory)]) + or argent.config.exclude[strip_end_slash(directory)] + then return end + + if not directory_exists(directory, parent) then + argent.createDirectory(argent.config.output_directory..parent..directory) + end + process_directory(directory, parent) + end + + + function process_directory(directory, parent) + local directory = add_end_slash(directory) or '' + local parent = add_end_slash(parent) or '' + local dirs, files = argent.scanDirectory(argent.config.site_directory..parent..directory) + for _, file in ipairs(files) do + process_file(file, parent..directory) + end + + for _, dir in ipairs(dirs) do + if dir ~= '.' and dir ~= '..' then + process_dir(dir, parent..directory) + end + end + end + + + -------------------------------- + -- + -- putting it all together + -- + -------------------------------- + + setup(config) + if not output_directory_exists() then + argent.createDirectory(argent.config.output_directory) + else + obliterate_directory() + end + process_directory() +end + diff --git a/src/options.c b/src/options.c index c4eb8d4..d221828 100644 --- a/src/options.c +++ b/src/options.c @@ -13,11 +13,10 @@ static void print_usage(const char *progname) int parse_options(struct argent_options *opts, int argc, char **argv) { opts->log_level = 0; - opts->conf_filename = "argent.lua"; - opts->output_dir = "public"; + opts->conf_filename = "config.lua"; int opt; - while ((opt = getopt(argc, argv, "vc:o:")) != -1) { + while ((opt = getopt(argc, argv, "vc:")) != -1) { switch (opt) { case 'v': opts->log_level += 1; @@ -27,10 +26,6 @@ int parse_options(struct argent_options *opts, int argc, char **argv) opts->conf_filename = optarg; break; - case 'o': - opts->output_dir = optarg; - break; - default: print_usage(argv[0]); return 1; diff --git a/src/options.h b/src/options.h index d62eb58..a54e2fa 100644 --- a/src/options.h +++ b/src/options.h @@ -3,7 +3,6 @@ struct argent_options { const char *conf_filename; - const char *output_dir; int log_level; }; -- cgit v1.2.1