mirror of
https://github.com/neovim/neovim.git
synced 2026-11-02 09:49:02 -06:00
feat(pack): allow choosing update target in update()
Problem: There are two fairly common workflows that involve lockfile and
can be made more straightforward in `vim.pack`:
1. Revert latest update. Like if it introduced unwanted behavior.
2. Update to a revision in the lockfile. Like if already updated
on another machine, verified that everything works, `git add` +
`git commit` + `git push` the config, and want to have the same
plugin states on current machine.
Solution: Make `update` allow `opts.target`. By default it uses
`version` from a plugin specification (like a regular "get new changes
from source" workflow). But it also allows `"lockfile"` value to
indicate that target revision after update should be taken from the
current lockfile verbatim.
With this, the workflows are:
1. Revert (somehow) to the lockfile before the update, restart, and
`vim.pack.update({ 'plugin' }, { target = 'lockfile' })`. If Git
tracked, revert with `git checkout HEAD -- nvim-pack-lock.json`.
For non-VCS tracked lockfile, the revisions can be taken from the
log file. It would be nicer if `update()` would backup a lockfile
before doing an update, but that might require discussions.
2. `git pull` + `:restart` +
`vim.pack.update(nil, { target = 'lockfile' })`.
The only caveats are for new and deleted plugins:
- New plugins (not present locally but present in the lockfile)
will be installed at lockfile revision during restart.
- Deleted plugins (present locally but not present in the
lockfile) will still be present: both locally *and* in the
lockfile. They can be located by
`git diff -- nvim-pack-lock.json` and require manual
`vim.pack.del({ 'old-plugin1', 'old-plugin2' })`.
This commit is contained in:
3 files changed
+94
-22
No files matched your search
+27
-10
@@ -309,16 +309,27 @@ Unfreeze plugin to start receiving updates ~
|
|||||||
• |:restart|.
|
• |:restart|.
|
||||||
|
|
||||||
Revert plugin after an update ~
|
Revert plugin after an update ~
|
||||||
• Locate plugin's revision at working state. For example:
|
• Revert the |vim.pack-lockfile| to the state before the update:
|
||||||
• If there is a previous version of |vim.pack-lockfile| (like from version
|
• If Git tracked: `git checkout HEAD -- nvim-pack-lock.json`
|
||||||
control history), use it to get plugin's `rev` field.
|
• If not tracked: examine log file ("nvim-pack.log" at "log" |stdpath()|),
|
||||||
• If there is a log file ("nvim-pack.log" at "log" |stdpath()|), open it and
|
locate the revisions before the latest update, and (carefully) adjust
|
||||||
navigate to latest updates (at the bottom). Locate lines about plugin
|
current lockfile to have those revisions.
|
||||||
update details and use revision from "State before".
|
• |:restart|.
|
||||||
• Freeze plugin to target revision (set `version` and |:restart|).
|
• `vim.pack.update({ 'plugin' }, { target = 'lockfile' })`. Read and confirm.
|
||||||
• Run `vim.pack.update({ 'plugin-name' }, { force = true })` to make plugin
|
|
||||||
state on disk follow target revision. |:restart|.
|
Synchronize config across machines ~
|
||||||
• When ready to deal with updating plugin, unfreeze it.
|
• On main machine:
|
||||||
|
• Add |vim.pack-lockfile| to VCS.
|
||||||
|
• Push to the remote server.
|
||||||
|
• On secondary machine:
|
||||||
|
• Pull from the server.
|
||||||
|
• |:restart|. New plugins (not present locally, but present in the lockfile)
|
||||||
|
are installed at proper revision.
|
||||||
|
• `vim.pack.update(nil, { target = 'lockfile' })`. Read and confirm.
|
||||||
|
• Manually delete outdated plugins (present locally, but were not present in
|
||||||
|
the lockfile prior to restart) with `vim.pack.del( { 'plugin' })`. They
|
||||||
|
can be located by examining the VCS difference of the lockfile
|
||||||
|
(`git diff -- nvim-pack-lock.json` for Git).
|
||||||
|
|
||||||
Remove plugins from disk ~
|
Remove plugins from disk ~
|
||||||
• Use |vim.pack.del()| with a list of plugin names to remove. Make sure their
|
• Use |vim.pack.del()| with a list of plugin names to remove. Make sure their
|
||||||
@@ -480,6 +491,12 @@ update({names}, {opts}) *vim.pack.update()*
|
|||||||
• {opts} (`table?`) A table with the following fields:
|
• {opts} (`table?`) A table with the following fields:
|
||||||
• {force}? (`boolean`) Whether to skip confirmation and make
|
• {force}? (`boolean`) Whether to skip confirmation and make
|
||||||
updates immediately. Default `false`.
|
updates immediately. Default `false`.
|
||||||
|
• {target}? (`string`) How to compute a new plugin revision.
|
||||||
|
One of:
|
||||||
|
• "version" (default) - use latest revision matching
|
||||||
|
`version` from plugin specification.
|
||||||
|
• "lockfile" - use revision from the lockfile. Useful for
|
||||||
|
reverting or performing controlled update.
|
||||||
|
|
||||||
|
|
||||||
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:
|
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:
|
||||||
+35
-12
@@ -113,16 +113,28 @@
|
|||||||
---
|
---
|
||||||
---Revert plugin after an update ~
|
---Revert plugin after an update ~
|
||||||
---
|
---
|
||||||
---- Locate plugin's revision at working state. For example:
|
---- Revert the |vim.pack-lockfile| to the state before the update:
|
||||||
--- - If there is a previous version of |vim.pack-lockfile| (like from version
|
--- - If Git tracked: `git checkout HEAD -- nvim-pack-lock.json`
|
||||||
--- control history), use it to get plugin's `rev` field.
|
--- - If not tracked: examine log file ("nvim-pack.log" at "log" |stdpath()|),
|
||||||
--- - If there is a log file ("nvim-pack.log" at "log" |stdpath()|), open it
|
--- locate the revisions before the latest update, and (carefully) adjust
|
||||||
--- and navigate to latest updates (at the bottom). Locate lines about plugin
|
--- current lockfile to have those revisions.
|
||||||
--- update details and use revision from "State before".
|
---- |:restart|.
|
||||||
---- Freeze plugin to target revision (set `version` and |:restart|).
|
---- `vim.pack.update({ 'plugin' }, { target = 'lockfile' })`. Read and confirm.
|
||||||
---- Run `vim.pack.update({ 'plugin-name' }, { force = true })` to make plugin
|
---
|
||||||
--- state on disk follow target revision. |:restart|.
|
---Synchronize config across machines ~
|
||||||
---- When ready to deal with updating plugin, unfreeze it.
|
---
|
||||||
|
---- On main machine:
|
||||||
|
--- - Add |vim.pack-lockfile| to VCS.
|
||||||
|
--- - Push to the remote server.
|
||||||
|
---- On secondary machine:
|
||||||
|
--- - Pull from the server.
|
||||||
|
--- - |:restart|. New plugins (not present locally, but present in the lockfile)
|
||||||
|
--- are installed at proper revision.
|
||||||
|
--- - `vim.pack.update(nil, { target = 'lockfile' })`. Read and confirm.
|
||||||
|
--- - Manually delete outdated plugins (present locally, but were not present
|
||||||
|
--- in the lockfile prior to restart) with `vim.pack.del( { 'plugin' })`.
|
||||||
|
--- They can be located by examining the VCS difference of the lockfile
|
||||||
|
--- (`git diff -- nvim-pack-lock.json` for Git).
|
||||||
---
|
---
|
||||||
---Remove plugins from disk ~
|
---Remove plugins from disk ~
|
||||||
---
|
---
|
||||||
@@ -1139,6 +1151,12 @@ end
|
|||||||
--- @class vim.pack.keyset.update
|
--- @class vim.pack.keyset.update
|
||||||
--- @inlinedoc
|
--- @inlinedoc
|
||||||
--- @field force? boolean Whether to skip confirmation and make updates immediately. Default `false`.
|
--- @field force? boolean Whether to skip confirmation and make updates immediately. Default `false`.
|
||||||
|
---
|
||||||
|
--- How to compute a new plugin revision. One of:
|
||||||
|
--- - "version" (default) - use latest revision matching `version` from plugin specification.
|
||||||
|
--- - "lockfile" - use revision from the lockfile. Useful for reverting or performing controlled
|
||||||
|
--- update.
|
||||||
|
--- @field target? string
|
||||||
|
|
||||||
--- Update plugins
|
--- Update plugins
|
||||||
---
|
---
|
||||||
@@ -1173,7 +1191,7 @@ end
|
|||||||
--- @param opts? vim.pack.keyset.update
|
--- @param opts? vim.pack.keyset.update
|
||||||
function M.update(names, opts)
|
function M.update(names, opts)
|
||||||
vim.validate('names', names, vim.islist, true, 'list')
|
vim.validate('names', names, vim.islist, true, 'list')
|
||||||
opts = vim.tbl_extend('force', { force = false }, opts or {})
|
opts = vim.tbl_extend('force', { force = false, target = 'version' }, opts or {})
|
||||||
|
|
||||||
local plug_list = plug_list_from_names(names)
|
local plug_list = plug_list_from_names(names)
|
||||||
if #plug_list == 0 then
|
if #plug_list == 0 then
|
||||||
@@ -1190,8 +1208,9 @@ function M.update(names, opts)
|
|||||||
--- @async
|
--- @async
|
||||||
--- @param p vim.pack.Plug
|
--- @param p vim.pack.Plug
|
||||||
local function do_update(p)
|
local function do_update(p)
|
||||||
|
local l_data = plugin_lock.plugins[p.spec.name]
|
||||||
-- Ensure proper `origin` if needed
|
-- Ensure proper `origin` if needed
|
||||||
if plugin_lock.plugins[p.spec.name].src ~= p.spec.src then
|
if l_data.src ~= p.spec.src then
|
||||||
git_cmd({ 'remote', 'set-url', 'origin', p.spec.src }, p.path)
|
git_cmd({ 'remote', 'set-url', 'origin', p.spec.src }, p.path)
|
||||||
plugin_lock.plugins[p.spec.name].src = p.spec.src
|
plugin_lock.plugins[p.spec.name].src = p.spec.src
|
||||||
needs_lock_write = true
|
needs_lock_write = true
|
||||||
@@ -1205,6 +1224,10 @@ function M.update(names, opts)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Compute change info: changelog if any, new tags if nothing to update
|
-- Compute change info: changelog if any, new tags if nothing to update
|
||||||
|
if opts.target == 'lockfile' then
|
||||||
|
p.info.version_str = '*lockfile*'
|
||||||
|
p.info.sha_target = l_data.rev
|
||||||
|
end
|
||||||
infer_update_details(p)
|
infer_update_details(p)
|
||||||
|
|
||||||
-- Checkout immediately if no need to confirm
|
-- Checkout immediately if no need to confirm
|
||||||
|
|||||||
@@ -1687,6 +1687,38 @@ describe('vim.pack', function()
|
|||||||
eq(hashes.fetch_new, get_lock_tbl().plugins.fetch.rev)
|
eq(hashes.fetch_new, get_lock_tbl().plugins.fetch.rev)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('can use lockfile revision as a target', function()
|
||||||
|
exec_lua(function()
|
||||||
|
vim.pack.add({ repos_src.fetch })
|
||||||
|
end)
|
||||||
|
eq('return "fetch main"', fn.readblob(fetch_lua_file))
|
||||||
|
|
||||||
|
-- Mock "update -> revert lockfile -> revert plugin"
|
||||||
|
local lock_path = get_lock_path()
|
||||||
|
local lockfile_before = fn.readblob(lock_path)
|
||||||
|
hashes.fetch_new = git_get_hash('main', 'fetch')
|
||||||
|
|
||||||
|
-- - Update
|
||||||
|
exec_lua('vim.pack.update({ "fetch" }, { force = true })')
|
||||||
|
eq('return "fetch new 2"', fn.readblob(fetch_lua_file))
|
||||||
|
|
||||||
|
-- - Revert lockfile
|
||||||
|
fn.writefile(vim.split(lockfile_before, '\n'), lock_path)
|
||||||
|
n.clear()
|
||||||
|
|
||||||
|
-- - Revert plugin
|
||||||
|
eq('return "fetch new 2"', fn.readblob(fetch_lua_file))
|
||||||
|
exec_lua('vim.pack.update({ "fetch" }, { target = "lockfile" })')
|
||||||
|
local confirm_lines = api.nvim_buf_get_lines(0, 0, -1, false)
|
||||||
|
n.exec('write')
|
||||||
|
eq('return "fetch main"', fn.readblob(fetch_lua_file))
|
||||||
|
eq(hashes.fetch_head, get_lock_tbl().plugins.fetch.rev)
|
||||||
|
|
||||||
|
-- - Should mention that new revision comes from *lockfile*
|
||||||
|
eq(confirm_lines[6], ('Revision before: %s'):format(hashes.fetch_new))
|
||||||
|
eq(confirm_lines[7], ('Revision after: %s (*lockfile*)'):format(hashes.fetch_head))
|
||||||
|
end)
|
||||||
|
|
||||||
it('can change `src` of installed plugin', function()
|
it('can change `src` of installed plugin', function()
|
||||||
local basic_src = repos_src.basic
|
local basic_src = repos_src.basic
|
||||||
local defbranch_src = repos_src.defbranch
|
local defbranch_src = repos_src.defbranch
|
||||||
|
|||||||
Reference in new issue
Block a user