-- End-to-end install over file:// URLs: real curl, real tar, real swap. local checksum = require('vimpack.checksum') local config = require('vimpack.config') local fsmod = require('vimpack.fs') local installer = require('vimpack.installer') local manifest = require('vimpack.manifest') local plan = require('vimpack.plan') local function make_tarball(root, version, body) local src = vim.fs.joinpath(root, 'src', 'demo.nvim-' .. version, 'lua') vim.fn.mkdir(src, 'p') vim.fn.writefile({ body }, vim.fs.joinpath(src, 'demo.lua')) local archive = vim.fs.joinpath(root, 'demo-' .. version .. '.tar.gz') vim.fn.system({ 'tar', '-czf', archive, '-C', vim.fs.joinpath(root, 'src'), 'demo.nvim-' .. version }) return archive end local function install(cfg, data, pack_root) local built = plan.build(cfg, data, fsmod.scan(pack_root)) local items = vim.list_extend(vim.deepcopy(built.install), built.update) local results installer.run(items, { manifest = data, pack_root = pack_root, timeout = 30000, concurrency = 2, }, function(r) results = r end) vim.wait(30000, function() return results ~= nil end) return results, items end describe('install end to end', function() it('downloads, extracts, swaps and records the manifest', function() local root = tmpdir() local pack_root = vim.fs.joinpath(root, 'pack') local archive = make_tarball(root, '1.0.0', 'return 1') local cfg = assert(config.normalize({ plugins = { { name = 'demo.nvim', version = '1.0.0', url = 'file://' .. archive } }, })) local data = manifest.empty() local results = install(cfg, data, pack_root) assert_eq(1, #results) assert_true(results[1].ok, tostring(results[1].err)) local installed = vim.fs.joinpath(pack_root, 'start', 'demo.nvim', 'lua', 'demo.lua') assert_true(fsmod.exists(installed), 'expected ' .. installed) assert_eq({ 'return 1' }, vim.fn.readfile(installed)) local entry = manifest.get(data, 'demo.nvim') assert_eq('1.0.0', entry.version) assert_eq(assert(checksum.sha256_file(archive)), entry.sha256) -- Second pass is a no-op: nothing left to install. local _, items = install(cfg, data, pack_root) assert_eq(0, #items) end) it('replaces the old tree on a version bump', function() local root = tmpdir() local pack_root = vim.fs.joinpath(root, 'pack') local data = manifest.empty() local v1 = make_tarball(root, '1.0.0', 'return 1') local cfg1 = assert(config.normalize({ plugins = { { name = 'demo.nvim', version = '1.0.0', url = 'file://' .. v1 } }, })) assert_true(install(cfg1, data, pack_root)[1].ok) local v2 = make_tarball(root, '2.0.0', 'return 2') local cfg2 = assert(config.normalize({ plugins = { { name = 'demo.nvim', version = '2.0.0', url = 'file://' .. v2 } }, })) local results = install(cfg2, data, pack_root) assert_true(results[1].ok, tostring(results[1].err)) assert_eq({ 'return 2' }, vim.fn.readfile(vim.fs.joinpath(pack_root, 'start', 'demo.nvim', 'lua', 'demo.lua'))) assert_eq('2.0.0', manifest.get(data, 'demo.nvim').version) end) it('aborts on a checksum mismatch and keeps the previous install', function() local root = tmpdir() local pack_root = vim.fs.joinpath(root, 'pack') local data = manifest.empty() local v1 = make_tarball(root, '1.0.0', 'return 1') assert_true(install( assert(config.normalize({ plugins = { { name = 'demo.nvim', version = '1.0.0', url = 'file://' .. v1 } }, })), data, pack_root )[1].ok) local v2 = make_tarball(root, '2.0.0', 'return 2') local results = install( assert(config.normalize({ plugins = { { name = 'demo.nvim', version = '2.0.0', url = 'file://' .. v2, sha256 = string.rep('a', 64) }, }, })), data, pack_root ) assert_true(not results[1].ok) assert_match('checksum mismatch', results[1].err) assert_eq({ 'return 1' }, vim.fn.readfile(vim.fs.joinpath(pack_root, 'start', 'demo.nvim', 'lua', 'demo.lua'))) assert_eq('1.0.0', manifest.get(data, 'demo.nvim').version) end) it('names the url when the download fails', function() local root = tmpdir() local missing = 'file://' .. vim.fs.joinpath(root, 'nope.tar.gz') local results = install( assert(config.normalize({ plugins = { { name = 'demo.nvim', version = '1.0.0', url = missing } }, })), manifest.empty(), vim.fs.joinpath(root, 'pack') ) assert_true(not results[1].ok) assert_match('download failed', results[1].err) assert_match(missing, results[1].err) end) it('installs with the cache on a different filesystem from the pack root', function() local root = tmpdir() local pack_root = vim.fs.joinpath(root, 'pack') local other = otherfs_dir(root) if not other then return end local real_cache_dir = fsmod.cache_dir fsmod.cache_dir = function() return vim.fs.joinpath(other, 'vimpack') end local archive = make_tarball(root, '1.0.0', 'return 1') local cfg = assert(config.normalize({ plugins = { { name = 'demo.nvim', version = '1.0.0', url = 'file://' .. archive } }, })) local data = manifest.empty() local ok, results = pcall(install, cfg, data, pack_root) fsmod.cache_dir = real_cache_dir fsmod.rm_rf(other) assert_true(ok, tostring(results)) assert_true(results[1].ok, tostring(results[1].err)) assert_eq({ 'return 1' }, vim.fn.readfile(vim.fs.joinpath(pack_root, 'start', 'demo.nvim', 'lua', 'demo.lua'))) end) it('moves a plugin from start to opt', function() local root = tmpdir() local pack_root = vim.fs.joinpath(root, 'pack') local data = manifest.empty() local archive = make_tarball(root, '1.0.0', 'return 1') assert_true(install( assert(config.normalize({ plugins = { { name = 'demo.nvim', version = '1.0.0', url = 'file://' .. archive } }, })), data, pack_root )[1].ok) local results = install( assert(config.normalize({ plugins = { { name = 'demo.nvim', version = '1.0.0', url = 'file://' .. archive, opt = true } }, })), data, pack_root ) assert_true(results[1].ok, tostring(results[1].err)) assert_true(fsmod.exists(vim.fs.joinpath(pack_root, 'opt', 'demo.nvim', 'lua', 'demo.lua'))) assert_true(not fsmod.exists(vim.fs.joinpath(pack_root, 'start', 'demo.nvim'))) end) end)