local conf = require("config") local tpl = require("template") local util = require("util") local writer = {} writer.app = { exec_name = "gw", last_updated = "2022-07-24", name = "gemwriter", version = "0.1", } writer.conf = {} writer.defaults = { atom_file = "atom.xml", author = "Gem", -- Atom feed date format entry_date_format = "%Y-%m-%dT%X+00:00", entry_ext = ".gmi", entry_slug = os.date("%Y-%m-%d-%H%M%S"), entry_file_pattern = "[%/](%d%d%d%d%-%d%d%-%d%d)(.*)[%.](%a*)", gen_atom_feed = true, gen_index_page = true, index_file = "index.gmi", page_slug = "untitled-" .. os.date("%Y%m%d%H%M%S"), title = "gemlog", subtitle = "a Gemini log", url = "", output_dir = "log", rsync_exec = "/usr/bin/rsync", rsync_options = "-avz", rsync_remote = "", } writer.entries = {} writer.msg = { add_entry = "Created ", help = writer.app.exec_name .. [[ [options] [slug] Options: page [slug] Add a new page with the given name post [slug] Add a new entry with the given name index Generate an index page and feed of entries publish Index and copy posts to a remote server (requires rsync) help Show this help message version Print version info ]], index = "Created index page and feed.", publish = "Published log.", } function writer.load_config(config) for k, v in pairs(writer.defaults) do if config[k] == nil then writer.conf[k] = writer.defaults[k] else writer.conf[k] = config[k] end end end function writer.replace_vars(str, vars, vals) local text = str for k, v in pairs(vars) do text = string.gsub(text, v, vals[k]) end return text end function writer.add_entry(slug) local text = tpl.log_gmi text = string.gsub(text, tpl.vars.entry.date, os.date(writer.conf.entry_date_format)) text = string.gsub(text, tpl.vars.entry.author, writer.conf.author) local entry_name = slug .. writer.conf.entry_ext os.execute("test -d " .. writer.conf.output_dir .. " || mkdir -p " .. writer.conf.output_dir) util.write_file(writer.conf.output_dir .. "/" .. entry_name, text) end function writer.get_entries() local ls_cmd = io.popen("ls " .. writer.conf.output_dir .. " | grep " .. writer.conf.entry_ext) local ls = ls_cmd:read("*a") local entries = {} local n = 0 local files_list = util.split_str(ls) for f = 1, #files_list do if files_list[f] ~= writer.conf.index_file then n = n + 1 entries[n] = { files_list[f], util.read_file(writer.conf.output_dir .. "/" .. files_list[f]) } end end return entries end function writer.get_entries_meta() local meta = {} local entries = writer.get_entries() for e = 1, #entries do meta[e] = {} if string.find(entries[e][2], "# ") == nil then meta[e]["title"] = entries[e][1] meta[e]["content"] = entries[e][2] else meta[e]["title"] = util.extract_str(entries[e][2], "# ", "\n") hi1, hi2 = string.find(entries[e][2], "# ") meta[e]["content"] = string.sub(entries[e][2], hi1, string.len(entries[e][2])) end if string.find(entries[e][2], "author: ") == nil then meta[e]["author"] = writer.conf.author else meta[e]["author"] = util.extract_str(entries[e][2], "author: ", "\n") end if string.find(entries[e][2], "date: ") == nil then meta[e]["date"] = util.extract_file_date(writer.conf.output_dir, entries[e][1]) if (meta[e]["date"] == "") or (meta[e]["date"] == nil) then meta[e]["date"] = os.date(writer.conf.entry_date_format) end else meta[e]["date"] = util.extract_str(entries[e][2], "date: ", "\n") end if string.find(entries[e][2], "summary: ") == nil then meta[e]["summary"] = meta[e]["title"] else meta[e]["summary"] = util.extract_str(entries[e][2], "summary: ", "\n") end if string.find(entries[e][2], "tags: ") == nil then meta[e]["tags"] = "" else meta[e]["tags"] = util.extract_str(entries[e][2], "tags: ", "\n") end meta[e]["url"] = writer.conf.url .. "/" .. entries[e][1] end return meta end function writer.gen_index_page() local index_text = writer.replace_vars(tpl.index_gmi, tpl.vars.log, writer.conf) local entries_text = "" -- Reverse insert links to log entries, newest first for e = #writer.entries, 1, -1 do local entry_date = util.split_str(writer.entries[e]["date"], "(.*)[T]")[1] -- Get entry filename from the url local fi1, fi2 = string.find(writer.entries[e]["url"], writer.conf.entry_file_pattern) entries_text = entries_text .. "\n=> " .. string.sub(writer.entries[e]["url"], fi1 + 1, fi2) .. " " .. entry_date .. " " .. writer.entries[e]["title"] end index_text = string.gsub(index_text, tpl.vars.index.entries, entries_text) util.write_file(writer.conf.output_dir .. "/" .. writer.conf.index_file, index_text) end function writer.gen_atom_feed() local feed_meta = { date = os.date(writer.conf.entry_date_format), url = writer.conf.url .. "/" .. writer.conf.atom_file, } local feed_text = writer.replace_vars(tpl.atom_header, tpl.vars.log, writer.conf) feed_text = writer.replace_vars(feed_text, tpl.vars.feed, feed_meta) local feed_entry = "" -- Reverse insert log entries, newest first for e = #writer.entries, 1, -1 do feed_entry = tpl.atom_entry feed_entry = writer.replace_vars(feed_entry, tpl.vars.entry, writer.entries[e]) feed_text = feed_text .. feed_entry end feed_text = feed_text .. tpl.atom_footer util.write_file(writer.conf.output_dir .. "/" .. writer.conf.atom_file, feed_text) end function writer.publish() os.execute(writer.conf.rsync_exec .. " " .. writer.conf.rsync_options .. " " .. writer.conf.output_dir .. " " .. writer.conf.rsync_remote) end local cli = {} function cli.handle_args(args) if (args[1] ~= "help") and (args[1] ~= "version") then writer.load_config(conf) end if (args[1] == "index") or (args[1] == "publish") then writer.entries = writer.get_entries_meta() if writer.conf.gen_index_page then writer.gen_index_page() end if writer.conf.gen_atom_feed then writer.gen_atom_feed() end end if args[1] == "post" then local slug = args[2] if slug == "" then slug = writer.conf.entry_slug else slug = os.date("%Y-%m-%d") .. "-" .. slug end writer.add_entry(slug) print(writer.msg.add_entry .. slug .. writer.conf.entry_ext) elseif args[1] == "page" then local slug = args[2] if slug == "" then slug = writer.conf.page_slug end writer.add_entry(slug) print(writer.msg.add_entry .. slug .. writer.conf.entry_ext) elseif args[1] == "index" then print(writer.msg.index) elseif args[1] == "publish" then writer.publish() print(writer.msg.publish) elseif args[1] == "help" then print(writer.msg.help) elseif args[1] == "version" then print(writer.app.name .. " " .. writer.app.version .. " (" .. writer.app.last_updated .. ")") end end cli.handle_args(arg)