From 3ffd31d0c52a51d064f4761d5c0bfad64129c1e9 Mon Sep 17 00:00:00 2001 From: Liam Dyer Date: Mon, 23 Dec 2024 12:37:09 -0500 Subject: [PATCH] fix: check version sha of locally built, better detection Related to #68 --- build.rs | 14 +++- lua/blink/cmp/config/fuzzy.lua | 5 +- lua/blink/cmp/fuzzy/download/files.lua | 26 +++--- lua/blink/cmp/fuzzy/download/init.lua | 106 ++++++++++++------------- lua/blink/cmp/init.lua | 2 +- 5 files changed, 81 insertions(+), 72 deletions(-) diff --git a/build.rs b/build.rs index 38093773..0b1bd47e 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,14 @@ fn main() { - // delete existing version.txt file created by downloader - let _ = std::fs::remove_file("target/release/version.txt"); + // delete existing version file created by downloader + let _ = std::fs::remove_file("target/release/version"); + + // get current sha from git + let output = std::process::Command::new("git") + .args(["rev-parse", "HEAD"]) + .output() + .unwrap(); + let sha = String::from_utf8(output.stdout).unwrap(); + + // write to version + std::fs::write("target/release/version", sha.trim()).unwrap(); } diff --git a/lua/blink/cmp/config/fuzzy.lua b/lua/blink/cmp/config/fuzzy.lua index bf19fa62..2bf287c6 100644 --- a/lua/blink/cmp/config/fuzzy.lua +++ b/lua/blink/cmp/config/fuzzy.lua @@ -7,9 +7,10 @@ --- @class (exact) blink.cmp.PrebuiltBinariesConfig --- @field download boolean Whenther or not to automatically download a prebuilt binary from github. If this is set to `false` you will need to manually build the fuzzy binary dependencies by running `cargo build --release` +--- @field ignore_version_mismatch boolean Ignores mismatched version between the built binary and the current git sha, when building locally --- @field force_version? string When downloading a prebuilt binary, force the downloader to resolve this version. If this is unset then the downloader will attempt to infer the version from the checked out git tag (if any). WARN: Beware that `main` may be incompatible with the version you select --- @field force_system_triple? string When downloading a prebuilt binary, force the downloader to use this system triple. If this is unset then the downloader will attempt to infer the system triple from `jit.os` and `jit.arch`. Check the latest release for all available system triples. WARN: Beware that `main` may be incompatible with the version you select ---- @field extra_curl_args? string[] Extra arguments that will be passed to curl like { 'curl', ..extra_curl_args, ..built_in_args } +--- @field extra_curl_args string[] Extra arguments that will be passed to curl like { 'curl', ..extra_curl_args, ..built_in_args } --- @alias blink.cmp.SortFunction fun(a: blink.cmp.CompletionItem, b: blink.cmp.CompletionItem): boolean | nil @@ -23,6 +24,7 @@ local fuzzy = { sorts = { 'score', 'sort_text' }, prebuilt_binaries = { download = true, + ignore_version_mismatch = false, force_version = nil, force_system_triple = nil, extra_curl_args = {}, @@ -51,6 +53,7 @@ function fuzzy.validate(config) }, config) validate('fuzzy.prebuilt_binaries', { download = { config.prebuilt_binaries.download, 'boolean' }, + ignore_version_mismatch = { config.prebuilt_binaries.ignore_version_mismatch, 'boolean' }, force_version = { config.prebuilt_binaries.force_version, { 'string', 'nil' } }, force_system_triple = { config.prebuilt_binaries.force_system_triple, { 'string', 'nil' } }, extra_curl_args = { config.prebuilt_binaries.extra_curl_args, { 'table' } }, diff --git a/lua/blink/cmp/fuzzy/download/files.lua b/lua/blink/cmp/fuzzy/download/files.lua index 3fe6317b..f1966d33 100644 --- a/lua/blink/cmp/fuzzy/download/files.lua +++ b/lua/blink/cmp/fuzzy/download/files.lua @@ -16,7 +16,7 @@ local lib_filename = 'libblink_cmp_fuzzy' .. get_lib_extension() local lib_path = lib_folder .. '/' .. lib_filename local checksum_filename = lib_filename .. '.sha256' local checksum_path = lib_path .. '.sha256' -local version_path = lib_folder .. '/version.txt' +local version_path = lib_folder .. '/version' local files = { get_lib_extension = get_lib_extension, @@ -73,22 +73,22 @@ end --- Prebuilt binary --- -function files.is_downloaded() - return files.exists(files.lib_path):map(function(exists) - if exists then return true end - - -- If not found, check without 'lib' prefix - return files.exists(string.gsub(files.lib_path, 'libblink_cmp_fuzzy', 'blink_cmp_fuzzy')) - end) -end - -function files.get_downloaded_version() - return files.read_file(files.version_path):catch(function() end) +function files.get_version() + return files + .read_file(files.version_path) + :map(function(version) + if #version == 40 then + return { sha = version } + else + return { tag = version } + end + end) + :catch(function() return {} end) end --- @param version string --- @return blink.cmp.Task -function files.set_downloaded_version(version) +function files.set_version(version) return files .create_dir(files.root_dir .. '/target') :map(function() return files.create_dir(files.lib_folder) end) diff --git a/lua/blink/cmp/fuzzy/download/init.lua b/lua/blink/cmp/fuzzy/download/init.lua index fb88ec0f..6d51aa4a 100644 --- a/lua/blink/cmp/fuzzy/download/init.lua +++ b/lua/blink/cmp/fuzzy/download/init.lua @@ -1,5 +1,6 @@ local download_config = require('blink.cmp.config').fuzzy.prebuilt_binaries local async = require('blink.cmp.lib.async') +local git = require('blink.cmp.fuzzy.download.git') local files = require('blink.cmp.fuzzy.download.files') local system = require('blink.cmp.fuzzy.download.system') @@ -12,33 +13,56 @@ function download.ensure_downloaded(callback) if not download_config.download then return callback() end async.task - .await_all({ download.get_git_tag(), files.get_downloaded_version(), files.is_downloaded() }) - :map( - function(results) - return { - git_version = results[1], - version = results[2], - is_downloaded = results[3], - } + .await_all({ git.get_version(), files.get_version() }) + :map(function(results) + return { + git = results[1], + current = results[2], + } + end) + :map(function(version) + local target_git_tag = download_config.force_version or version.git.tag + + -- not built locally, not on a git tag, error + assert( + version.current.sha ~= nil or target_git_tag ~= nil, + "Can't download from github due to not being on a git tag and no fuzzy.prebuilt_binaries.force_version set, but found no built version of the library. " + .. 'Either run `cargo build --release` via your package manager, switch to a git tag, or set `fuzzy.prebuilt_binaries.force_version` in config. ' + .. 'See the docs for more info.' + ) + + -- built locally, ignore + if + version.current.sha == version.git.sha + or version.current.sha ~= nil and download_config.ignore_version_mismatch + then + return end - ) - :map(function(state) - local target_version = download_config.force_version or state.git_version - - -- not built locally, not a git tag, error - if not state.is_downloaded and not target_version then - return callback( - "Can't download from github due to not being on a git tag and no fuzzy.prebuilt_binaries.force_version set, but found no built version of the library. " - .. 'Either run `cargo build --release` via your package manager, switch to a git tag, or set `fuzzy.prebuilt_binaries.force_version` in config. ' - .. 'See the README for more info.' + + -- built locally but outdated and not on a git tag, error + if version.current.sha ~= nil and version.current.sha ~= version.git.sha then + assert( + target_git_tag or download_config.ignore_version_mismatch, + "Found an outdated version of the fuzzy matching library, but can't download from github due to not being on a git tag. " + .. '\n!! FOR DEVELOPERS !!, set `fuzzy.prebuilt_binaries.ignore_version_mismatch = true` in config. ' + .. '\n!! FOR USERS !!, either run `cargo build --release` via your package manager, switch to a git tag, or set `fuzzy.prebuilt_binaries.force_version` in config. ' + .. 'See the docs for more info.' ) + if not download_config.ignore_version_mismatch then + vim.schedule( + function() + vim.notify( + '[blink.cmp]: Found an outdated version of the fuzzy matching library built locally', + vim.log.levels.INFO, + { title = 'blink.cmp' } + ) + end + ) + end end - -- built locally, ignore - if state.is_downloaded and (state.version == nil) then return end - -- already downloaded and the correct version, just verify the checksum, and re-download if checksum fails - if state.version == target_version and state.is_downloaded then + if version.current.tag ~= nil and version.current.tag == target_git_tag then return files.verify_checksum():catch(function(err) vim.schedule(function() vim.notify(err, vim.log.levels.WARN, { title = 'blink.cmp' }) @@ -48,18 +72,18 @@ function download.ensure_downloaded(callback) { title = 'blink.cmp' } ) end) - return download.download(target_version) + return download.download(target_git_tag) end) end -- unknown state - if not target_version then error('Unknown error while getting pre-built binary. Consider re-installing') end + if not target_git_tag then error('Unknown error while getting pre-built binary. Consider re-installing') end -- download as per usual vim.schedule( function() vim.notify('Downloading pre-built binary', vim.log.levels.INFO, { title = 'blink.cmp' }) end ) - return download.download(target_version) + return download.download(target_git_tag) end) :map(function() callback() end) :catch(function(err) callback(err) end) @@ -68,38 +92,10 @@ end function download.download(version) -- NOTE: we set the version to 'v0.0.0' to avoid a failure causing the pre-built binary being marked as locally built return files - .set_downloaded_version('v0.0.0') + .set_version('v0.0.0') :map(function() return download.from_github(version) end) :map(function() return files.verify_checksum() end) - :map(function() return files.set_downloaded_version(version) end) -end - -function download.get_git_tag() - return async.task.new(function(resolve, reject) - -- If repo_dir is nil, no git reposiory is found, similar to `out.code == 128` - local repo_dir = vim.fs.root(files.root_dir, '.git') - if not repo_dir then resolve() end - - vim.system({ - 'git', - '--git-dir', - vim.fs.joinpath(repo_dir, '.git'), - '--work-tree', - repo_dir, - 'describe', - '--tags', - '--exact-match', - }, { cwd = files.root_dir }, function(out) - if out.code == 128 then return resolve() end - if out.code ~= 0 then - return reject('While getting git tag, git exited with code ' .. out.code .. ': ' .. out.stderr) - end - - local lines = vim.split(out.stdout, '\n') - if not lines[1] then return reject('Expected atleast 1 line of output from git describe') end - return resolve(lines[1]) - end) - end) + :map(function() return files.set_version(version) end) end --- @param tag string diff --git a/lua/blink/cmp/init.lua b/lua/blink/cmp/init.lua index a3c439b8..dcb748e1 100644 --- a/lua/blink/cmp/init.lua +++ b/lua/blink/cmp/init.lua @@ -18,7 +18,7 @@ function cmp.setup(opts) config.merge_with(opts) require('blink.cmp.fuzzy.download').ensure_downloaded(function(err) - if err then error('Error while downloading blink.cmp pre-built binary: ' .. err) end + if err then vim.notify(err, vim.log.levels.ERROR) end -- setup highlights, keymap, completion and signature help require('blink.cmp.highlights').setup()