Skip to content

fix: avoid recursion when copying folder to itself #358

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions lua/plenary/path.lua
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ function Path:copy(opts)
end
-- dir
if opts.recursive then
local suffix = table.remove(self:_split())
dest:mkdir {
parents = F.if_nil(opts.parents, false, opts.parents),
exists_ok = F.if_nil(opts.exists_ok, true, opts.exists_ok),
Expand All @@ -561,13 +562,16 @@ function Path:copy(opts)
})
for _, entry in ipairs(data) do
local entry_path = Path:new(entry)
local suffix = table.remove(entry_path:_split())
local new_dest = dest:joinpath(suffix)
-- clear destination as it might be Path table otherwise failing w/ extend
opts.destination = nil
local new_opts = vim.tbl_deep_extend("force", opts, { destination = new_dest })
-- nil: not overriden if `override = false`
success[new_dest] = entry_path:copy(new_opts) or false
local entry_suffix = table.remove(entry_path:_split())
-- avoid repeated recursive copying if folder is copied into itself
if suffix ~= entry_suffix then
local new_dest = dest:joinpath(entry_suffix)
-- clear destination as it might be Path table otherwise failing w/ extend
opts.destination = nil
local new_opts = vim.tbl_deep_extend("force", opts, { destination = new_dest })
-- nil: not overriden if `override = false`
success[new_dest] = entry_path:copy(new_opts) or false
end
end
return success
else
Expand Down
43 changes: 43 additions & 0 deletions tests/plenary/path_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,49 @@ describe("Path", function()
src_dir:rm { recursive = true }
end)

it("self copies folders only once", function()
local scan = require "plenary.scandir"
-- create nested folder
local src_dir = Path:new "src"
src_dir:mkdir()
src_dir:joinpath("file1.lua"):touch()
local src_sub_dir = src_dir:joinpath "sub_dir"
src_sub_dir:mkdir()
src_sub_dir:joinpath("file2.lua"):touch()
-- src
-- ├── file1.lua
-- └── sub_dir
-- └── file2_2.lua

local trg_dir = src_dir:joinpath "src"
src_dir:copy { destination = trg_dir, recursive = true }
-- src/
-- ├── file1.lua
-- ├── src
-- │   ├── file1.lua
-- │   └── sub_dir
-- │   └── file2.lua
-- └── sub_dir
-- └── file2.lua
local src_dir_data = scan.scan_dir(src_dir:absolute(), { depth = 1, add_dirs = true })
local trg_dir_data = scan.scan_dir(trg_dir:absolute(), { depth = 1, add_dirs = true })
table.insert(trg_dir_data, trg_dir:absolute())
-- check that equal number of items
assert(#src_dir_data == #trg_dir_data)
-- insert file/folder stems into set
local path_set = {}
-- get suffixes of absolute paths in respective folders and check match by creating set
for _, value in ipairs(src_dir_data) do
value = table.remove(Path:new(value):_split())
path_set[value] = true
end
for _, value in ipairs(trg_dir_data) do
value = table.remove(Path:new(value):_split())
assert(path_set[value])
end
src_dir:rm { recursive = true }
end)

it("can copy directories recursively", function()
-- vim.tbl_flatten doesn't work here as copy doesn't return a list
local flatten
Expand Down