Skip to content

Commit

Permalink
Define GitShortHash and AbstractGitHash
Browse files Browse the repository at this point in the history
  • Loading branch information
ararslan committed Jan 6, 2017
1 parent 7d9edd3 commit 977fa7d
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 30 deletions.
13 changes: 13 additions & 0 deletions base/libgit2/blob.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,23 @@ function Base.length(blob::GitBlob)
return ccall((:git_blob_rawsize, :libgit2), Int64, (Ptr{Void},), blob.ptr)
end

"""
lookup(repo::GitRepo, oid::AbstractGitHash)
Look up the Git blob corresponding to the hash `oid` within the given repository.
"""
function lookup(repo::GitRepo, oid::GitHash)
blob_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
@check ccall((:git_blob_lookup, :libgit2), Cint,
(Ptr{Ptr{Void}}, Ptr{Void}, Ref{GitHash}),
blob_ptr_ptr, repo.ptr, Ref(oid))
return GitBlob(blob_ptr_ptr[])
end

function lookup(repo::GitRepo, oid::GitShortHash)
blob_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
@check ccall((:git_blob_lookup_prefix, :libgit2), Cint,
(Ptr{Ptr{Void}}, Ptr{Void}, Ref{GitHash}),
blob_ptr_ptr, repo.ptr, Ref(oid.hash), oid.len)
return GitBlob(blob_ptr_ptr[])
end
4 changes: 2 additions & 2 deletions base/libgit2/commit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ function commit(repo::GitRepo, msg::AbstractString;
refname::AbstractString=Consts.HEAD_FILE,
author::Signature = Signature(repo),
committer::Signature = Signature(repo),
tree_id::GitHash = GitHash(),
parent_ids::Vector{GitHash}=GitHash[])
tree_id::AbstractGitHash = GitHash(),
parent_ids::Vector{AbstractGitHash}=AbstractGitHash[])
# Retrieve tree identifier
if iszero(tree_id)
tree_id = with(GitIndex, repo) do idx; write_tree!(idx) end
Expand Down
2 changes: 1 addition & 1 deletion base/libgit2/index.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function owner(idx::GitIndex)
return GitRepo(repo_ptr)
end

