wbthomason / packer.nvim

A use-package inspired plugin manager for Neovim. Uses native packages, supports Luarocks dependencies, written in Lua, allows for expressive config
MIT License
7.88k stars 265 forks source link

Packer compilation doesn't order 'try_loadstring(...)' according to dependency graph #726

Closed ianbattersby closed 2 years ago

ianbattersby commented 2 years ago

I appreciate this behaviour may not be considered a bug but expected. However, given I only noticed it on upgrading to Neovim v0.6.0 it has made me question if there were changes in Neovim itself (ala asyncronousity) that could be causing this. In raising this issue my hope is to understand if it is known/expected and/or gain awareness of anyone else experiencing it.

Steps to reproduce

NB: I find this easier to produce using my own (much larger) nvim configuration however I can reproduce it on the small solution enclosed below.

Actual behaviour

The compilation operation is non-deterministic, in that the ordering of the compiled try_loadstring(...) statements does not always follow the dependency graph implied (via requires {...}) and/or the use statement order.

time([[Defining packer_plugins]], false)
-- Config for: alpha-nvim
time([[Config for alpha-nvim]], true)
try_loadstring("\27LJ\2\n^\0\0\5\0\5\0\n6\0\0\0'\2\1\0B\0\2\0029\0\2\0006\2\0\0'\4\3\0B\2\2\0029\2\4\2B\0\2\1K\0\1\0\topts\26alpha.themes.startify\nsetup\nalpha\frequire\0", "config", "alpha-nvim")
time([[Config for alpha-nvim]], false)
-- Config for: onedark.nvim
time([[Config for onedark.nvim]], true)
try_loadstring("\27LJ\2\n9\0\0\3\0\3\0\a6\0\0\0'\2\1\0B\0\2\0029\0\2\0004\2\0\0B\0\2\1K\0\1\0\nsetup\fonedark\frequire\0", "config", "onedark.nvim")
time([[Config for onedark.nvim]], false)

Expected behaviour

It is expected that the operation always produces the same result, and that it (ideally) performs try_loadstring(...) in the order implied by the dependency graph.

time([[Defining packer_plugins]], false)
-- Config for: onedark.nvim
time([[Config for onedark.nvim]], true)
try_loadstring("\27LJ\2\n9\0\0\3\0\3\0\a6\0\0\0'\2\1\0B\0\2\0029\0\2\0004\2\0\0B\0\2\1K\0\1\0\nsetup\fonedark\frequire\0", "config", "onedark.nvim")
time([[Config for onedark.nvim]], false)
-- Config for: alpha-nvim
time([[Config for alpha-nvim]], true)
try_loadstring("\27LJ\2\n^\0\0\5\0\5\0\n6\0\0\0'\2\1\0B\0\2\0029\0\2\0006\2\0\0'\4\3\0B\2\2\0029\2\4\2B\0\2\1K\0\1\0\topts\26alpha.themes.startify\nsetup\nalpha\frequire\0", "config", "alpha-nvim")
time([[Config for alpha-nvim]], false)

packer files

