local M = {}
local function build_env(opts)
local env_t = {}
if opts.repository then env_t.RUSTIC_REPOSITORY = opts.repository end
if opts.password then env_t.RUSTIC_PASSWORD = opts.password end
if opts.access_key_id then env_t.AWS_ACCESS_KEY_ID = opts.access_key_id end
if opts.secret_access_key then env_t.AWS_SECRET_ACCESS_KEY = opts.secret_access_key end
if opts.region then env_t.AWS_REGION = opts.region end
return env_t
end
local function shell_quote(s)
return "'" .. tostring(s):gsub("'", [['\'']]) .. "'"
end
local function run(opts, args, exec_opts)
exec_opts = exec_opts or {}
exec_opts.env = build_env(opts)
local cmd = "rustic " .. table.concat(args, " ")
return shell.exec(cmd, exec_opts)
end
local function err_from_result(name, r)
return ("rustic %s failed (exit %s): %s"):format(
name,
tostring(r and r.status),
(r and r.stderr) or "unknown")
end
local function decode_json_or_err(r, name)
if not r or r.status ~= 0 then return nil, err_from_result(name, r) end
local ok, parsed = pcall(json.parse, r.stdout or "")
if not ok then
return nil, ("rustic %s: parse error: %s"):format(name, tostring(parsed))
end
return parsed
end
function M.snapshots(opts)
local r = run(opts, { "snapshots", "--json" }, { timeout = opts.timeout or 60 })
return decode_json_or_err(r, "snapshots")
end
function M.snapshot_detail(opts, id)
local r = run(opts,
{ "snapshots", shell_quote(id), "--json" },
{ timeout = opts.timeout or 60 })
return decode_json_or_err(r, "snapshot_detail")
end
function M.check(opts)
local r = run(opts, { "check" }, { timeout = opts.timeout or 600 })
if not r or r.status ~= 0 then return nil, err_from_result("check", r) end
return { ok = true }
end
function M.init(opts)
local r = run(opts, { "init" }, { timeout = opts.timeout or 120 })
if not r or r.status ~= 0 then return nil, err_from_result("init", r) end
return { ok = true, stdout = r.stdout }
end
function M.backup(opts, args)
args = args or {}
local cmd = { "backup" }
for _, t in ipairs(args.tags or {}) do cmd[#cmd+1] = "--tag"; cmd[#cmd+1] = shell_quote(t) end
for _, e in ipairs(args.exclude or {}) do cmd[#cmd+1] = "--exclude"; cmd[#cmd+1] = shell_quote(e) end
if args.json then cmd[#cmd+1] = "--json" end
for _, s in ipairs(args.sources or {}) do cmd[#cmd+1] = shell_quote(s) end
local r = run(opts, cmd, { timeout = args.timeout or 7200 })
if not r or r.status ~= 0 then return nil, err_from_result("backup", r) end
local out = { ok = true, stdout = r.stdout, stderr = r.stderr }
if args.json then
local ok, summary = pcall(json.parse, r.stdout or "")
if ok then out.summary = summary end
end
return out
end
function M.restore(opts, id, target, args)
args = args or {}
local cmd = { "restore", shell_quote(id), shell_quote(target) }
if args.dry_run then cmd[#cmd+1] = "--dry-run" end
local r = run(opts, cmd, { timeout = args.timeout or 7200 })
if not r or r.status ~= 0 then return nil, err_from_result("restore", r) end
return { ok = true, stdout = r.stdout, stderr = r.stderr }
end
function M.forget(opts, args)
args = args or {}
local cmd = { "forget" }
for _, k in ipairs({
"keep_daily", "keep_weekly", "keep_monthly", "keep_yearly", "keep_hourly", "keep_last",
}) do
if args[k] then
cmd[#cmd+1] = "--" .. k:gsub("_", "-")
cmd[#cmd+1] = tostring(args[k])
end
end
for _, t in ipairs(args.tags or {}) do cmd[#cmd+1] = "--tag"; cmd[#cmd+1] = shell_quote(t) end
if args.prune then cmd[#cmd+1] = "--prune" end
if args.json then cmd[#cmd+1] = "--json" end
local r = run(opts, cmd, { timeout = args.timeout or 1800 })
if not r or r.status ~= 0 then return nil, err_from_result("forget", r) end
local out = { ok = true, stdout = r.stdout }
if args.json then
local ok, parsed = pcall(json.parse, r.stdout or "")
if ok then out.removed = parsed end
end
return out
end
return M