commit 1dc59c9ede62842dbbaa76f058df3088105f7da2
parent 9954ac5aa193f27492fd86d2bba17c0c369b3f7f
Author: Juan F. Meleiro <juan@juanmeleiro.mat.br>
Date: Mon, 26 Jun 2023 09:50:09 -0300
Implement event recording and fix report logic
Diffstat:
| A | absurdor | | | 164 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | report | | | 117 | ------------------------------------------------------------------------------- |
| M | template.m4 | | | 1 | - |
3 files changed, 164 insertions(+), 118 deletions(-)
diff --git a/absurdor b/absurdor
@@ -0,0 +1,164 @@
+#!/usr/bin/env lua
+local argparse = require "argparse"
+local json = require "json"
+local path = require "path"
+local fs = require "path.fs"
+local date = require "date"
+
+function die(err, msg)
+ msg = tostring(msg or err)
+ if err then
+ io.stderr:write(msg .. "\n")
+ os.exit(1)
+ end
+end
+
+function maildate(s)
+ local d = date(s)
+ local sec = date.diff(d, date.epoch()):spanseconds()
+ return sec
+end
+
+function yn(prompt)
+ meaning = {Y = true, y = true, n = false, N = false}
+ while meaning[ans] == nil do
+ io.write(prompt)
+ ans = io.read(1)
+ end
+ return ans
+end
+
+function decodewith(decoder, fn)
+ die(not path.exists(fn), fn.." does not exist.")
+ die(not path.isfile(fn), fn.." is not a file.")
+ local f, err = io.open(fn, "r")
+ die(err)
+ status, res = xpcall(decoder, die, f:read("a"))
+ f:close()
+ die(not status, res)
+ return res
+end
+
+function encodewith(encoder, fn, data)
+ local f, err = io.open(fn, "w")
+ die(not status, err)
+ status, err = f:write(encoder(data))
+ die(not status, err)
+end
+
+function format(fmt, dict, sett)
+ -- A identifier is
+ -- > any string of Latin letters, Arabic-Indic digits, and
+ -- > underscores, not beginning with a digit and not being a reserved
+ -- > word
+
+ -- local reserved = {
+ -- "and", "break", "do", "else", "elseif", "end", "false", "for",
+ -- "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat",
+ -- "return", "then", "true", "until", "while"
+ -- }
+ res = fmt
+ for s in string.gmatch(fmt, "%{([_a-zA-Z][._a-zA-Z0-9]*)%}") do
+ local value = dict
+ local pref = sett
+ for k in string.gmatch(s, "([_a-zA-Z][_a-zA-Z0-9]*)") do
+ if type(value) == "table" then value = value[k] end
+ if type(pref) == "table" then pref = pref[k] end
+ end
+ if pref and value then string.format(pref, value) end
+ res = fmt.gsub(res, "{"..s.."}", value or "nil")
+ end
+ return res
+end
+
+function fmt_event(e)
+ date = os.date("%Y-%m-%d %H:%M:%S %z", e.when)
+ args = {ts = date}
+ if e.what == "report" then
+ fmt = "[{ts}] Reported boulder at height {height}"
+ args.height = e.height
+ elseif e.what == "push" then
+ fmt = "[{ts}] {who} pushed the boulder"
+ args.who = e.who
+ end
+ return format(fmt, args)
+end
+
+local parser = argparse("absurdor", "Manage Absurdor duties")
+ :command_target("command")
+parser:command("report", "Generate and send absurdor report")
+local cmd_record = parser:command("record", "Record events")
+ :command_target("what")
+local cmd_press = cmd_record:command("push", "A push of The Boulder")
+cmd_press:argument("who", "Name of the player")
+cmd_press:argument("when", "Timestamp of boulder push")
+ :convert(maildate)
+parser:command("log", "Display log")
+
+local args = parser:parse()
+
+fn = "log.json"
+log = decodewith(json.decode, fn)
+
+if args.command == "report" then
+
+ height = 0
+
+ for i,e in ipairs(log) do
+ if e.what == "push" then
+ height = height + 1
+ end
+ end
+
+ height = height % 100
+
+ vars = {
+ YYYY = os.date("%Y"),
+ MM = os.date("%m"),
+ DD = os.date("%d"),
+ N = height
+ }
+
+ defs = ""
+
+ for k, v in pairs(vars) do
+ defs = defs .. string.format(" --define=%s=%s", k, v)
+ end
+
+ tmpname = ".tmp"
+ os.execute(string.format("m4 %s template.m4 >> %s", defs, tmpname))
+
+ f = io.open(tmpname, "a")
+ f:write("There is no log, for there is no point.\n")
+ f:write("There is no log, for there is no hope.\n")
+ f:write("There is no log. But do not despair;\n\n rebel\n\n")
+ f:write("======================================================================")
+ f:close()
+
+ os.execute(string.format("neomutt -H %s -E", tmpname))
+
+ if yn("Archive report? [Yn] ") then
+ table.insert(log, {
+ when = os.time(),
+ what = "report",
+ height = height,
+ })
+ os.rename(tmpname, string.format("archive/%s", os.date("%F")))
+ end
+elseif args.command == "record" then
+ if args.what == "push" then
+ io.write(string.format("%s pushed the boulder at %d\n", args.who, args.when))
+ table.insert(log, {
+ when = args.when,
+ what = "push",
+ who = args.who
+ })
+ end
+elseif args.command == "log" then
+ for _,e in ipairs(log) do
+ io.write(fmt_event(e).."\n")
+ end
+end
+
+encodewith(json.encode, fn, log)
+
diff --git a/report b/report
@@ -1,117 +0,0 @@
-#!/usr/bin/env lua
-local argparse = require "argparse"
-local json = require "json"
-local path = require "path"
-local fs = require "path.fs"
-
-function die(err, msg)
- msg = tostring(msg or err)
- if err then
- io.stderr:write(msg .. "\n")
- os.exit(1)
- end
-end
-
-function decodewith(decoder, fn)
- die(not path.exists(fn), fn.." does not exist.")
- die(not path.isfile(fn), fn.." is not a file.")
- local f, err = io.open(fn, "r")
- die(err)
- status, res = xpcall(decoder, die, f:read("a"))
- f:close()
- die(not status, res)
- return res
-end
-
-function encodewith(encoder, fn, data)
- local f, err = io.open(fn, "w")
- die(not status, err)
- status, err = f:write(encoder(data))
- die(not status, err)
-end
-
-function format(fmt, dict, sett)
- -- A identifier is
- -- > any string of Latin letters, Arabic-Indic digits, and
- -- > underscores, not beginning with a digit and not being a reserved
- -- > word
-
- -- local reserved = {
- -- "and", "break", "do", "else", "elseif", "end", "false", "for",
- -- "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat",
- -- "return", "then", "true", "until", "while"
- -- }
- res = fmt
- for s in string.gmatch(fmt, "%{([_a-zA-Z][._a-zA-Z0-9]*)%}") do
- local value = dict
- local pref = sett
- for k in string.gmatch(s, "([_a-zA-Z][_a-zA-Z0-9]*)") do
- if type(value) == "table" then value = value[k] end
- if type(pref) == "table" then pref = pref[k] end
- end
- if pref and value then string.format(pref, value) end
- res = fmt.gsub(res, "{"..s.."}", value or "nil")
- end
- return res
-end
-
-local parser = argparse("report", "Generate and send the Absurdor report")
--- parser:argument("input", "Input file.")
--- parser:option("-o --output", "Output file.", "a.out")
-
-local args = parser:parse()
-
-fn = "log.json"
-log = decodewith(json.decode, fn)
-
-height = 0
-
-for i,e in ipairs(log) do
- if e.type == "push" then
- height = height + 1
- end
-end
-
-height = height % 100
-
-vars = {
- YYYY = os.date("%Y"),
- MM = os.date("%m"),
- DD = os.date("%d"),
- N = height
-}
-
-defs = ""
-
-for k, v in pairs(vars) do
- defs = defs .. string.format(" --define=%s=%s", k, v)
-end
-
-tmpname = ".tmp"
-os.execute(string.format("m4 %s template.m4 >> %s", defs, tmpname))
-os.execute(string.format("neomutt -H %s -E", tmpname))
-
-table.insert(log, {
- timestamp = os.time(),
- ["type"] = "report",
- height = height
-})
-
-valid = {
- Y = true,
- y = true,
- n = false,
- N = false
-}
-
-ans = nil
-while valid[ans] == nil do
- io.write("Archive report? [Yn] ")
- ans = io.read(1)
-end
-
-if valid[ans] then
- encodewith(json.encode, fn, log)
- os.rename(tmpname, string.format("archive/%s", os.date("%F")))
-end
-
diff --git a/template.m4 b/template.m4
@@ -22,5 +22,4 @@ absurdor: juan The State of the Absurd YYYY-MM-DD
`_/
/
-======================================================================