Skip to content

Commit

Permalink
Merge pull request JuliaLang#33113 from JuliaLang/sk/readdir
Browse files Browse the repository at this point in the history
readdir: add `join` option to join `dir` with names
  • Loading branch information
StefanKarpinski committed Aug 30, 2019
2 parents 1b90a88 + 1ec9ab4 commit 2021d03
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 15 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ New library functions
* The `splitpath` function now accepts any `AbstractString` whereas previously it only accepted paths of type `String` ([#33012]).
* The `tempname` function now takes an optional `parent::AbstractString` argument to give it a directory in which to attempt to produce a temporary path name ([#33090]).
* The `tempname` function now takes a `cleanup::Bool` keyword argument defaulting to `true`, which causes the process to try to ensure that any file or directory at the path returned by `tempname` is deleted upon process exit ([#33090]).
* The `readdir` function now takes a `join::Bool` keyword argument defaulting to `false`, which when set causes `readdir` to join its directory argument with each listed name ([#33113]).


Standard library changes
Expand Down
74 changes: 59 additions & 15 deletions base/file.jl
Original file line number Diff line number Diff line change
Expand Up @@ -671,41 +671,87 @@ struct uv_dirent_t
end

"""
readdir(dir::AbstractString=".") -> Vector{String}
readdir(dir::AbstractString=pwd(); join::Bool=true) -> Vector{String}
Return the files and directories in the directory `dir` (or the current working directory if not given).
Return the names in the directory `dir` or the current working directory if not
given. When `join` is false, `readdir` returns just the names in the directory
as is; when `join` is true, it returns `joinpath(dir, name)` for each `name` so
that the returned strings are full paths. If you want to get absolute paths
back, call `readdir` with an absolute directory path and `join` set to true.
!!! compat "Julia 1.4"
The `join` keyword argument requires at least Julia 1.4.
# Examples
```julia-repl
julia> readdir("/home/JuliaUser/Projects/julia")
34-element Array{String,1}:
".circleci"
".freebsdci.sh"
julia> cd("/home/JuliaUser/dev/julia")
julia> readdir()
30-element Array{String,1}:
".appveyor.yml"
".git"
".gitattributes"
".github"
"test"
"ui"
"usr"
"usr-staging"
julia> readdir(join=true)
30-element Array{String,1}:
"/home/JuliaUser/dev/julia/.appveyor.yml"
"/home/JuliaUser/dev/julia/.git"
"/home/JuliaUser/dev/julia/.gitattributes"
"/home/JuliaUser/dev/julia/ui"
"/home/JuliaUser/dev/julia/usr"
"/home/JuliaUser/dev/julia/usr-staging"
julia> readdir("base")
145-element Array{String,1}:
".gitignore"
"Base.jl"
"Enums.jl"
"version_git.sh"
"views.jl"
"weakkeydict.jl"
julia> readdir("base", join=true)
145-element Array{String,1}:
"base/.gitignore"
"base/Base.jl"
"base/Enums.jl"
"base/version_git.sh"
"base/views.jl"
"base/weakkeydict.jl"```
julia> readdir(abspath("base"), join=true)
145-element Array{String,1}:
"/home/JuliaUser/dev/julia/base/.gitignore"
"/home/JuliaUser/dev/julia/base/Base.jl"
"/home/JuliaUser/dev/julia/base/Enums.jl"
"/home/JuliaUser/dev/julia/base/version_git.sh"
"/home/JuliaUser/dev/julia/base/views.jl"
"/home/JuliaUser/dev/julia/base/weakkeydict.jl"
```
"""
function readdir(path::AbstractString)
function readdir(dir::AbstractString=pwd(); join::Bool=false)
# Allocate space for uv_fs_t struct
uv_readdir_req = zeros(UInt8, ccall(:jl_sizeof_uv_fs_t, Int32, ()))

# defined in sys.c, to call uv_fs_readdir, which sets errno on error.
err = ccall(:uv_fs_scandir, Int32, (Ptr{Cvoid}, Ptr{UInt8}, Cstring, Cint, Ptr{Cvoid}),
C_NULL, uv_readdir_req, path, 0, C_NULL)
err < 0 && throw(SystemError("unable to read directory $path", -err))
#uv_error("unable to read directory $path", err)
C_NULL, uv_readdir_req, dir, 0, C_NULL)
err < 0 && throw(SystemError("unable to read directory $dir", -err))

# iterate the listing into entries
entries = String[]
ent = Ref{uv_dirent_t}()
while Base.UV_EOF != ccall(:uv_fs_scandir_next, Cint, (Ptr{Cvoid}, Ptr{uv_dirent_t}), uv_readdir_req, ent)
push!(entries, unsafe_string(ent[].name))
name = unsafe_string(ent[].name)
push!(entries, join ? joinpath(dir, name) : name)
end

# Clean up the request string
Expand All @@ -714,8 +760,6 @@ function readdir(path::AbstractString)
return entries
end

readdir() = readdir(".")

"""
walkdir(dir; topdown=true, follow_symlinks=false, onerror=throw)
Expand Down
28 changes: 28 additions & 0 deletions test/file.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1404,3 +1404,31 @@ end
@test sizeof(basename(tmpdir)) == 6
end
end

@testset "readir tests" begin
(a, b) = sort(a) == sort(b)
mktempdir() do dir
d = cd(pwd, dir) # might resolve symlinks
@test isempty(readdir(d))
@test isempty(readdir(d, join=true))
cd(d) do
@test isempty(readdir())
@test isempty(readdir(join=true))
end
touch(joinpath(d, "file"))
mkdir(joinpath(d, "dir"))
names = ["dir", "file"]
paths = [joinpath(d, x) for x in names]
@test readdir(d) names
@test readdir(d, join=true) paths
cd(d) do
@test readdir() names
@test readdir(join=true) paths
end
t, b = splitdir(d)
cd(t) do
@test readdir(b) names
@test readdir(b, join=true) [joinpath(b, x) for x in names]
end
end
end

0 comments on commit 2021d03

Please sign in to comment.