460dc2c5c8
Many upstream plugins publish no tags at all, so a tag-only installer cannot manage them. - Add a branch spec field, mutually exclusive with tag and validated the same way - Build archive/refs/heads/<branch> URLs for branch specs - Refetch a branch only on :ArtiPackUpdate or a forced sync, never from cache - Record the branch, archive digest and fetch time in the lockfile - Report a branch plugin as tracked and fetched, never as up to date
126 lines
3.7 KiB
Lua
126 lines
3.7 KiB
Lua
local t = require('tests.harness')
|
|
local fs = require('arti-pack.fs')
|
|
|
|
local function tmpdir()
|
|
local dir = vim.fn.tempname()
|
|
vim.fn.mkdir(dir, 'p')
|
|
return dir
|
|
end
|
|
|
|
local function write(path, contents)
|
|
local fd = assert(io.open(path, 'wb'))
|
|
fd:write(contents)
|
|
fd:close()
|
|
return path
|
|
end
|
|
|
|
t.describe('fs.archive_root', function()
|
|
t.it('strips the single wrapper directory a tag archive unpacks to', function()
|
|
local dir = tmpdir()
|
|
vim.fn.mkdir(dir .. '/plenary.nvim-0.1.4/lua', 'p')
|
|
t.eq(dir .. '/plenary.nvim-0.1.4', fs.archive_root(dir))
|
|
end)
|
|
|
|
t.it('keeps the directory when the archive unpacked flat', function()
|
|
local dir = tmpdir()
|
|
vim.fn.mkdir(dir .. '/lua', 'p')
|
|
write(dir .. '/README.md', 'hi')
|
|
t.eq(dir, fs.archive_root(dir))
|
|
end)
|
|
|
|
t.it('keeps the directory when its only entry is a file', function()
|
|
local dir = tmpdir()
|
|
write(dir .. '/init.lua', 'return {}')
|
|
t.eq(dir, fs.archive_root(dir))
|
|
end)
|
|
end)
|
|
|
|
t.describe('fs.verify_archive', function()
|
|
t.it('accepts a zip magic header', function()
|
|
local path = write(tmpdir() .. '/a.zip', 'PK\3\4rest of the file')
|
|
t.truthy(fs.verify_archive(path, 'zip'))
|
|
end)
|
|
|
|
t.it('accepts a gzip magic header', function()
|
|
local path = write(tmpdir() .. '/a.tar.gz', '\31\139\8\0padding')
|
|
t.truthy(fs.verify_archive(path, 'tar.gz'))
|
|
end)
|
|
|
|
t.it('rejects an empty download', function()
|
|
local path = write(tmpdir() .. '/a.zip', '')
|
|
local ok, err = fs.verify_archive(path, 'zip')
|
|
t.falsy(ok)
|
|
t.matches('empty', err)
|
|
end)
|
|
|
|
t.it('rejects an html error page served in place of a zip', function()
|
|
local path = write(tmpdir() .. '/a.zip', '<!DOCTYPE html><html>404</html>')
|
|
local ok, err = fs.verify_archive(path, 'zip')
|
|
t.falsy(ok)
|
|
t.matches('not a zip', err)
|
|
end)
|
|
|
|
t.it('rejects a zip when a tar.gz was expected', function()
|
|
local path = write(tmpdir() .. '/a.tar.gz', 'PK\3\4rest')
|
|
local ok, err = fs.verify_archive(path, 'tar.gz')
|
|
t.falsy(ok)
|
|
t.matches('not a tar%.gz', err)
|
|
end)
|
|
|
|
t.it('rejects a missing file', function()
|
|
local ok, err = fs.verify_archive(tmpdir() .. '/absent.zip', 'zip')
|
|
t.falsy(ok)
|
|
t.matches('empty', err)
|
|
end)
|
|
end)
|
|
|
|
t.describe('fs.digest', function()
|
|
t.it('identifies file contents, not the file name', function()
|
|
local dir = tmpdir()
|
|
local a = write(dir .. '/a.zip', 'PK\3\4payload')
|
|
local b = write(dir .. '/b.zip', 'PK\3\4payload')
|
|
t.eq(fs.digest(a), fs.digest(b))
|
|
t.eq(64, #fs.digest(a), 'a sha256 hex digest')
|
|
end)
|
|
|
|
t.it('changes when the bytes change', function()
|
|
local dir = tmpdir()
|
|
local before = fs.digest(write(dir .. '/a.zip', 'PK\3\4one'))
|
|
local after = fs.digest(write(dir .. '/a.zip', 'PK\3\4two'))
|
|
t.truthy(before ~= after, 'a refetched archive with new contents digests differently')
|
|
end)
|
|
|
|
t.it('returns nothing for a missing file', function()
|
|
t.eq(nil, fs.digest(tmpdir() .. '/absent.zip'))
|
|
end)
|
|
end)
|
|
|
|
t.describe('fs.extract', function()
|
|
t.it('reports a missing archive instead of raising', function()
|
|
local ok, err = fs.extract(tmpdir() .. '/absent.zip', tmpdir(), 'zip')
|
|
t.falsy(ok)
|
|
t.truthy(err)
|
|
end)
|
|
|
|
t.it('reports an empty archive', function()
|
|
local path = write(tmpdir() .. '/a.zip', '')
|
|
local ok, err = fs.extract(path, tmpdir() .. '/dest', 'zip')
|
|
t.falsy(ok)
|
|
t.matches('empty', err)
|
|
end)
|
|
end)
|
|
|
|
t.describe('fs.rm_rf', function()
|
|
t.it('removes a populated directory tree', function()
|
|
local dir = tmpdir()
|
|
vim.fn.mkdir(dir .. '/a/b', 'p')
|
|
write(dir .. '/a/b/c.txt', 'x')
|
|
fs.rm_rf(dir .. '/a')
|
|
t.falsy(fs.exists(dir .. '/a'))
|
|
end)
|
|
|
|
t.it('is a no-op on a path that is not there', function()
|
|
fs.rm_rf(tmpdir() .. '/never-existed')
|
|
end)
|
|
end)
|