refactor: rewrite virtualenv healthcheck in lua

This is required to remove the vimscript checkhealth functions.
This commit is contained in:
dundargoc 2023-04-10 11:28:42 +02:00 committed by GitHub
parent 3c724fe1f3
commit 5ed7ede1f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 88 additions and 75 deletions

View File

@ -90,79 +90,6 @@ function! s:disabled_via_loaded_var(provider) abort
return 0
endfunction
" Resolves Python executable path by invoking and checking `sys.executable`.
function! s:python_exepath(invocation) abort
return s:normalize_path(system(fnameescape(a:invocation)
\ . ' -c "import sys; sys.stdout.write(sys.executable)"'))
endfunction
" Checks that $VIRTUAL_ENV Python executables are found at front of $PATH in
" Nvim and subshells.
function! s:check_virtualenv() abort
call health#report_start('Python virtualenv')
if !exists('$VIRTUAL_ENV')
call health#report_ok('no $VIRTUAL_ENV')
return
endif
let errors = []
" Keep hints as dict keys in order to discard duplicates.
let hints = {}
" The virtualenv should contain some Python executables, and those
" executables should be first both on Nvim's $PATH and the $PATH of
" subshells launched from Nvim.
let bin_dir = has('win32') ? '/Scripts' : '/bin'
let venv_bins = glob($VIRTUAL_ENV . bin_dir . '/python*', v:true, v:true)
" XXX: Remove irrelevant executables found in bin/.
let venv_bins = filter(venv_bins, 'v:val !~# "python-config"')
if len(venv_bins)
for venv_bin in venv_bins
let venv_bin = s:normalize_path(venv_bin)
let py_bin_basename = fnamemodify(venv_bin, ':t')
let nvim_py_bin = s:python_exepath(exepath(py_bin_basename))
let subshell_py_bin = s:python_exepath(py_bin_basename)
if venv_bin !=# nvim_py_bin
call add(errors, '$PATH yields this '.py_bin_basename.' executable: '.nvim_py_bin)
let hint = '$PATH ambiguities arise if the virtualenv is not '
\.'properly activated prior to launching Nvim. Close Nvim, activate the virtualenv, '
\.'check that invoking Python from the command line launches the correct one, '
\.'then relaunch Nvim.'
let hints[hint] = v:true
endif
if venv_bin !=# subshell_py_bin
call add(errors, '$PATH in subshells yields this '
\.py_bin_basename . ' executable: '.subshell_py_bin)
let hint = '$PATH ambiguities in subshells typically are '
\.'caused by your shell config overriding the $PATH previously set by the '
\.'virtualenv. Either prevent them from doing so, or use this workaround: '
\.'https://vi.stackexchange.com/a/34996'
let hints[hint] = v:true
endif
endfor
else
call add(errors, 'no Python executables found in the virtualenv '.bin_dir.' directory.')
endif
let msg = '$VIRTUAL_ENV is set to: '.$VIRTUAL_ENV
if len(errors)
if len(venv_bins)
let msg .= "\nAnd its ".bin_dir.' directory contains: '
\.join(map(venv_bins, "fnamemodify(v:val, ':t')"), ', ')
endif
let conj = "\nBut "
for error in errors
let msg .= conj.error
let conj = "\nAnd "
endfor
let msg .= "\nSo invoking Python may lead to unexpected results."
call health#report_warn(msg, keys(hints))
else
call health#report_info(msg)
call health#report_info('Python version: '
\.system('python -c "import platform, sys; sys.stdout.write(platform.python_version())"'))
call health#report_ok('$VIRTUAL_ENV provides :!python.')
endif
endfunction
function! s:check_ruby() abort
call health#report_start('Ruby provider (optional)')
@ -372,7 +299,6 @@ function! s:check_perl() abort
endfunction
function! health#provider2#check() abort
call s:check_virtualenv()
call s:check_ruby()
call s:check_node()
call s:check_perl()

