Skip to content
8 changes: 2 additions & 6 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,8 @@ version = "0.5.0"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[compat]
julia = "1"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test"]
43 changes: 21 additions & 22 deletions src/FilePathsBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ module FilePathsBase
using Dates
using LinearAlgebra
using Printf
using UUIDs

import Base: ==
export
# Types
AbstractPath,
Path,
SystemPath,
PosixPath,
WindowsPath,
Mode,
Expand All @@ -21,7 +23,7 @@ export
cwd,
drive,
home,
parts,
components,
root,
hasparent,
parents,
Expand All @@ -34,7 +36,10 @@ export
created,
modified,
relative,
move,
ismount,
islink,
cp,
mv,
remove,
tmpname,
tmpdir,
Expand All @@ -45,6 +50,8 @@ export
readable,
writable,
raw,
readpath,
walkpath,

# Macros
@p_str,
Expand Down Expand Up @@ -73,44 +80,36 @@ Defines an abstract filesystem path. Subtypes of `AbstractPath` should implement
following methods:

- `Base.print(io, p)` (default: call base julia's joinpath with drive and path parts)
- `FilePathsBase.parts(p)`
- `FilePathsBase.path(p)`
- `FilePathsBase.root(p)`
- `FilePathsBase.drive(p)`
- `FilePathsBase.ispathtype(::Type{MyPath}, x::AbstractString) = true`
"""
abstract type AbstractPath end
abstract type AbstractPath end # Define the AbstractPath here to avoid circular include dependencies

"""
register(::Type{<:AbstractPath})

Registers a new path type to support using `Path("...")` constructor and p"..." string
macro.
"""
function register(T::Type{<:AbstractPath})
# We add the type to the beginning of our PATH_TYPES,
# so that they can take precedence over the Posix and
# Windows paths.
pushfirst!(PATH_TYPES, T)
end

#=
We only want to print the macro string syntax when compact is true and
we want print to just return the string (this allows `string` to work normally)
=#
Base.print(io::IO, path::AbstractPath) = print(io, joinpath(drive(path), parts(path)...))

function Base.show(io::IO, path::AbstractPath)
get(io, :compact, false) ? print(io, path) : print(io, "p\"$path\"")
end

Base.parse(::Type{<:AbstractPath}, x::AbstractString) = Path(x)
Base.convert(::Type{AbstractPath}, x::AbstractString) = Path(x)
Base.convert(::Type{String}, x::AbstractPath) = string(x)
Base.promote_rule(::Type{String}, ::Type{<:AbstractPath}) = String
ispathtype(::Type{<:AbstractPath}, x::AbstractString) = false

include("constants.jl")
include("utils.jl")
include("libc.jl")
include("mode.jl")
include("status.jl")
include("buffer.jl")
include("path.jl")
include("posix.jl")
include("windows.jl")
include("path.jl")
include("deprecates.jl")
include("system.jl")
include("test.jl")

end # end of module
87 changes: 87 additions & 0 deletions src/buffer.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""
FileBuffer <: IO

A generic buffer type to provide an IO interface for none IO based path types.

NOTES:
- All `read` operations will read the entire file into the internal buffer at once.
Subsequent calls to `read` will only operate on the internal buffer and will not access
the filepath.
- All `write` operations will only write to the internal buffer and `flush`/`close` are
required to update the filepath contents.
"""
struct FileBuffer <: IO
path::AbstractPath
io::IOBuffer
read::Bool
write::Bool
create::Bool
end

function FileBuffer(
fp::AbstractPath; read=true, write=false, create=false, truncate=false, append=false
)
buffer = FileBuffer(fp, IOBuffer(), read, write, create)

# If we're wanting to append data then we we need to prepopulate the internal buffer
if write && append
_read(buffer)
seekend(buffer)
end

return buffer
end

Base.isreadable(buffer::FileBuffer) = buffer.read
Base.iswritable(buffer::FileBuffer) = buffer.write
Base.seek(buffer::FileBuffer, n::Integer) = seek(buffer.io, n)
Base.seekstart(buffer::FileBuffer) = seekstart(buffer.io)
Base.seekend(buffer::FileBuffer) = seekend(buffer.io)
Base.eof(buffer::FileBuffer) = eof(buffer.io)

function _read(buffer::FileBuffer)
# If our IOBuffer is empty then populate it with the
# filepath contents
if buffer.io.size == 0
write(buffer.io, read(buffer.path))
end
end

function Base.read(buffer::FileBuffer)
isreadable(buffer) || throw(ArgumentError("read failed, FileBuffer is not readable"))
_read(buffer)
seekstart(buffer)
read(buffer.io)
end

function Base.read(buffer::FileBuffer, ::Type{String})
isreadable(buffer) || throw(ArgumentError("read failed, FileBuffer is not readable"))
_read(buffer)
seekstart(buffer)
read(buffer.io, String)
end

#=
NOTE: We need to define multiple methods because of ambiguity error with base IO methods.
=#
function Base.write(buffer::FileBuffer, x::Vector{UInt8})
iswritable(buffer) || throw(ArgumentError("write failed, FileBuffer is not writeable"))
write(buffer.io, x)
end

function Base.write(buffer::FileBuffer, x::String)
iswritable(buffer) || throw(ArgumentError("write failed, FileBuffer is not writeable"))
write(buffer.io, x)
end

function Base.flush(buffer::FileBuffer)
if iswritable(buffer)
seekstart(buffer)
write(buffer.path, read(buffer.io))
end
end

function Base.close(buffer::FileBuffer)
flush(buffer)
close(buffer.io)
end
20 changes: 10 additions & 10 deletions src/deprecates.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import Base:
mv,
rm

@deprecate dirname(path::AbstractPath) parent(path)
@deprecate ispath(path::AbstractPath) exists(path)
@deprecate realpath(path::AbstractPath) real(path)
@deprecate normpath(path::AbstractPath) norm(path)
@deprecate abspath(path::AbstractPath) abs(path)
@deprecate relpath(path::AbstractPath) relative(path)
@deprecate filemode(path::AbstractPath) mode(path)
@deprecate isabspath(path::AbstractPath) isabs(path)
@deprecate mkpath(path::AbstractPath) mkdir(path; recursive=true, exist_ok=true)
@deprecate dirname(fp::AbstractPath) parent(fp)
@deprecate ispath(fp::AbstractPath) exists(fp)
@deprecate realpath(fp::AbstractPath) real(fp)
@deprecate normpath(fp::AbstractPath) norm(fp)
@deprecate abspath(fp::AbstractPath) abs(fp)
@deprecate relpath(fp::AbstractPath) relative(fp)
@deprecate filemode(fp::AbstractPath) mode(fp)
@deprecate isabspath(fp::AbstractPath) isabs(fp)
@deprecate mkpath(fp::AbstractPath) mkdir(fp; recursive=true, exist_ok=true)
@deprecate mv(src::AbstractPath, dest::AbstractPath; kwargs...) move(src, dest; kwargs...)
@deprecate rm(path::AbstractPath; kwargs...) remove(path; kwargs...)
@deprecate rm(fp::AbstractPath; kwargs...) remove(fp; kwargs...)
Loading