Change config format
- Change config format and parsing - Fix support for multiple capsules - Include scp as a transfer option - Fix more bugspull/1/head
parent
e1400e1ed8
commit
baead4e5f1
|
@ -1,4 +1,2 @@
|
||||||
log
|
gemwriter
|
||||||
config.lua
|
gemwriter.luastatic.c
|
||||||
config.ini
|
|
||||||
template.ini
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
local config = {
|
|
||||||
author = "Gem",
|
|
||||||
title = "gemlog",
|
|
||||||
subtitle = "a Gemini log",
|
|
||||||
url = "gemini://",
|
|
||||||
output_dir = "/path/to/local/log",
|
|
||||||
rsync_remote = "/path/to/remote/log",
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
local env = {}
|
||||||
|
|
||||||
|
-- App information
|
||||||
|
env.app = {
|
||||||
|
name = "gemwriter",
|
||||||
|
exec_name = "gemwriter",
|
||||||
|
version = "0.2",
|
||||||
|
last_updated = "2022-08-05",
|
||||||
|
}
|
||||||
|
|
||||||
|
env.defaults = {
|
||||||
|
config_dir = "$HOME/.config/" .. env.app.exec_name,
|
||||||
|
config_files = {
|
||||||
|
atom_entry = "atom.entry.xml",
|
||||||
|
atom_header = "atom.header.xml",
|
||||||
|
config = "config.toml",
|
||||||
|
index = "index.gmi",
|
||||||
|
page = "page.gmi",
|
||||||
|
post = "post.gmi",
|
||||||
|
},
|
||||||
|
post_slug = "untitled",
|
||||||
|
post_slug_date_format = "%Y-%m-%d",
|
||||||
|
-- Atom feed date format
|
||||||
|
post_date_format = "%Y-%m-%dT%H:%M:%SZ",
|
||||||
|
post_ext = ".gmi",
|
||||||
|
post_file_pattern = "[%/](%d%d%d%d%-%d%d%-%d%d)(.*)[%.](%a*)",
|
||||||
|
page_slug = os.date("%Y%m%d-%H%M%S"),
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Configurable settings
|
||||||
|
env.toml_vars = {
|
||||||
|
general = "general",
|
||||||
|
capsules = "capsules",
|
||||||
|
}
|
||||||
|
env.general = {
|
||||||
|
app_lang = "en",
|
||||||
|
main_capsule = "main",
|
||||||
|
}
|
||||||
|
env.capsules = {
|
||||||
|
main = {
|
||||||
|
author = "Gem",
|
||||||
|
title = "Gemlog",
|
||||||
|
subtitle = "A Gemini log",
|
||||||
|
url = "gemini://domain.tld",
|
||||||
|
log_url = "gemini://domain.tld/log",
|
||||||
|
capsule_dir = env.defaults.config_dir .. "/capsule",
|
||||||
|
gemlog_dir = env.defaults.config_dir .. "/capsule/log",
|
||||||
|
gen_index_page = true,
|
||||||
|
index_page = "index.gmi",
|
||||||
|
gen_atom_feed = true,
|
||||||
|
atom_feed = "atom.xml",
|
||||||
|
transfer_mode = "scp",
|
||||||
|
scp_exec = "/usr/bin/scp",
|
||||||
|
scp_target = "/path/to/remote/capsule",
|
||||||
|
rsync_exec = "/usr/bin/rsync",
|
||||||
|
rsync_options = "-avz",
|
||||||
|
rsync_dest = "/path/to/remote/capsule",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
env.defaults_toml = [[
|
||||||
|
[]] .. env.toml_vars.general .. [[]
|
||||||
|
app_lang = "]] .. env.general.app_lang .. [["
|
||||||
|
main_capsule = "]] .. env.general.main_capsule .. [["
|
||||||
|
|
||||||
|
[]] .. env.toml_vars.capsules .. "." .. env.general.main_capsule .. [[]
|
||||||
|
author = "]] .. env.capsules.main.author .. [["
|
||||||
|
title = "]] .. env.capsules.main.title .. [["
|
||||||
|
subtitle = "]] .. env.capsules.main.subtitle .. [["
|
||||||
|
url = "]] .. env.capsules.main.url .. [["
|
||||||
|
log_url = "]] .. env.capsules.main.log_url .. [["
|
||||||
|
capsule_dir = "]] .. env.capsules.main.capsule_dir .. [["
|
||||||
|
gemlog_dir = "]] .. env.capsules.main.gemlog_dir .. [["
|
||||||
|
gen_index_page = "]] .. tostring(env.capsules.main.gen_index_page) .. [["
|
||||||
|
index_page = "]] .. env.capsules.main.index_page .. [["
|
||||||
|
gen_atom_feed = "]] .. tostring(env.capsules.main.gen_atom_feed) .. [["
|
||||||
|
atom_feed = "]] .. env.capsules.main.atom_feed .. [["
|
||||||
|
transfer_mode = "]] .. env.capsules.main.transfer_mode .. [["
|
||||||
|
scp_exec = "]] .. env.capsules.main.scp_exec .. [["
|
||||||
|
scp_target = "]] .. env.capsules.main.scp_target .. [["
|
||||||
|
rsync_exec = "]] .. env.capsules.main.rsync_exec .. [["
|
||||||
|
rsync_options = "]] .. env.capsules.main.rsync_options .. [["
|
||||||
|
rsync_dest = "]] .. env.capsules.main.rsync_dest .. [["
|
||||||
|
]]
|
||||||
|
|
||||||
|
return env
|
459
gemwriter.lua
459
gemwriter.lua
|
@ -1,245 +1,382 @@
|
||||||
local conf = require("config")
|
local env = require("env")
|
||||||
local tpl = require("template")
|
local lang = require("lang.en")
|
||||||
local util = require("util")
|
local util = require("util")
|
||||||
|
|
||||||
|
|
||||||
local writer = {}
|
local writer = {}
|
||||||
|
writer.docs = {}
|
||||||
writer.app = {
|
|
||||||
exec_name = "gw",
|
|
||||||
last_updated = "2022-07-24",
|
|
||||||
name = "gemwriter",
|
|
||||||
version = "0.1",
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.conf = {}
|
writer.conf = {}
|
||||||
writer.defaults = {
|
writer.posts = {}
|
||||||
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.docs.gen_config = [[
|
||||||
|
Generate a default config directory.
|
||||||
writer.msg = {
|
]]
|
||||||
add_entry = "Created ",
|
function writer.gen_config()
|
||||||
help = writer.app.exec_name .. [[ [options] [slug]
|
writer.conf.config_dir = util.replace_shell_vars(env.defaults.config_dir)
|
||||||
|
util.make_dir(writer.conf.config_dir)
|
||||||
Options:
|
for name, file in pairs(env.defaults.config_files) do
|
||||||
|
-- Check each file individually anyway to avoid overwriting existing
|
||||||
page [slug] Add a new page with the given name
|
-- files
|
||||||
post [slug] Add a new entry with the given name
|
if util.read_file(writer.conf.config_dir .. "/" .. file) == "" then
|
||||||
index Generate an index page and feed of entries
|
if file == env.defaults.config_files.config then
|
||||||
publish Index and copy posts to a remote server (requires rsync)
|
util.write_file(writer.conf.config_dir .. "/" .. file,
|
||||||
help Show this help message
|
env.defaults_toml)
|
||||||
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
|
else
|
||||||
writer.conf[k] = config[k]
|
util.write_file(writer.conf.config_dir .. "/" .. file, lang[name])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Create capsule and gemlog directories
|
||||||
|
util.make_dir(env.capsules.main.capsule_dir)
|
||||||
|
util.make_dir(env.capsules.main.gemlog_dir)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
writer.docs.parse_config = [[
|
||||||
|
Read a config file in TOML format and load the values into a table.
|
||||||
|
]]
|
||||||
|
function writer.parse_config(config_file)
|
||||||
|
local lines = util.split_lines(config_file)
|
||||||
|
local config_group = env.toml_vars.general
|
||||||
|
local line_cap = ""
|
||||||
|
writer.conf.capsules = {}
|
||||||
|
for l = 1, #lines do
|
||||||
|
-- Config group
|
||||||
|
if string.sub(lines[l], 1, 1) == "[" then
|
||||||
|
for tv, label in pairs(env.toml_vars) do
|
||||||
|
if string.find(lines[l], label) ~= nil then config_group = label end
|
||||||
|
end
|
||||||
|
if config_group == env.toml_vars.capsules then
|
||||||
|
local _, lb_sep = string.find(lines[l], "%[" .. config_group .. "%.")
|
||||||
|
local rb_sep, _ = string.find(lines[l], "%]")
|
||||||
|
if lb_sep ~= nil then
|
||||||
|
line_cap = string.sub(lines[l], lb_sep + 1, rb_sep - 1)
|
||||||
|
writer.conf.capsules[line_cap] = {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Config variables (ignore comments)
|
||||||
|
elseif (string.sub(lines[l], 1, 1) ~= "#") and
|
||||||
|
(string.find(lines[l], "=") ~= nil) then
|
||||||
|
local eq_sep, _ = string.find(lines[l], " = ")
|
||||||
|
local qt_sep, _ = string.find(lines[l], "\"")
|
||||||
|
local k = string.sub(lines[l], 1, eq_sep - 1)
|
||||||
|
local val = string.sub(lines[l], eq_sep + 4, string.len(lines[l]) - 1)
|
||||||
|
if qt_sep == nil then
|
||||||
|
val = string.sub(lines[l], eq_sep + 3, string.len(lines[l]))
|
||||||
|
end
|
||||||
|
-- Load settings by key and their values to the config table
|
||||||
|
if config_group == env.toml_vars.general then
|
||||||
|
writer.conf[k] = val
|
||||||
|
elseif config_group == env.toml_vars.capsules then
|
||||||
|
-- Convert boolean values
|
||||||
|
if (val == "\"true\"") or (val == "\"false\"") then
|
||||||
|
writer.conf.capsules[line_cap][k] = util.to_bool(val)
|
||||||
|
else
|
||||||
|
writer.conf.capsules[line_cap][k] = val
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- If the main capsule id is not the app default, update the id
|
||||||
function writer.replace_vars(str, vars, vals)
|
if (writer.conf.cap_id == env.general.main_capsule) and
|
||||||
local text = str
|
(writer.conf.main_capsule ~= env.general.main_capsule) then
|
||||||
for k, v in pairs(vars) do
|
writer.conf.cap_id = writer.conf.main_capsule
|
||||||
text = string.gsub(text, v, vals[k])
|
|
||||||
end
|
end
|
||||||
return text
|
-- Add an alias to the selected capsule's table
|
||||||
|
writer.conf.cap = writer.conf.capsules[writer.conf.cap_id]
|
||||||
|
|
||||||
|
-- Fill in the remaining defaults
|
||||||
|
for k, v in pairs(env.defaults) do
|
||||||
|
if writer.conf[k] == nil then
|
||||||
|
writer.conf[k] = env.defaults[k]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Replace shell variables in paths to make them usable
|
||||||
|
for c_id, _ in pairs(writer.conf.capsules) do
|
||||||
|
writer.conf.capsules[c_id]["capsule_dir"] = util.replace_shell_vars(
|
||||||
|
writer.conf.capsules[c_id]["capsule_dir"])
|
||||||
|
writer.conf.capsules[c_id]["gemlog_dir"] = util.replace_shell_vars(
|
||||||
|
writer.conf.capsules[c_id]["gemlog_dir"])
|
||||||
|
-- Create capsule and gemlog directories
|
||||||
|
util.make_dir(writer.conf.capsules[c_id]["capsule_dir"])
|
||||||
|
util.make_dir(writer.conf.capsules[c_id]["gemlog_dir"])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set lang
|
||||||
|
lang = require("lang." .. writer.conf.app_lang)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function writer.add_entry(slug)
|
writer.docs.load_config = [[
|
||||||
local text = tpl.log_gmi
|
Check whether there is an existing config and load it if found. Exit if a
|
||||||
text = string.gsub(text, tpl.vars.entry.date,
|
capsule is not found.
|
||||||
os.date(writer.conf.entry_date_format))
|
]]
|
||||||
text = string.gsub(text, tpl.vars.entry.author, writer.conf.author)
|
function writer.load_config(cap_id)
|
||||||
|
writer.conf.config_dir = util.replace_shell_vars(env.defaults.config_dir)
|
||||||
|
local config_file = util.read_file(writer.conf.config_dir .. "/" ..
|
||||||
|
env.defaults.config_files.config)
|
||||||
|
local config_new = false
|
||||||
|
|
||||||
local entry_name = slug .. writer.conf.entry_ext
|
-- No config found
|
||||||
os.execute("test -d " .. writer.conf.output_dir .. " || mkdir -p " ..
|
if (config_file == "") and (not config_new) then
|
||||||
writer.conf.output_dir)
|
writer.gen_config()
|
||||||
util.write_file(writer.conf.output_dir .. "/" .. entry_name, text)
|
config_new = true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Config found, read the configuration and load the values to an
|
||||||
|
-- associative table, writer.conf.
|
||||||
|
if (config_file ~= "") and (not config_new) then
|
||||||
|
-- Check capsule id exists, abort if no valid capsule found
|
||||||
|
if (cap_id == nil) or (string.find(cap_id, " ") ~= nil) then
|
||||||
|
writer.conf.cap_id = env.general.main_capsule
|
||||||
|
else
|
||||||
|
writer.conf.cap_id = cap_id
|
||||||
|
end
|
||||||
|
local cap_label = "%[" .. env.toml_vars.capsules .. "%." ..
|
||||||
|
tostring(cap_id) .. "%]"
|
||||||
|
if (string.find(config_file, cap_label) == nil) and
|
||||||
|
(writer.conf.cap_id ~= env.general.main_capsule) then
|
||||||
|
print(lang.errs.invalid_cap_id)
|
||||||
|
os.exit()
|
||||||
|
end
|
||||||
|
|
||||||
|
writer.parse_config(config_file)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function writer.get_entries()
|
writer.docs.add_gemtext = [[
|
||||||
local ls_cmd = io.popen("ls " .. writer.conf.output_dir .. " | grep " ..
|
Given a title and mode, create a new gemtext file. Supported modes: page,
|
||||||
writer.conf.entry_ext)
|
post.
|
||||||
local ls = ls_cmd:read("*a")
|
]]
|
||||||
local entries = {}
|
function writer.add_gemtext(title, mode)
|
||||||
|
local file_name = title
|
||||||
|
local post_title = title
|
||||||
|
if ((title == "") or (title == nil)) and (mode == "post") then
|
||||||
|
file_name = os.date(writer.conf.post_slug_date_format) .. "-" ..
|
||||||
|
writer.conf.post_slug .. writer.conf.post_ext
|
||||||
|
post_title = writer.conf.post_slug
|
||||||
|
elseif ((title == "") or (title == nil)) and (mode == "page") then
|
||||||
|
file_name = writer.conf.page_slug .. writer.conf.post_ext
|
||||||
|
post_title = writer.conf.page_slug
|
||||||
|
else
|
||||||
|
-- Strip punctuation from the title and convert to file name
|
||||||
|
local delim = "delim-" .. tostring(math.random(90000000000))
|
||||||
|
file_name = string.gsub(file_name, " ", delim)
|
||||||
|
if mode == "post" then
|
||||||
|
file_name = os.date(writer.conf.post_slug_date_format) .. "-" ..
|
||||||
|
string.gsub(file_name, "%p", "") .. writer.conf.post_ext
|
||||||
|
else
|
||||||
|
file_name = string.gsub(file_name, "%p", "") .. writer.conf.post_ext
|
||||||
|
end
|
||||||
|
file_name = string.lower(string.gsub(file_name, delim, "-"))
|
||||||
|
end
|
||||||
|
|
||||||
|
local text = lang.post
|
||||||
|
local file_path = writer.conf.cap.gemlog_dir .. "/" .. file_name
|
||||||
|
if mode == "page" then
|
||||||
|
text = lang.page
|
||||||
|
file_path = writer.conf.cap.capsule_dir .. "/" .. file_name
|
||||||
|
end
|
||||||
|
text = string.gsub(text, lang.tpl_vars.post.date,
|
||||||
|
os.date(writer.conf.post_date_format))
|
||||||
|
text = string.gsub(text, lang.tpl_vars.post.author, writer.conf.cap.author)
|
||||||
|
text = string.gsub(text, lang.tpl_vars.post.title, post_title)
|
||||||
|
|
||||||
|
util.write_file(file_path, text)
|
||||||
|
return file_name
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
writer.docs.get_posts = [[
|
||||||
|
Get a list of gemlog posts and return the file names and their contents in a
|
||||||
|
table.
|
||||||
|
]]
|
||||||
|
function writer.get_posts()
|
||||||
|
local ls = util.ls_grep(writer.conf.cap.gemlog_dir, writer.conf.post_ext)
|
||||||
|
local posts = {}
|
||||||
local n = 0
|
local n = 0
|
||||||
local files_list = util.split_str(ls)
|
local files_list = util.split_str(ls)
|
||||||
for f = 1, #files_list do
|
for f = 1, #files_list do
|
||||||
if files_list[f] ~= writer.conf.index_file then
|
if files_list[f] ~= writer.conf.cap.index_page then
|
||||||
n = n + 1
|
n = n + 1
|
||||||
entries[n] = { files_list[f], util.read_file(writer.conf.output_dir ..
|
posts[n] = { files_list[f], util.read_file(writer.conf.cap.gemlog_dir ..
|
||||||
"/" .. files_list[f]) }
|
"/" .. files_list[f]) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return entries
|
return posts
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function writer.get_entries_meta()
|
writer.docs.get_posts_meta = [[
|
||||||
|
Extract gemlog posts metadata and return them as an associative table.
|
||||||
|
]]
|
||||||
|
function writer.get_posts_meta()
|
||||||
local meta = {}
|
local meta = {}
|
||||||
local entries = writer.get_entries()
|
local posts = writer.get_posts()
|
||||||
for e = 1, #entries do
|
for e = 1, #posts do
|
||||||
meta[e] = {}
|
meta[e] = {}
|
||||||
if string.find(entries[e][2], "# ") == nil then
|
if string.find(posts[e][2], "# ") == nil then
|
||||||
meta[e]["title"] = entries[e][1]
|
meta[e]["title"] = posts[e][1]
|
||||||
meta[e]["content"] = entries[e][2]
|
meta[e]["content"] = posts[e][2]
|
||||||
else
|
else
|
||||||
meta[e]["title"] = util.extract_str(entries[e][2], "# ", "\n")
|
meta[e]["title"] = util.extract_str(posts[e][2], "# ", "\n")
|
||||||
hi1, hi2 = string.find(entries[e][2], "# ")
|
hi1, hi2 = string.find(posts[e][2], "# ")
|
||||||
meta[e]["content"] = string.sub(entries[e][2], hi1,
|
meta[e]["content"] = string.sub(posts[e][2], hi1,
|
||||||
string.len(entries[e][2]))
|
string.len(posts[e][2]))
|
||||||
end
|
end
|
||||||
if string.find(entries[e][2], "author: ") == nil then
|
if string.find(posts[e][2], "author: ") == nil then
|
||||||
meta[e]["author"] = writer.conf.author
|
meta[e]["author"] = writer.conf.cap.author
|
||||||
else
|
else
|
||||||
meta[e]["author"] = util.extract_str(entries[e][2], "author: ", "\n")
|
meta[e]["author"] = util.extract_str(posts[e][2], "author: ", "\n")
|
||||||
end
|
end
|
||||||
if string.find(entries[e][2], "date: ") == nil then
|
if string.find(posts[e][2], "date: ") == nil then
|
||||||
meta[e]["date"] = util.extract_file_date(writer.conf.output_dir,
|
meta[e]["date"] = util.extract_file_date(writer.conf.cap.gemlog_dir,
|
||||||
entries[e][1])
|
posts[e][1])
|
||||||
if (meta[e]["date"] == "") or (meta[e]["date"] == nil) then
|
if (meta[e]["date"] == "") or (meta[e]["date"] == nil) then
|
||||||
meta[e]["date"] = os.date(writer.conf.entry_date_format)
|
meta[e]["date"] = os.date(writer.conf.post_date_format)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
meta[e]["date"] = util.extract_str(entries[e][2], "date: ", "\n")
|
meta[e]["date"] = util.extract_str(posts[e][2], "date: ", "\n")
|
||||||
end
|
end
|
||||||
if string.find(entries[e][2], "summary: ") == nil then
|
if string.find(posts[e][2], "summary: ") == nil then
|
||||||
meta[e]["summary"] = meta[e]["title"]
|
meta[e]["summary"] = meta[e]["title"]
|
||||||
else
|
else
|
||||||
meta[e]["summary"] = util.extract_str(entries[e][2], "summary: ", "\n")
|
meta[e]["summary"] = util.extract_str(posts[e][2], "summary: ", "\n")
|
||||||
end
|
end
|
||||||
if string.find(entries[e][2], "tags: ") == nil then
|
if string.find(posts[e][2], "tags: ") == nil then
|
||||||
meta[e]["tags"] = ""
|
meta[e]["tags"] = ""
|
||||||
else
|
else
|
||||||
meta[e]["tags"] = util.extract_str(entries[e][2], "tags: ", "\n")
|
meta[e]["tags"] = util.extract_str(posts[e][2], "tags: ", "\n")
|
||||||
end
|
end
|
||||||
meta[e]["url"] = writer.conf.url .. "/" .. entries[e][1]
|
meta[e]["url"] = writer.conf.cap.log_url .. "/" .. posts[e][1]
|
||||||
end
|
end
|
||||||
return meta
|
return meta
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
writer.docs.gen_index_page = [[
|
||||||
|
Generate a gemlog index page listing all gemlog posts.
|
||||||
|
]]
|
||||||
function writer.gen_index_page()
|
function writer.gen_index_page()
|
||||||
local index_text = writer.replace_vars(tpl.index_gmi, tpl.vars.log,
|
local index_text = util.replace_vars(lang.index, lang.tpl_vars.log,
|
||||||
writer.conf)
|
writer.conf.cap)
|
||||||
local entries_text = ""
|
local posts_text = ""
|
||||||
-- Reverse insert links to log entries, newest first
|
-- Reverse insert links to log posts, newest first
|
||||||
for e = #writer.entries, 1, -1 do
|
for e = #writer.posts, 1, -1 do
|
||||||
local entry_date = util.split_str(writer.entries[e]["date"], "(.*)[T]")[1]
|
local post_date = util.split_str(writer.posts[e]["date"], "(.*)[T]")[1]
|
||||||
-- Get entry filename from the url
|
-- If post date cannot be extracted, revert to current date
|
||||||
local fi1, fi2 = string.find(writer.entries[e]["url"],
|
if post_date == nil then
|
||||||
writer.conf.entry_file_pattern)
|
post_date = os.date(writer.conf.post_date_format)
|
||||||
entries_text = entries_text .. "\n=> " ..
|
|
||||||
string.sub(writer.entries[e]["url"], fi1 + 1, fi2) .. " " ..
|
|
||||||
entry_date .. " " .. writer.entries[e]["title"]
|
|
||||||
end
|
end
|
||||||
index_text = string.gsub(index_text, tpl.vars.index.entries, entries_text)
|
-- Get post filename from the url
|
||||||
util.write_file(writer.conf.output_dir .. "/" .. writer.conf.index_file,
|
local fi1, fi2 = string.find(writer.posts[e]["url"],
|
||||||
index_text)
|
writer.conf.post_file_pattern)
|
||||||
|
posts_text = posts_text .. "\n=> " ..
|
||||||
|
string.sub(writer.posts[e]["url"], fi1 + 1, fi2) .. " " ..
|
||||||
|
post_date .. " " .. writer.posts[e]["title"]
|
||||||
|
end
|
||||||
|
index_text = string.gsub(index_text, lang.tpl_vars.index.posts,
|
||||||
|
posts_text)
|
||||||
|
util.write_file(writer.conf.cap.gemlog_dir .. "/" ..
|
||||||
|
writer.conf.cap.index_page, index_text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
writer.docs.gen_atom_feed = [[
|
||||||
|
Generate an Atom feed of gemlog posts.
|
||||||
|
]]
|
||||||
function writer.gen_atom_feed()
|
function writer.gen_atom_feed()
|
||||||
local feed_meta = {
|
local feed_meta = {
|
||||||
date = os.date(writer.conf.entry_date_format),
|
date = os.date(writer.conf.post_date_format),
|
||||||
url = writer.conf.url .. "/" .. writer.conf.atom_file,
|
url = writer.conf.cap.url .. "/" .. writer.conf.cap.atom_feed,
|
||||||
}
|
}
|
||||||
local feed_text = writer.replace_vars(tpl.atom_header, tpl.vars.log,
|
local feed_text = util.replace_vars(lang.atom_header, lang.tpl_vars.log,
|
||||||
writer.conf)
|
writer.conf.cap)
|
||||||
feed_text = writer.replace_vars(feed_text, tpl.vars.feed, feed_meta)
|
feed_text = util.replace_vars(feed_text, lang.tpl_vars.feed, feed_meta)
|
||||||
local feed_entry = ""
|
local feed_post = ""
|
||||||
-- Reverse insert log entries, newest first
|
-- Reverse insert log posts, newest first
|
||||||
for e = #writer.entries, 1, -1 do
|
for e = #writer.posts, 1, -1 do
|
||||||
feed_entry = tpl.atom_entry
|
feed_post = lang.atom_entry
|
||||||
feed_entry = writer.replace_vars(feed_entry, tpl.vars.entry,
|
-- Escape html entities in post contents. "%" is also a special character
|
||||||
writer.entries[e])
|
-- for string.gsub() and similar functions, and will cause an error if not
|
||||||
feed_text = feed_text .. feed_entry
|
-- escaped.
|
||||||
|
writer.posts[e]["content"] =
|
||||||
|
util.replace_html_entities(writer.posts[e]["content"])
|
||||||
|
feed_post = util.replace_vars(feed_post, lang.tpl_vars.post,
|
||||||
|
writer.posts[e])
|
||||||
|
feed_text = feed_text .. feed_post
|
||||||
end
|
end
|
||||||
feed_text = feed_text .. tpl.atom_footer
|
feed_text = feed_text .. lang.atom_footer
|
||||||
util.write_file(writer.conf.output_dir .. "/" .. writer.conf.atom_file,
|
util.write_file(writer.conf.cap.gemlog_dir .. "/" ..
|
||||||
feed_text)
|
writer.conf.cap.atom_feed, feed_text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
writer.docs.publish = [[
|
||||||
|
Transfer a capsule's contents to a remote location.
|
||||||
|
]]
|
||||||
function writer.publish()
|
function writer.publish()
|
||||||
os.execute(writer.conf.rsync_exec .. " " .. writer.conf.rsync_options ..
|
if writer.conf.cap.transfer_mode == "rsync" then
|
||||||
" " .. writer.conf.output_dir .. " " .. writer.conf.rsync_remote)
|
os.execute(writer.conf.cap.rsync_exec .. " " ..
|
||||||
|
writer.conf.cap.rsync_options .. " " .. writer.conf.cap.capsule_dir ..
|
||||||
|
"/ " .. writer.conf.cap.rsync_dest .. "/")
|
||||||
|
else
|
||||||
|
os.execute(writer.conf.cap.scp_exec .. " -r " ..
|
||||||
|
writer.conf.cap.capsule_dir .. "/* " .. writer.conf.cap.scp_target)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local cli = {}
|
local cli = {}
|
||||||
|
cli.docs = {}
|
||||||
|
|
||||||
|
|
||||||
|
cli.docs.handle_args = [[
|
||||||
|
Match command-line options to the respective application functions, passing
|
||||||
|
any additional arguments to the functions.
|
||||||
|
]]
|
||||||
function cli.handle_args(args)
|
function cli.handle_args(args)
|
||||||
if (args[1] ~= "help") and (args[1] ~= "version") then
|
if (args[1] ~= lang.opts.help) and (args[1] ~= lang.opts.version) then
|
||||||
writer.load_config(conf)
|
writer.load_config(args[2])
|
||||||
end
|
end
|
||||||
|
|
||||||
if (args[1] == "index") or (args[1] == "publish") then
|
if (args[1] == lang.opts.index) or (args[1] == lang.opts.publish) then
|
||||||
writer.entries = writer.get_entries_meta()
|
writer.posts = writer.get_posts_meta()
|
||||||
if writer.conf.gen_index_page then writer.gen_index_page() end
|
if writer.conf.cap.gen_index_page then writer.gen_index_page() end
|
||||||
if writer.conf.gen_atom_feed then writer.gen_atom_feed() end
|
if writer.conf.cap.gen_atom_feed then writer.gen_atom_feed() end
|
||||||
end
|
end
|
||||||
|
|
||||||
if args[1] == "post" then
|
if args[1] == lang.opts.config then
|
||||||
local slug = args[2]
|
writer.load_config()
|
||||||
if slug == "" then
|
print(lang.msgs.load_config .. writer.conf.config_dir)
|
||||||
slug = writer.conf.entry_slug
|
|
||||||
|
elseif (args[1] == lang.opts.post) or (args[1] == lang.opts.page) then
|
||||||
|
local file_name = ""
|
||||||
|
if args[3] ~= nil then
|
||||||
|
file_name = writer.add_gemtext(args[3], args[1])
|
||||||
else
|
else
|
||||||
slug = os.date("%Y-%m-%d") .. "-" .. slug
|
file_name = writer.add_gemtext(args[2], args[1])
|
||||||
end
|
end
|
||||||
writer.add_entry(slug)
|
print(lang.msgs.add_gemtext .. file_name)
|
||||||
print(writer.msg.add_entry .. slug .. writer.conf.entry_ext)
|
|
||||||
|
|
||||||
elseif args[1] == "page" then
|
elseif args[1] == lang.opts.index then
|
||||||
local slug = args[2]
|
print(lang.msgs.index)
|
||||||
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
|
elseif args[1] == lang.opts.publish then
|
||||||
print(writer.msg.index)
|
|
||||||
|
|
||||||
elseif args[1] == "publish" then
|
|
||||||
writer.publish()
|
writer.publish()
|
||||||
print(writer.msg.publish)
|
print(lang.msgs.publish)
|
||||||
|
|
||||||
elseif args[1] == "help" then
|
elseif args[1] == lang.opts.help then
|
||||||
print(writer.msg.help)
|
print(env.app.exec_name .. lang.msgs.help)
|
||||||
|
|
||||||
elseif args[1] == "version" then
|
elseif args[1] == lang.opts.version then
|
||||||
print(writer.app.name .. " " .. writer.app.version ..
|
print(env.app.name .. " " .. env.app.version ..
|
||||||
" (" .. writer.app.last_updated .. ")")
|
" (" .. env.app.last_updated .. ")")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
local en = {}
|
||||||
|
|
||||||
|
-- Templates
|
||||||
|
en.tpl_vars = {
|
||||||
|
post = {
|
||||||
|
author = "{{ post_author }}",
|
||||||
|
content = "{{ post_content }}",
|
||||||
|
date = "{{ post_date }}",
|
||||||
|
summary = "{{ post_summary }}",
|
||||||
|
tags = "{{ post_tags }}",
|
||||||
|
title = "{{ post_title }}",
|
||||||
|
url = "{{ post_url }}",
|
||||||
|
},
|
||||||
|
feed = {
|
||||||
|
date = "{{ feed_date }}",
|
||||||
|
url = "{{ feed_url }}",
|
||||||
|
},
|
||||||
|
index = {
|
||||||
|
posts = "{{ posts }}",
|
||||||
|
},
|
||||||
|
log = {
|
||||||
|
author = "{{ log_author }}",
|
||||||
|
subtitle = "{{ log_subtitle }}",
|
||||||
|
title = "{{ log_title }}",
|
||||||
|
log_url = "{{ log_url }}",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
en.atom_header = [[<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||||
|
<id>{{ log_url }}</id>
|
||||||
|
<title>{{ log_title }}</title>
|
||||||
|
<subtitle>{{ log_subtitle }}</subtitle>
|
||||||
|
<updated>{{ feed_date }}</updated>
|
||||||
|
<author>
|
||||||
|
<name>{{ log_author }}</name>
|
||||||
|
</author>
|
||||||
|
<link href="{{ log_url }}" rel="alternate"/>
|
||||||
|
<link href="{{ feed_url }}" rel="self" type="application/atom+xml"/>
|
||||||
|
]]
|
||||||
|
|
||||||
|
en.atom_entry = [[
|
||||||
|
<entry>
|
||||||
|
<id>{{ post_url }}</id>
|
||||||
|
<title>
|
||||||
|
<![CDATA[{{ post_title }}]] .. "]]>" .. [[
|
||||||
|
|
||||||
|
</title>
|
||||||
|
<updated>{{ post_date }}</updated>
|
||||||
|
<author>
|
||||||
|
<name>{{ post_author }}</name>
|
||||||
|
</author>
|
||||||
|
<link href="{{ post_url }}" rel="alternate"/>
|
||||||
|
<summary>
|
||||||
|
<![CDATA[{{ post_summary }}]] .. "]]>" .. [[
|
||||||
|
|
||||||
|
</summary>
|
||||||
|
<content>
|
||||||
|
<![CDATA[{{ post_content }}]] .. "]]>" .. [[
|
||||||
|
|
||||||
|
</content>
|
||||||
|
</entry>
|
||||||
|
]]
|
||||||
|
|
||||||
|
en.atom_footer = [[</feed>]]
|
||||||
|
|
||||||
|
en.post = [[---
|
||||||
|
date: {{ post_date }}
|
||||||
|
---
|
||||||
|
|
||||||
|
# {{ post_title }}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
=> gemini:// link
|
||||||
|
=> gemini:// link (img)
|
||||||
|
=> https:// link (https)]]
|
||||||
|
|
||||||
|
en.index = [[
|
||||||
|
# {{ log_title }}
|
||||||
|
{{ posts }}
|
||||||
|
]]
|
||||||
|
|
||||||
|
en.page = [[
|
||||||
|
# {{ post_title }}
|
||||||
|
|
||||||
|
## Heading 2
|
||||||
|
### Heading 3
|
||||||
|
|
||||||
|
List:
|
||||||
|
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
|
||||||
|
```
|
||||||
|
Preformatted text
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
=> gemini:// link
|
||||||
|
=> gemini:// link (img)
|
||||||
|
=> https:// link (https)]]
|
||||||
|
|
||||||
|
-- App command options and messages output
|
||||||
|
en.opts = {
|
||||||
|
config = "config",
|
||||||
|
page = "page",
|
||||||
|
post = "post",
|
||||||
|
index = "index",
|
||||||
|
publish = "publish",
|
||||||
|
help = "help",
|
||||||
|
version = "version",
|
||||||
|
}
|
||||||
|
|
||||||
|
en.msgs = {
|
||||||
|
add_gemtext = "Created ",
|
||||||
|
help = [[ [options] [capsule] [title]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
config Generate a config directory
|
||||||
|
page [capsule] [title] Add a new page with the given title
|
||||||
|
post [capsule] [title] Add a new gemlog post with the given title
|
||||||
|
index Generate an index page and feed of posts
|
||||||
|
publish Index and copy posts remotely using scp
|
||||||
|
help Show this help message
|
||||||
|
version Print version info]],
|
||||||
|
index = "Created index page and feed.",
|
||||||
|
load_config = [[Created config files. Please edit them with the correct
|
||||||
|
details before proceeding. The config files can be found at:
|
||||||
|
]],
|
||||||
|
publish = "Published capsule.",
|
||||||
|
}
|
||||||
|
|
||||||
|
en.errs = {
|
||||||
|
invalid_cap_id = "Error: unknown capsule id.",
|
||||||
|
}
|
||||||
|
|
||||||
|
return en
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Gemwriter
|
||||||
|
|
||||||
|
A little command-line helper for publishing [Gemini] sites or "capsules".
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
Options:
|
||||||
|
|
||||||
|
config Generate a config directory
|
||||||
|
page [capsule] [title] Add a new page with the given title
|
||||||
|
post [capsule] [title] Add a new gemlog post with the given title
|
||||||
|
index Generate an index page and feed of posts
|
||||||
|
publish Index and copy posts remotely using scp
|
||||||
|
help Show this help message
|
||||||
|
version Print version info
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Linux or Unix-based OS
|
||||||
|
- [Lua] 5.4 (other versions >= 5.1 will probably be fine but are untested)
|
||||||
|
- [scp] or [rsync], to transfer files remotely
|
||||||
|
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
- Install Lua and [luastatic].
|
||||||
|
|
||||||
|
- Clone this repository and change into the directory. Run:
|
||||||
|
|
||||||
|
```
|
||||||
|
luastatic gemwriter.lua env.lua util.lua lang/en.lua /usr/lib/liblua.so -I/usr/include -o gemwriter
|
||||||
|
```
|
||||||
|
|
||||||
|
The paths to `liblua.so` and the development headers (i.e.
|
||||||
|
`/usr/include/lua.h`) may need to be adjusted for your distribution.
|
||||||
|
|
||||||
|
- Move the `gemwriter` executable to a location in your `$PATH`.
|
||||||
|
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
1. Generate a new config: `gemwriter config`
|
||||||
|
|
||||||
|
2. Edit `~/.config/gemwriter/config.toml` with the correct details about your
|
||||||
|
capsule and gemlog.
|
||||||
|
|
||||||
|
3. Create a new gemlog post: `gemwriter post "Hello World!"`
|
||||||
|
|
||||||
|
4. Publish your capsule: `gemwriter publish`
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
BSD-3-Clause
|
||||||
|
|
||||||
|
|
||||||
|
[Gemini]: https://gemini.circumlunar.space/
|
||||||
|
[Lua]: https://www.lua.org/
|
||||||
|
[scp]: https://www.openssh.com/
|
||||||
|
[rsync]: https://rsync.samba.org/
|
||||||
|
[luastatic]: https://github.com/ers35/luastatic
|
96
template.lua
96
template.lua
|
@ -1,96 +0,0 @@
|
||||||
local tpl = {}
|
|
||||||
|
|
||||||
tpl.vars = {
|
|
||||||
entry = {
|
|
||||||
author = "{{ entry_author }}",
|
|
||||||
content = "{{ entry_content }}",
|
|
||||||
date = "{{ entry_date }}",
|
|
||||||
summary = "{{ entry_summary }}",
|
|
||||||
tags = "{{ entry_tags }}",
|
|
||||||
title = "{{ entry_title }}",
|
|
||||||
url = "{{ entry_url }}",
|
|
||||||
},
|
|
||||||
feed = {
|
|
||||||
date = "{{ feed_date }}",
|
|
||||||
url = "{{ feed_url }}",
|
|
||||||
},
|
|
||||||
index = {
|
|
||||||
entries = "{{ entries }}",
|
|
||||||
},
|
|
||||||
log = {
|
|
||||||
author = "{{ log_author }}",
|
|
||||||
subtitle = "{{ log_subtitle }}",
|
|
||||||
title = "{{ log_title }}",
|
|
||||||
url = "{{ log_url }}",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
tpl.atom_header = [[<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
|
||||||
<id>{{ log_url }}</id>
|
|
||||||
<title>{{ log_title }}</title>
|
|
||||||
<subtitle>{{ log_subtitle }}</subtitle>
|
|
||||||
<updated>{{ feed_date }}</updated>
|
|
||||||
<author>
|
|
||||||
<name>{{ log_author }}</name>
|
|
||||||
</author>
|
|
||||||
<link href="{{ log_url }}" rel="alternate"/>
|
|
||||||
<link href="{{ feed_url }}" rel="self" type="application/atom+xml"/>]]
|
|
||||||
|
|
||||||
tpl.atom_entry = [[ <entry>
|
|
||||||
<id>{{ entry_url }}</id>
|
|
||||||
<title>
|
|
||||||
<![CDATA[{{ entry_title }}]] .. "]]>" .. [[
|
|
||||||
|
|
||||||
</title>
|
|
||||||
<updated>{{ entry_date }}</updated>
|
|
||||||
<author>
|
|
||||||
<name>{{ entry_author }}</name>
|
|
||||||
</author>
|
|
||||||
<link href="{{ entry_url }}" rel="alternate"/>
|
|
||||||
<summary>
|
|
||||||
<![CDATA[{{ entry_summary }}]] .. "]]>" .. [[
|
|
||||||
|
|
||||||
</summary>
|
|
||||||
<content>
|
|
||||||
<![CDATA[{{ entry_content }}]] .. "]]>" .. [[
|
|
||||||
|
|
||||||
</content>
|
|
||||||
</entry>
|
|
||||||
]]
|
|
||||||
|
|
||||||
tpl.atom_footer = [[</feed>]]
|
|
||||||
|
|
||||||
tpl.log_gmi = [[---
|
|
||||||
date: {{ entry_date }}
|
|
||||||
---
|
|
||||||
|
|
||||||
# {{ entry_title }}
|
|
||||||
|
|
||||||
# Heading 1
|
|
||||||
## Heading 2
|
|
||||||
### Heading 3
|
|
||||||
|
|
||||||
List:
|
|
||||||
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
|
|
||||||
```
|
|
||||||
Preformatted text
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Links
|
|
||||||
|
|
||||||
=> gemini:// link
|
|
||||||
=> gemini:// link (img)
|
|
||||||
=> https:// link (https)]]
|
|
||||||
|
|
||||||
tpl.index_gmi = [[
|
|
||||||
# {{ log_title }}
|
|
||||||
{{ entries }}
|
|
||||||
]]
|
|
||||||
|
|
||||||
return tpl
|
|
120
util.lua
120
util.lua
|
@ -12,11 +12,115 @@ function util.split_str(str, sep)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function util.split_lines(str)
|
||||||
|
local tbl = {}
|
||||||
|
local si = 1
|
||||||
|
for i = 1, #str do
|
||||||
|
if string.find(string.sub(str, i, i), "\n") ~= nil then
|
||||||
|
tbl[#tbl + 1] = string.sub(str, si, i - 1)
|
||||||
|
si = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return tbl
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function util.extract_str(full_str, find_str, end_str)
|
function util.extract_str(full_str, find_str, end_str)
|
||||||
fi1, fi2 = string.find(full_str, find_str, 1)
|
local fi1, fi2 = string.find(full_str, find_str, 1)
|
||||||
ei1, ei2 = string.find(full_str, end_str, fi2)
|
local ei1, ei2 = string.find(full_str, end_str, fi2)
|
||||||
|
if end_str == "\n" then
|
||||||
|
return string.sub(full_str, fi2 + 1, ei1 - 2)
|
||||||
|
else
|
||||||
return string.sub(full_str, fi2 + 1, ei1 - 1)
|
return string.sub(full_str, fi2 + 1, ei1 - 1)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function util.to_bool(str)
|
||||||
|
local bool = { ["true"] = true, ["false"] = false }
|
||||||
|
return bool(str)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function util.table_keys(tbl)
|
||||||
|
local keys = {}
|
||||||
|
local n = 0
|
||||||
|
for k, v in pairs(tbl) do
|
||||||
|
n = n + 1
|
||||||
|
keys[n] = k
|
||||||
|
end
|
||||||
|
return keys
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function util.has_key(tbl, str)
|
||||||
|
local keys = util.table_keys(tbl)
|
||||||
|
for k = 1, #keys do
|
||||||
|
if str == keys[k] then
|
||||||
|
do return true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function util.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 util.replace_html_entities(str)
|
||||||
|
local html_ents = {
|
||||||
|
percent = { "%%", "%" },
|
||||||
|
less_than = { "<", "<" },
|
||||||
|
greater_than = { ">", ">" },
|
||||||
|
left_bracket = { "%[", "[" },
|
||||||
|
right_bracket = { "%]", "]" },
|
||||||
|
}
|
||||||
|
local text = str
|
||||||
|
for e, c in pairs(html_ents) do
|
||||||
|
text = string.gsub(text, c[1], c[2])
|
||||||
|
end
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function util.make_dir(dir)
|
||||||
|
os.execute("test -d " .. dir .. " || mkdir -p " .. dir)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function util.ls_grep(dir, str)
|
||||||
|
local ls_cmd = io.popen("ls " .. dir .. " | grep " .. str)
|
||||||
|
return ls_cmd:read("*a")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function util.get_shell_var(str)
|
||||||
|
local var = os.getenv(str)
|
||||||
|
if var == "" then
|
||||||
|
return nil
|
||||||
|
else
|
||||||
|
return var
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function util.replace_shell_vars(str)
|
||||||
|
-- Replace common shell variable paths
|
||||||
|
if string.find(str, "%$") ~= nil then
|
||||||
|
local shell_vars = { "HOME", "USER" }
|
||||||
|
for v = 1, #shell_vars do
|
||||||
|
str = string.gsub(str, "$" .. shell_vars[v],
|
||||||
|
util.get_shell_var(shell_vars[v]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function util.extract_file_date(dir, file)
|
function util.extract_file_date(dir, file)
|
||||||
|
@ -30,18 +134,18 @@ end
|
||||||
function util.read_file(file)
|
function util.read_file(file)
|
||||||
local fh = io.open(file, "r")
|
local fh = io.open(file, "r")
|
||||||
local text = ""
|
local text = ""
|
||||||
io.input(fh)
|
if fh ~= nil then
|
||||||
text = io.read("*a")
|
text = fh:read("*a")
|
||||||
io.close(fh)
|
fh:close()
|
||||||
|
end
|
||||||
return text
|
return text
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function util.write_file(file, str)
|
function util.write_file(file, str)
|
||||||
local fh = io.open(file, "w")
|
local fh = io.open(file, "w")
|
||||||
io.output(fh)
|
fh:write(str)
|
||||||
io.write(str)
|
fh:close()
|
||||||
io.close(fh)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return util
|
return util
|
||||||
|
|
Reference in New Issue