Skip to content

Commit cfb77bb

Browse files
committed
Add support for a few more remote operations
* Detached remote * Read remote reference advertisement list * Read remote default branch
1 parent cb2a0d4 commit cfb77bb

File tree

4 files changed

+125
-1
lines changed

4 files changed

+125
-1
lines changed

stdlib/LibGit2/src/consts.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,4 +473,9 @@ end
473473
_OID_DEFAULT = 0,
474474
OID_SHA1 = 1)
475475

476+
# Direction of the connection.
477+
@enum(GIT_DIRECTION,
478+
DIRECTION_FETCH = 0,
479+
DIRECTION_PUSH = 1)
480+
476481
end

stdlib/LibGit2/src/remote.jl

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ function GitRemoteAnon(repo::GitRepo, url::AbstractString)
6363
return GitRemote(repo, rmt_ptr_ptr[])
6464
end
6565

66+
"""
67+
GitRemoteDetached(url::AbstractString) -> GitRemote
68+
69+
Create a remote without a connected local repo.
70+
"""
71+
function GitRemoteDetached(url::AbstractString)
72+
ensure_initialized()
73+
rmt_ptr_ptr = Ref{Ptr{Cvoid}}(C_NULL)
74+
@check ccall((:git_remote_create_detached, :libgit2), Cint,
75+
(Ptr{Ptr{Cvoid}}, Cstring), rmt_ptr_ptr, url)
76+
return GitRemote(rmt_ptr_ptr[])
77+
end
78+
6679
"""
6780
lookup_remote(repo::GitRepo, remote_name::AbstractString) -> Union{GitRemote, Nothing}
6881
@@ -414,3 +427,70 @@ function set_remote_url(path::AbstractString, remote_name::AbstractString, url::
414427
set_remote_url(repo, remote_name, url)
415428
end
416429
end
430+
431+
"""
432+
connect(rmt::GitRemote, direction::Consts.GIT_DIRECTION)
433+
434+
Open a connection to a remote. `direction` can be either `DIRECTION_FETCH`
435+
or `DIRECTION_PUSH`.
436+
"""
437+
function connect(rmt::GitRemote, direction::Consts.GIT_DIRECTION)
438+
@check ccall((:git_remote_connect, :libgit2),
439+
Cint, (Ptr{Cvoid}, Cint, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}),
440+
rmt.ptr, direction, C_NULL, C_NULL, C_NULL)
441+
return rmt
442+
end
443+
444+
"""
445+
connected(rmt::GitRemote)
446+
447+
Check whether the remote is connected
448+
"""
449+
function connected(rmt::GitRemote)
450+
return ccall((:git_remote_connected, :libgit2), Cint, (Ptr{Cvoid},), rmt.ptr) != 0
451+
end
452+
453+
"""
454+
disconnect(rmt::GitRemote)
455+
456+
Close the connection to the remote.
457+
"""
458+
function disconnect(rmt::GitRemote)
459+
@check ccall((:git_remote_disconnect, :libgit2), Cint, (Ptr{Cvoid},), rmt.ptr)
460+
return
461+
end
462+
463+
"""
464+
default_branch(rmt::GitRemote)
465+
466+
Retrieve the name of the remote's default branch.
467+
468+
This function must only be called after connecting (See [`connect`](@ref)).
469+
"""
470+
function default_branch(rmt::GitRemote)
471+
buf_ref = Ref(Buffer())
472+
@check ccall((:git_remote_default_branch, :libgit2), Cint,
473+
(Ptr{Buffer}, Ptr{Cvoid}), buf_ref, rmt.ptr)
474+
buf = buf_ref[]
475+
str = unsafe_string(buf.ptr, buf.size)
476+
free(buf_ref)
477+
return str
478+
end
479+
480+
"""
481+
ls(rmt::GitRemote) -> Vector{GitRemoteHead}
482+
483+
Get the remote repository's reference advertisement list.
484+
485+
This function must only be called after connecting (See [`connect`](@ref)).
486+
"""
487+
function ls(rmt::GitRemote)
488+
nheads = Ref{Csize_t}()
489+
head_refs = Ref{Ptr{Ptr{_GitRemoteHead}}}()
490+
@check ccall((:git_remote_ls, :libgit2), Cint,
491+
(Ptr{Ptr{Ptr{_GitRemoteHead}}}, Ptr{Csize_t}, Ptr{Cvoid}),
492+
head_refs, nheads, rmt.ptr)
493+
head_ptr = head_refs[]
494+
return [GitRemoteHead(unsafe_load(unsafe_load(head_ptr, i)))
495+
for i in 1:nheads[]]
496+
end

stdlib/LibGit2/src/types.jl

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,7 @@ for (typ, owntyp, sup, cname) in Tuple{Symbol,Any,Symbol,Symbol}[
10071007
(:GitRepo, nothing, :AbstractGitObject, :git_repository),
10081008
(:GitConfig, :(Union{GitRepo, Nothing}), :AbstractGitObject, :git_config),
10091009
(:GitIndex, :(Union{GitRepo, Nothing}), :AbstractGitObject, :git_index),
1010-
(:GitRemote, :GitRepo, :AbstractGitObject, :git_remote),
1010+
(:GitRemote, :(Union{GitRepo, Nothing}), :AbstractGitObject, :git_remote),
10111011
(:GitRevWalker, :GitRepo, :AbstractGitObject, :git_revwalk),
10121012
(:GitReference, :GitRepo, :AbstractGitObject, :git_reference),
10131013
(:GitDescribeResult, :GitRepo, :AbstractGitObject, :git_describe_result),
@@ -1483,3 +1483,26 @@ end
14831483

14841484
# Useful for functions which can handle various kinds of credentials
14851485
const Creds = Union{CredentialPayload, AbstractCredential, CachedCredentials, Nothing}
1486+
1487+
struct _GitRemoteHead
1488+
available_local::Cint
1489+
oid::GitHash
1490+
loid::GitHash
1491+
name::Cstring
1492+
symref_target::Cstring
1493+
end
1494+
1495+
struct GitRemoteHead
1496+
available_local::Bool
1497+
oid::GitHash
1498+
loid::GitHash
1499+
name::String
1500+
symref_target::Union{Nothing,String}
1501+
function GitRemoteHead(head::_GitRemoteHead)
1502+
name = unsafe_string(head.name)
1503+
symref_target = (head.symref_target != C_NULL ?
1504+
unsafe_string(head.symref_target) : nothing)
1505+
return new(head.available_local != 0,
1506+
head.oid, head.loid, name, symref_target)
1507+
end
1508+
end

stdlib/LibGit2/test/online-tests.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,22 @@ mktempdir() do dir
9090
end
9191
end
9292

93+
@testset "Remote" begin
94+
repo_url = "https://github.com/JuliaLang/Example.jl"
95+
LibGit2.with(LibGit2.GitRemoteDetached(repo_url)) do remote
96+
@test !LibGit2.connected(remote)
97+
LibGit2.connect(remote, LibGit2.Consts.DIRECTION_FETCH)
98+
@test LibGit2.connected(remote)
99+
remote_heads = LibGit2.ls(remote)
100+
default_branch = LibGit2.default_branch(remote)
101+
@test !isempty(remote_heads)
102+
@test startswith(default_branch, "refs/heads/")
103+
@test any(head.name == default_branch for head in remote_heads)
104+
LibGit2.disconnect(remote)
105+
@test !LibGit2.connected(remote)
106+
end
107+
end
108+
93109
# needs to be run in separate process so it can re-initialize libgit2
94110
# with a useless self-signed certificate authority root certificate
95111
file = joinpath(@__DIR__, "bad_ca_roots.jl")

0 commit comments

Comments
 (0)