Files
arti-pack/lua/arti-pack/fs.lua
T
unkin-agent 46517953e5
ci/woodpecker/pr/lint Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Add arti-pack plugin manager scaffold
- add lua modules for spec parsing, lock state, fs helpers and the installer
- add ArtiPackSync/ArtiPackClean/ArtiPackList commands and help doc
- add headless nvim test harness and specs
- add make test/lint/fmt/pre-commit and patch/minor/major bump targets
- add woodpecker test, lint and pre-commit pipelines
2026-09-08 23:22:15 +10:00

89 lines
1.8 KiB
Lua

local uv = vim.uv or vim.loop
local M = {}
local ZIP_MAGIC = 'PK\3\4'
local GZIP_MAGIC = '\31\139'
function M.join(...)
return table.concat({ ... }, '/')
end
function M.mkdirp(path)
vim.fn.mkdir(path, 'p')
return path
end
function M.rm_rf(path)
if uv.fs_stat(path) then
vim.fn.delete(path, 'rf')
end
end
function M.exists(path)
return uv.fs_stat(path) ~= nil
end
function M.entries(dir)
local handle = uv.fs_scandir(dir)
if not handle then
return {}
end
local out = {}
while true do
local name, kind = uv.fs_scandir_next(handle)
if not name then
break
end
table.insert(out, { name = name, kind = kind })
end
return out
end
-- Tag archives wrap everything in a single "<repo>-<tag>" directory. Detect it
-- rather than reconstructing the name, since the leading "v" is dropped.
function M.archive_root(dir)
local entries = M.entries(dir)
if #entries == 1 and entries[1].kind == 'directory' then
return M.join(dir, entries[1].name)
end
return dir
end
function M.read_head(path, bytes)
local fd = io.open(path, 'rb')
if not fd then
return nil
end
local head = fd:read(bytes)
fd:close()
return head
end
function M.verify_archive(path, ext)
local stat = uv.fs_stat(path)
if not stat or stat.size == 0 then
return false, 'downloaded archive is empty'
end
local magic = ext == 'zip' and ZIP_MAGIC or GZIP_MAGIC
local head = M.read_head(path, #magic)
if head ~= magic then
return false, string.format('downloaded archive is not a %s', ext)
end
return true
end
function M.extract_cmd(archive, dest, ext)
if ext == 'zip' then
return { 'unzip', '-q', '-o', archive, '-d', dest }
end
return { 'tar', '-xzf', archive, '-C', dest }
end
function M.rename(from, to)
return uv.fs_rename(from, to)
end
return M