Files
neovim/test/functional/fixtures/fake-ssh.lua
T
Justin M. Keyes 893d90fced feat(remote-ssh): supervise server in Lua, "Update Nvim" for nightly #42706
Problem:
- remote_ssh.sh detects ssh disconnect by writing a heartbeat every 1s,
  which the local side buffers for the whole session.
- The server's stdout (e.g. `io.write()` from a random plugin) writes to
  the tunnel, which in theory may contain a bogus "NVIM_READY".
- A nightly install is never updated on the remote.

Solution:
- Supervise the server in `vim.net._ssh.serve()` (Lua). It detects
  disconnect via stdin EOF and discards server stdout. The script only
  finds or installs `nvim`.
  - Also a step toward Windows remotes.
- User may choose "Update Nvim" to reinstall the nightly.
2026-11-05 09:48:04 -05:00

77 lines
2.4 KiB
Lua

-- Fake `ssh` for remote-ssh tests: `nvim -l fake-ssh.lua {config} {ssh-args}`. Behaves as {config}
-- (JSON, see `setup_fake_ssh()` in ssh_spec.lua) says, and writes to its `dir`:
-- tunnel.args Args of the tunnel (`-L`) command, and the script it got on stdin.
-- tunnel.pid PID of the tunnel.
-- forward.cancelled Created by `-O cancel -L`.
io.stdout:setvbuf('no')
local config = vim.json.decode(table.remove(_G.arg, 1))
local dir = config.dir
local args = table.concat(_G.arg, ' ')
local function fail(msg)
io.stderr:write(msg, '\n')
os.exit(1)
end
local function write(name, data)
local f = assert(io.open(vim.fs.joinpath(dir, name), 'wb'))
f:write(data)
f:close()
end
if args:find('^%-G ') then
io.stdout:write(config.ssh_config)
os.exit(0)
elseif args:find('uname -s && uname -m', 1, true) then
io.stdout:write(config.uname)
os.exit(0)
elseif args:find('-O cancel -L', 1, true) then
write('forward.cancelled', '')
os.exit(0)
elseif not args:find(' -L ', 1, true) then
fail(('Unexpected SSH command: %s'):format(args))
end
-- The script on stdin, which stays open (see `run_script()`).
local script = {} --- @type string[]
for line in io.stdin:lines() do
script[#script + 1] = line
if line == 'main "$@"' then
break
end
end
args = ('%s %s'):format(args, table.concat(script, '\n'))
if not args:find('ControlMaster', 1, true) then
fail('FAIL: Multiplexing flags missing!')
elseif not args:find(' sh %-s .*main "%$@"') then
fail('FAIL: tunnel script not fed to sh -s')
end
write('tunnel.args', args)
write('tunnel.pid', tostring(vim.uv.os_getpid()))
local tunnel = config.tunnel
local server --- @type vim.SystemObj?
if tunnel.serve then
-- Serves a headless Nvim at the `-L` socket, as the remote does. Its stdin (`--embed`) ends with
-- this process, and so does the server.
local sock = assert(args:match('%-L ([^:]+)'))
local cmd = { config.nvim_prog, '--embed', '--headless', '--clean', '-i', 'NONE' }
server = vim.system(vim.list_extend(cmd, { '--listen', sock }), { stdin = true })
vim.wait(10000, function()
return vim.uv.fs_stat(sock) ~= nil
end)
io.stdout:write('NVIM_READY\n')
end
io.stdout:write(tunnel.stdout or '')
io.stderr:write(tunnel.stderr or '')
if tunnel.exit then
os.exit(tunnel.exit)
elseif server then
-- As the remote script: ends when its server exits.
server:wait()
os.exit(0)
end
-- Until killed.
vim.wait(60000)