From d87d586b62d7807f6e9f714377bc451e82be9412 Mon Sep 17 00:00:00 2001 From: Marc Jakobi Date: Sun, 7 Jul 2024 19:59:39 +0200 Subject: [PATCH] feat: lockfile support --- README.md | 7 ++ doc/rocks.txt | 4 +- flake.lock | 6 +- flake.nix | 10 +- lua/rocks/config/init.lua | 5 +- lua/rocks/config/internal.lua | 5 +- lua/rocks/fs.lua | 11 ++- lua/rocks/operations/add.lua | 2 + lua/rocks/operations/helpers.lua | 38 +++++--- lua/rocks/operations/lock.lua | 87 +++++++++++++++++ lua/rocks/operations/prune.lua | 2 + lua/rocks/operations/sync.lua | 4 +- lua/rocks/operations/update.lua | 2 + nix/plugin-overlay.nix | 35 ++----- nix/test-overlay.nix | 2 +- spec/operations/lock_spec.lua | 157 +++++++++++++++++++++++++++++++ spec/operations/sync_spec.lua | 22 ++--- 17 files changed, 324 insertions(+), 75 deletions(-) create mode 100644 lua/rocks/operations/lock.lua create mode 100644 spec/operations/lock_spec.lua diff --git a/README.md b/README.md index 1f420839..10a5a2bf 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ - Name-based installation (` "nvim-neorg/neorg" ` becomes `:Rocks install neorg` instead). - Supports [multiple versions of the same dependency](https://github.com/luarocks/luarocks/wiki/Using-LuaRocks#multiple-versions-using-the-luarocks-package-loader). +- Lockfile `rocks.lock` for dependencies. - Minimal, non-intrusive UI. - Async execution. - Extensible, with a Lua API. @@ -469,6 +470,12 @@ You can also pin/unpin installed plugins with: :Rocks [pin|unpin] {rock} ``` +### lockfile + +When installing or updating, `rocks.nvim` maintains a `rocks.lock` file, +which pins all SemVer dependency versions for each plugin. +You can check the lockfile into SCM. + ## :package: Extending `rocks.nvim` This plugin provides a Lua API for extensibility. diff --git a/doc/rocks.txt b/doc/rocks.txt index 33435164..66127ad2 100644 --- a/doc/rocks.txt +++ b/doc/rocks.txt @@ -105,8 +105,10 @@ RocksOpts *RocksOpts* (Default: a `rocks` directory in `vim.fn.stdpath("data")`). {config_path?} (string) Rocks declaration file path (Default: `rocks.toml`) in `vim.fn.stdpath("config")`. + {lockfile_path?} (string) + Rocks lockfile path. Defaults to `rocks.lock` in `vim.fn.stdpath("config")`. {luarocks_binary?} (string) - Luarocks binary path (Default: `{rocks_path}/bin/luarocks`). + Luarocks binary path. Defaults to the bundled installation if executable. {lazy?} (boolean) Whether to query luarocks.org lazily (Default: `false`). Setting this to `true` may improve startup time, diff --git a/flake.lock b/flake.lock index 0df35d5b..9f0395a8 100644 --- a/flake.lock +++ b/flake.lock @@ -588,11 +588,11 @@ }, "nixpkgs_5": { "locked": { - "lastModified": 1719708123, - "narHash": "sha256-kzzvyhGQ3IUF+pJ2UHJRTeH3c8CzE7uUeVXQKTY3ujc=", + "lastModified": 1720376781, + "narHash": "sha256-qtvL3oS9Kv78U/u6y9DS1MaM4ynLc8jKiwY0ZlcKt7c=", "owner": "nixos", "repo": "nixpkgs", - "rev": "079457313a259f66e32acc08a52bc54ff88dce43", + "rev": "c5a88c73c67d6c1f4dcdfa1a1fe380fc92fa0406", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 15605c6c..3cc6b3b6 100644 --- a/flake.nix +++ b/flake.nix @@ -50,13 +50,7 @@ "x86_64-darwin" "aarch64-darwin" ]; - perSystem = { - config, - self', - inputs', - system, - ... - }: let + perSystem = {system, ...}: let pkgs = import nixpkgs { inherit system; overlays = [ @@ -140,7 +134,7 @@ packages = rec { default = rocks-nvim; - inherit (pkgs.luajitPackages) rocks-nvim luarocks-rock; + inherit (pkgs.luajitPackages) rocks-nvim; inherit (pkgs) neovim-with-rocks diff --git a/lua/rocks/config/init.lua b/lua/rocks/config/init.lua index 15f7ccaa..2436b355 100644 --- a/lua/rocks/config/init.lua +++ b/lua/rocks/config/init.lua @@ -24,7 +24,10 @@ local config = {} --- Rocks declaration file path (Default: `rocks.toml`) in `vim.fn.stdpath("config")`. ---@field config_path? string --- ---- Luarocks binary path (Default: `{rocks_path}/bin/luarocks`). +--- Rocks lockfile path. Defaults to `rocks.lock` in `vim.fn.stdpath("config")`. +---@field lockfile_path? string +--- +--- Luarocks binary path. Defaults to the bundled installation if executable. ---@field luarocks_binary? string --- --- Whether to query luarocks.org lazily (Default: `false`). diff --git a/lua/rocks/config/internal.lua b/lua/rocks/config/internal.lua index aa0bc213..55676770 100644 --- a/lua/rocks/config/internal.lua +++ b/lua/rocks/config/internal.lua @@ -45,8 +45,9 @@ local default_config = { ---@type string Local path in your filesystem to install rocks rocks_path = default_rocks_path, ---@type string Rocks declaration file path - ---@diagnostic disable-next-line: param-type-mismatch - config_path = vim.fs.joinpath(vim.fn.stdpath("config"), "rocks.toml"), + config_path = vim.fs.joinpath(vim.fn.stdpath("config") --[[@as string]], "rocks.toml"), + ---@type string Rocks lockfile path + lockfile_path = vim.fs.joinpath(vim.fn.stdpath("config") --[[@as string]], "rocks.lock"), ---@type string Luarocks binary path luarocks_binary = get_default_luarocks_binary(default_rocks_path), ---@type boolean Whether to query luarocks.org lazily diff --git a/lua/rocks/fs.lua b/lua/rocks/fs.lua index 6083fe9b..0c9159fd 100644 --- a/lua/rocks/fs.lua +++ b/lua/rocks/fs.lua @@ -36,13 +36,13 @@ function fs.file_exists(location) return false end ---- Write `contents` to a file +--- Write `contents` to a file asynchronously ---@param location string file path ---@param mode string mode to open the file for ---@param contents string file contents ---@param callback? function function fs.write_file(location, mode, contents, callback) - local dir = vim.fn.fnamemodify(location, ":h") + local dir = vim.fsdirname(location) fs.mkdir_p(dir) -- 644 sets read and write permissions for the owner, and it sets read-only -- mode for the group and others @@ -55,7 +55,12 @@ function fs.write_file(location, mode, contents, callback) if write_err then local msg = ("Error writing %s: %s"):format(location, err) log.error(msg) - vim.notify(msg, vim.log.levels.ERROR) + vim.schedule(function() + vim.notify(msg, vim.log.levels.ERROR) + end) + if file then + uv.fs_close(file) + end end uv.fs_close(file) if callback then diff --git a/lua/rocks/operations/add.lua b/lua/rocks/operations/add.lua index 441b2fb8..84362030 100644 --- a/lua/rocks/operations/add.lua +++ b/lua/rocks/operations/add.lua @@ -23,6 +23,7 @@ local config = require("rocks.config.internal") local cache = require("rocks.cache") local helpers = require("rocks.operations.helpers") local handlers = require("rocks.operations.handlers") +local lock = require("rocks.operations.lock") local parser = require("rocks.operations.parser") local nio = require("nio") local progress = require("fidget.progress") @@ -203,6 +204,7 @@ Use 'Rocks install {rock_name}' or install rocks-git.nvim. user_rocks.plugins[rock_name] = installed_rock.version end fs.write_file_await(config.config_path, "w", tostring(user_rocks)) + lock.update_lockfile(installed_rock.name) cache.populate_removable_rock_cache() vim.schedule(function() -- Re-generate help tags diff --git a/lua/rocks/operations/helpers.lua b/lua/rocks/operations/helpers.lua index 75fdfae5..8b83b984 100644 --- a/lua/rocks/operations/helpers.lua +++ b/lua/rocks/operations/helpers.lua @@ -16,6 +16,7 @@ ---@brief ]] local luarocks = require("rocks.luarocks") +local lock = require("rocks.operations.lock") local constants = require("rocks.constants") local config = require("rocks.config.internal") local fs = require("rocks.fs") @@ -47,18 +48,19 @@ function helpers.get_rock_and_key(rocks_toml, rock_name) return rocks_key, rocks_key and rocks_toml[rocks_key][rock_name] end +---@class rocks.helpers.InstallOpts +---@field use_lockfile boolean + ---@param rock_spec RockSpec ----@param progress_handle? ProgressHandle +---@param opts? rocks.helpers.InstallOpts ---@return nio.control.Future -helpers.install = nio.create(function(rock_spec, progress_handle) +helpers.install = nio.create(function(rock_spec, opts) + opts = opts or {} cache.invalidate_removable_rocks() local name = rock_spec.name:lower() local version = rock_spec.version local message = version and ("Installing: %s -> %s"):format(name, version) or ("Installing: %s"):format(name) log.info(message) - if progress_handle then - progress_handle:report({ message = message }) - end -- TODO(vhyrro): Input checking on name and version local future = nio.control.future() local install_cmd = { @@ -86,14 +88,24 @@ helpers.install = nio.create(function(rock_spec, progress_handle) table.insert(install_cmd, install_arg) end) table.insert(install_cmd, 2, "--force") + local install_opts = { + servers = servers, + } + if opts.use_lockfile then + -- luarocks locks dependencies when there is a lockfile in the cwd + local lockfile = lock.create_luarocks_lock(rock_spec.name) + if lockfile and vim.uv.fs_stat(lockfile) then + install_opts.cwd = vim.fs.dirname(lockfile) + end + end + -- We always want to insert --pin so that the luarocks.lock is created in the + -- install directory on the rtp + table.insert(install_cmd, "--pin") luarocks.cli(install_cmd, function(sc) ---@cast sc vim.SystemCompleted if sc.code ~= 0 then message = ("Failed to install %s"):format(name) log.error(message) - if progress_handle then - progress_handle:report({ message = message }) - end future.set_error(sc.stderr) else ---@type Rock @@ -106,22 +118,20 @@ helpers.install = nio.create(function(rock_spec, progress_handle) } message = ("Installed: %s -> %s"):format(installed_rock.name, installed_rock.version) log.info(message) - if progress_handle then - progress_handle:report({ message = message }) - end nio.run(function() adapter.init_site_symlinks() if config.dynamic_rtp and not rock_spec.opt then nio.scheduler() runtime.packadd(name) + else + -- Add rock to the rtp, but don't source any scripts + runtime.packadd(name, { bang = true }) end future.set(installed_rock) end) end - end, { - servers = servers, - }) + end, install_opts) return future end, 2) diff --git a/lua/rocks/operations/lock.lua b/lua/rocks/operations/lock.lua new file mode 100644 index 00000000..fc518b60 --- /dev/null +++ b/lua/rocks/operations/lock.lua @@ -0,0 +1,87 @@ +---@mod rocks.operations.lock +-- +-- Copyright (C) 2024 Neorocks Org. +-- +-- License: GPLv3 +-- Created: 7 Jul 2024 +-- Updated: 7 Jul 2024 +-- Homepage: https://github.com/nvim-neorocks/rocks.nvim +-- Maintainers: NTBBloodbath , Vhyrro , mrcjkb +-- +---@brief [[ +-- +-- Lockfile management. +-- +---@brief ]] + +local config = require("rocks.config.internal") +local fs = require("rocks.fs") +local nio = require("nio") + +local lock = {} + +---@param reset boolean +local function parse_rocks_lock(reset) + local lockfile = reset and "" or fs.read_or_create(config.lockfile_path, "") + return require("toml_edit").parse(lockfile) +end + +---@param rock_name? rock_name +lock.update_lockfile = nio.create(function(rock_name) + local luarocks_lockfiles = vim.iter(vim.api.nvim_get_runtime_file("luarocks.lock", true)) + :filter(function(path) + return not rock_name or path:find(rock_name .. "/[^%/]+/luarocks.lock$") ~= nil + end) + :totable() + local reset = rock_name == nil + local rocks_lock = parse_rocks_lock(reset) + for _, luarocks_lockfile in ipairs(luarocks_lockfiles) do + local rock_key = rock_name or luarocks_lockfile:match("/([^%/]+)/[^%/]+/luarocks.lock$") + if rock_key then + local ok, loader = pcall(loadfile, luarocks_lockfile) + if not ok or not loader then + return + end + local success, luarocks_lock_tbl = pcall(loader) + if not success or not luarocks_lock_tbl or not luarocks_lock_tbl.dependencies then + return + end + rocks_lock[rock_key] = {} + local has_deps = false + for dep, version in pairs(luarocks_lock_tbl.dependencies) do + local is_semver = pcall(vim.version.parse, version:match("([^-]+)") or version) + if is_semver and dep ~= "lua" then + rocks_lock[rock_key][dep] = version + has_deps = true + end + end + if not has_deps then + rocks_lock[rock_key] = nil + end + end + end + fs.write_file_await(config.lockfile_path, "w", tostring(rocks_lock)) +end, 1) + +---@param rock_name rock_name +---@return string | nil luarocks_lock +lock.create_luarocks_lock = nio.create(function(rock_name) + local lockfile = require("toml_edit").parse_as_tbl(fs.read_or_create(config.lockfile_path, "")) + local dependencies = lockfile[rock_name] + if not dependencies then + return + end + local temp_dir = + vim.fs.joinpath(vim.fn.stdpath("run") --[[@as string]], ("luarocks-lock-%X"):format(math.random(256 ^ 7))) + fs.mkdir_p(temp_dir) + local luarocks_lock = vim.fs.joinpath(temp_dir, "luarocks.lock") + local content = ([[ +return { + dependencies = %s, +} +]]):format(vim.inspect(dependencies)) + fs.write_file_await(luarocks_lock, "w", content) + return luarocks_lock +end, 1) + +return lock diff --git a/lua/rocks/operations/prune.lua b/lua/rocks/operations/prune.lua index 66ff2ae0..25ac582f 100644 --- a/lua/rocks/operations/prune.lua +++ b/lua/rocks/operations/prune.lua @@ -23,6 +23,7 @@ local config = require("rocks.config.internal") local cache = require("rocks.cache") local helpers = require("rocks.operations.helpers") local handlers = require("rocks.operations.handlers") +local lock = require("rocks.operations.lock") local nio = require("nio") local progress = require("fidget.progress") @@ -59,6 +60,7 @@ prune.prune = function(rock_name) success = false end fs.write_file_await(config.config_path, "w", tostring(user_config)) + lock.update_lockfile() local user_rocks = config.get_user_rocks() handlers.prune_user_rocks(user_rocks, report_progress, report_error) cache.populate_removable_rock_cache() diff --git a/lua/rocks/operations/sync.lua b/lua/rocks/operations/sync.lua index 95a0c695..720e646d 100644 --- a/lua/rocks/operations/sync.lua +++ b/lua/rocks/operations/sync.lua @@ -117,7 +117,7 @@ operations.sync = function(user_rocks, on_complete) if vim.startswith(user_rocks[key].version, "scm-") then user_rocks[key].version = "dev" end - local future = helpers.install(user_rocks[key]) + local future = helpers.install(user_rocks[key], { use_lockfile = true }) local success = pcall(future.wait) ct = ct + 1 @@ -162,7 +162,7 @@ operations.sync = function(user_rocks, on_complete) message = is_downgrading and ("Downgrading: %s"):format(key) or ("Updating: %s"):format(key), }) - local future = helpers.install(user_rocks[key]) + local future = helpers.install(user_rocks[key], { use_lockfile = true }) local success = pcall(future.wait) ct = ct + 1 diff --git a/lua/rocks/operations/update.lua b/lua/rocks/operations/update.lua index dc1cfa8e..62654660 100644 --- a/lua/rocks/operations/update.lua +++ b/lua/rocks/operations/update.lua @@ -23,6 +23,7 @@ local config = require("rocks.config.internal") local state = require("rocks.state") local cache = require("rocks.cache") local helpers = require("rocks.operations.helpers") +local lock = require("rocks.operations.lock") local handlers = require("rocks.operations.handlers") local nio = require("nio") local progress = require("fidget.progress") @@ -170,6 +171,7 @@ update.update = function(on_complete, opts) end end fs.write_file_await(config.config_path, "w", tostring(user_rocks)) + lock.update_lockfile() nio.scheduler() if not vim.tbl_isempty(error_handles) then local message = "Update completed with errors! Run ':Rocks log' for details." diff --git a/nix/plugin-overlay.nix b/nix/plugin-overlay.nix index 1a6d1125..dbd18b0c 100644 --- a/nix/plugin-overlay.nix +++ b/nix/plugin-overlay.nix @@ -3,30 +3,7 @@ self, }: final: prev: let lib = final.lib; - rocks-nvim-luaPackage-override = luaself: luaprev: { - # Workaround for https://github.com/NixOS/nixpkgs/issues/316009 - luarocks-rock = luaself.callPackage ({ - buildLuarocksPackage, - fetchFromGitHub, - fetchurl, - }: - buildLuarocksPackage { - pname = "luarocks"; - version = "3.11.1-1"; - knownRockspec = - (fetchurl { - url = "mirror://luarocks/luarocks-3.11.1-1.rockspec"; - sha256 = "0xg0siza8nlnnkaarmw73q12qx3frlfbysd5ipmxxi1d7yc38bbn"; - }) - .outPath; - src = fetchFromGitHub { - owner = "luarocks"; - repo = "luarocks"; - rev = "v3.11.1"; - hash = "sha256-GglygI8HP+aDFEuucOkjQ2Pgfv4+jW+og+2vL3KoZCQ="; - }; - }) {}; - + luaPackage-override = luaself: luaprev: { toml-edit = (luaself.callPackage ({ buildLuarocksPackage, @@ -156,7 +133,7 @@ luaOlder, buildLuarocksPackage, lua, - luarocks-rock, + luarocks, toml-edit, fidget-nvim, nvim-nio, @@ -170,7 +147,7 @@ src = self; disabled = luaOlder "5.1"; propagatedBuildInputs = [ - luarocks-rock + luarocks toml-edit fidget-nvim nvim-nio @@ -180,11 +157,11 @@ }) {}; }; lua5_1 = prev.lua5_1.override { - packageOverrides = rocks-nvim-luaPackage-override; + packageOverrides = luaPackage-override; }; lua51Packages = prev.lua51Packages // final.lua5_1.pkgs; luajit = prev.luajit.override { - packageOverrides = rocks-nvim-luaPackage-override; + packageOverrides = luaPackage-override; }; luajitPackages = prev.luajitPackages // final.luajit.pkgs; in { @@ -226,7 +203,7 @@ in { -- Copied from installer.lua local rocks_config = { rocks_path = vim.fn.stdpath("data") .. "/rocks", - luarocks_binary = "${final.lua51Packages.luarocks-rock}/bin/luarocks", + luarocks_binary = "${final.lua51Packages.luarocks}/bin/luarocks", } vim.g.rocks_nvim = rocks_config diff --git a/nix/test-overlay.nix b/nix/test-overlay.nix index afa7222f..39900e4c 100644 --- a/nix/test-overlay.nix +++ b/nix/test-overlay.nix @@ -11,7 +11,7 @@ neovim = nvim; luaPackages = ps: with ps; [ - final.lua51Packages.luarocks-rock + final.lua51Packages.luarocks toml-edit fidget-nvim fzy diff --git a/spec/operations/lock_spec.lua b/spec/operations/lock_spec.lua new file mode 100644 index 00000000..b55e3e22 --- /dev/null +++ b/spec/operations/lock_spec.lua @@ -0,0 +1,157 @@ +---@diagnostic disable: inject-field + +local tempdir = vim.fn.tempname() +vim.system({ "rm", "-r", tempdir }):wait() +vim.system({ "mkdir", "-p", tempdir }):wait() +vim.g.rocks_nvim = { + luarocks_binary = "luarocks", + rocks_path = tempdir, + config_path = vim.fs.joinpath(tempdir, "rocks.toml"), +} + +local lock = require("rocks.operations.lock") +local fs = require("rocks.fs") +local config = require("rocks.config.internal") +local helpers = require("rocks.operations.helpers") +local state = require("rocks.state") +local nio = require("nio") + +vim.env.PLENARY_TEST_TIMEOUT = 60000 * 5 + +describe("operations.lock", function() + nio.tests.it("Lockfile roundtrip", function() + config.lockfile_path = assert(vim.fn.tempname(), "Could not create tempname") + local lockfile_content = [[ +[neorg] +"pathlib.nvim" = "2.2.0-1" +"plenary.nvim" = "0.1.4-1" +say = "1.4.1-3" +"nui.nvim" = "0.3.0-1" +"lua-utils.nvim" = "1.0.2-1" +luassert = "1.9.0-1" +nvim-nio = "1.7.0-1" +[neotest] +luassert = "1.9.0-1" +say = "1.4.1-3" +"plenary.nvim" = "0.1.4-1" +]] + local fh = assert(io.open(config.lockfile_path, "w"), "Could not open rocks.lock for writing") + fh:write(lockfile_content) + fh:close() + assert.same(lockfile_content, fs.read_or_create(config.lockfile_path, "")) + local neorg_lockfile = assert(lock.create_luarocks_lock("neorg"), "Failed to create neorg luarocks.lock") + vim.fs.joinpath(vim.fn.stdpath("run") --[[@as string]], ("luarocks-lock-%X"):format(math.random(256 ^ 7))) + assert(fs.mkdir_p(tempdir), "Failed to create tempdir " .. tempdir) + local neorg_rtp_path = vim.fs.joinpath(tempdir, "neorg", "1.0.0-1") + local neotest_rtp_path = vim.fs.joinpath(tempdir, "neotest", "1.0.0-1") + + fs.mkdir_p(neorg_rtp_path) + local future = nio.control.future() + vim.system({ "mv", neorg_lockfile, vim.fs.joinpath(neorg_rtp_path, "luarocks.lock") }, nil, function() + future.set(true) + end) + future.wait() + future = nio.control.future() + vim.schedule(function() + vim.opt.runtimepath:append(neorg_rtp_path) + future.set(true) + end) + future.wait() + local neotest_lockfile = assert(lock.create_luarocks_lock("neotest"), "Failed to create neotest luarocks.lock") + fs.mkdir_p(neotest_rtp_path) + future = nio.control.future() + vim.system({ "mv", neotest_lockfile, vim.fs.joinpath(neotest_rtp_path, "luarocks.lock") }, nil, function() + future.set(true) + end) + future.wait() + future = nio.control.future() + vim.schedule(function() + vim.opt.runtimepath:append(neotest_rtp_path) + future.set(true) + end) + future.wait() + -- Reset lockfile path + config.lockfile_path = assert(vim.fn.tempname(), "Could not create tempname") + lock.update_lockfile() + nio.sleep(2000) + future = nio.control.future() + vim.schedule(function() + vim.opt.runtimepath:remove(neorg_rtp_path) + vim.opt.runtimepath:remove(neotest_rtp_path) + future.set(true) + end) + future.wait() + local roundtrip_content = fs.read_or_create(config.lockfile_path, "") + local result = require("toml_edit").parse_as_tbl(roundtrip_content) + local expected = { + neorg = { + ["nvim-nio"] = "1.7.0-1", + luassert = "1.9.0-1", + ["lua-utils.nvim"] = "1.0.2-1", + ["nui.nvim"] = "0.3.0-1", + say = "1.4.1-3", + ["plenary.nvim"] = "0.1.4-1", + ["pathlib.nvim"] = "2.2.0-1", + }, + neotest = { + ["plenary.nvim"] = "0.1.4-1", + luassert = "1.9.0-1", + say = "1.4.1-3", + }, + } + assert.same(expected, result) + end) + nio.tests.it("Excludes lua and dev dependencies", function() + local luarocks_lockfile_content = [[ +return { + dependencies = { + lua = "5.1-1", + luassert = "1.9.0-1", + ["plenary.nvim"] = "scm-1", + say = "1.4.1-3" + }, +} +]] + tempdir = vim.fn.tempname() + local neotest_rtp_path = vim.fs.joinpath(tempdir, "neotest", "1.0.0-1") + fs.mkdir_p(neotest_rtp_path) + local luarocks_lockfile_path = vim.fs.joinpath(neotest_rtp_path, "luarocks.lock") + local fh = assert(io.open(luarocks_lockfile_path, "w"), "Could not open luarocks.lock for writing") + fh:write(luarocks_lockfile_content) + fh:close() + local future = nio.control.future() + vim.schedule(function() + vim.opt.runtimepath:append(neotest_rtp_path) + future.set(true) + end) + future.wait() + config.lockfile_path = assert(vim.fn.tempname(), "Could not create tempname") + lock.update_lockfile() + nio.sleep(2000) + local lockfile_content = fs.read_or_create(config.lockfile_path, "") + local result = require("toml_edit").parse_as_tbl(lockfile_content) + local expected = { + neotest = { + luassert = "1.9.0-1", + say = "1.4.1-3", + }, + } + assert.same(expected, result) + end) + nio.tests.it("install installs pinned dependencies", function() + local lockfile_content = [[ +["oil.nvim"] +"nvim-web-devicons" = "0.99-1" +]] + config.lockfile_path = assert(vim.fn.tempname(), "Could not create tempname") + local fh = assert(io.open(config.lockfile_path, "w"), "Could not open rocks.lock for writing") + fh:write(lockfile_content) + fh:close() + helpers.install({ name = "oil.nvim", version = "2.7.0" }, { use_lockfile = true }).wait() + local installed_rocks = state.installed_rocks() + assert.same({ + name = "nvim-web-devicons", + version = "0.99", + }, installed_rocks["nvim-web-devicons"]) + end) +end) diff --git a/spec/operations/sync_spec.lua b/spec/operations/sync_spec.lua index d2d2cb05..72d221d0 100644 --- a/spec/operations/sync_spec.lua +++ b/spec/operations/sync_spec.lua @@ -5,14 +5,15 @@ vim.g.rocks_nvim = { luarocks_binary = "luarocks", rocks_path = tempdir, config_path = vim.fs.joinpath(tempdir, "rocks.toml"), + lockfile_path = vim.fs.joinpath(tempdir, "rocks.lock"), } local nio = require("nio") +local operations = require("rocks.operations") +local helpers = require("rocks.operations.helpers") +local state = require("rocks.state") +local config = require("rocks.config.internal") vim.env.PLENARY_TEST_TIMEOUT = 60000 * 5 describe("operations", function() - local operations = require("rocks.operations") - local helpers = require("rocks.operations.helpers") - local state = require("rocks.state") - local config = require("rocks.config.internal") vim.system({ "mkdir", "-p", config.rocks_path }):wait() nio.tests.it("sync", function() -- Test sync without any rocks @@ -46,11 +47,11 @@ nlua = "0.1.0" helpers.install({ name = "sweetie.nvim", version = "3.0.0" }).wait() -- One to update (removing the dependency on plenary.nvim) helpers.install({ name = "haskell-tools.nvim", version = "2.4.0" }).wait() + -- and nlua to install local installed_rocks = state.installed_rocks() - local installed_rock_names = vim.tbl_keys(installed_rocks) - assert.False(vim.tbl_contains(installed_rock_names, "nlua")) - assert.True(vim.tbl_contains(installed_rock_names, "telescope.nvim")) - assert.True(vim.tbl_contains(installed_rock_names, "plenary.nvim")) + assert.is_not_nil(installed_rocks["telescope.nvim"]) + assert.is_not_nil(installed_rocks["plenary.nvim"]) + assert.is_nil(installed_rocks.nlua) assert.same({ name = "sweetie.nvim", version = "3.0.0", @@ -65,9 +66,8 @@ nlua = "0.1.0" end) future.wait() installed_rocks = state.installed_rocks() - installed_rock_names = vim.tbl_keys(installed_rocks) - assert.False(vim.tbl_contains(installed_rock_names, "telescope.nvim")) - assert.False(vim.tbl_contains(installed_rock_names, "plenary.nvim")) + assert.is_nil(installed_rocks["telescope.nvim"]) + assert.is_nil(installed_rocks["plenary.nvim"]) assert.same({ name = "sweetie.nvim", version = "1.2.1",