Files
vimpack/doc/vimpack.txt
T
unkin-agent 6e1b018adb
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/lint Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Validate zip symlinks and backslash paths before extraction
- treat `\` as a separator in safe_relative so `\abs` and `..\..\x` are refused
- read zip symlink targets with `unzip -p` off the `unzip -Z -l` listing and reject escapes before unpacking
2026-09-05 16:59:24 +10:00

179 lines
7.8 KiB
Plaintext

*vimpack.txt* Install Neovim plugins from archives on an artifact registry
==============================================================================
CONTENTS *vimpack-contents*
1. Introduction ............................. |vimpack-introduction|
2. Setup .................................... |vimpack-setup|
3. Plugin spec .............................. |vimpack-spec|
4. Registries ............................... |vimpack-registries|
5. Auth ..................................... |vimpack-auth|
6. Commands ................................. |vimpack-commands|
7. Layout ................................... |vimpack-layout|
8. Lua API .................................. |vimpack-api|
==============================================================================
1. INTRODUCTION *vimpack-introduction*
vimpack installs Neovim plugins from tarballs or zips served by an artifact
registry, at an explicit version, rather than by cloning git repositories.
Downloads are checksum-verified and swapped into place atomically, so a failed
install never leaves a half-written plugin behind.
Requirements: Neovim 0.10+, `curl`, and `tar` (plus `unzip` for .zip
archives).
==============================================================================
2. SETUP *vimpack-setup*
>lua
require('vimpack').setup({
registry = {
kind = 'artifactapi',
base_url = 'https://artifactapi.k8s.syd1.au.unkin.net',
repo = 'nvim-plugins',
auth = { env = 'ARTIFACTAPI_TOKEN' },
},
plugins = {
{ name = 'telescope.nvim', version = '0.1.8' },
{ name = 'vim-fugitive', version = '3.7', opt = true },
},
concurrency = 4,
timeout = 120000,
})
<
`setup()` validates the spec and returns the normalised config, or nil plus an
error message. Nothing is downloaded until |:VimpackInstall|.
Top-level options ~
registry default registry for every plugin (table, optional)
plugins list of plugin specs (list, default {})
concurrency maximum simultaneous downloads (number, default 4)
timeout per-download timeout in milliseconds (number, default 120000)
==============================================================================
3. PLUGIN SPEC *vimpack-spec*
name Plugin name. Required. Also the directory name under
pack/vimpack/{start,opt}/ unless dir_name overrides it.
version Required unless `url` is given. Passed to the resolver.
sha256 Expected digest of the archive. A mismatch aborts the install
and reports both the expected and the actual digest.
opt When true the plugin lands in opt/ for |:packadd|.
url Fully explicit archive URL; registry resolution is skipped.
ext Archive extension, default "tar.gz".
registry Per-plugin registry, overriding the top-level one.
dir_name On-disk directory name.
==============================================================================
4. REGISTRIES *vimpack-registries*
A registry maps (name, version) to a download URL. `kind` selects the
resolver; the default kind is "template".
template ~
Substitutes ${name}, ${version}, ${ext}, ${slug}, ${repo} and ${base_url} into
`url_template`. An unrecognised placeholder is reported as an error.
`filename_template` optionally names the cached archive.
>lua
registry = {
kind = 'template',
url_template = 'https://artifactory.example.com/artifactory/nvim-generic/'
.. '${name}/${version}/${name}-${version}.${ext}',
}
<
artifactapi ~
Builds ${base_url}/api/v2/remotes/${repo}/files/${path}. `path_template`
defaults to "${name}/${name}-${version}.${ext}".
>lua
registry = {
kind = 'artifactapi',
base_url = 'https://artifactapi.k8s.syd1.au.unkin.net',
repo = 'nvim-plugins',
}
<
custom ~
A resolver is `(spec, registry) -> resolved | nil, err`, where `resolved` is
`{ url, headers, filename, sha256? }`.
>lua
require('vimpack').register_resolver('mine', function(spec, registry)
return { url = registry.base_url .. '/' .. spec.name .. '-'
.. spec.version .. '.tar.gz', headers = {} }
end)
<
==============================================================================
5. AUTH *vimpack-auth*
Tokens are never stored in the config. `registry.auth` accepts:
env name of an environment variable holding the token
token_cmd command (list or shell string) that prints the token
header header name, default "Authorization"
prefix value prefix, default "Bearer " for Authorization
A literal `token` key is rejected at |vimpack-setup| time.
>lua
auth = { header = 'X-JFrog-Art-Api', prefix = '',
token_cmd = { 'pass', 'show', 'artifactory/api-key' } }
<
==============================================================================
6. COMMANDS *vimpack-commands*
*:VimpackInstall*
:VimpackInstall [{name}...]
Install plugins that are missing or whose installed version, digest or
start/opt placement has drifted from the spec. Up-to-date plugins are
skipped. With names, restrict the work to those plugins.
*:VimpackUpdate*
:VimpackUpdate [{name}...]
Re-fetch plugins whether or not the manifest says they are current.
*:VimpackClean*
:VimpackClean
Remove installed plugins and manifest entries that are no longer in the
spec.
*:VimpackStatus*
:VimpackStatus
Print wanted versus installed version per plugin, with a state of "ok",
"missing", "drift" or "orphan".
==============================================================================
7. LAYOUT *vimpack-layout*
stdpath('cache')/vimpack/archives/ downloaded archives
stdpath('data')/site/pack/vimpack/.vimpack-stage/ extraction staging area
stdpath('data')/vimpack/manifest.json installed name/version/sha256
stdpath('data')/site/pack/vimpack/start/<name>
stdpath('data')/site/pack/vimpack/opt/<name>
An install extracts to the staging area, hoists a single wrapper directory if
the archive has one, then renames into place after parking any previous tree
aside. If the rename fails the previous tree is restored. Staging sits under
the pack root so that rename stays on one filesystem.
Every member is listed and validated before extraction: absolute paths, `..`
and `..\` escapes, devices, fifos and links pointing out of the destination
are all refused. Zip symlink targets are read with `unzip -p` (stdout only,
nothing written) because the zip listing does not carry them.
Lazy loading is out of scope: `opt = true` only chooses the opt/ bucket.
==============================================================================
8. LUA API *vimpack-api*
require('vimpack').setup(opts) configure; returns cfg or nil,err
require('vimpack').install(names?) same as |:VimpackInstall|
require('vimpack').update(names?) same as |:VimpackUpdate|
require('vimpack').clean() same as |:VimpackClean|
require('vimpack').status() same as |:VimpackStatus|
require('vimpack').status_rows() status as a list of tables
require('vimpack').register_resolver(n, fn) add a registry resolver
vim:tw=78:ts=8:ft=help:norl: