Skip to content

Commit

Permalink
Merge pull request JuliaLang#27082 from JuliaLang/kf/libgit2close
Browse files Browse the repository at this point in the history
Make LibGit2 GitRepo API robust against closed repos
  • Loading branch information
Keno authored May 12, 2018
2 parents 6863555 + a224143 commit 2a60371
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 1 deletion.
22 changes: 21 additions & 1 deletion stdlib/LibGit2/src/repository.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ in the `.git` subdirectory. This means that there is nowhere to check out the wo
tree, and no tracking information for remote branches or configurations is present.
"""
function isbare(repo::GitRepo)
@assert repo.ptr != C_NULL
return ccall((:git_repository_is_bare, :libgit2), Cint, (Ptr{Cvoid},), repo.ptr) == 1
end

Expand All @@ -101,6 +102,7 @@ Determine if `repo` is detached - that is, whether its HEAD points to a commit
(detached) or whether HEAD points to a branch tip (attached).
"""
function isattached(repo::GitRepo)
@assert repo.ptr != C_NULL
ccall((:git_repository_head_detached, :libgit2), Cint, (Ptr{Cvoid},), repo.ptr) != 1
end

Expand Down Expand Up @@ -129,6 +131,7 @@ end

function (::Type{T})(repo::GitRepo, spec::AbstractString) where T<:GitObject
obj_ptr_ptr = Ref{Ptr{Cvoid}}(C_NULL)
@assert repo.ptr != C_NULL
@check ccall((:git_revparse_single, :libgit2), Cint,
(Ptr{Ptr{Cvoid}}, Ptr{Cvoid}, Cstring), obj_ptr_ptr, repo.ptr, spec)
# check object is of correct type
Expand All @@ -143,6 +146,7 @@ function (::Type{T})(repo::GitRepo, oid::GitHash) where T<:GitObject
oid_ptr = Ref(oid)
obj_ptr_ptr = Ref{Ptr{Cvoid}}(C_NULL)

@assert repo.ptr != C_NULL
@check ccall((:git_object_lookup, :libgit2), Cint,
(Ptr{Ptr{Cvoid}}, Ptr{Cvoid}, Ptr{GitHash}, Consts.OBJECT),
obj_ptr_ptr, repo.ptr, oid_ptr, Consts.OBJECT(T))
Expand All @@ -153,6 +157,7 @@ function (::Type{T})(repo::GitRepo, oid::GitShortHash) where T<:GitObject
oid_ptr = Ref(oid.hash)
obj_ptr_ptr = Ref{Ptr{Cvoid}}(C_NULL)