Plugin specification file(s) ``` local function config_alpha() require("alpha").setup(require("alpha.themes.startify").opts) end local function config_theme() require("onedark").setup({}) end local function packer_setup() local packer = require("packer") packer.init({}) packer.startup(function(use) use("wbthomason/packer.nvim") use({ "monsonjeremy/onedark.nvim", config = config_theme, }) use({ "goolord/alpha-nvim", requires = { { "kyazdani42/nvim-web-devicons" }, { "monsonjeremy/onedark.nvim" }, }, config = config_alpha, }) end) end packer_setup() ```
packer log file ``
packer compiled file ``` -- Automatically generated packer.nvim plugin loader code if vim.api.nvim_call_function('has', {'nvim-0.5'}) ~= 1 then vim.api.nvim_command('echohl WarningMsg | echom "Invalid Neovim version for packer.nvim! | echohl None"') return end vim.api.nvim_command('packadd packer.nvim') local no_errors, error_msg = pcall(function() local time local profile_info local should_profile = false if should_profile then local hrtime = vim.loop.hrtime profile_info = {} time = function(chunk, start) if start then profile_info[chunk] = hrtime() else profile_info[chunk] = (hrtime() - profile_info[chunk]) / 1e6 end end else time = function(chunk, start) end end local function save_profiles(threshold) local sorted_times = {} for chunk_name, time_taken in pairs(profile_info) do sorted_times[#sorted_times + 1] = {chunk_name, time_taken} end table.sort(sorted_times, function(a, b) return a[2] > b[2] end) local results = {} for i, elem in ipairs(sorted_times) do if not threshold or threshold and elem[2] > threshold then results[i] = elem[1] .. ' took ' .. elem[2] .. 'ms' end end _G._packer = _G._packer or {} _G._packer.profile_output = results end time([[Luarocks path setup]], true) local package_path_str = "/Users/ian/.cache/nvim/packer_hererocks/2.1.0-beta3/share/lua/5.1/?.lua;/Users/ian/.cache/nvim/packer_hererocks/2.1.0-beta3/share/lua/5.1/?/init.lua;/Users/ian/.cache/nvim/packer_hererocks/2.1.0-beta3/lib/luarocks/rocks-5.1/?.lua;/Users/ian/.cache/nvim/packer_hererocks/2.1.0-beta3/lib/luarocks/rocks-5.1/?/init.lua" local install_cpath_pattern = "/Users/ian/.cache/nvim/packer_hererocks/2.1.0-beta3/lib/lua/5.1/?.so" if not string.find(package.path, package_path_str, 1, true) then package.path = package.path .. ';' .. package_path_str end if not string.find(package.cpath, install_cpath_pattern, 1, true) then package.cpath = package.cpath .. ';' .. install_cpath_pattern end time([[Luarocks path setup]], false) time([[try_loadstring definition]], true) local function try_loadstring(s, component, name) local success, result = pcall(loadstring(s), name, _G.packer_plugins[name]) if not success then vim.schedule(function() vim.api.nvim_notify('packer.nvim: Error running ' .. component .. ' for ' .. name .. ': ' .. result, vim.log.levels.ERROR, {}) end) end return result end time([[try_loadstring definition]], false) time([[Defining packer_plugins]], true) _G.packer_plugins = { ["alpha-nvim"] = { config = { "\27LJ\2\n^\0\0\5\0\5\0\n6\0\0\0'\2\1\0B\0\2\0029\0\2\0006\2\0\0'\4\3\0B\2\2\0029\2\4\2B\0\2\1K\0\1\0\topts\26alpha.themes.startify\nsetup\nalpha\frequire\0" }, loaded = true, path = "/Users/ian/.local/share/nvim/site/pack/packer/start/alpha-nvim", url = "https://github.com/goolord/alpha-nvim" }, ["nvim-web-devicons"] = { loaded = true, path = "/Users/ian/.local/share/nvim/site/pack/packer/start/nvim-web-devicons", url = "https://github.com/kyazdani42/nvim-web-devicons" }, ["onedark.nvim"] = { config = { "\27LJ\2\n9\0\0\3\0\3\0\a6\0\0\0'\2\1\0B\0\2\0029\0\2\0004\2\0\0B\0\2\1K\0\1\0\nsetup\fonedark\frequire\0" }, loaded = true, path = "/Users/ian/.local/share/nvim/site/pack/packer/start/onedark.nvim", url = "https://github.com/monsonjeremy/onedark.nvim" }, ["packer.nvim"] = { loaded = true, path = "/Users/ian/.local/share/nvim/site/pack/packer/start/packer.nvim", url = "https://github.com/wbthomason/packer.nvim" } } time([[Defining packer_plugins]], false) -- Config for: alpha-nvim time([[Config for alpha-nvim]], true) try_loadstring("\27LJ\2\n^\0\0\5\0\5\0\n6\0\0\0'\2\1\0B\0\2\0029\0\2\0006\2\0\0'\4\3\0B\2\2\0029\2\4\2B\0\2\1K\0\1\0\topts\26alpha.themes.startify\nsetup\nalpha\frequire\0", "config", "alpha-nvim") time([[Config for alpha-nvim]], false) -- Config for: onedark.nvim time([[Config for onedark.nvim]], true) try_loadstring("\27LJ\2\n9\0\0\3\0\3\0\a6\0\0\0'\2\1\0B\0\2\0029\0\2\0004\2\0\0B\0\2\1K\0\1\0\nsetup\fonedark\frequire\0", "config", "onedark.nvim") time([[Config for onedark.nvim]], false) if should_profile then save_profiles() end end) if not no_errors then vim.api.nvim_command('echohl ErrorMsg | echom "Error in packer_compiled: '..error_msg..'" | echom "Please check your config for correctness" | echohl None') end ```
wbthomason commented 2 years ago

Ah - I think the problem here is that requires currently does not imply an ordering, just a "this plugin needs this other plugin to be downloaded" relationship. after or wants control sequencing. There has been discussion of merging these three into something less confusing in the past, but nothing has come of it yet.

ianbattersby commented 2 years ago

Thanks @wbthomason. And sincere apologies - I'd totally missed after when scanning the README.md. It does indeed achieve the desired result in sequencing the load-order in packer_compiled.lua 🙇

wbthomason commented 2 years ago

No worries - this point is particularly confusing, and something I should really improve. I'm glad things are working now!

HrvojeJuric commented 2 years ago

Sorry for necro posting but I just wanted to thank for raising this issue because I ran into that same exact problem. 🙌