From 72e13dff9ff4fde91b84054167da91a5d27cb952 Mon Sep 17 00:00:00 2001 From: sanine Date: Tue, 4 Jan 2022 22:28:43 -0600 Subject: add working rss: --- src/lua-script/cify.lua | 2 + src/lua-script/script.h | 204 ++++++++++++++++++++++++++++++++++++++++++++-- src/lua-script/script.lua | 204 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 394 insertions(+), 16 deletions(-) (limited to 'src/lua-script') 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\\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\\n%s%s',\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" + " '\\n\\n%s\\n%s\\n',\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\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\n%s%s', + 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( + '\n\n%s\n%s\n', + 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 -- cgit v1.2.1