diff options
| author | kylo252 <[email protected]> | 2022-06-23 16:11:47 +0200 | 
|---|---|---|
| committer | GitHub <[email protected]> | 2022-06-23 16:11:47 +0200 | 
| commit | 8989984b781367b2744c4857e73d8943311db241 (patch) | |
| tree | 29aba4fb65811b8bb3643ac7ef24eff6df8457c8 | |
| parent | ecd344128734fe6b0772505e22922dea28338e26 (diff) | |
feat(installer): add verify-plugins hook (#2751)
| -rw-r--r-- | lua/lvim/plugins.lua | 16 | ||||
| -rw-r--r-- | tests/specs/plugins_load_spec.lua | 3 | ||||
| -rw-r--r-- | utils/ci/generate_new_lockfile.lua | 35 | ||||
| -rw-r--r-- | utils/ci/verify_plugins.lua | 134 | ||||
| -rw-r--r-- | utils/ci/verify_plugins.sh | 5 | ||||
| -rwxr-xr-x | utils/installer/install.sh | 11 | 
6 files changed, 183 insertions, 21 deletions
| diff --git a/lua/lvim/plugins.lua b/lua/lvim/plugins.lua index 9397318e..dd40b967 100644 --- a/lua/lvim/plugins.lua +++ b/lua/lvim/plugins.lua @@ -246,9 +246,19 @@ local core_plugins = {    },  } -for _, entry in ipairs(core_plugins) do -  if not os.getenv "LVIM_DEV_MODE" then -    entry["lock"] = true +local default_snapshot_path = join_paths(get_lvim_base_dir(), "snapshots", "default.json") +local content = vim.fn.readfile(default_snapshot_path) +local default_sha1 = vim.fn.json_decode(content) + +local get_default_sha1 = function(spec) +  local short_name, _ = require("packer.util").get_plugin_short_name(spec) +  return default_sha1[short_name] and default_sha1[short_name].commit +end + +for _, spec in ipairs(core_plugins) do +  if not vim.env.LVIM_DEV_MODE then +    -- Manually lock the commit hash since Packer's snapshots are unreliable in headless mode +    spec["commit"] = get_default_sha1(spec)    end  end diff --git a/tests/specs/plugins_load_spec.lua b/tests/specs/plugins_load_spec.lua index 1f11279e..283d5547 100644 --- a/tests/specs/plugins_load_spec.lua +++ b/tests/specs/plugins_load_spec.lua @@ -38,7 +38,8 @@ a.describe("plugin-loader", function()        assert.truthy(package.loaded[plugin])      end    end) -  a.it("should be able to rollback plugins without errors", function() + +  pending("should be able to rollback plugins without errors", function()      local plugin = { name = "onedarker.nvim" }      plugin.path = vim.tbl_filter(function(package)        return package:match(plugin.name) diff --git a/utils/ci/generate_new_lockfile.lua b/utils/ci/generate_new_lockfile.lua index 9f274597..fd10775c 100644 --- a/utils/ci/generate_new_lockfile.lua +++ b/utils/ci/generate_new_lockfile.lua @@ -1,18 +1,18 @@  local sp = os.getenv "SNAPSHOT_PATH"  local function call_proc(process, opts, cb) -  local std_output = "" -  local error_output = "" - -  local function onread(_, is_stderr) -    return function(err, data) -      if data then -        if is_stderr then -          error_output = (error_output or "") .. err -        else -          std_output = (std_output or "") .. data -        end -      end +  local output, error_output = "", "" +  local handle_stdout = function(err, chunk) +    assert(not err, err) +    if chunk then +      output = output .. chunk +    end +  end + +  local handle_stderr = function(err, chunk) +    assert(not err, err) +    if chunk then +      error_output = error_output .. chunk      end    end @@ -26,7 +26,7 @@ local function call_proc(process, opts, cb)    handle = uv.spawn(      process, -    { args = opts.args, cwd = uv.cwd(), stdio = stdio }, +    { args = opts.args, cwd = opts.cwd or uv.cwd(), stdio = stdio },      vim.schedule_wrap(function(code)        if code ~= 0 then          stdout:read_stop() @@ -42,13 +42,13 @@ local function call_proc(process, opts, cb)          end          check:stop()          handle:close() -        cb(code, std_output, error_output) +        cb(code, output, error_output)        end)      end)    ) -  uv.read_start(stdout, onread(handle, false)) -  uv.read_start(stderr, onread(handle, true)) +  uv.read_start(stdout, handle_stdout) +  uv.read_start(stderr, handle_stderr)    return handle  end @@ -91,11 +91,12 @@ local function write_lockfile(verbose)      end      local handle = call_proc("git", { args = { "ls-remote", entry.url, "HEAD" } }, on_done) +    assert(handle)      table.insert(active_jobs, handle)    end    print("active: " .. #active_jobs) -  print("parsers: " .. #default_plugins) +  print("plugins: " .. #default_plugins)    vim.wait(#active_jobs * 60 * 1000, function()      return completed == #active_jobs diff --git a/utils/ci/verify_plugins.lua b/utils/ci/verify_plugins.lua new file mode 100644 index 00000000..c56d85d1 --- /dev/null +++ b/utils/ci/verify_plugins.lua @@ -0,0 +1,134 @@ +local completed = 0 +local collection = {} +local active_jobs = {} + +local fmt = string.format +local core_plugins = require "lvim.plugins" + +local default_snapshot_path = join_paths(get_lvim_base_dir(), "snapshots", "default.json") +local fd = io.open(default_snapshot_path, "rb") +local content +if fd then +  content = fd:read "*a" +end +local default_sha1 = vim.json.decode(content) + +local get_short_name = function(spec) +  return spec[1]:match "/(%S*)" +end + +local get_default_sha1 = function(spec) +  local short_name, _ = get_short_name(spec) +  assert(default_sha1[short_name]) +  return default_sha1[short_name].commit +end + +local is_directory = require("lvim.utils").is_directory +-- see packer.init() +local packdir = join_paths(get_runtime_dir(), "site", "pack", "packer") +local packer_config = { opt_dir = join_paths(packdir, "opt"), start_dir = join_paths(packdir, "start") } +local is_optional = function(spec) +  return spec.opt or spec.event or spec.cmd or spec.module +end +local get_install_path = function(spec) +  local prefix = is_optional(spec) and packer_config.opt_dir or packer_config.start_dir +  local path = join_paths(prefix, get_short_name(spec)) +  assert(is_directory(path)) +  return path +end + +local function call_proc(process, opts, cb) +  local output, error_output = "", "" +  local handle_stdout = function(err, chunk) +    assert(not err, err) +    if chunk then +      output = output .. chunk +    end +  end + +  local handle_stderr = function(err, chunk) +    assert(not err, err) +    if chunk then +      error_output = error_output .. chunk +    end +  end + +  local uv = vim.loop +  local handle + +  local stdout = uv.new_pipe(false) +  local stderr = uv.new_pipe(false) + +  local stdio = { nil, stdout, stderr } + +  handle = uv.spawn( +    process, +    { args = opts.args, cwd = opts.cwd or uv.cwd(), stdio = stdio }, +    vim.schedule_wrap(function(code) +      if code ~= 0 then +        stdout:read_stop() +        stderr:read_stop() +      end + +      local check = uv.new_check() +      check:start(function() +        for _, pipe in ipairs(stdio) do +          if pipe and not pipe:is_closing() then +            return +          end +        end +        check:stop() +        handle:close() +        cb(code, output, error_output) +      end) +    end) +  ) + +  uv.read_start(stdout, handle_stdout) +  uv.read_start(stderr, handle_stderr) + +  return handle +end + +local function verify_core_plugins(verbose) +  for _, spec in pairs(core_plugins) do +    if not spec.disable then +      table.insert(collection, { +        name = get_short_name(spec), +        commit = get_default_sha1(spec), +        path = get_install_path(spec), +      }) +    end +  end + +  for _, entry in pairs(collection) do +    local on_done = function(code, result, errors) +      completed = completed + 1 +      if code ~= 0 then +        io.write(errors .. "\n") +        -- os.exit(code) +      else +        if verbose then +          io.write(fmt("verified [%s]\n", entry.name)) +        end +      end +      local current_commit = result:gsub("\n", ""):gsub([[']], [[]]) +      -- just in case there are some extra qutoes or it's a longer commit hash +      if current_commit ~= entry.commit then +        io.write(fmt("mismatch at [%s]: expected [%s], got [%s]\n", entry.name, entry.commit, current_commit)) +        os.exit(1) +      end +    end + +    local handle = call_proc("git", { args = { "log", "--pretty='%h'", "-1" }, cwd = entry.path }, on_done) +    assert(handle) +    table.insert(active_jobs, handle) +  end + +  vim.wait(#active_jobs * 60 * 1000, function() +    return completed == #active_jobs +  end) +end + +verify_core_plugins() +vim.cmd "q" diff --git a/utils/ci/verify_plugins.sh b/utils/ci/verify_plugins.sh new file mode 100644 index 00000000..7d0d764b --- /dev/null +++ b/utils/ci/verify_plugins.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -e + +lvim --headless \ +  -c "luafile ./utils/ci/verify_plugins.lua" diff --git a/utils/installer/install.sh b/utils/installer/install.sh index 2903dd7f..ec675e6d 100755 --- a/utils/installer/install.sh +++ b/utils/installer/install.sh @@ -206,6 +206,15 @@ function check_neovim_min_version() {    fi  } +function verify_core_plugins() { +  msg "Verifying core plugins" +  if ! bash "$LUNARVIM_BASE_DIR/utils/ci/verify_plugins.sh"; then +    echo "[ERROR]: Unable to verify plugins, makde sure to manually run ':PackerSync' when starting lvim for the first time." +    exit 1 +  fi +  echo "Verification complete!" +} +  function validate_lunarvim_files() {    local verify_version_cmd='if v:errmsg != "" | cquit | else | quit | endif'    if ! "$INSTALL_PREFIX/bin/lvim" --headless -c 'LvimUpdate' -c "$verify_version_cmd" &>/dev/null; then @@ -418,6 +427,8 @@ function setup_lvim() {      -c 'PackerSync'    echo "Packer setup complete" + +  verify_core_plugins  }  function print_logo() { | 