@assert repo.ptr != C_NULL
@check ccall((:git_object_lookup_prefix, :libgit2), Cint,
(Ptr{Ptr{Cvoid}}, Ptr{Cvoid}, Ptr{GitHash}, Csize_t, Consts.OBJECT),
obj_ptr_ptr, repo.ptr, oid_ptr, oid.len, Consts.OBJECT(T))
Expand All @@ -174,6 +179,7 @@ Return the location of the "git" files of `repo`:
See also [`workdir`](@ref), [`path`](@ref).
"""
function gitdir(repo::GitRepo)
@assert repo.ptr != C_NULL
return unsafe_string(ccall((:git_repository_path, :libgit2), Cstring,
(Ptr{Cvoid},), repo.ptr))
end
Expand All @@ -193,6 +199,7 @@ This will throw an error for bare repositories.
See also [`gitdir`](@ref), [`path`](@ref).
"""
function workdir(repo::GitRepo)
@assert repo.ptr != C_NULL
sptr = ccall((:git_repository_workdir, :libgit2), Cstring,
(Ptr{Cvoid},), repo.ptr)
sptr == C_NULL && throw(GitError(Error.Object, Error.ERROR, "No working directory found."))
Expand Down Expand Up @@ -290,6 +297,7 @@ information.
"""
function GitDescribeResult(repo::GitRepo; options::DescribeOptions=DescribeOptions())
result_ptr_ptr = Ref{Ptr{Cvoid}}(C_NULL)
@assert repo.ptr != C_NULL
@check ccall((:git_describe_workdir, :libgit2), Cint,
(Ptr{Ptr{Cvoid}}, Ptr{Cvoid}, Ptr{DescribeOptions}),
result_ptr_ptr, repo.ptr, Ref(options))
Expand Down Expand Up @@ -330,6 +338,7 @@ be performed. See [`CheckoutOptions`](@ref) for more information.
"""
function checkout_tree(repo::GitRepo, obj::GitObject;
options::CheckoutOptions = CheckoutOptions())
@assert repo.ptr != C_NULL
@check ccall((:git_checkout_tree, :libgit2), Cint,
(Ptr{Cvoid}, Ptr{Cvoid}, Ptr{CheckoutOptions}),
repo.ptr, obj.ptr, Ref(options))
Expand All @@ -344,6 +353,7 @@ See [`CheckoutOptions`](@ref) for more information.
"""
function checkout_index(repo::GitRepo, idx::Union{GitIndex, Nothing} = nothing;
options::CheckoutOptions = CheckoutOptions())
@assert repo.ptr != C_NULL
@check ccall((:git_checkout_index, :libgit2), Cint,
(Ptr{Cvoid}, Ptr{Cvoid}, Ptr{CheckoutOptions}),
repo.ptr,
Expand All @@ -362,6 +372,7 @@ Update the index and working tree of `repo` to match the commit pointed to by HE
conflicts.
"""
function checkout_head(repo::GitRepo; options::CheckoutOptions = CheckoutOptions())
@assert repo.ptr != C_NULL
@check ccall((:git_checkout_head, :libgit2), Cint,
(Ptr{Cvoid}, Ptr{CheckoutOptions}),
repo.ptr, Ref(options))
Expand All @@ -379,13 +390,15 @@ The keyword argument `options` sets checkout and merge options for the cherrypic
call [`commit`](@ref) yourself.
"""
function cherrypick(repo::GitRepo, commit::GitCommit; options::CherrypickOptions = CherrypickOptions())
@assert repo.ptr != C_NULL
@check ccall((:git_cherrypick, :libgit2), Cint,
(Ptr{Cvoid}, Ptr{Cvoid}, Ptr{CherrypickOptions}),
repo.ptr, commit.ptr, Ref(options))
end

"""Updates some entries, determined by the `pathspecs`, in the index from the target commit tree."""
function reset!(repo::GitRepo, obj::Union{GitObject, Nothing}, pathspecs::AbstractString...)
@assert repo.ptr != C_NULL
@check ccall((:git_reset_default, :libgit2), Cint,
(Ptr{Cvoid}, Ptr{Cvoid}, Ptr{StrArrayStruct}),
repo.ptr,
Expand All @@ -397,6 +410,7 @@ end
"""Sets the current head to the specified commit oid and optionally resets the index and working tree to match."""
function reset!(repo::GitRepo, obj::GitObject, mode::Cint;
checkout_opts::CheckoutOptions = CheckoutOptions())
@assert repo.ptr != C_NULL
@check ccall((:git_reset, :libgit2), Cint,
(Ptr{Cvoid}, Ptr{Cvoid}, Cint, Ptr{CheckoutOptions}),
repo.ptr, obj.ptr, mode, Ref(checkout_opts))
Expand Down Expand Up @@ -452,6 +466,7 @@ false
function fetchheads(repo::GitRepo)
fh = FetchHead[]
ffcb = fetchhead_foreach_cb()
@assert repo.ptr != C_NULL
@check ccall((:git_repository_fetchhead_foreach, :libgit2), Cint,
(Ptr{Cvoid}, Ptr{Cvoid}, Any),
repo.ptr, ffcb, fh)
Expand All @@ -465,6 +480,7 @@ Return a vector of the names of the remotes of `repo`.
"""
function remotes(repo::GitRepo)
sa_ref = Ref(StrArrayStruct())
@assert repo.ptr != C_NULL
@check ccall((:git_remote_list, :libgit2), Cint,
(Ptr{StrArrayStruct}, Ptr{Cvoid}), sa_ref, repo.ptr)
res = convert(Vector{String}, sa_ref[])
Expand All @@ -474,6 +490,10 @@ end

function Base.show(io::IO, repo::GitRepo)
print(io, "LibGit2.GitRepo(")
show(io, path(repo))
if repo.ptr == C_NULL
print(io, "<closed>")
else
show(io, path(repo))
end
print(io, ")")
end
7 changes: 7 additions & 0 deletions stdlib/LibGit2/test/libgit2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,13 @@ mktempdir() do dir
end
end

@testset "Show closed repo" begin
# Make sure this doesn't crash
buf = IOBuffer()
Base.show(buf, LibGit2.with(identity, LibGit2.GitRepo(test_repo)))
@test String(take!(buf)) == "LibGit2.GitRepo(<closed>)"
end

@testset "Fetch from cache repository" begin
LibGit2.with(LibGit2.GitRepo(test_repo)) do repo
# fetch changes
Expand Down

0 comments on commit 2a60371

Please sign in to comment.