function read_tree!(idx::GitIndex, tree_id::GitHash)
function read_tree!(idx::GitIndex, tree_id::AbstractGitHash)
repo = owner(idx)
tree = get(GitTree, repo, tree_id)
try
Expand Down
2 changes: 1 addition & 1 deletion base/libgit2/libgit2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ function reset!(repo::GitRepo, committish::AbstractString, pathspecs::AbstractSt
end

""" git reset [--soft | --mixed | --hard] <commit> """
function reset!(repo::GitRepo, commit::GitHash, mode::Cint = Consts.RESET_MIXED)
function reset!(repo::GitRepo, commit::AbstractGitHash, mode::Cint = Consts.RESET_MIXED)
obj = get(GitAnyObject, repo, commit)
# object must exist for reset
obj === nothing && throw(GitError(Error.Object, Error.ERROR, "Commit `$(string(commit))` object not found"))
Expand Down
2 changes: 2 additions & 0 deletions base/libgit2/merge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ function GitAnnotated(repo::GitRepo, commit_id::GitHash)
return GitAnnotated(ann_ptr_ptr[])
end

GitAnnotated(repo::GitRepo, commit_id::GitShortHash) = GitAnnotated(repo, commit_id.hash)

function GitAnnotated(repo::GitRepo, ref::GitReference)
ann_ref_ref = Ref{Ptr{Void}}(C_NULL)
@check ccall((:git_annotated_commit_from_ref, :libgit2), Cint,
Expand Down
81 changes: 71 additions & 10 deletions base/libgit2/oid.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,39 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

function _githash(h::String)
len = length(h)
if len == OID_HEXSZ
return GitHash(h)
elseif len < OID_HEXSZ
return GitShortHash(GitHash(h), len)
else
error("string \"$h\" is too long to be a Git hash")
end
end

"""
@githash_str
Construct a `GitHash` or `GitShortHash` depending on the length of the provided string.
"""
macro githash_str(h)
:(_githash($h))
end

GitHash(id::GitHash) = id
GitHash(ptr::Ptr{GitHash}) = unsafe_load(ptr)::GitHash

function GitHash(id::GitShortHash)
if id.len < OID_RAWSZ
throw(ArgumentError("cannot convert a GitShortHash with length < $OID_RAWSZ to a full GitHash"))
end
return id.hash
end

GitShortHash(id::GitShortHash) = id
GitShortHash(id::GitHash) = GitShortHash(id, OID_RAWSZ)
GitShortHash(ptr::Ptr{GitHash}) = GitShortHash(unsafe_load(ptr)::GitHash)

function GitHash(ptr::Ptr{UInt8})
if ptr == C_NULL
throw(ArgumentError("NULL pointer passed to GitHash() constructor"))
Expand All @@ -12,28 +43,38 @@ function GitHash(ptr::Ptr{UInt8})
return oid_ptr[]
end

GitShortHash(ptr::Ptr{UInt8}) = GitShortHash(GitHash(ptr))

function GitHash(id::Array{UInt8,1})
if length(id) != OID_RAWSZ
throw(ArgumentError("invalid raw buffer size"))
end
return GitHash(pointer(id))
end

GitShortHash(id::Array{UInt8,1}) = GitShortHash(GitHash(id))

function GitHash(id::AbstractString)
bstr = String(id)
len = sizeof(bstr)
oid_ptr = Ref(GitHash())
err = if len < OID_HEXSZ
ccall((:git_oid_fromstrn, :libgit2), Cint,
(Ptr{GitHash}, Ptr{UInt8}, Csize_t), oid_ptr, bstr, len)
else
ccall((:git_oid_fromstrp, :libgit2), Cint,
(Ptr{GitHash}, Cstring), oid_ptr, bstr)
end
err != 0 && return GitHash()
len == OID_RAWSZ || throw(ArgumentError("expected a string of length $OID_RAWSZ, got $len"))
oid_ptr = Ref(GitHash())
err = ccall((:git_oid_fromstrp, :libgit2), Cint,
(Ptr{GitHash}, Cstring), oid_ptr, bstr)
err == 0 || return GitHash()
return oid_ptr[]
end

function GitShortHash(id::AbstractString)
bstr = String(id)
len = sizeof(bstr)
oid_ptr = Ref(GitHash())
err = ccall((:git_oid_fromstrn, :libgit2), Cint,
(Ptr{GitHash}, Ptr{UInt8}, Csize_t), oid_ptr, bstr, len)
err == 0 || return GitShortHash(GitHash())
return GitShortHash(oid_ptr[], len)
end

function GitHash(ref::GitReference)
isempty(ref) && return GitHash()
reftype(ref) != Consts.REF_OID && return GitHash()
Expand All @@ -42,6 +83,8 @@ function GitHash(ref::GitReference)
return GitHash(oid_ptr)
end

GitShortHash(ref::GitReference) = GitShortHash(GitHash(ref))

function GitHash(repo::GitRepo, ref_name::AbstractString)
isempty(repo) && return GitHash()
oid_ptr = Ref(GitHash())
Expand All @@ -51,32 +94,47 @@ function GitHash(repo::GitRepo, ref_name::AbstractString)
return oid_ptr[]
end

GitShortHash(repo::GitRepo, ref_name::AbstractString) = GitShortHash(GitHash(repo, ref_name))

function GitHash(obj::Ptr{Void})
oid_ptr = ccall((:git_object_id, :libgit2), Ptr{UInt8}, (Ptr{Void},), obj)
oid_ptr == C_NULL && return GitHash()
return GitHash(oid_ptr)
end

GitShortHash(obj::Ptr{Void}) = GitShortHash(GitHash(obj))

function GitHash{T<:GitObject}(obj::T)
obj === nothing && return GitHash()
return GitHash(obj.ptr)
end

GitShortHash(obj::GitObject) = GitShortHash(GitHash(obj))

Base.hex(id::GitHash) = join([hex(i,2) for i in id.val])
Base.hex(id::GitShortHash) = join([hex(i,2) for i in id.hash.val[1:id.len]])

raw(id::GitHash) = collect(id.val)
raw(id::GitShortHash) = collect(id.hash.val[1:len])

Base.string(id::GitHash) = hex(id)
Base.string(id::GitShortHash) = hex(id.hash)

Base.show(io::IO, id::GitHash) = print(io, "GitHash($(string(id)))")
Base.show(io::IO, id::GitShortHash) = print(io, "GitShortHash($(string(id)[1:id.len]))")

Base.hash(id::GitHash, h::UInt) = hash(id.val, h)
Base.hash(id::GitShortHash, h::UInt) = hash(id.hash, h)

cmp(id1::GitHash, id2::GitHash) = Int(ccall((:git_oid_cmp, :libgit2), Cint,
(Ptr{GitHash}, Ptr{GitHash}), Ref(id1), Ref(id2)))
cmp(id1::GitShortHash, id2::GitShortHash) = cmp(id1.hash, id2.hash)

==(id1::GitHash, id2::GitHash) = cmp(id1, id2) == 0
Base.isless(id1::GitHash, id2::GitHash) = cmp(id1, id2) < 0
==(id1::GitShortHash, id2::GitShortHash) = cmp(id1, id2) == 0

Base.isless(id1::GitHash, id2::GitHash) = cmp(id1, id2) < 0
Base.isless(id1::GitShortHash, id2::GitShortHash) = cmp(id1, id2) < 0

function iszero(id::GitHash)
for i in 1:OID_RAWSZ
Expand All @@ -85,4 +143,7 @@ function iszero(id::GitHash)
return true
end

iszero(id::GitShortHash) = iszero(id.hash)

Base.zero(::Type{GitHash}) = GitHash()
Base.zero(::Type{GitShortHash}) = GitShortHash(GitHash())
39 changes: 25 additions & 14 deletions base/libgit2/repository.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,31 @@ function revparseid(repo::GitRepo, objname::AbstractString)
return oid
end

function get{T <: GitObject}(::Type{T}, r::GitRepo, oid::GitHash, oid_size::Int=OID_HEXSZ)
id_ptr = Ref(oid)
function get{T<:GitObject}(::Type{T}, r::GitRepo, oid::GitHash)
obj_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
git_otype = getobjecttype(T)

err = if oid_size != OID_HEXSZ
ccall((:git_object_lookup_prefix, :libgit2), Cint,
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{GitHash}, Csize_t, Cint),
obj_ptr_ptr, r.ptr, id_ptr, Csize_t(oid_size), git_otype)
else
ccall((:git_object_lookup, :libgit2), Cint,
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{GitHash}, Cint),
obj_ptr_ptr, r.ptr, id_ptr, git_otype)