View File

@ -489,7 +489,7 @@ local function python()
if not is_blank(pyenv_root) then
venv_root = pyenv_root
else
venv_root = vim.fs.basename(venv)
venv_root = vim.fs.dirname(venv)
end
if vim.startswith(vim.fn.resolve(python_exe), venv_root .. '/') then
@ -571,9 +571,96 @@ local function python()
end
end
-- Resolves Python executable path by invoking and checking `sys.executable`.
local function python_exepath(invocation)
return vim.fs.normalize(
system(vim.fn.fnameescape(invocation) .. ' -c "import sys; sys.stdout.write(sys.executable)"')
)
end
-- Checks that $VIRTUAL_ENV Python executables are found at front of $PATH in
-- Nvim and subshells.
local function virtualenv()
start('Python virtualenv')
if not os.getenv('VIRTUAL_ENV') then
ok('no $VIRTUAL_ENV')
return
end
local errors = {}
-- Keep hints as dict keys in order to discard duplicates.
local hints = {}
-- The virtualenv should contain some Python executables, and those
-- executables should be first both on Nvim's $PATH and the $PATH of
-- subshells launched from Nvim.
local bin_dir = (iswin and '/Scripts' or '/bin')
local venv_bins = vim.fn.glob(os.getenv('VIRTUAL_ENV') .. bin_dir .. '/python*', true, true)
-- XXX: Remove irrelevant executables found in bin/.
venv_bins = vim.fn.filter(venv_bins, 'v:val !~# "python-config"')
if vim.tbl_coun(venv_bins) > 0 then
for _, venv_bin in pairs(venv_bins) do
venv_bin = vim.fs.normalize(venv_bin)
local py_bin_basename = vim.fs.basename(venv_bin)
local nvim_py_bin = python_exepath(vim.fn.exepath(py_bin_basename))
local subshell_py_bin = python_exepath(py_bin_basename)
if venv_bin ~= nvim_py_bin then
errors[#errors + 1] = '$PATH yields this '
.. py_bin_basename
.. ' executable: '
.. nvim_py_bin
local hint = '$PATH ambiguities arise if the virtualenv is not '
.. 'properly activated prior to launching Nvim. Close Nvim, activate the virtualenv, '
.. 'check that invoking Python from the command line launches the correct one, '
.. 'then relaunch Nvim.'
hints[hint] = true
end
if venv_bin ~= subshell_py_bin then
errors[#errors + 1] = '$PATH in subshells yields this '
.. py_bin_basename
.. ' executable: '
.. subshell_py_bin
local hint = '$PATH ambiguities in subshells typically are '
.. 'caused by your shell config overriding the $PATH previously set by the '
.. 'virtualenv. Either prevent them from doing so, or use this workaround: '
.. 'https://vi.stackexchange.com/a/34996'
hints[hint] = true
end
end
else
errors[#errors + 1] = 'no Python executables found in the virtualenv '
.. bin_dir
.. ' directory.'
end
local msg = '$VIRTUAL_ENV is set to: ' .. os.getenv('VIRTUAL_ENV')
if vim.tbl_count(errors) > 0 then
if vim.tbl_count(venv_bins) > 0 then
msg = msg
.. '\nAnd its '
.. bin_dir
.. ' directory contains: '
.. vim.fn.join(vim.fn.map(venv_bins, [[fnamemodify(v:val, ':t')]]), ', ')
end
local conj = '\nBut '
for _, err in ipairs(errors) do
msg = msg .. conj .. err
conj = '\nAnd '
end
msg = msg .. '\nSo invoking Python may lead to unexpected results.'
warn(msg, vim.fn.keys(hints))
else
info(msg)
info(
'Python version: '
.. system('python -c "import platform, sys; sys.stdout.write(platform.python_version())"')
)
ok('$VIRTUAL_ENV provides :!python.')
end
end
function M.check()
clipboard()
python()
virtualenv()
end
return M