Skip to content

Commit

Permalink
Implement walkdir. fixes #8814
Browse files Browse the repository at this point in the history
  • Loading branch information
dhoegh committed Oct 22, 2015
1 parent 1079755 commit 504281b
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 0 deletions.
59 changes: 59 additions & 0 deletions base/file.jl
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,62 @@ function readdir(path::AbstractString)
end

readdir() = readdir(".")

"""
walkdir(dir; topdown=true, follow_symlinks=false, onerror=throw)
The walkdir method return an iterator that walks the directory tree of a directory. The iterator returns a tuple containing
`(rootpath, dirs, files)`. The directory tree can be traversed top-down or bottom-up. If walkdir encounters a SystemError
it will raise the error. A custom error handling function can be provided through `onerror` keyword argument, the function
is called with a SystemError as argument.
for (root, dirs, files) in walkdir(".")
println("Directories in \$root")
for dir in dirs
println(joinpath(root, dir)) # path to directories
end
println("Files in \$root")
for file in files
println(joinpath(root, file)) # path to files
end
end
"""
function walkdir(root; topdown=true, follow_symlinks=false, onerror=throw)
content = nothing
try
content = readdir(root)
catch err
isa(SystemError) || throw(err)
onerror(err)
return
end
dirs = Array(eltype(content), 0)
files = Array(eltype(content), 0)
for name in content
if isdir(joinpath(root, name))
push!(dirs, name)
else
push!(files, name)
end
end

function _it()
if topdown
produce(root, dirs, files)
end
for dir in dirs
path = joinpath(root,dir)
if follow_symlinks || !islink(path)
for (root_l, dirs_l, files_l) in walkdir(path, topdown=topdown, follow_symlinks=follow_symlinks, onerror=onerror)
produce(root_l, dirs_l, files_l)
end
end
end
if !topdown
produce(root, dirs, files)
end
end
Task(_it)
end

80 changes: 80 additions & 0 deletions test/file.jl
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,86 @@ end
@test_throws ArgumentError download("good", "ba\0d")
@test_throws ArgumentError download("ba\0d", "good")

###################
# walkdir #
###################

dir = mktempdir()
cd(dir) do
for i=1:2
mkdir("sub_dir$i")
open("file$i", "w") do f end

mkdir(joinpath("sub_dir1", "subsub_dir$i"))
open(joinpath("sub_dir1", "file$i"), "w") do f end
end
open(joinpath("sub_dir2", "file_dir2"), "w")
has_symlinks = @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER)
follow_symlink_vec = has_symlinks ? [true, false] : [false]
has_symlinks && symlink("sub_dir2", joinpath("sub_dir1", "link"))
for follow_symlinks in follow_symlink_vec
task = walkdir(".", follow_symlinks=follow_symlinks)
root, dirs, files = consume(task)
@test root == "."
@test dirs == ["sub_dir1", "sub_dir2"]
@test files == ["file1", "file2"]

root, dirs, files = consume(task)
@test root == joinpath(".", "sub_dir1")
@test dirs == (has_symlinks ? ["link", "subsub_dir1", "subsub_dir2"] : ["subsub_dir1", "subsub_dir2"])
@test files == ["file1", "file2"]

root, dirs, files = consume(task)
if follow_symlinks
@test root == joinpath(".", "sub_dir1", "link")
@test dirs == []
@test files == ["file_dir2"]
root, dirs, files = consume(task)
end
for i=1:2
@test root == joinpath(".", "sub_dir1", "subsub_dir$i")
@test dirs == []
@test files == []
root, dirs, files = consume(task)
end

@test root == joinpath(".", "sub_dir2")
@test dirs == []
@test files == ["file_dir2"]
end

for follow_symlinks in follow_symlink_vec
task = walkdir(".", follow_symlinks=follow_symlinks, topdown=false)
root, dirs, files = consume(task)
if follow_symlinks
@test root == joinpath(".", "sub_dir1", "link")
@test dirs == []
@test files == ["file_dir2"]
root, dirs, files = consume(task)
end
for i=1:2
@test root == joinpath(".", "sub_dir1", "subsub_dir$i")
@test dirs == []
@test files == []
root, dirs, files = consume(task)
end
@test root == joinpath(".", "sub_dir1")
@test dirs == (has_symlinks ? ["link", "subsub_dir1", "subsub_dir2"] : ["subsub_dir1", "subsub_dir2"])
@test files == ["file1", "file2"]

root, dirs, files = consume(task)
@test root == joinpath(".", "sub_dir2")
@test dirs == []
@test files == ["file_dir2"]

root, dirs, files = consume(task)
@test root == "."
@test dirs == ["sub_dir1", "sub_dir2"]
@test files == ["file1", "file2"]
end
end
rm(dir, recursive=true)

############
# Clean up #
############
Expand Down

0 comments on commit 504281b

Please sign in to comment.