err = ccall((:git_object_lookup, :libgit2), Cint,
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{GitHash}, Csize_t, Cint),
obj_ptr_ptr, r.ptr, Ref(oid), getobjecttype(T))

if err == Int(Error.ENOTFOUND)
return nothing
elseif err != Int(Error.GIT_OK)
if obj_ptr_ptr[] != C_NULL
finalize(GitAnyObject(obj_ptr_ptr[]))
end
throw(Error.GitError(err))
end
return T(obj_ptr_ptr[])
end

function get{T<:GitObject}(::Type{T}, r::GitRepo, oid::GitShortHash)
obj_ptr_ptr = Ref{Ptr{Void}}(C_NULL)

err = ccall((:git_object_lookup_prefix, :libgit2), Cint,
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{GitHash}, Csize_t, Cint),
obj_ptr_ptr, r.ptr, Ref(oid.hash), oid.len, getobjecttype(T))

if err == Int(Error.ENOTFOUND)
return nothing
elseif err != Int(Error.GIT_OK)
Expand All @@ -111,8 +122,8 @@ function get{T <: GitObject}(::Type{T}, r::GitRepo, oid::GitHash, oid_size::Int=
return T(obj_ptr_ptr[])
end

function get{T <: GitObject}(::Type{T}, r::GitRepo, oid::AbstractString)
return get(T, r, GitHash(oid), length(oid))
function get{T<:GitObject}(::Type{T}, r::GitRepo, oid::AbstractString)
return get(T, r, _githash(oid))
end

function gitdir(repo::GitRepo)
Expand Down
2 changes: 1 addition & 1 deletion base/libgit2/tag.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function tag_delete(repo::GitRepo, tag::AbstractString)
(Ptr{Void}, Cstring, ), repo.ptr, tag)
end

function tag_create(repo::GitRepo, tag::AbstractString, commit::Union{AbstractString,GitHash};
function tag_create(repo::GitRepo, tag::AbstractString, commit::Union{AbstractString,AbstractGitHash};
msg::AbstractString = "",
force::Bool = false,
sig::Signature = Signature(repo))
Expand Down
20 changes: 19 additions & 1 deletion base/libgit2/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,30 @@ const OID_RAWSZ = 20
const OID_HEXSZ = OID_RAWSZ * 2
const OID_MINPREFIXLEN = 4

immutable GitHash
abstract AbstractGitHash

"""
LibGit2.GitHash
The unique hash (also known as the object ID or OID) of any Git object.
Matches the [`git_oid`](https://libgit2.github.com/libgit2/#HEAD/type/git_oid) struct.
"""
immutable GitHash <: AbstractGitHash
val::NTuple{OID_RAWSZ, UInt8}
GitHash(val::NTuple{OID_RAWSZ, UInt8}) = new(val)
end
GitHash() = GitHash(ntuple(i->zero(UInt8), OID_RAWSZ))

"""
LibGit2.GitShortHash
An abbreviation with a specified length of a `LibGit2.GitHash`.
"""
immutable GitShortHash <: AbstractGitHash
hash::GitHash
len::Csize_t
end

"""
LibGit2.TimeStruct
Expand Down

0 comments on commit 977fa7d

Please sign in to comment.