summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-01-04 22:28:43 -0600
committersanine <sanine.not@pm.me>2022-01-04 22:28:43 -0600
commit72e13dff9ff4fde91b84054167da91a5d27cb952 (patch)
treefca4ac07fe5b8e03ab6352fb999be1459f115db4
parent43347c36ec9b1f5e988cf6c89edd4d901061a303 (diff)
add working rss:
-rwxr-xr-xsrc/lua-script/cify.lua2
-rw-r--r--src/lua-script/script.h204
-rw-r--r--src/lua-script/script.lua204
3 files changed, 394 insertions, 16 deletions
diff --git a/src/lua-script/cify.lua b/src/lua-script/cify.lua
index a2fbcbe..1c6a16b 100755
--- a/src/lua-script/cify.lua
+++ b/src/lua-script/cify.lua
@@ -8,6 +8,8 @@ output_file = io.open('script.h', 'w')
output_file:write('const char *argent_script =\n')
for line in io.lines('script.lua') do
+ line = string.gsub(line, '\\', '\\\\')
+ line = string.gsub(line, '"', '\\"')
output_file:write(' "'..line..'\\n"\n')
end
diff --git a/src/lua-script/script.h b/src/lua-script/script.h
index 9406097..0b58f11 100644
--- a/src/lua-script/script.h
+++ b/src/lua-script/script.h
@@ -1,4 +1,134 @@
const char *argent_script =
+ "local RssChannel = {}\n"
+ "RssChannel.new = function(title, link, description, settings)\n"
+ " local settings = settings or {}\n"
+ "\n"
+ " local channel = {\n"
+ " title=title,\n"
+ " link=link,\n"
+ " description=description,\n"
+ " }\n"
+ "\n"
+ " channel.language = settings.language\n"
+ " channel.copyright = settings.copyright\n"
+ " channel.managingEditor = settings.managingEditor\n"
+ " channel.webMaster = settings.webMaster\n"
+ " channel.lastBuildDate = settings.lastBuildDate\n"
+ " channel.category = settings.category\n"
+ " channel.generator = 'argent v0.1.0'\n"
+ " channel.docs = 'https://www.rssboard.org/rss-specification'\n"
+ "\n"
+ " channel.items = {}\n"
+ "\n"
+ " setmetatable(\n"
+ " channel,\n"
+ " {\n"
+ " __index=RssChannel,\n"
+ " __tostring=RssChannel.tostring,\n"
+ " }\n"
+ " )\n"
+ " return channel\n"
+ "end\n"
+ "\n"
+ "\n"
+ "RssChannel.addItem = function(self, tbl)\n"
+ " local to_rfc822 = function(datestring, zone)\n"
+ " if not string.match(datestring, '^%d%d%d%d%-%d%d%-%d%d$') then\n"
+ " error(string.format('%q is not a valid date string', datestring))\n"
+ " end\n"
+ " \n"
+ " local year = string.match(datestring, '^%d%d%d%d')\n"
+ " local month = string.match(datestring, '-(%d%d)-')\n"
+ " local day = string.match(datestring, '%d%d$')\n"
+ "\n"
+ " local month_names = {'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'}\n"
+ " month = month_names[tonumber(month)]\n"
+ "\n"
+ " return string.format('%s %s %s 00:00:00 %s', day, month, year, zone)\n"
+ " end\n"
+ " \n"
+ " if not (tbl.title or tbl.description) then\n"
+ " error('items must specify either a title or description!')\n"
+ " end\n"
+ "\n"
+ " if not tbl.pubDate then\n"
+ " error('items must specify a pubDate!')\n"
+ " else\n"
+ " tbl.pubDate = to_rfc822(tbl.pubDate, 'Z')\n"
+ " print(tbl.pubDate)\n"
+ " end\n"
+ "\n"
+ " table.insert(self.items, tbl)\n"
+ "end\n"
+ "\n"
+ "\n"
+ "local tag_builder = function(source_table, indent_level)\n"
+ " local str = ''\n"
+ " local indent = string.rep(' ', indent_level)\n"
+ " local add_tag = function(tag)\n"
+ " if source_table[tag] then\n"
+ " str = str ..\n"
+ " string.format('%s<%s>%s</%s>\\n',\n"
+ " indent, tag, source_table[tag], tag)\n"
+ " end\n"
+ " end\n"
+ " local content = function()\n"
+ " return str\n"
+ " end\n"
+ " return add_tag, content\n"
+ "end\n"
+ "\n"
+ "local render_item = function(item_tbl)\n"
+ " local add_tag, content = tag_builder(item_tbl, 2)\n"
+ " add_tag('title')\n"
+ " add_tag('link')\n"
+ " add_tag('description')\n"
+ " add_tag('author')\n"
+ " add_tag('category')\n"
+ " add_tag('comments')\n"
+ " add_tag('guid')\n"
+ " add_tag('pubDate')\n"
+ "\n"
+ " local indent = string.rep(' ', 1)\n"
+ " return string.format('%s<item>\\n%s%s</item>',\n"
+ " indent, content(), indent)\n"
+ "end\n"
+ "\n"
+ "RssChannel.tostring = function(self)\n"
+ " local add_tag, content = tag_builder(self, 1)\n"
+ " add_tag('title')\n"
+ " add_tag('link')\n"
+ " add_tag('description')\n"
+ "\n"
+ " add_tag('language')\n"
+ " add_tag('copyright')\n"
+ " add_tag('managingEditor')\n"
+ " add_tag('webMaster')\n"
+ " add_tag('pubDate')\n"
+ " add_tag('lastBuildDate')\n"
+ " add_tag('category')\n"
+ " add_tag('generator')\n"
+ " add_tag('docs')\n"
+ "\n"
+ " items_str = ''\n"
+ "\n"
+ " for _, item in ipairs(self.items) do\n"
+ " items_str = items_str .. render_item(item) .. '\\n'\n"
+ " end\n"
+ "\n"
+ " return string.format(\n"
+ " '<rss version=\"2.0\">\\n<channel>\\n%s\\n%s</channel>\\n</rss>',\n"
+ " content(), items_str)\n"
+ "end\n"
+ "\n"
+ "\n"
+ "RssChannel.save = function(self, filename)\n"
+ " file = io.open(filename, 'w')\n"
+ " file:write(self:tostring())\n"
+ " file:close()\n"
+ "end\n"
+ "\n"
+ "\n"
"return function(config)\n"
" local fmt = string.format\n"
"\n"
@@ -22,6 +152,7 @@ const char *argent_script =
"\n"
" function set_tostring(set)\n"
" local str = '[empty]'\n"
+ " if not set then return str end\n"
" for element in pairs(set) do\n"
" if str == '[empty]' then\n"
" str = tostring(element)\n"
@@ -83,17 +214,30 @@ const char *argent_script =
"\n"
" function setup(config)\n"
" argent.log('debug', 'begin setup')\n"
- " \n"
+ "\n"
+ " if not config.site_name then\n"
+ " error('site_name MUST be set!')\n"
+ " end\n"
+ "\n"
" argent.config = {\n"
+ " site_name = config.site_name,\n"
+ " site_address = add_end_slash(config.site_address) or nil,\n"
+ " site_description = config.site_description or '',\n"
+ " site_language = config.site_language,\n"
+ " site_copyright = config.site_copyright,\n"
+ " \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 nil,\n"
" plugin_directory = add_end_slash(config.plugin_directory) or nil,\n"
+ " \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"
+ " rss_include = Set(config.rss_include, strip_end_slash) or nil,\n"
+ " webmaster_email = config.webmaster_email,\n"
" }\n"
"\n"
" argent.log('info', fmt('site directory: %s', argent.config.site_directory))\n"
@@ -119,6 +263,22 @@ const char *argent_script =
" add_end_slash(argent.currentWorkingDirectory())\n"
" ..argent.config.plugin_directory..'?.lua;'..package.path\n"
" end\n"
+ "\n"
+ " if argent.config.rss_include then\n"
+ " if not argent.config.site_address then\n"
+ " error('rss_include is set, but site_address is not!')\n"
+ " end\n"
+ " argent.rss_channel = RssChannel.new(\n"
+ " argent.config.site_name,\n"
+ " argent.config.site_address,\n"
+ " argent.config.site_description,\n"
+ " { language = argent.config.site_language,\n"
+ " copyright = argent.config.site_copyright,\n"
+ " webMaster = argent.config.webmaster_email,\n"
+ " }\n"
+ " )\n"
+ " end\n"
+ " \n"
" argent.log('debug', 'end setup')\n"
" end\n"
"\n"
@@ -176,11 +336,11 @@ const char *argent_script =
" end\n"
"\n"
" argent.log('debug', fmt('obliterating files in %q', parent..dir))\n"
- " return obliterate_directory(dir, parent)\n"
+ " return obliterate(dir, parent)\n"
" end\n"
"\n"
"\n"
- " function obliterate_directory(dirname, parent)\n"
+ " function obliterate(dirname, parent)\n"
" local dirname = add_end_slash(dirname) or ''\n"
" local parent = parent or ''\n"
"\n"
@@ -325,6 +485,30 @@ const char *argent_script =
" local output_file = io.open(argent.config.output_directory..parent..output_name, 'w')\n"
" output_file:write(output_data)\n"
" output_file:close()\n"
+ "\n"
+ " for pattern in pairs(argent.config.rss_include) do\n"
+ " if string.match(filename, pattern)\n"
+ " or string.match(parent..filename, pattern)\n"
+ " then -- add to the RSS feed!\n"
+ " if not result.date then\n"
+ " argent.log(\n"
+ " 'warn',\n"
+ " fmt(\n"
+ " '%q did not specify a date; it will not be included in rss.xml!',\n"
+ " parent..filename\n"
+ " )\n"
+ " )\n"
+ " return\n"
+ " end\n"
+ " \n"
+ " argent.rss_channel:addItem{\n"
+ " title=result.title,\n"
+ " link=argent.config.site_address..parent..output_name,\n"
+ " description = result.description,\n"
+ " pubDate = result.date,\n"
+ " }\n"
+ " end\n"
+ " end\n"
" end\n"
"\n"
"\n"
@@ -337,11 +521,11 @@ const char *argent_script =
" if not directory_exists(directory, parent) then\n"
" argent.createDirectory(argent.config.output_directory..parent..directory)\n"
" end\n"
- " process_directory(directory, parent)\n"
+ " process(directory, parent)\n"
" end\n"
"\n"
"\n"
- " function process_directory(directory, parent)\n"
+ " function process(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"
@@ -367,8 +551,12 @@ const char *argent_script =
" if not output_directory_exists() then\n"
" argent.createDirectory(argent.config.output_directory)\n"
" else\n"
- " obliterate_directory()\n"
+ " obliterate()\n"
+ " end\n"
+ " process()\n"
+ "\n"
+ " if argent.rss_channel then\n"
+ " argent.rss_channel:save(argent.config.output_directory..'rss.xml')\n"
" end\n"
- " process_directory()\n"
"end\n"
; \ No newline at end of file
diff --git a/src/lua-script/script.lua b/src/lua-script/script.lua
index e44ece5..65bf0cf 100644
--- a/src/lua-script/script.lua
+++ b/src/lua-script/script.lua
@@ -1,3 +1,133 @@
+local RssChannel = {}
+RssChannel.new = function(title, link, description, settings)
+ local settings = settings or {}
+
+ local channel = {
+ title=title,
+ link=link,
+ description=description,
+ }
+
+ channel.language = settings.language
+ channel.copyright = settings.copyright
+ channel.managingEditor = settings.managingEditor
+ channel.webMaster = settings.webMaster
+ channel.lastBuildDate = settings.lastBuildDate
+ channel.category = settings.category
+ channel.generator = 'argent v0.1.0'
+ channel.docs = 'https://www.rssboard.org/rss-specification'
+
+ channel.items = {}
+
+ setmetatable(
+ channel,
+ {
+ __index=RssChannel,
+ __tostring=RssChannel.tostring,
+ }
+ )
+ return channel
+end
+
+
+RssChannel.addItem = function(self, tbl)
+ local to_rfc822 = function(datestring, zone)
+ if not string.match(datestring, '^%d%d%d%d%-%d%d%-%d%d$') then
+ error(string.format('%q is not a valid date string', datestring))
+ end
+
+ local year = string.match(datestring, '^%d%d%d%d')
+ local month = string.match(datestring, '-(%d%d)-')
+ local day = string.match(datestring, '%d%d$')
+
+ local month_names = {'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'}
+ month = month_names[tonumber(month)]
+
+ return string.format('%s %s %s 00:00:00 %s', day, month, year, zone)
+ end
+
+ if not (tbl.title or tbl.description) then
+ error('items must specify either a title or description!')
+ end
+
+ if not tbl.pubDate then
+ error('items must specify a pubDate!')
+ else
+ tbl.pubDate = to_rfc822(tbl.pubDate, 'Z')
+ print(tbl.pubDate)
+ end
+
+ table.insert(self.items, tbl)
+end
+
+
+local tag_builder = function(source_table, indent_level)
+ local str = ''
+ local indent = string.rep(' ', indent_level)
+ local add_tag = function(tag)
+ if source_table[tag] then
+ str = str ..
+ string.format('%s<%s>%s</%s>\n',
+ indent, tag, source_table[tag], tag)
+ end
+ end
+ local content = function()
+ return str
+ end
+ return add_tag, content
+end
+
+local render_item = function(item_tbl)
+ local add_tag, content = tag_builder(item_tbl, 2)
+ add_tag('title')
+ add_tag('link')
+ add_tag('description')
+ add_tag('author')
+ add_tag('category')
+ add_tag('comments')
+ add_tag('guid')
+ add_tag('pubDate')
+
+ local indent = string.rep(' ', 1)
+ return string.format('%s<item>\n%s%s</item>',
+ indent, content(), indent)
+end
+
+RssChannel.tostring = function(self)
+ local add_tag, content = tag_builder(self, 1)
+ add_tag('title')
+ add_tag('link')
+ add_tag('description')
+
+ add_tag('language')
+ add_tag('copyright')
+ add_tag('managingEditor')
+ add_tag('webMaster')
+ add_tag('pubDate')
+ add_tag('lastBuildDate')
+ add_tag('category')
+ add_tag('generator')
+ add_tag('docs')
+
+ items_str = ''
+
+ for _, item in ipairs(self.items) do
+ items_str = items_str .. render_item(item) .. '\n'
+ end
+
+ return string.format(
+ '<rss version="2.0">\n<channel>\n%s\n%s</channel>\n</rss>',
+ content(), items_str)
+end
+
+
+RssChannel.save = function(self, filename)
+ file = io.open(filename, 'w')
+ file:write(self:tostring())
+ file:close()
+end
+
+
return function(config)
local fmt = string.format
@@ -21,6 +151,7 @@ return function(config)
function set_tostring(set)
local str = '[empty]'
+ if not set then return str end
for element in pairs(set) do
if str == '[empty]' then
str = tostring(element)
@@ -82,17 +213,30 @@ return function(config)
function setup(config)
argent.log('debug', 'begin setup')
-
+
+ if not config.site_name then
+ error('site_name MUST be set!')
+ end
+
argent.config = {
+ site_name = config.site_name,
+ site_address = add_end_slash(config.site_address) or nil,
+ site_description = config.site_description or '',
+ site_language = config.site_language,
+ site_copyright = config.site_copyright,
+
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 nil,
plugin_directory = add_end_slash(config.plugin_directory) or nil,
+
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 {},
+
+ rss_include = Set(config.rss_include, strip_end_slash) or nil,
+ webmaster_email = config.webmaster_email,
}
argent.log('info', fmt('site directory: %s', argent.config.site_directory))
@@ -118,6 +262,22 @@ return function(config)
add_end_slash(argent.currentWorkingDirectory())
..argent.config.plugin_directory..'?.lua;'..package.path
end
+
+ if argent.config.rss_include then
+ if not argent.config.site_address then
+ error('rss_include is set, but site_address is not!')
+ end
+ argent.rss_channel = RssChannel.new(
+ argent.config.site_name,
+ argent.config.site_address,
+ argent.config.site_description,
+ { language = argent.config.site_language,
+ copyright = argent.config.site_copyright,
+ webMaster = argent.config.webmaster_email,
+ }
+ )
+ end
+
argent.log('debug', 'end setup')
end
@@ -175,11 +335,11 @@ return function(config)
end
argent.log('debug', fmt('obliterating files in %q', parent..dir))
- return obliterate_directory(dir, parent)
+ return obliterate(dir, parent)
end
- function obliterate_directory(dirname, parent)
+ function obliterate(dirname, parent)
local dirname = add_end_slash(dirname) or ''
local parent = parent or ''
@@ -324,6 +484,30 @@ return function(config)
local output_file = io.open(argent.config.output_directory..parent..output_name, 'w')
output_file:write(output_data)
output_file:close()
+
+ for pattern in pairs(argent.config.rss_include) do
+ if string.match(filename, pattern)
+ or string.match(parent..filename, pattern)
+ then -- add to the RSS feed!
+ if not result.date then
+ argent.log(
+ 'warn',
+ fmt(
+ '%q did not specify a date; it will not be included in rss.xml!',
+ parent..filename
+ )
+ )
+ return
+ end
+
+ argent.rss_channel:addItem{
+ title=result.title,
+ link=argent.config.site_address..parent..output_name,
+ description = result.description,
+ pubDate = result.date,
+ }
+ end
+ end
end
@@ -336,11 +520,11 @@ return function(config)
if not directory_exists(directory, parent) then
argent.createDirectory(argent.config.output_directory..parent..directory)
end
- process_directory(directory, parent)
+ process(directory, parent)
end
- function process_directory(directory, parent)
+ function process(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)
@@ -366,7 +550,11 @@ return function(config)
if not output_directory_exists() then
argent.createDirectory(argent.config.output_directory)
else
- obliterate_directory()
+ obliterate()
+ end
+ process()
+
+ if argent.rss_channel then
+ argent.rss_channel:save(argent.config.output_directory..'rss.xml')
end
- process_directory()
end