summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-01-04 00:28:38 -0600
committersanine <sanine.not@pm.me>2022-01-04 00:28:38 -0600
commitcb4f641884ae6104f44967949f9b52a9a72f7baf (patch)
tree4819c0cc48f18b87d119d9b4bb393ef2bf4fe290
parent5830f684ba172664df43eee26636e99e5a228028 (diff)
write first-pass main lua script
-rw-r--r--src/argent.c37
-rw-r--r--src/lua-script/cify.lua13
-rw-r--r--src/lua-script/script.h209
-rw-r--r--src/lua-script/script.lua207
-rw-r--r--src/options.c9
-rw-r--r--src/options.h1
6 files changed, 457 insertions, 19 deletions
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;
};