From b7f475787ee8e4ce3e2015d00044163a265c0d4e Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Tue, 17 Mar 2026 22:20:32 -0400 Subject: [PATCH] fix(ftp): recursively delete directory contents before RMD Problem: FTP's RMD command fails with '550 Directory not empty' if the directory has any contents. Unlike the S3 adapter which uses `aws s3 rm --recursive`, FTP has no protocol-level recursive delete. Solution: emit a Python rmtree helper inside the ftpcmd script that walks the directory via MLSD, recursively deletes children (DELE for files, rmtree for subdirs), then sends RMD on the now-empty directory. --- lua/oil/adapters/ftp.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lua/oil/adapters/ftp.lua b/lua/oil/adapters/ftp.lua index 84298f9..a09fbdb 100644 --- a/lua/oil/adapters/ftp.lua +++ b/lua/oil/adapters/ftp.lua @@ -496,7 +496,16 @@ M.perform_action = function(action, cb) local res = M.parse_url(action.url) local ftp_path = ftp_abs_path(res) if action.entry_type == 'directory' then - ftpcmd(res, { string.format('ftp.voidcmd(%q)', 'RMD ' .. ftp_path) }, cb) + ftpcmd(res, { + 'def rmtree(f, p):', + ' for name, facts in f.mlsd(p):', + ' if name in (".", ".."): continue', + ' child = p.rstrip("/") + "/" + name', + ' if facts["type"] == "dir": rmtree(f, child)', + ' else: f.voidcmd("DELE " + child)', + ' f.voidcmd("RMD " + p)', + string.format('rmtree(ftp, %q)', ftp_path), + }, cb) else ftpcmd(res, { string.format('ftp.voidcmd(%q)', 'DELE ' .. ftp_path) }, cb) end