Add: julia-0.6.2
Former-commit-id: ccc667cf67d569f3fb3df39aa57c2134755a7551
This commit is contained in:
69
julia-0.6.2/share/julia/base/libgit2/blob.jl
Normal file
69
julia-0.6.2/share/julia/base/libgit2/blob.jl
Normal file
@@ -0,0 +1,69 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function Base.length(blob::GitBlob)
|
||||
return ccall((:git_blob_rawsize, :libgit2), Int64, (Ptr{Void},), blob.ptr)
|
||||
end
|
||||
|
||||
function rawcontent(blob::GitBlob)
|
||||
ptr = ccall((:git_blob_rawcontent, :libgit2), Ptr{UInt8}, (Ptr{Void},), blob.ptr)
|
||||
copy(unsafe_wrap(Array, ptr, (length(blob),), false))
|
||||
end
|
||||
|
||||
"""
|
||||
content(blob::GitBlob)
|
||||
|
||||
Fetch the contents of the `GitBlob` `blob`. If the `blob` contains
|
||||
binary data (which can be determined using [`isbinary`](@ref)),
|
||||
throw an error. Otherwise, return a `String` containing the contents
|
||||
of the `blob`.
|
||||
"""
|
||||
function content(blob::GitBlob)
|
||||
s = String(rawcontent(blob))
|
||||
isvalid(s) || error("Blob does not contain valid UTF-8 data")
|
||||
return s
|
||||
end
|
||||
|
||||
"""
|
||||
Use a heuristic to guess if a file is binary: searching for NULL bytes and
|
||||
looking for a reasonable ratio of printable to non-printable characters among
|
||||
the first 8000 bytes.
|
||||
"""
|
||||
function isbinary(blob::GitBlob)
|
||||
bin_flag = ccall((:git_blob_is_binary, :libgit2), Cint, (Ptr{Void},), blob.ptr)
|
||||
return bin_flag == 1
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.addblob!(repo::GitRepo, path::AbstractString)
|
||||
|
||||
Reads the file at `path` and adds it to the object database of `repo` as a loose blob.
|
||||
Returns the `GitHash` of the resulting blob.
|
||||
|
||||
# Example
|
||||
|
||||
```julia
|
||||
hash_str = hex(commit_oid)
|
||||
blob_file = joinpath(repo_path, ".git", "objects", hash_str[1:2], hash_str[3:end])
|
||||
id = LibGit2.addblob!(repo, blob_file)
|
||||
```
|
||||
"""
|
||||
function addblob!(repo::GitRepo, path::AbstractString)
|
||||
id_ref = Ref{GitHash}()
|
||||
@check ccall((:git_blob_create_fromdisk, :libgit2), Cint,
|
||||
(Ptr{GitHash}, Ptr{Void}, Cstring),
|
||||
id_ref, repo.ptr, path)
|
||||
return id_ref[]
|
||||
end
|
||||
|
||||
function Base.show(io::IO, blob::GitBlob)
|
||||
if !isbinary(blob)
|
||||
conts = split(content(blob), "\n")
|
||||
showlen = max(length(conts), 3)
|
||||
println(io, "GitBlob:\nBlob id: ", GitHash(blob), "\nContents:")
|
||||
for i in 1:showlen
|
||||
println(io, conts[i])
|
||||
end
|
||||
else
|
||||
println(io, "GitBlob:\nBlob id: ", GitHash(blob), "\nContents are binary.")
|
||||
end
|
||||
end
|
||||
265
julia-0.6.2/share/julia/base/libgit2/callbacks.jl
Normal file
265
julia-0.6.2/share/julia/base/libgit2/callbacks.jl
Normal file
@@ -0,0 +1,265 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
"""Mirror callback function
|
||||
|
||||
Function sets `+refs/*:refs/*` refspecs and `mirror` flag for remote reference.
|
||||
"""
|
||||
function mirror_callback(remote::Ptr{Ptr{Void}}, repo_ptr::Ptr{Void},
|
||||
name::Cstring, url::Cstring, payload::Ptr{Void})
|
||||
# Create the remote with a mirroring url
|
||||
fetch_spec = "+refs/*:refs/*"
|
||||
err = ccall((:git_remote_create_with_fetchspec, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cstring, Cstring, Cstring),
|
||||
remote, repo_ptr, name, url, fetch_spec)
|
||||
err != 0 && return Cint(err)
|
||||
|
||||
# And set the configuration option to true for the push command
|
||||
config = GitConfig(GitRepo(repo_ptr,false))
|
||||
name_str = unsafe_string(name)
|
||||
err= try set!(config, "remote.$name_str.mirror", true)
|
||||
catch -1
|
||||
finally close(config)
|
||||
end
|
||||
err != 0 && return Cint(err)
|
||||
return Cint(0)
|
||||
end
|
||||
|
||||
function authenticate_ssh(creds::SSHCredentials, libgit2credptr::Ptr{Ptr{Void}},
|
||||
username_ptr, schema, host)
|
||||
isusedcreds = checkused!(creds)
|
||||
|
||||
# Note: The same SSHCredentials can be used to authenticate separate requests using the
|
||||
# same credential cache. e.g. using Pkg.update when there are two private packages.
|
||||
errcls, errmsg = Error.last_error()
|
||||
if errcls != Error.None
|
||||
# Check if we used ssh-agent
|
||||
if creds.usesshagent == "U"
|
||||
creds.usesshagent = "E" # reported ssh-agent error, disables ssh agent use for the future
|
||||
end
|
||||
end
|
||||
|
||||
# first try ssh-agent if credentials support its usage
|
||||
if creds.usesshagent == "Y" || creds.usesshagent == "U"
|
||||
err = ccall((:git_cred_ssh_key_from_agent, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Cstring), libgit2credptr, username_ptr)
|
||||
creds.usesshagent = "U" # used ssh-agent only one time
|
||||
err == 0 && return Cint(0)
|
||||
end
|
||||
|
||||
if creds.prompt_if_incorrect
|
||||
# if username is not provided, then prompt for it
|
||||
username = if username_ptr == Cstring(C_NULL)
|
||||
uname = creds.user # check if credentials were already used
|
||||
!isusedcreds ? uname : prompt("Username for '$schema$host'", default=uname)
|
||||
else
|
||||
unsafe_string(username_ptr)
|
||||
end
|
||||
isempty(username) && return Cint(Error.EAUTH)
|
||||
|
||||
# For SSH we need a private key location
|
||||
privatekey = if haskey(ENV,"SSH_KEY_PATH")
|
||||
ENV["SSH_KEY_PATH"]
|
||||
else
|
||||
keydefpath = creds.prvkey # check if credentials were already used
|
||||
if isempty(keydefpath) || isusedcreds
|
||||
defaultkeydefpath = joinpath(homedir(),".ssh","id_rsa")
|
||||
if isempty(keydefpath) && isfile(defaultkeydefpath)
|
||||
keydefpath = defaultkeydefpath
|
||||
else
|
||||
keydefpath =
|
||||
prompt("Private key location for '$schema$username@$host'", default=keydefpath)
|
||||
end
|
||||
end
|
||||
keydefpath
|
||||
end
|
||||
|
||||
# If the private key changed, invalidate the cached public key
|
||||
(privatekey != creds.prvkey) &&
|
||||
(creds.pubkey = "")
|
||||
|
||||
# For SSH we need a public key location, look for environment vars SSH_* as well
|
||||
publickey = if haskey(ENV,"SSH_PUB_KEY_PATH")
|
||||
ENV["SSH_PUB_KEY_PATH"]
|
||||
else
|
||||
keydefpath = creds.pubkey # check if credentials were already used
|
||||
if isempty(keydefpath) || isusedcreds
|
||||
if isempty(keydefpath)
|
||||
keydefpath = privatekey*".pub"
|
||||
end
|
||||
if !isfile(keydefpath)
|
||||
prompt("Public key location for '$schema$username@$host'", default=keydefpath)
|
||||
end
|
||||
end
|
||||
keydefpath
|
||||
end
|
||||
|
||||
passphrase_required = true
|
||||
if !isfile(privatekey)
|
||||
warn("Private key not found")
|
||||
else
|
||||
# In encrypted private keys, the second line is "Proc-Type: 4,ENCRYPTED"
|
||||
open(privatekey) do f
|
||||
readline(f)
|
||||
passphrase_required = readline(f) == "Proc-Type: 4,ENCRYPTED"
|
||||
end
|
||||
end
|
||||
|
||||
passphrase = if haskey(ENV,"SSH_KEY_PASS")
|
||||
ENV["SSH_KEY_PASS"]
|
||||
else
|
||||
passdef = creds.pass # check if credentials were already used
|
||||
if passphrase_required && (isempty(passdef) || isusedcreds)
|
||||
if is_windows()
|
||||
passdef = Base.winprompt(
|
||||
"Your SSH Key requires a password, please enter it now:",
|
||||
"Passphrase required", privatekey; prompt_username = false)
|
||||
isnull(passdef) && return Cint(Error.EAUTH)
|
||||
passdef = Base.get(passdef)[2]
|
||||
else
|
||||
passdef = prompt("Passphrase for $privatekey", password=true)
|
||||
end
|
||||
end
|
||||
passdef
|
||||
end
|
||||
((creds.user != username) || (creds.pass != passphrase) ||
|
||||
(creds.prvkey != privatekey) || (creds.pubkey != publickey)) && reset!(creds)
|
||||
|
||||
creds.user = username # save credentials
|
||||
creds.prvkey = privatekey # save credentials
|
||||
creds.pubkey = publickey # save credentials
|
||||
creds.pass = passphrase
|
||||
else
|
||||
isusedcreds && return Cint(Error.EAUTH)
|
||||
end
|
||||
|
||||
return ccall((:git_cred_ssh_key_new, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Cstring, Cstring, Cstring, Cstring),
|
||||
libgit2credptr, creds.user, creds.pubkey, creds.prvkey, creds.pass)
|
||||
end
|
||||
|
||||
function authenticate_userpass(creds::UserPasswordCredentials, libgit2credptr::Ptr{Ptr{Void}},
|
||||
schema, host, urlusername)
|
||||
isusedcreds = checkused!(creds)
|
||||
|
||||
if creds.prompt_if_incorrect
|
||||
username = creds.user
|
||||
userpass = creds.pass
|
||||
if is_windows()
|
||||
if isempty(username) || isempty(userpass) || isusedcreds
|
||||
res = Base.winprompt("Please enter your credentials for '$schema$host'", "Credentials required",
|
||||
isempty(username) ? urlusername : username; prompt_username = true)
|
||||
isnull(res) && return Cint(Error.EAUTH)
|
||||
username, userpass = Base.get(res)
|
||||
end
|
||||
elseif isusedcreds
|
||||
username = prompt("Username for '$schema$host'",
|
||||
default=isempty(username) ? urlusername : username)
|
||||
userpass = prompt("Password for '$schema$username@$host'", password=true)
|
||||
end
|
||||
((creds.user != username) || (creds.pass != userpass)) && reset!(creds)
|
||||
creds.user = username # save credentials
|
||||
creds.pass = userpass # save credentials
|
||||
|
||||
isempty(username) && isempty(userpass) && return Cint(Error.EAUTH)
|
||||
else
|
||||
isusedcreds && return Cint(Error.EAUTH)
|
||||
end
|
||||
|
||||
return ccall((:git_cred_userpass_plaintext_new, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Cstring, Cstring),
|
||||
libgit2credptr, creds.user, creds.pass)
|
||||
end
|
||||
|
||||
|
||||
"""Credentials callback function
|
||||
|
||||
Function provides different credential acquisition functionality w.r.t. a connection protocol.
|
||||
If a payload is provided then `payload_ptr` should contain a `LibGit2.AbstractCredentials` object.
|
||||
|
||||
For `LibGit2.Consts.CREDTYPE_USERPASS_PLAINTEXT` type, if the payload contains fields:
|
||||
`user` & `pass`, they are used to create authentication credentials.
|
||||
Empty `user` name and `pass`word trigger an authentication error.
|
||||
|
||||
For `LibGit2.Consts.CREDTYPE_SSH_KEY` type, if the payload contains fields:
|
||||
`user`, `prvkey`, `pubkey` & `pass`, they are used to create authentication credentials.
|
||||
Empty `user` name triggers an authentication error.
|
||||
|
||||
Credentials are checked in the following order (if supported):
|
||||
- ssh key pair (`ssh-agent` if specified in payload's `usesshagent` field)
|
||||
- plain text
|
||||
|
||||
**Note**: Due to the specifics of the `libgit2` authentication procedure, when
|
||||
authentication fails, this function is called again without any indication whether
|
||||
authentication was successful or not. To avoid an infinite loop from repeatedly
|
||||
using the same faulty credentials, the `checkused!` function can be called. This
|
||||
function returns `true` if the credentials were used.
|
||||
Using credentials triggers a user prompt for (re)entering required information.
|
||||
`UserPasswordCredentials` and `CachedCredentials` are implemented using a call
|
||||
counting strategy that prevents repeated usage of faulty credentials.
|
||||
"""
|
||||
function credentials_callback(libgit2credptr::Ptr{Ptr{Void}}, url_ptr::Cstring,
|
||||
username_ptr::Cstring,
|
||||
allowed_types::Cuint, payload_ptr::Ptr{Void})
|
||||
err = Cint(0)
|
||||
url = unsafe_string(url_ptr)
|
||||
|
||||
# parse url for schema and host
|
||||
urlparts = match(URL_REGEX, url)
|
||||
schema = urlparts[:scheme] === nothing ? "" : urlparts[:scheme] * "://"
|
||||
urlusername = urlparts[:user] === nothing ? "" : urlparts[:user]
|
||||
host = urlparts[:host]
|
||||
|
||||
# get credentials object from payload pointer
|
||||
@assert payload_ptr != C_NULL
|
||||
creds = unsafe_pointer_to_objref(payload_ptr)
|
||||
explicit = !isnull(creds[]) && !isa(Base.get(creds[]), CachedCredentials)
|
||||
# use ssh key or ssh-agent
|
||||
if isset(allowed_types, Cuint(Consts.CREDTYPE_SSH_KEY))
|
||||
sshcreds = get_creds!(creds, "ssh://$host", reset!(SSHCredentials(true), -1))
|
||||
if isa(sshcreds, SSHCredentials)
|
||||
err = authenticate_ssh(sshcreds, libgit2credptr, username_ptr, schema, host)
|
||||
err == 0 && return err
|
||||
end
|
||||
end
|
||||
|
||||
if isset(allowed_types, Cuint(Consts.CREDTYPE_USERPASS_PLAINTEXT))
|
||||
defaultcreds = reset!(UserPasswordCredentials(true), -1)
|
||||
credid = "$schema$host"
|
||||
upcreds = get_creds!(creds, credid, defaultcreds)
|
||||
# If there were stored SSH credentials, but we ended up here that must
|
||||
# mean that something went wrong. Replace the SSH credentials by user/pass
|
||||
# credentials
|
||||
if !isa(upcreds, UserPasswordCredentials)
|
||||
upcreds = defaultcreds
|
||||
isa(Base.get(creds[]), CachedCredentials) && (Base.get(creds[]).creds[credid] = upcreds)
|
||||
end
|
||||
return authenticate_userpass(upcreds, libgit2credptr, schema, host, urlusername)
|
||||
end
|
||||
|
||||
# No authentication method we support succeeded. The most likely cause is
|
||||
# that explicit credentials were passed in, but said credentials are incompatible
|
||||
# with the remote host.
|
||||
if err == 0
|
||||
if explicit
|
||||
warn("The explicitly provided credentials were incompatible with " *
|
||||
"the server's supported authentication methods")
|
||||
end
|
||||
err = Cint(Error.EAUTH)
|
||||
end
|
||||
return err
|
||||
end
|
||||
|
||||
function fetchhead_foreach_callback(ref_name::Cstring, remote_url::Cstring,
|
||||
oid_ptr::Ptr{GitHash}, is_merge::Cuint, payload::Ptr{Void})
|
||||
fhead_vec = unsafe_pointer_to_objref(payload)::Vector{FetchHead}
|
||||
push!(fhead_vec, FetchHead(unsafe_string(ref_name), unsafe_string(remote_url),
|
||||
unsafe_load(oid_ptr), is_merge == 1))
|
||||
return Cint(0)
|
||||
end
|
||||
|
||||
"C function pointer for `mirror_callback`"
|
||||
mirror_cb() = cfunction(mirror_callback, Cint, Tuple{Ptr{Ptr{Void}}, Ptr{Void}, Cstring, Cstring, Ptr{Void}})
|
||||
"C function pointer for `credentials_callback`"
|
||||
credentials_cb() = cfunction(credentials_callback, Cint, Tuple{Ptr{Ptr{Void}}, Cstring, Cstring, Cuint, Ptr{Void}})
|
||||
"C function pointer for `fetchhead_foreach_callback`"
|
||||
fetchhead_foreach_cb() = cfunction(fetchhead_foreach_callback, Cint, Tuple{Cstring, Cstring, Ptr{GitHash}, Cuint, Ptr{Void}})
|
||||
95
julia-0.6.2/share/julia/base/libgit2/commit.jl
Normal file
95
julia-0.6.2/share/julia/base/libgit2/commit.jl
Normal file
@@ -0,0 +1,95 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function message(c::GitCommit, raw::Bool=false)
|
||||
local msg_ptr::Cstring
|
||||
msg_ptr = raw? ccall((:git_commit_message_raw, :libgit2), Cstring, (Ptr{Void},), c.ptr) :
|
||||
ccall((:git_commit_message, :libgit2), Cstring, (Ptr{Void},), c.ptr)
|
||||
if msg_ptr == C_NULL
|
||||
return nothing
|
||||
end
|
||||
return unsafe_string(msg_ptr)
|
||||
end
|
||||
|
||||
function author(c::GitCommit)
|
||||
ptr = ccall((:git_commit_author, :libgit2), Ptr{SignatureStruct}, (Ptr{Void},), c.ptr)
|
||||
@assert ptr != C_NULL
|
||||
return Signature(ptr)
|
||||
end
|
||||
|
||||
function committer(c::GitCommit)
|
||||
ptr = ccall((:git_commit_committer, :libgit2), Ptr{SignatureStruct}, (Ptr{Void},), c.ptr)
|
||||
@assert ptr != C_NULL
|
||||
return Signature(ptr)
|
||||
end
|
||||
|
||||
function Base.show(io::IO, c::GitCommit)
|
||||
authstr = sprint(show, author(c))
|
||||
cmtrstr = sprint(show, committer(c))
|
||||
print(io, "Git Commit:\nCommit Author: $authstr\nCommitter: $cmtrstr\nSHA: $(GitHash(c))\nMessage:\n$(message(c))")
|
||||
end
|
||||
|
||||
""" Wrapper around `git_commit_create` """
|
||||
function commit(repo::GitRepo,
|
||||
refname::AbstractString,
|
||||
msg::AbstractString,
|
||||
author::GitSignature,
|
||||
committer::GitSignature,
|
||||
tree::GitTree,
|
||||
parents::GitCommit...)
|
||||
commit_id_ptr = Ref(GitHash())
|
||||
nparents = length(parents)
|
||||
parentptrs = Ptr{Void}[c.ptr for c in parents]
|
||||
@check ccall((:git_commit_create, :libgit2), Cint,
|
||||
(Ptr{GitHash}, Ptr{Void}, Ptr{UInt8},
|
||||
Ptr{SignatureStruct}, Ptr{SignatureStruct},
|
||||
Ptr{UInt8}, Ptr{UInt8}, Ptr{Void},
|
||||
Csize_t, Ptr{Ptr{Void}}),
|
||||
commit_id_ptr, repo.ptr, isempty(refname) ? C_NULL : refname,
|
||||
author.ptr, committer.ptr,
|
||||
C_NULL, msg, tree.ptr,
|
||||
nparents, nparents > 0 ? parentptrs : C_NULL)
|
||||
return commit_id_ptr[]
|
||||
end
|
||||
|
||||
"""Commit changes to repository"""
|
||||
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[])
|
||||
# Retrieve tree identifier
|
||||
if iszero(tree_id)
|
||||
tree_id = with(GitIndex, repo) do idx; write_tree!(idx) end
|
||||
end
|
||||
|
||||
# Retrieve parents from HEAD
|
||||
if isempty(parent_ids)
|
||||
try # if throws then HEAD not found -> empty repo
|
||||
push!(parent_ids, GitHash(repo, refname))
|
||||
end
|
||||
end
|
||||
|
||||
# return commit id
|
||||
commit_id = GitHash()
|
||||
|
||||
# get necessary objects
|
||||
tree = GitTree(repo, tree_id)
|
||||
auth_sig = convert(GitSignature, author)
|
||||
comm_sig = convert(GitSignature, committer)
|
||||
parents = GitCommit[]
|
||||
try
|
||||
for id in parent_ids
|
||||
push!(parents, GitCommit(repo, id))
|
||||
end
|
||||
commit_id = commit(repo, refname, msg, auth_sig, comm_sig, tree, parents...)
|
||||
finally
|
||||
for parent in parents
|
||||
close(parent)
|
||||
end
|
||||
close(tree)
|
||||
close(auth_sig)
|
||||
close(comm_sig)
|
||||
end
|
||||
return commit_id
|
||||
end
|
||||
130
julia-0.6.2/share/julia/base/libgit2/config.jl
Normal file
130
julia-0.6.2/share/julia/base/libgit2/config.jl
Normal file
@@ -0,0 +1,130 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function GitConfig(path::AbstractString,
|
||||
level::Consts.GIT_CONFIG = Consts.CONFIG_LEVEL_APP,
|
||||
force::Bool=false)
|
||||
# create new config object
|
||||
cfg_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_config_new, :libgit2), Cint, (Ptr{Ptr{Void}},), cfg_ptr_ptr)
|
||||
cfg = GitConfig(cfg_ptr_ptr[])
|
||||
try
|
||||
addfile(cfg, path, level, force)
|
||||
catch ex
|
||||
close(cfg)
|
||||
rethrow(ex)
|
||||
end
|
||||
return cfg
|
||||
end
|
||||
|
||||
function GitConfig(repo::GitRepo)
|
||||
cfg_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_repository_config, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}), cfg_ptr_ptr, repo.ptr)
|
||||
return GitConfig(repo, cfg_ptr_ptr[])
|
||||
end
|
||||
|
||||
function GitConfig(level::Consts.GIT_CONFIG = Consts.CONFIG_LEVEL_DEFAULT)
|
||||
cfg_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_config_open_default, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}},), cfg_ptr_ptr)
|
||||
cfg = GitConfig(cfg_ptr_ptr[])
|
||||
if level != Consts.CONFIG_LEVEL_DEFAULT
|
||||
glb_cfg_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
tmpcfg = cfg
|
||||
try
|
||||
@check ccall((:git_config_open_level, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cint),
|
||||
glb_cfg_ptr_ptr, cfg.ptr, Cint(level))
|
||||
cfg = GitConfig(glb_cfg_ptr_ptr[])
|
||||
finally
|
||||
close(tmpcfg)
|
||||
end
|
||||
end
|
||||
return cfg
|
||||
end
|
||||
|
||||
function addfile(cfg::GitConfig, path::AbstractString,
|
||||
level::Consts.GIT_CONFIG = Consts.CONFIG_LEVEL_APP,
|
||||
force::Bool=false)
|
||||
@check ccall((:git_config_add_file_ondisk, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Cstring, Cint, Cint),
|
||||
cfg.ptr, path, Cint(level), Cint(force))
|
||||
end
|
||||
|
||||
function get(::Type{<:AbstractString}, c::GitConfig, name::AbstractString)
|
||||
buf_ref = Ref(Buffer())
|
||||
@check ccall((:git_config_get_string_buf, :libgit2), Cint,
|
||||
(Ptr{Buffer}, Ptr{Void}, Cstring), buf_ref, c.ptr, name)
|
||||
buf = buf_ref[]
|
||||
str = unsafe_string(buf.ptr, buf.size)
|
||||
free(buf_ref)
|
||||
str
|
||||
end
|
||||
|
||||
function get(::Type{Bool}, c::GitConfig, name::AbstractString)
|
||||
val_ptr = Ref(Cint(0))
|
||||
@check ccall((:git_config_get_bool, :libgit2), Cint,
|
||||
(Ptr{Cint}, Ptr{Void}, Cstring), val_ptr, c.ptr, name)
|
||||
return Bool(val_ptr[])
|
||||
end
|
||||
|
||||
function get(::Type{Int32}, c::GitConfig, name::AbstractString)
|
||||
val_ptr = Ref(Cint(0))
|
||||
@check ccall((:git_config_get_int32, :libgit2), Cint,
|
||||
(Ptr{Cint}, Ptr{Void}, Cstring), val_ptr, c.ptr, name)
|
||||
return val_ptr[]
|
||||
end
|
||||
|
||||
function get(::Type{Int64}, c::GitConfig, name::AbstractString)
|
||||
val_ptr = Ref(Cintmax_t(0))
|
||||
@check ccall((:git_config_get_int64, :libgit2), Cint,
|
||||
(Ptr{Cintmax_t}, Ptr{Void}, Cstring), val_ptr, c.ptr, name)
|
||||
return val_ptr[]
|
||||
end
|
||||
|
||||
function get(c::GitConfig, name::AbstractString, default::T) where T
|
||||
res = default
|
||||
try res = get(T,c,name) end
|
||||
return res
|
||||
end
|
||||
|
||||
function getconfig(r::GitRepo, name::AbstractString, default)
|
||||
with(GitConfig, r) do cfg
|
||||
get(cfg, name, default)
|
||||
end
|
||||
end
|
||||
|
||||
function getconfig(rname::AbstractString, name::AbstractString, default)
|
||||
with(GitRepo, rname) do r
|
||||
with(GitConfig, r) do cfg
|
||||
get(cfg, name, default)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function getconfig(name::AbstractString, default)
|
||||
with(GitConfig) do cfg
|
||||
get(cfg, name, default)
|
||||
end
|
||||
end
|
||||
|
||||
function set!(c::GitConfig, name::AbstractString, value::AbstractString)
|
||||
@check ccall((:git_config_set_string, :libgit2), Cint,
|
||||
(Ptr{Void}, Cstring, Cstring), c.ptr, name, value)
|
||||
end
|
||||
|
||||
function set!(c::GitConfig, name::AbstractString, value::Bool)
|
||||
bval = Int32(value)
|
||||
@check ccall((:git_config_set_bool, :libgit2), Cint,
|
||||
(Ptr{Void}, Cstring, Cint), c.ptr, name, bval)
|
||||
end
|
||||
|
||||
function set!(c::GitConfig, name::AbstractString, value::Int32)
|
||||
@check ccall((:git_config_set_int32, :libgit2), Cint,
|
||||
(Ptr{Void}, Cstring, Cint), c.ptr, name, value)
|
||||
end
|
||||
|
||||
function set!(c::GitConfig, name::AbstractString, value::Int64)
|
||||
@check ccall((:git_config_set_int64, :libgit2), Cint,
|
||||
(Ptr{Void}, Cstring, Cintmax_t), c.ptr, name, value)
|
||||
end
|
||||
353
julia-0.6.2/share/julia/base/libgit2/consts.jl
Normal file
353
julia-0.6.2/share/julia/base/libgit2/consts.jl
Normal file
@@ -0,0 +1,353 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
module Consts
|
||||
|
||||
const HEAD_FILE = "HEAD"
|
||||
const FETCH_HEAD = "FETCH_HEAD"
|
||||
const REMOTE_ORIGIN = "origin"
|
||||
|
||||
# objs
|
||||
@enum(OBJECT,
|
||||
OBJ_ANY = -2,
|
||||
OBJ_BAD = -1,
|
||||
OBJ_COMMIT = 1,
|
||||
OBJ_TREE = 2,
|
||||
OBJ_BLOB = 3,
|
||||
OBJ_TAG = 4)
|
||||
|
||||
#revwalk
|
||||
const SORT_NONE = Cint(0)
|
||||
const SORT_TOPOLOGICAL = Cint(1 << 0)
|
||||
const SORT_TIME = Cint(1 << 1)
|
||||
const SORT_REVERSE = Cint(1 << 2)
|
||||
|
||||
# refs
|
||||
const REF_INVALID = Cint(0)
|
||||
const REF_OID = Cint(1)
|
||||
const REF_SYMBOLIC = Cint(2)
|
||||
const REF_LISTALL = REF_OID | REF_SYMBOLIC
|
||||
|
||||
# checkout
|
||||
const CHECKOUT_NONE = Cuint(0)
|
||||
const CHECKOUT_SAFE = Cuint(1 << 0)
|
||||
const CHECKOUT_FORCE = Cuint(1 << 1)
|
||||
const CHECKOUT_RECREATE_MISSING = Cuint(1 << 2)
|
||||
const CHECKOUT_ALLOW_CONFLICTS = Cuint(1 << 4)
|
||||
const CHECKOUT_REMOVE_UNTRACKED = Cuint(1 << 5)
|
||||
const CHECKOUT_REMOVE_IGNORED = Cuint(1 << 6)
|
||||
const CHECKOUT_UPDATE_ONLY = Cuint(1 << 7)
|
||||
const CHECKOUT_DONT_UPDATE_INDEX = Cuint(1 << 8)
|
||||
const CHECKOUT_NO_REFRESH = Cuint(1 << 9)
|
||||
const CHECKOUT_SKIP_UNMERGED = Cuint(1 << 10)
|
||||
const CHECKOUT_USE_OURS = Cuint(1 << 11)
|
||||
const CHECKOUT_USE_THEIRS = Cuint(1 << 12)
|
||||
const CHECKOUT_DISABLE_PATHSPEC_MATCH = Cuint(1 << 13)
|
||||
const CHECKOUT_SKIP_LOCKED_DIRECTORIES = Cuint(1 << 18)
|
||||
const CHECKOUT_DONT_OVERWRITE_IGNORED = Cuint(1 << 19)
|
||||
const CHECKOUT_CONFLICT_STYLE_MERGE = Cuint(1 << 20)
|
||||
const CHECKOUT_CONFLICT_STYLE_DIFF3 = Cuint(1 << 21)
|
||||
const CHECKOUT_DONT_REMOVE_EXISTING = Cuint(1 << 22)
|
||||
|
||||
const CHECKOUT_UPDATE_SUBMODULES = Cuint(1 << 16)
|
||||
const CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED = Cuint(1 << 17)
|
||||
|
||||
const CHECKOUT_NOTIFY_NONE = Cuint(0)
|
||||
const CHECKOUT_NOTIFY_CONFLICT = Cuint(1 << 0)
|
||||
const CHECKOUT_NOTIFY_DIRTY = Cuint(1 << 1)
|
||||
const CHECKOUT_NOTIFY_UPDATED = Cuint(1 << 2)
|
||||
const CHECKOUT_NOTIFY_UNTRACKED = Cuint(1 << 3)
|
||||
const CHECKOUT_NOTIFY_IGNORED = Cuint(1 << 4)
|
||||
const CHECKOUT_NOTIFY_ALL = 0x0FFFF
|
||||
|
||||
# diff
|
||||
const DIFF_OPTIONS_VERSION = Cuint(1)
|
||||
|
||||
const DIFF_NORMAL = Cuint(0)
|
||||
const DIFF_REVERSE = Cuint(1 << 0)
|
||||
const DIFF_INCLUDE_IGNORED = Cuint(1 << 1)
|
||||
const DIFF_RECURSE_IGNORED_DIRS = Cuint(1 << 2)
|
||||
const DIFF_INCLUDE_UNTRACKED = Cuint(1 << 3)
|
||||
const DIFF_RECURSE_UNTRACKED_DIRS = Cuint(1 << 4)
|
||||
const DIFF_INCLUDE_UNMODIFIED = Cuint(1 << 5)
|
||||
const DIFF_INCLUDE_TYPECHANGE = Cuint(1 << 6)
|
||||
const DIFF_INCLUDE_TYPECHANGE_TREES = Cuint(1 << 7)
|
||||
const DIFF_IGNORE_FILEMODE = Cuint(1 << 8)
|
||||
const DIFF_IGNORE_SUBMODULES = Cuint(1 << 9)
|
||||
const DIFF_IGNORE_CASE = Cuint(1 << 10)
|
||||
const DIFF_DISABLE_PATHSPEC_MATCH = Cuint(1 << 12)
|
||||
const DIFF_SKIP_BINARY_CHECK = Cuint(1 << 13)
|
||||
const DIFF_ENABLE_FAST_UNTRACKED_DIRS = Cuint(1 << 14)
|
||||
|
||||
const DIFF_FORCE_TEXT = Cuint(1 << 20)
|
||||
const DIFF_FORCE_BINARY = Cuint(1 << 21)
|
||||
const DIFF_IGNORE_WHITESPACE = Cuint(1 << 22)
|
||||
const DIFF_IGNORE_WHITESPACE_CHANGE = Cuint(1 << 23)
|
||||
const DIFF_IGNORE_WHITESPACE_EOL = Cuint(1 << 24)
|
||||
const DIFF_SHOW_UNTRACKED_CONTENT = Cuint(1 << 25)
|
||||
const DIFF_SHOW_UNMODIFIED = Cuint(1 << 26)
|
||||
const DIFF_PATIENCE = Cuint(1 << 28)
|
||||
const DIFF_MINIMAL = Cuint(1 << 29)
|
||||
|
||||
const DIFF_FLAG_BINARY = Cuint(1 << 0)
|
||||
const DIFF_FLAG_NOT_BINARY = Cuint(1 << 1)
|
||||
const DIFF_FLAG_VALID_OID = Cuint(1 << 2)
|
||||
|
||||
const DIFF_FORMAT_PATCH = Cuint(1)
|
||||
const DIFF_FORMAT_PATCH_HEADER = Cuint(2)
|
||||
const DIFF_FORMAT_RAW = Cuint(3)
|
||||
const DIFF_FORMAT_NAME_ONLY = Cuint(4)
|
||||
const DIFF_FORMAT_NAME_STATUS = Cuint(5)
|
||||
|
||||
@enum(DELTA_STATUS, DELTA_UNMODIFIED = Cint(0),
|
||||
DELTA_ADDED = Cint(1),
|
||||
DELTA_DELETED = Cint(2),
|
||||
DELTA_MODIFIED = Cint(3),
|
||||
DELTA_RENAMED = Cint(4),
|
||||
DELTA_COPIED = Cint(5),
|
||||
DELTA_IGNORED = Cint(6),
|
||||
DELTA_UNTRACKED = Cint(7),
|
||||
DELTA_TYPECHANGE = Cint(8))
|
||||
|
||||
# index
|
||||
const IDXENTRY_NAMEMASK = (0x0fff)
|
||||
const IDXENTRY_STAGEMASK = (0x3000)
|
||||
const IDXENTRY_EXTENDED = (0x4000)
|
||||
const IDXENTRY_VALID = (0x8000)
|
||||
const IDXENTRY_STAGESHIFT = Cint(12)
|
||||
|
||||
const IDXENTRY_UPDATE = Cint(1 << 0)
|
||||
const IDXENTRY_REMOVE = Cint(1 << 1)
|
||||
const IDXENTRY_UPTODATE = Cint(1 << 2)
|
||||
const IDXENTRY_ADDED = Cint(1 << 3)
|
||||
|
||||
const IDXENTRY_HASHED = Cint(1 << 4)
|
||||
const IDXENTRY_UNHASHED = Cint(1 << 5)
|
||||
const IDXENTRY_WT_REMOVE = Cint(1 << 6)
|
||||
const IDXENTRY_CONFLICTED = Cint(1 << 7)
|
||||
|
||||
const IDXENTRY_UNPACKED = Cint(1 << 8)
|
||||
const IDXENTRY_NEW_SKIP_WORKTREE = Cint(1 << 9)
|
||||
|
||||
const INDEXCAP_IGNORE_CASE = Cuint(1)
|
||||
const INDEXCAP_NO_FILEMODE = Cuint(2)
|
||||
const INDEXCAP_NO_SYMLINKS = Cuint(4)
|
||||
const INDEXCAP_FROM_OWNER = ~Cuint(0)
|
||||
|
||||
const INDEX_ADD_DEFAULT = Cuint(0)
|
||||
const INDEX_ADD_FORCE = Cuint(1 << 0)
|
||||
const INDEX_ADD_DISABLE_PATHSPEC_MATCH = Cuint(1 << 1)
|
||||
const INDEX_ADD_CHECK_PATHSPEC = Cuint(1 << 2)
|
||||
|
||||
const INDEX_STAGE_ANY = Cint(-1)
|
||||
|
||||
# merge
|
||||
@enum(GIT_MERGE, MERGE_FIND_RENAMES = 1 << 0,
|
||||
MERGE_FAIL_ON_CONFLICT = 1 << 1,
|
||||
MERGE_SKIP_REUC = 1 << 2,
|
||||
MERGE_NO_RECURSIVE = 1 << 3)
|
||||
|
||||
@enum(GIT_MERGE_FILE, MERGE_FILE_DEFAULT = 0, # Defaults
|
||||
MERGE_FILE_STYLE_MERGE = 1 << 0, # Create standard conflicted merge files
|
||||
MERGE_FILE_STYLE_DIFF3 = 1 << 1, # Create diff3-style files
|
||||
MERGE_FILE_SIMPLIFY_ALNUM = 1 << 2, # Condense non-alphanumeric regions for simplified diff file
|
||||
MERGE_FILE_IGNORE_WHITESPACE = 1 << 3, # Ignore all whitespace
|
||||
MERGE_FILE_IGNORE_WHITESPACE_CHANGE = 1 << 4, # Ignore changes in amount of whitespace
|
||||
MERGE_FILE_IGNORE_WHITESPACE_EOL = 1 << 5, # Ignore whitespace at end of line
|
||||
MERGE_FILE_DIFF_PATIENCE = 1 << 6, # Use the "patience diff" algorithm
|
||||
MERGE_FILE_DIFF_MINIMAL = 1 << 7) # Take extra time to find minimal diff
|
||||
|
||||
@enum(GIT_MERGE_FILE_FAVOR, MERGE_FILE_FAVOR_NORMAL = 0,
|
||||
MERGE_FILE_FAVOR_OURS = 1,
|
||||
MERGE_FILE_FAVOR_THEIRS = 2,
|
||||
MERGE_FILE_FAVOR_UNION = 3)
|
||||
|
||||
@enum(GIT_MERGE_PREFERENCE, MERGE_PREFERENCE_NONE = 0,
|
||||
MERGE_PREFERENCE_NO_FASTFORWARD = 1,
|
||||
MERGE_PREFERENCE_FASTFORWARD_ONLY = 2)
|
||||
|
||||
@enum(GIT_MERGE_ANALYSIS, MERGE_ANALYSIS_NONE = 0,
|
||||
MERGE_ANALYSIS_NORMAL = 1 << 0,
|
||||
MERGE_ANALYSIS_UP_TO_DATE = 1 << 1,
|
||||
MERGE_ANALYSIS_FASTFORWARD = 1 << 2,
|
||||
MERGE_ANALYSIS_UNBORN = 1 << 3)
|
||||
|
||||
# reset
|
||||
const RESET_SOFT = Cint(1) # Move the head to the given commit
|
||||
const RESET_MIXED = Cint(2) # SOFT plus reset index to the commit
|
||||
const RESET_HARD = Cint(3) # MIXED plus changes in working tree discarded
|
||||
|
||||
#rebase
|
||||
@enum(GIT_REBASE_OPERATION, REBASE_OPERATION_PICK = Cint(0),
|
||||
REBASE_OPERATION_REWORD = Cint(1),
|
||||
REBASE_OPERATION_EDIT = Cint(2),
|
||||
REBASE_OPERATION_SQUASH = Cint(3),
|
||||
REBASE_OPERATION_FIXUP = Cint(4),
|
||||
REBASE_OPERATION_EXEC = Cint(5))
|
||||
|
||||
# fetch_prune
|
||||
const FETCH_PRUNE_UNSPECIFIED = Cint(0)
|
||||
const FETCH_PRUNE = Cint(1)
|
||||
const FETCH_NO_PRUNE = Cint(2)
|
||||
|
||||
# remote_autotag
|
||||
const REMOTE_DOWNLOAD_TAGS_UNSPECIFIED = Cint(0)
|
||||
const REMOTE_DOWNLOAD_TAGS_AUTO = Cint(1)
|
||||
const REMOTE_DOWNLOAD_TAGS_NONE = Cint(2)
|
||||
const REMOTE_DOWNLOAD_TAGS_ALL = Cint(3)
|
||||
|
||||
# clone
|
||||
const CLONE_LOCAL_AUTO = Cint(0)
|
||||
const CLONE_LOCAL = Cint(1)
|
||||
const CLONE_NO_LOCAL = Cint(2)
|
||||
const CLONE_LOCAL_NO_LINKS = Cint(3)
|
||||
|
||||
# status
|
||||
const STATUS_CURRENT = Cuint(0)
|
||||
const STATUS_INDEX_NEW = Cuint(1 << 0)
|
||||
const STATUS_INDEX_MODIFIED = Cuint(1 << 1)
|
||||
const STATUS_INDEX_DELETED = Cuint(1 << 2)
|
||||
const STATUS_INDEX_RENAMED = Cuint(1 << 3)
|
||||
const STATUS_INDEX_TYPECHANGE = Cuint(1 << 4)
|
||||
const STATUS_WT_NEW = Cuint(1 << 7)
|
||||
const STATUS_WT_MODIFIED = Cuint(1 << 8)
|
||||
const STATUS_WT_DELETED = Cuint(1 << 9)
|
||||
const STATUS_WT_TYPECHANGE = Cuint(1 << 10)
|
||||
const STATUS_WT_RENAMED = Cuint(1 << 11)
|
||||
const STATUS_WT_UNREADABLE = Cuint(1 << 12)
|
||||
const STATUS_IGNORED = Cuint(1 << 14)
|
||||
const STATUS_CONFLICTED = Cuint(1 << 15)
|
||||
|
||||
# status show
|
||||
const STATUS_SHOW_INDEX_AND_WORKDIR = Cint(0)
|
||||
const STATUS_SHOW_INDEX_ONLY = Cint(1)
|
||||
const STATUS_SHOW_WORKDIR_ONLY = Cint(2)
|
||||
|
||||
# status options
|
||||
const STATUS_OPT_INCLUDE_UNTRACKED = Cuint(1 << 0)
|
||||
const STATUS_OPT_INCLUDE_IGNORED = Cuint(1 << 1)
|
||||
const STATUS_OPT_INCLUDE_UNMODIFIED = Cuint(1 << 2)
|
||||
const STATUS_OPT_EXCLUDE_SUBMODULES = Cuint(1 << 3)
|
||||
const STATUS_OPT_RECURSE_UNTRACKED_DIRS = Cuint(1 << 4)
|
||||
const STATUS_OPT_DISABLE_PATHSPEC_MATCH = Cuint(1 << 5)
|
||||
const STATUS_OPT_RECURSE_IGNORED_DIRS = Cuint(1 << 6)
|
||||
const STATUS_OPT_RENAMES_HEAD_TO_INDEX = Cuint(1 << 7)
|
||||
const STATUS_OPT_RENAMES_INDEX_TO_WORKDIR = Cuint(1 << 8)
|
||||
const STATUS_OPT_SORT_CASE_SENSITIVELY = Cuint(1 << 9)
|
||||
const STATUS_OPT_SORT_CASE_INSENSITIVELY = Cuint(1 << 10)
|
||||
const STATUS_OPT_RENAMES_FROM_REWRITES = Cuint(1 << 11)
|
||||
const STATUS_OPT_NO_REFRESH = Cuint(1 << 12)
|
||||
const STATUS_OPT_UPDATE_INDEX = Cuint(1 << 13)
|
||||
const STATUS_OPT_INCLUDE_UNREADABLE = Cuint(1 << 14)
|
||||
const STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED = Cuint(1 << 15)
|
||||
|
||||
@enum(GIT_SUBMODULE_IGNORE, SUBMODULE_IGNORE_UNSPECIFIED = -1, # use the submodule's configuration
|
||||
SUBMODULE_IGNORE_NONE = 1, # any change or untracked == dirty
|
||||
SUBMODULE_IGNORE_UNTRACKED = 2, # dirty if tracked files change
|
||||
SUBMODULE_IGNORE_DIRTY = 3, # only dirty if HEAD moved
|
||||
SUBMODULE_IGNORE_ALL = 4) # never dirty
|
||||
|
||||
"""
|
||||
Option flags for `GitRepo`.
|
||||
|
||||
* `REPOSITORY_OPEN_NO_SEARCH` - Only open the repository if it can be immediately found in the `path`. Do not walk up from the `path` looking at parent directories.
|
||||
* `REPOSITORY_OPEN_CROSS_FS` - Unless this flag is set, open will not continue searching across filesystem boundaries. (E.g. Searching in a user's home directory `/home/user/source/` will not return `/.git/` as the found repo if `/` is a different filesystem than `/home`.)
|
||||
* `REPOSITORY_OPEN_BARE` - Open repository as a bare repo regardless of core.bare config, and defer loading config file for faster setup.
|
||||
"""
|
||||
@enum(GIT_REPOSITORY_OPEN, REPOSITORY_OPEN_DEFAULT = 0,
|
||||
REPOSITORY_OPEN_NO_SEARCH = 1<<0,
|
||||
REPOSITORY_OPEN_CROSS_FS = 1<<1,
|
||||
REPOSITORY_OPEN_BARE = 1<<2)
|
||||
|
||||
@enum(GIT_BRANCH, BRANCH_LOCAL = 1, BRANCH_REMOTE = 2)
|
||||
|
||||
@enum(GIT_FILEMODE, FILEMODE_UNREADABLE = 0o000000,
|
||||
FILEMODE_TREE = 0o040000,
|
||||
FILEMODE_BLOB = 0o100644,
|
||||
FILEMODE_BLOB_EXECUTABLE = 0o100755,
|
||||
FILEMODE_LINK = 0o120000,
|
||||
FILEMODE_COMMIT = 0o160000)
|
||||
|
||||
@enum(GIT_CREDTYPE, CREDTYPE_USERPASS_PLAINTEXT = Cuint(1 << 0),
|
||||
CREDTYPE_SSH_KEY = Cuint(1 << 1),
|
||||
CREDTYPE_SSH_CUSTOM = Cuint(1 << 2),
|
||||
CREDTYPE_DEFAULT = Cuint(1 << 3),
|
||||
CREDTYPE_SSH_INTERACTIVE = Cuint(1 << 4),
|
||||
CREDTYPE_USERNAME = Cuint(1 << 5),
|
||||
CREDTYPE_SSH_MEMORY = Cuint(1 << 6))
|
||||
|
||||
@enum(GIT_FEATURE, FEATURE_THREADS = Cuint(1 << 0),
|
||||
FEATURE_HTTPS = Cuint(1 << 1),
|
||||
FEATURE_SSH = Cuint(1 << 2),
|
||||
FEATURE_NSEC = Cuint(1 << 3))
|
||||
|
||||
if LibGit2.version() >= v"0.24.0"
|
||||
"""
|
||||
Priority level of a config file.
|
||||
|
||||
These priority levels correspond to the natural escalation logic (from higher to lower) when searching for config entries in git.
|
||||
|
||||
* `CONFIG_LEVEL_DEFAULT` - Open the global, XDG and system configuration files if any available.
|
||||
* `CONFIG_LEVEL_PROGRAMDATA` - System-wide on Windows, for compatibility with portable git
|
||||
* `CONFIG_LEVEL_SYSTEM` - System-wide configuration file; `/etc/gitconfig` on Linux systems
|
||||
* `CONFIG_LEVEL_XDG` - XDG compatible configuration file; typically `~/.config/git/config`
|
||||
* `CONFIG_LEVEL_GLOBAL` - User-specific configuration file (also called Global configuration file); typically `~/.gitconfig`
|
||||
* `CONFIG_LEVEL_LOCAL` - Repository specific configuration file; `\$WORK_DIR/.git/config` on non-bare repos
|
||||
* `CONFIG_LEVEL_APP` - Application specific configuration file; freely defined by applications
|
||||
* `CONFIG_HIGHEST_LEVEL` - Represents the highest level available config file (i.e. the most specific config file available that actually is loaded)
|
||||
"""
|
||||
@enum(GIT_CONFIG, CONFIG_LEVEL_DEFAULT = 0,
|
||||
CONFIG_LEVEL_PROGRAMDATA = 1,
|
||||
CONFIG_LEVEL_SYSTEM = 2,
|
||||
CONFIG_LEVEL_XDG = 3,
|
||||
CONFIG_LEVEL_GLOBAL = 4,
|
||||
CONFIG_LEVEL_LOCAL = 5,
|
||||
CONFIG_LEVEL_APP = 6,
|
||||
CONFIG_HIGHEST_LEVEL =-1)
|
||||
else
|
||||
"""
|
||||
Priority level of a config file.
|
||||
|
||||
These priority levels correspond to the natural escalation logic (from higher to lower) when searching for config entries in git.
|
||||
|
||||
* `CONFIG_LEVEL_DEFAULT` - Open the global, XDG and system configuration files if any available.
|
||||
* `CONFIG_LEVEL_SYSTEM` - System-wide configuration file; `/etc/gitconfig` on Linux systems
|
||||
* `CONFIG_LEVEL_XDG` - XDG compatible configuration file; typically `~/.config/git/config`
|
||||
* `CONFIG_LEVEL_GLOBAL` - User-specific configuration file (also called Global configuration file); typically `~/.gitconfig`
|
||||
* `CONFIG_LEVEL_LOCAL` - Repository specific configuration file; `\$WORK_DIR/.git/config` on non-bare repos
|
||||
* `CONFIG_LEVEL_APP` - Application specific configuration file; freely defined by applications
|
||||
* `CONFIG_HIGHEST_LEVEL` - Represents the highest level available config file (i.e. the most specific config file available that actually is loaded)
|
||||
"""
|
||||
@enum(GIT_CONFIG, CONFIG_LEVEL_DEFAULT = 0,
|
||||
CONFIG_LEVEL_SYSTEM = 1,
|
||||
CONFIG_LEVEL_XDG = 2,
|
||||
CONFIG_LEVEL_GLOBAL = 3,
|
||||
CONFIG_LEVEL_LOCAL = 4,
|
||||
CONFIG_LEVEL_APP = 5,
|
||||
CONFIG_HIGHEST_LEVEL =-1)
|
||||
end
|
||||
|
||||
"""
|
||||
Global library options.
|
||||
|
||||
These are used to select which global option to set or get and are used in `git_libgit2_opts()`.
|
||||
"""
|
||||
@enum(GIT_OPT, GET_MWINDOW_SIZE = 0,
|
||||
SET_MWINDOW_SIZE = 1,
|
||||
GET_MWINDOW_MAPPED_LIMIT = 2,
|
||||
SET_MWINDOW_MAPPED_LIMIT = 3,
|
||||
GET_SEARCH_PATH = 4,
|
||||
SET_SEARCH_PATH = 5,
|
||||
SET_CACHE_OBJECT_LIMIT = 6,
|
||||
SET_CACHE_MAX_SIZE = 7,
|
||||
ENABLE_CACHING = 8,
|
||||
GET_CACHED_MEMORY = 9,
|
||||
GET_TEMPLATE_PATH = 10,
|
||||
SET_TEMPLATE_PATH = 11,
|
||||
SET_SSL_CERT_LOCATIONS = 12)
|
||||
|
||||
|
||||
@enum(GIT_PROXY, PROXY_NONE,
|
||||
PROXY_AUTO,
|
||||
PROXY_SPECIFIED)
|
||||
|
||||
end
|
||||
82
julia-0.6.2/share/julia/base/libgit2/diff.jl
Normal file
82
julia-0.6.2/share/julia/base/libgit2/diff.jl
Normal file
@@ -0,0 +1,82 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# TODO: make this a general purpose solution
|
||||
function Base.cconvert(::Type{Ptr{DiffOptionsStruct}}, pathspecs::AbstractString)
|
||||
str_ref = Base.cconvert(Ref{Cstring}, [pathspecs])
|
||||
sa = StrArrayStruct(Base.unsafe_convert(Ref{Cstring}, str_ref), 1)
|
||||
do_ref = Ref(DiffOptionsStruct(pathspec = sa))
|
||||
do_ref, str_ref
|
||||
end
|
||||
function Base.unsafe_convert(::Type{Ptr{DiffOptionsStruct}}, rr::Tuple{Ref{DiffOptionsStruct}, Ref{Cstring}})
|
||||
Base.unsafe_convert(Ptr{DiffOptionsStruct}, first(rr))
|
||||
end
|
||||
|
||||
|
||||
function diff_tree(repo::GitRepo, tree::GitTree, pathspecs::AbstractString=""; cached::Bool=false)
|
||||
diff_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
if cached
|
||||
@check ccall((:git_diff_tree_to_index, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{Void}, Ptr{Void}, Ptr{DiffOptionsStruct}),
|
||||
diff_ptr_ptr, repo.ptr, tree.ptr, C_NULL, isempty(pathspecs) ? C_NULL : pathspecs)
|
||||
else
|
||||
@check ccall((:git_diff_tree_to_workdir_with_index, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{Void}, Ptr{DiffOptionsStruct}),
|
||||
diff_ptr_ptr, repo.ptr, tree.ptr, isempty(pathspecs) ? C_NULL : pathspecs)
|
||||
end
|
||||
return GitDiff(repo, diff_ptr_ptr[])
|
||||
end
|
||||
|
||||
function diff_tree(repo::GitRepo, oldtree::GitTree, newtree::GitTree)
|
||||
diff_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_diff_tree_to_tree, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{Void}, Ptr{Void}, Ptr{DiffOptionsStruct}),
|
||||
diff_ptr_ptr, repo.ptr, oldtree.ptr, newtree.ptr, C_NULL)
|
||||
return GitDiff(repo, diff_ptr_ptr[])
|
||||
end
|
||||
|
||||
function GitDiffStats(diff::GitDiff)
|
||||
diff_stat_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_diff_get_stats, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}),
|
||||
diff_stat_ptr_ptr, diff.ptr)
|
||||
return GitDiffStats(diff.owner, diff_stat_ptr_ptr[])
|
||||
end
|
||||
|
||||
function files_changed(diff_stat::GitDiffStats)
|
||||
return ccall((:git_diff_stats_files_changed, :libgit2), Csize_t, (Ptr{Void},), diff_stat.ptr)
|
||||
end
|
||||
|
||||
function insertions(diff_stat::GitDiffStats)
|
||||
return ccall((:git_diff_stats_insertions, :libgit2), Csize_t, (Ptr{Void},), diff_stat.ptr)
|
||||
end
|
||||
|
||||
function deletions(diff_stat::GitDiffStats)
|
||||
return ccall((:git_diff_stats_deletions, :libgit2), Csize_t, (Ptr{Void},), diff_stat.ptr)
|
||||
end
|
||||
|
||||
function Base.count(diff::GitDiff)
|
||||
return ccall((:git_diff_num_deltas, :libgit2), Cint, (Ptr{Void},), diff.ptr)
|
||||
end
|
||||
|
||||
function Base.getindex(diff::GitDiff, i::Integer)
|
||||
if i < 1 || i > count(diff)
|
||||
throw(BoundsError(diff, (i,)))
|
||||
end
|
||||
delta_ptr = ccall((:git_diff_get_delta, :libgit2),
|
||||
Ptr{DiffDelta},
|
||||
(Ptr{Void}, Csize_t), diff.ptr, i-1)
|
||||
return unsafe_load(delta_ptr)
|
||||
end
|
||||
|
||||
function Base.show(io::IO, diff_stat::GitDiffStats)
|
||||
println(io, "GitDiffStats:")
|
||||
println(io, "Files changed: $(files_changed(diff_stat))")
|
||||
println(io, "Insertions: $(insertions(diff_stat))")
|
||||
println(io, "Deletions: $(deletions(diff_stat))")
|
||||
end
|
||||
|
||||
function Base.show(io::IO, diff::GitDiff)
|
||||
println(io, "GitDiff:")
|
||||
println(io, "Number of deltas: $(count(diff))")
|
||||
show(io, GitDiffStats(diff))
|
||||
end
|
||||
103
julia-0.6.2/share/julia/base/libgit2/error.jl
Normal file
103
julia-0.6.2/share/julia/base/libgit2/error.jl
Normal file
@@ -0,0 +1,103 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
module Error
|
||||
|
||||
export GitError
|
||||
|
||||
@enum(Code, GIT_OK = Cint(0), # no error
|
||||
ERROR = Cint(-01), # generic error
|
||||
ENOTFOUND = Cint(-03), # requested object could not be found
|
||||
EEXISTS = Cint(-04), # object exits preventing op
|
||||
EAMBIGUOUS = Cint(-05), # more than one object matches
|
||||
EBUFS = Cint(-06), # output buffer too small to hold data
|
||||
EUSER = Cint(-07), # user callback generated error
|
||||
EBAREREPO = Cint(-08), # operation not allowed on bare repo
|
||||
EUNBORNBRANCH = Cint(-09), # HEAD refers to branch with 0 commits
|
||||
EUNMERGED = Cint(-10), # merge in progress prevented op
|
||||
ENONFASTFORWARD = Cint(-11), # ref not fast-forwardable
|
||||
EINVALIDSPEC = Cint(-12), # name / ref not in valid format
|
||||
EMERGECONFLICT = Cint(-13), # merge conflict prevented op
|
||||
ELOCKED = Cint(-14), # lock file prevented op
|
||||
EMODIFIED = Cint(-15), # ref value does not match expected
|
||||
EAUTH = Cint(-16), # authentication error
|
||||
ECERTIFICATE = Cint(-17), # server certificate is invalid
|
||||
EAPPLIED = Cint(-18), # patch/merge has already been applied
|
||||
EPEEL = Cint(-19), # the requested peel operation is not possible
|
||||
EEOF = Cint(-20), # Unexpted EOF
|
||||
PASSTHROUGH = Cint(-30), # internal only
|
||||
ITEROVER = Cint(-31)) # signals end of iteration
|
||||
|
||||
@enum(Class, None,
|
||||
NoMemory,
|
||||
OS,
|
||||
Invalid,
|
||||
Reference,
|
||||
Zlib,
|
||||
Repository,
|
||||
Config,
|
||||
Regex,
|
||||
Odb,
|
||||
Index,
|
||||
Object,
|
||||
Net,
|
||||
Tag,
|
||||
Tree,
|
||||
Indexer,
|
||||
SSL,
|
||||
Submodule,
|
||||
Thread,
|
||||
Stash,
|
||||
Checkout,
|
||||
FetchHead,
|
||||
Merge,
|
||||
SSH,
|
||||
Filter,
|
||||
Revert,
|
||||
Callback,
|
||||
CherryPick,
|
||||
Describe,
|
||||
Rebase)
|
||||
|
||||
struct ErrorStruct
|
||||
message::Ptr{UInt8}
|
||||
class::Cint
|
||||
end
|
||||
|
||||
struct GitError <: Exception
|
||||
class::Class
|
||||
code::Code
|
||||
msg::AbstractString
|
||||
end
|
||||
Base.show(io::IO, err::GitError) = print(io, "GitError(Code:$(err.code), Class:$(err.class), $(err.msg))")
|
||||
|
||||
function last_error()
|
||||
err = ccall((:giterr_last, :libgit2), Ptr{ErrorStruct}, ())
|
||||
if err != C_NULL
|
||||
err_obj = unsafe_load(err)
|
||||
err_class = Class[err_obj.class][]
|
||||
err_msg = unsafe_string(err_obj.message)
|
||||
else
|
||||
err_class = Class[0][]
|
||||
err_msg = "No errors"
|
||||
end
|
||||
return (err_class, err_msg)
|
||||
end
|
||||
|
||||
function GitError(code::Integer)
|
||||
err_code = Code[code][]
|
||||
err_class, err_msg = last_error()
|
||||
return GitError(err_class, err_code, err_msg)
|
||||
end
|
||||
|
||||
end # Error module
|
||||
|
||||
macro check(git_func)
|
||||
quote
|
||||
local err::Cint
|
||||
err = $(esc(git_func::Expr))
|
||||
if err < 0
|
||||
throw(Error.GitError(err))
|
||||
end
|
||||
err
|
||||
end
|
||||
end
|
||||
124
julia-0.6.2/share/julia/base/libgit2/index.jl
Normal file
124
julia-0.6.2/share/julia/base/libgit2/index.jl
Normal file
@@ -0,0 +1,124 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function GitIndex(repo::GitRepo)
|
||||
idx_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_repository_index, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}), idx_ptr_ptr, repo.ptr)
|
||||
return GitIndex(repo, idx_ptr_ptr[])
|
||||
end
|
||||
|
||||
function read!(idx::GitIndex, force::Bool = false)
|
||||
@check ccall((:git_index_read, :libgit2), Cint, (Ptr{Void}, Cint), idx.ptr, Cint(force))
|
||||
return idx
|
||||
end
|
||||
|
||||
function write!(idx::GitIndex)
|
||||
@check ccall((:git_index_write, :libgit2), Cint, (Ptr{Void},), idx.ptr)
|
||||
return idx
|
||||
end
|
||||
|
||||
function write_tree!(idx::GitIndex)
|
||||
oid_ptr = Ref(GitHash())
|
||||
@check ccall((:git_index_write_tree, :libgit2), Cint,
|
||||
(Ptr{GitHash}, Ptr{Void}), oid_ptr, idx.ptr)
|
||||
return oid_ptr[]
|
||||
end
|
||||
|
||||
function repository(idx::GitIndex)
|
||||
if isnull(idx.owner)
|
||||
throw(GitError(Error.Index, Error.ENOTFOUND, "Index does not have an owning repository."))
|
||||
else
|
||||
return Base.get(idx.owner)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.read_tree!(idx::GitIndex, tree::GitTree)
|
||||
LibGit2.read_tree!(idx::GitIndex, treehash::AbstractGitHash)
|
||||
|
||||
Read the tree `tree` (or the tree pointed to by `treehash` in the repository owned by
|
||||
`idx`) into the index `idx`. The current index contents will be replaced.
|
||||
"""
|
||||
function read_tree!(idx::GitIndex, tree::GitTree)
|
||||
@check ccall((:git_index_read_tree, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{Void}), idx.ptr, tree.ptr)
|
||||
end
|
||||
read_tree!(idx::GitIndex, hash::AbstractGitHash) =
|
||||
read_tree!(idx, GitTree(repository(idx), hash))
|
||||
|
||||
function add!(idx::GitIndex, files::AbstractString...;
|
||||
flags::Cuint = Consts.INDEX_ADD_DEFAULT)
|
||||
@check ccall((:git_index_add_all, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{StrArrayStruct}, Cuint, Ptr{Void}, Ptr{Void}),
|
||||
idx.ptr, collect(files), flags, C_NULL, C_NULL)
|
||||
end
|
||||
|
||||
function update!(idx::GitIndex, files::AbstractString...)
|
||||
@check ccall((:git_index_update_all, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{StrArrayStruct}, Ptr{Void}, Ptr{Void}),
|
||||
idx.ptr, collect(files), C_NULL, C_NULL)
|
||||
end
|
||||
|
||||
function remove!(idx::GitIndex, files::AbstractString...)
|
||||
@check ccall((:git_index_remove_all, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{StrArrayStruct}, Ptr{Void}, Ptr{Void}),
|
||||
idx.ptr, collect(files), C_NULL, C_NULL)
|
||||
end
|
||||
|
||||
function add!(repo::GitRepo, files::AbstractString...;
|
||||
flags::Cuint = Consts.INDEX_ADD_DEFAULT)
|
||||
with(GitIndex, repo) do idx
|
||||
add!(idx, files..., flags = flags)
|
||||
write!(idx)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function update!(repo::GitRepo, files::AbstractString...)
|
||||
with(GitIndex, repo) do idx
|
||||
update!(idx, files...)
|
||||
write!(idx)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function remove!(repo::GitRepo, files::AbstractString...)
|
||||
with(GitIndex, repo) do idx
|
||||
remove!(idx, files...)
|
||||
write!(idx)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function read!(repo::GitRepo, force::Bool = false)
|
||||
with(GitIndex, repo) do idx
|
||||
read!(idx, force)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function Base.count(idx::GitIndex)
|
||||
return ccall((:git_index_entrycount, :libgit2), Csize_t, (Ptr{Void},), idx.ptr)
|
||||
end
|
||||
|
||||
function Base.getindex(idx::GitIndex, i::Integer)
|
||||
ie_ptr = ccall((:git_index_get_byindex, :libgit2),
|
||||
Ptr{IndexEntry},
|
||||
(Ptr{Void}, Csize_t), idx.ptr, i-1)
|
||||
ie_ptr == C_NULL && return nothing
|
||||
return unsafe_load(ie_ptr)
|
||||
end
|
||||
|
||||
function Base.find(path::String, idx::GitIndex)
|
||||
pos_ref = Ref{Csize_t}(0)
|
||||
ret = ccall((:git_index_find, :libgit2), Cint,
|
||||
(Ref{Csize_t}, Ptr{Void}, Cstring), pos_ref, idx.ptr, path)
|
||||
ret == Cint(Error.ENOTFOUND) && return Nullable{Csize_t}()
|
||||
return Nullable(pos_ref[]+1)
|
||||
end
|
||||
|
||||
stage(ie::IndexEntry) = ccall((:git_index_entry_stage, :libgit2), Cint, (Ptr{IndexEntry},), Ref(ie))
|
||||
|
||||
function Base.show(io::IO, idx::GitIndex)
|
||||
println(io, "GitIndex:\nRepository: ", repository(idx), "\nNumber of elements: ", count(idx))
|
||||
end
|
||||
949
julia-0.6.2/share/julia/base/libgit2/libgit2.jl
Normal file
949
julia-0.6.2/share/julia/base/libgit2/libgit2.jl
Normal file
@@ -0,0 +1,949 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
module LibGit2
|
||||
|
||||
import Base: merge!, ==
|
||||
|
||||
export with, GitRepo, GitConfig
|
||||
|
||||
const GITHUB_REGEX =
|
||||
r"^(?:git@|git://|https://(?:[\w\.\+\-]+@)?)github.com[:/](([^/].+)/(.+?))(?:\.git)?$"i
|
||||
|
||||
const REFCOUNT = Threads.Atomic{UInt}()
|
||||
|
||||
include("utils.jl")
|
||||
include("consts.jl")
|
||||
include("types.jl")
|
||||
include("error.jl")
|
||||
include("signature.jl")
|
||||
include("oid.jl")
|
||||
include("reference.jl")
|
||||
include("commit.jl")
|
||||
include("repository.jl")
|
||||
include("config.jl")
|
||||
include("walker.jl")
|
||||
include("remote.jl")
|
||||
include("strarray.jl")
|
||||
include("index.jl")
|
||||
include("merge.jl")
|
||||
include("tag.jl")
|
||||
include("blob.jl")
|
||||
include("diff.jl")
|
||||
include("rebase.jl")
|
||||
include("status.jl")
|
||||
include("tree.jl")
|
||||
include("callbacks.jl")
|
||||
|
||||
using .Error
|
||||
|
||||
struct State
|
||||
head::GitHash
|
||||
index::GitHash
|
||||
work::GitHash
|
||||
end
|
||||
|
||||
"""
|
||||
head(pkg::AbstractString) -> String
|
||||
|
||||
Return current HEAD [`GitHash`](@ref) of
|
||||
the `pkg` repo as a string.
|
||||
"""
|
||||
function head(pkg::AbstractString)
|
||||
with(GitRepo, pkg) do repo
|
||||
string(head_oid(repo))
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
need_update(repo::GitRepo)
|
||||
|
||||
Equivalent to `git update-index`. Returns `true`
|
||||
if `repo` needs updating.
|
||||
"""
|
||||
function need_update(repo::GitRepo)
|
||||
if !isbare(repo)
|
||||
# read updates index from filesystem
|
||||
read!(repo, true)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
iscommit(id::AbstractString, repo::GitRepo) -> Bool
|
||||
|
||||
Checks if commit `id` (which is a [`GitHash`](@ref) in string form)
|
||||
is in the repository.
|
||||
|
||||
# Example
|
||||
|
||||
```julia-repl
|
||||
julia> repo = LibGit2.GitRepo(repo_path);
|
||||
|
||||
julia> LibGit2.add!(repo, test_file);
|
||||
|
||||
julia> commit_oid = LibGit2.commit(repo, "add test_file");
|
||||
|
||||
julia> LibGit2.iscommit(string(commit_oid), repo)
|
||||
true
|
||||
```
|
||||
"""
|
||||
function iscommit(id::AbstractString, repo::GitRepo)
|
||||
res = true
|
||||
try
|
||||
c = GitCommit(repo, id)
|
||||
if c === nothing
|
||||
res = false
|
||||
else
|
||||
close(c)
|
||||
end
|
||||
catch
|
||||
res = false
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.isdirty(repo::GitRepo, pathspecs::AbstractString=""; cached::Bool=false) -> Bool
|
||||
|
||||
Checks if there have been any changes to tracked files in the working tree (if
|
||||
`cached=false`) or the index (if `cached=true`).
|
||||
`pathspecs` are the specifications for options for the diff.
|
||||
|
||||
# Example
|
||||
```julia
|
||||
repo = LibGit2.GitRepo(repo_path)
|
||||
LibGit2.isdirty(repo) # should be false
|
||||
open(joinpath(repo_path, new_file), "a") do f
|
||||
println(f, "here's my cool new file")
|
||||
end
|
||||
LibGit2.isdirty(repo) # now true
|
||||
LibGit2.isdirty(repo, new_file) # now true
|
||||
```
|
||||
|
||||
Equivalent to `git diff-index HEAD [-- <pathspecs>]`.
|
||||
"""
|
||||
isdirty(repo::GitRepo, paths::AbstractString=""; cached::Bool=false) =
|
||||
isdiff(repo, Consts.HEAD_FILE, paths, cached=cached)
|
||||
|
||||
"""
|
||||
LibGit2.isdiff(repo::GitRepo, treeish::AbstractString, pathspecs::AbstractString=""; cached::Bool=false)
|
||||
|
||||
Checks if there are any differences between the tree specified by `treeish` and the
|
||||
tracked files in the working tree (if `cached=false`) or the index (if `cached=true`).
|
||||
`pathspecs` are the specifications for options for the diff.
|
||||
|
||||
# Example
|
||||
```julia
|
||||
repo = LibGit2.GitRepo(repo_path)
|
||||
LibGit2.isdiff(repo, "HEAD") # should be false
|
||||
open(joinpath(repo_path, new_file), "a") do f
|
||||
println(f, "here's my cool new file")
|
||||
end
|
||||
LibGit2.isdiff(repo, "HEAD") # now true
|
||||
```
|
||||
|
||||
Equivalent to `git diff-index <treeish> [-- <pathspecs>]`.
|
||||
"""
|
||||
function isdiff(repo::GitRepo, treeish::AbstractString, paths::AbstractString=""; cached::Bool=false)
|
||||
tree = GitTree(repo, "$treeish^{tree}")
|
||||
try
|
||||
diff = diff_tree(repo, tree, paths, cached=cached)
|
||||
result = count(diff) > 0
|
||||
close(diff)
|
||||
return result
|
||||
finally
|
||||
close(tree)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
diff_files(repo::GitRepo, branch1::AbstractString, branch2::AbstractString; kwarg...) -> Vector{AbstractString}
|
||||
|
||||
Show which files have changed in the git repository `repo` between branches `branch1`
|
||||
and `branch2`.
|
||||
|
||||
The keyword argument is:
|
||||
* `filter::Set{Consts.DELTA_STATUS}=Set([Consts.DELTA_ADDED, Consts.DELTA_MODIFIED, Consts.DELTA_DELETED]))`,
|
||||
and it sets options for the diff. The default is to show files added, modified, or deleted.
|
||||
|
||||
Returns only the *names* of the files which have changed, *not* their contents.
|
||||
|
||||
# Example
|
||||
|
||||
```julia
|
||||
LibGit2.branch!(repo, "branch/a")
|
||||
LibGit2.branch!(repo, "branch/b")
|
||||
# add a file to repo
|
||||
open(joinpath(LibGit2.path(repo),"file"),"w") do f
|
||||
write(f, "hello repo\n")
|
||||
end
|
||||
LibGit2.add!(repo, "file")
|
||||
LibGit2.commit(repo, "add file")
|
||||
# returns ["file"]
|
||||
filt = Set([LibGit2.Consts.DELTA_ADDED])
|
||||
files = LibGit2.diff_files(repo, "branch/a", "branch/b", filter=filt)
|
||||
# returns [] because existing files weren't modified
|
||||
filt = Set([LibGit2.Consts.DELTA_MODIFIED])
|
||||
files = LibGit2.diff_files(repo, "branch/a", "branch/b", filter=filt)
|
||||
```
|
||||
|
||||
Equivalent to `git diff --name-only --diff-filter=<filter> <branch1> <branch2>`.
|
||||
"""
|
||||
function diff_files(repo::GitRepo, branch1::AbstractString, branch2::AbstractString;
|
||||
filter::Set{Consts.DELTA_STATUS}=Set([Consts.DELTA_ADDED, Consts.DELTA_MODIFIED, Consts.DELTA_DELETED]))
|
||||
b1_id = revparseid(repo, branch1*"^{tree}")
|
||||
b2_id = revparseid(repo, branch2*"^{tree}")
|
||||
tree1 = GitTree(repo, b1_id)
|
||||
tree2 = GitTree(repo, b2_id)
|
||||
files = AbstractString[]
|
||||
try
|
||||
diff = diff_tree(repo, tree1, tree2)
|
||||
for i in 1:count(diff)
|
||||
delta = diff[i]
|
||||
delta === nothing && break
|
||||
if Consts.DELTA_STATUS(delta.status) in filter
|
||||
push!(files, unsafe_string(delta.new_file.path))
|
||||
end
|
||||
end
|
||||
close(diff)
|
||||
finally
|
||||
close(tree1)
|
||||
close(tree2)
|
||||
end
|
||||
return files
|
||||
end
|
||||
|
||||
"""
|
||||
is_ancestor_of(a::AbstractString, b::AbstractString, repo::GitRepo) -> Bool
|
||||
|
||||
Returns `true` if `a`, a [`GitHash`](@ref) in string form, is an ancestor of
|
||||
`b`, a [`GitHash`](@ref) in string form.
|
||||
|
||||
# Example
|
||||
|
||||
```julia-repl
|
||||
julia> repo = LibGit2.GitRepo(repo_path);
|
||||
|
||||
julia> LibGit2.add!(repo, test_file1);
|
||||
|
||||
julia> commit_oid1 = LibGit2.commit(repo, "commit1");
|
||||
|
||||
julia> LibGit2.add!(repo, test_file2);
|
||||
|
||||
julia> commit_oid2 = LibGit2.commit(repo, "commit2");
|
||||
|
||||
julia> LibGit2.is_ancestor_of(string(commit_oid1), string(commit_oid2), repo)
|
||||
true
|
||||
```
|
||||
"""
|
||||
function is_ancestor_of(a::AbstractString, b::AbstractString, repo::GitRepo)
|
||||
A = revparseid(repo, a)
|
||||
merge_base(repo, a, b) == A
|
||||
end
|
||||
|
||||
"""
|
||||
set_remote_url(repo::GitRepo, url::AbstractString; remote::AbstractString="origin")
|
||||
|
||||
Set the `url` for `remote` for the git repository `repo`.
|
||||
The default name of the remote is `"origin"`.
|
||||
|
||||
# Examples
|
||||
|
||||
```julia
|
||||
repo_path = joinpath("test_directory", "Example")
|
||||
repo = LibGit2.init(repo_path)
|
||||
url1 = "https://github.com/JuliaLang/Example.jl"
|
||||
LibGit2.set_remote_url(repo, url1, remote="upstream")
|
||||
url2 = "https://github.com/JuliaLang/Example2.jl"
|
||||
LibGit2.set_remote_url(repo_path, url2, remote="upstream2")
|
||||
```
|
||||
"""
|
||||
function set_remote_url(repo::GitRepo, url::AbstractString; remote::AbstractString="origin")
|
||||
with(GitConfig, repo) do cfg
|
||||
set!(cfg, "remote.$remote.url", url)
|
||||
set!(cfg, "remote.$remote.pushurl", url)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
set_remote_url(path::AbstractString, url::AbstractString; remote::AbstractString="origin")
|
||||
|
||||
Set the `url` for `remote` for the git repository located at `path`.
|
||||
The default name of the remote is `"origin"`.
|
||||
"""
|
||||
function set_remote_url(path::AbstractString, url::AbstractString; remote::AbstractString="origin")
|
||||
with(GitRepo, path) do repo
|
||||
set_remote_url(repo, url, remote=remote)
|
||||
end
|
||||
end
|
||||
|
||||
function make_payload(payload::Nullable{<:AbstractCredentials})
|
||||
Ref{Nullable{AbstractCredentials}}(payload)
|
||||
end
|
||||
|
||||
"""
|
||||
fetch(repo::GitRepo; kwargs...)
|
||||
|
||||
Fetches updates from an upstream of the repository `repo`.
|
||||
|
||||
The keyword arguments are:
|
||||
* `remote::AbstractString="origin"`: which remote, specified by name,
|
||||
of `repo` to fetch from. If this is empty, the URL will be used to
|
||||
construct an anonymous remote.
|
||||
* `remoteurl::AbstractString=""`: the URL of `remote`. If not specified,
|
||||
will be assumed based on the given name of `remote`.
|
||||
* `refspecs=AbstractString[]`: determines properties of the fetch.
|
||||
* `payload=Nullable{AbstractCredentials}()`: provides credentials, if necessary,
|
||||
for instance if `remote` is a private repository.
|
||||
|
||||
Equivalent to `git fetch [<remoteurl>|<repo>] [<refspecs>]`.
|
||||
"""
|
||||
function fetch(repo::GitRepo; remote::AbstractString="origin",
|
||||
remoteurl::AbstractString="",
|
||||
refspecs::Vector{<:AbstractString}=AbstractString[],
|
||||
payload::Nullable{<:AbstractCredentials}=Nullable{AbstractCredentials}())
|
||||
rmt = if isempty(remoteurl)
|
||||
get(GitRemote, repo, remote)
|
||||
else
|
||||
GitRemoteAnon(repo, remoteurl)
|
||||
end
|
||||
try
|
||||
payload = make_payload(payload)
|
||||
fo = FetchOptions(callbacks=RemoteCallbacks(credentials_cb(), payload))
|
||||
fetch(rmt, refspecs, msg="from $(url(rmt))", options = fo)
|
||||
finally
|
||||
close(rmt)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
push(repo::GitRepo; kwargs...)
|
||||
|
||||
Pushes updates to an upstream of `repo`.
|
||||
|
||||
The keyword arguments are:
|
||||
* `remote::AbstractString="origin"`: the name of the upstream remote to push to.
|
||||
* `remoteurl::AbstractString=""`: the URL of `remote`.
|
||||
* `refspecs=AbstractString[]`: determines properties of the push.
|
||||
* `force::Bool=false`: determines if the push will be a force push,
|
||||
overwriting the remote branch.
|
||||
* `payload=Nullable{AbstractCredentials}()`: provides credentials, if necessary,
|
||||
for instance if `remote` is a private repository.
|
||||
|
||||
Equivalent to `git push [<remoteurl>|<repo>] [<refspecs>]`.
|
||||
"""
|
||||
function push(repo::GitRepo; remote::AbstractString="origin",
|
||||
remoteurl::AbstractString="",
|
||||
refspecs::Vector{<:AbstractString}=AbstractString[],
|
||||
force::Bool=false,
|
||||
payload::Nullable{<:AbstractCredentials}=Nullable{AbstractCredentials}())
|
||||
rmt = if isempty(remoteurl)
|
||||
get(GitRemote, repo, remote)
|
||||
else
|
||||
GitRemoteAnon(repo, remoteurl)
|
||||
end
|
||||
try
|
||||
payload = make_payload(payload)
|
||||
push_opts=PushOptions(callbacks=RemoteCallbacks(credentials_cb(), payload))
|
||||
push(rmt, refspecs, force=force, options=push_opts)
|
||||
finally
|
||||
close(rmt)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
branch(repo::GitRepo)
|
||||
|
||||
Equivalent to `git branch`.
|
||||
Create a new branch from the current HEAD.
|
||||
"""
|
||||
function branch(repo::GitRepo)
|
||||
head_ref = head(repo)
|
||||
try
|
||||
branch(head_ref)
|
||||
finally
|
||||
close(head_ref)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
branch!(repo::GitRepo, branch_name::AbstractString, commit::AbstractString=""; kwargs...)
|
||||
|
||||
Checkout a new git branch in the `repo` repository. `commit` is the [`GitHash`](@ref),
|
||||
in string form, which will be the start of the new branch.
|
||||
If `commit` is an empty string, the current HEAD will be used.
|
||||
|
||||
The keyword arguments are:
|
||||
* `track::AbstractString=""`: the name of the
|
||||
remote branch this new branch should track, if any.
|
||||
If empty (the default), no remote branch
|
||||
will be tracked.
|
||||
* `force::Bool=false`: if `true`, branch creation will
|
||||
be forced.
|
||||
* `set_head::Bool=true`: if `true`, after the branch creation
|
||||
finishes the branch head will be set as the HEAD of `repo`.
|
||||
|
||||
Equivalent to `git checkout [-b|-B] <branch_name> [<commit>] [--track <track>]`.
|
||||
|
||||
# Example
|
||||
|
||||
```julia
|
||||
repo = LibGit2.GitRepo(repo_path)
|
||||
LibGit2.branch!(repo, "new_branch", set_head=false)
|
||||
```
|
||||
"""
|
||||
function branch!(repo::GitRepo, branch_name::AbstractString,
|
||||
commit::AbstractString = ""; # start point
|
||||
track::AbstractString = "", # track remote branch
|
||||
force::Bool=false, # force branch creation
|
||||
set_head::Bool=true) # set as head reference on exit
|
||||
# try to lookup branch first
|
||||
branch_ref = force ? Nullable{GitReference}() : lookup_branch(repo, branch_name)
|
||||
if isnull(branch_ref)
|
||||
branch_rmt_ref = isempty(track) ? Nullable{GitReference}() : lookup_branch(repo, "$track/$branch_name", true)
|
||||
# if commit is empty get head commit oid
|
||||
commit_id = if isempty(commit)
|
||||
if isnull(branch_rmt_ref)
|
||||
with(head(repo)) do head_ref
|
||||
with(peel(GitCommit, head_ref)) do hrc
|
||||
GitHash(hrc)
|
||||
end
|
||||
end
|
||||
else
|
||||
tmpcmt = with(peel(GitCommit, Base.get(branch_rmt_ref))) do hrc
|
||||
GitHash(hrc)
|
||||
end
|
||||
close(Base.get(branch_rmt_ref))
|
||||
tmpcmt
|
||||
end
|
||||
else
|
||||
GitHash(commit)
|
||||
end
|
||||
iszero(commit_id) && return
|
||||
cmt = GitCommit(repo, commit_id)
|
||||
new_branch_ref = nothing
|
||||
try
|
||||
new_branch_ref = Nullable(create_branch(repo, branch_name, cmt, force=force))
|
||||
finally
|
||||
close(cmt)
|
||||
isnull(new_branch_ref) && throw(GitError(Error.Object, Error.ERROR, "cannot create branch `$branch_name` with `$commit_id`"))
|
||||
branch_ref = new_branch_ref
|
||||
end
|
||||
end
|
||||
try
|
||||
#TODO: what if branch tracks other then "origin" remote
|
||||
if !isempty(track) # setup tracking
|
||||
try
|
||||
with(GitConfig, repo) do cfg
|
||||
set!(cfg, "branch.$branch_name.remote", Consts.REMOTE_ORIGIN)
|
||||
set!(cfg, "branch.$branch_name.merge", name(Base.get(branch_ref)))
|
||||
end
|
||||
catch
|
||||
warn("Please provide remote tracking for branch '$branch_name' in '$(path(repo))'")
|
||||
end
|
||||
end
|
||||
|
||||
if set_head
|
||||
# checkout selected branch
|
||||
with(peel(GitTree, Base.get(branch_ref))) do btree
|
||||
checkout_tree(repo, btree)
|
||||
end
|
||||
|
||||
# switch head to the branch
|
||||
head!(repo, Base.get(branch_ref))
|
||||
end
|
||||
finally
|
||||
close(Base.get(branch_ref))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
"""
|
||||
checkout!(repo::GitRepo, commit::AbstractString=""; force::Bool=true)
|
||||
|
||||
Equivalent to `git checkout [-f] --detach <commit>`.
|
||||
Checkout the git commit `commit` (a [`GitHash`](@ref) in string form)
|
||||
in `repo`. If `force` is `true`, force the checkout and discard any
|
||||
current changes. Note that this detaches the current HEAD.
|
||||
|
||||
# Example
|
||||
|
||||
```julia
|
||||
repo = LibGit2.init(repo_path)
|
||||
open(joinpath(LibGit2.path(repo), "file1"), "w") do f
|
||||
write(f, "111\n")
|
||||
end
|
||||
LibGit2.add!(repo, "file1")
|
||||
commit_oid = LibGit2.commit(repo, "add file1")
|
||||
open(joinpath(LibGit2.path(repo), "file1"), "w") do f
|
||||
write(f, "112\n")
|
||||
end
|
||||
# would fail without the force=true
|
||||
# since there are modifications to the file
|
||||
LibGit2.checkout!(repo, string(commit_oid), force=true)
|
||||
```
|
||||
"""
|
||||
function checkout!(repo::GitRepo, commit::AbstractString = "";
|
||||
force::Bool = true)
|
||||
# nothing to do
|
||||
isempty(commit) && return
|
||||
|
||||
# grab head name
|
||||
head_name = Consts.HEAD_FILE
|
||||
try
|
||||
with(head(repo)) do head_ref
|
||||
head_name = shortname(head_ref)
|
||||
# if it is HEAD use short OID instead
|
||||
if head_name == Consts.HEAD_FILE
|
||||
head_name = string(GitHash(head_ref))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# search for commit to get a commit object
|
||||
obj = GitObject(repo, GitHash(commit))
|
||||
peeled = peel(GitCommit, obj)
|
||||
obj_oid = GitHash(peeled)
|
||||
|
||||
# checkout commit
|
||||
checkout_tree(repo, peeled, options = force ? CheckoutOptions(checkout_strategy = Consts.CHECKOUT_FORCE) : CheckoutOptions())
|
||||
|
||||
GitReference(repo, obj_oid, force=force,
|
||||
msg="libgit2.checkout: moving from $head_name to $(obj_oid))")
|
||||
|
||||
return nothing
|
||||
end
|
||||
|
||||
"""
|
||||
clone(repo_url::AbstractString, repo_path::AbstractString; kwargs...)
|
||||
|
||||
Clone a remote repository located at `repo_url` to the local filesystem location `repo_path`.
|
||||
|
||||
The keyword arguments are:
|
||||
* `branch::AbstractString=""`: which branch of the remote to clone,
|
||||
if not the default repository branch (usually `master`).
|
||||
* `isbare::Bool=false`: if `true`, clone the remote as a bare repository,
|
||||
which will make `repo_path` itself the git directory instead of `repo_path/.git`.
|
||||
This means that a working tree cannot be checked out. Plays the role of the
|
||||
git CLI argument `--bare`.
|
||||
* `remote_cb::Ptr{Void}=C_NULL`: a callback which will be used to create the remote
|
||||
before it is cloned. If `C_NULL` (the default), no attempt will be made to create
|
||||
the remote - it will be assumed to already exist.
|
||||
* `payload::Nullable{P<:AbstractCredentials}=Nullable{AbstractCredentials}()`:
|
||||
provides credentials if necessary, for instance if the remote is a private
|
||||
repository.
|
||||
|
||||
Equivalent to `git clone [-b <branch>] [--bare] <repo_url> <repo_path>`.
|
||||
|
||||
# Examples
|
||||
|
||||
```julia
|
||||
repo_url = "https://github.com/JuliaLang/Example.jl"
|
||||
repo1 = LibGit2.clone(repo_url, "test_path")
|
||||
repo2 = LibGit2.clone(repo_url, "test_path", isbare=true)
|
||||
julia_url = "https://github.com/JuliaLang/julia"
|
||||
julia_repo = LibGit2.clone(julia_url, "julia_path", branch="release-0.6")
|
||||
```
|
||||
"""
|
||||
function clone(repo_url::AbstractString, repo_path::AbstractString;
|
||||
branch::AbstractString="",
|
||||
isbare::Bool = false,
|
||||
remote_cb::Ptr{Void} = C_NULL,
|
||||
payload::Nullable{<:AbstractCredentials}=Nullable{AbstractCredentials}())
|
||||
# setup clone options
|
||||
lbranch = Base.cconvert(Cstring, branch)
|
||||
payload = make_payload(payload)
|
||||
fetch_opts=FetchOptions(callbacks = RemoteCallbacks(credentials_cb(), payload))
|
||||
clone_opts = CloneOptions(
|
||||
bare = Cint(isbare),
|
||||
checkout_branch = isempty(lbranch) ? Cstring(C_NULL) : Base.unsafe_convert(Cstring, lbranch),
|
||||
fetch_opts=fetch_opts,
|
||||
remote_cb = remote_cb
|
||||
)
|
||||
return clone(repo_url, repo_path, clone_opts)
|
||||
end
|
||||
|
||||
""" git reset [<committish>] [--] <pathspecs>... """
|
||||
function reset!(repo::GitRepo, committish::AbstractString, pathspecs::AbstractString...)
|
||||
obj = GitObject(repo, isempty(committish) ? Consts.HEAD_FILE : committish)
|
||||
# do not remove entries in the index matching the provided pathspecs with empty target commit tree
|
||||
reset!(repo, Nullable(obj), pathspecs...)
|
||||
end
|
||||
|
||||
"""
|
||||
reset!(repo::GitRepo, id::GitHash, mode::Cint = Consts.RESET_MIXED)
|
||||
|
||||
Reset the repository `repo` to its state at `id`, using one of three modes
|
||||
set by `mode`:
|
||||
1. `Consts.RESET_SOFT` - move HEAD to `id`.
|
||||
2. `Consts.RESET_MIXED` - default, move HEAD to `id` and reset the index to `id`.
|
||||
3. `Consts.RESET_HARD` - move HEAD to `id`, reset the index to `id`, and discard all working changes.
|
||||
|
||||
Equivalent to `git reset [--soft | --mixed | --hard] <id>`.
|
||||
|
||||
# Example
|
||||
|
||||
```julia
|
||||
repo = LibGit2.GitRepo(repo_path)
|
||||
head_oid = LibGit2.head_oid(repo)
|
||||
open(joinpath(repo_path, "file1"), "w") do f
|
||||
write(f, "111\n")
|
||||
end
|
||||
LibGit2.add!(repo, "file1")
|
||||
mode = LibGit2.Consts.RESET_HARD
|
||||
# will discard the changes to file1
|
||||
# and unstage it
|
||||
new_head = LibGit2.reset!(repo, head_oid, mode)
|
||||
```
|
||||
"""
|
||||
reset!(repo::GitRepo, id::GitHash, mode::Cint = Consts.RESET_MIXED) =
|
||||
reset!(repo, GitObject(repo, id), mode)
|
||||
|
||||
"""
|
||||
LibGit2.revcount(repo::GitRepo, commit1::AbstractString, commit2::AbstractString)
|
||||
|
||||
List the number of revisions between `commit1` and `commit2` (committish OIDs in string form).
|
||||
Since `commit1` and `commit2` may be on different branches, `revcount` performs a "left-right"
|
||||
revision list (and count), returning a tuple of `Int`s - the number of left and right
|
||||
commits, respectively. A left (or right) commit refers to which side of a symmetric
|
||||
difference in a tree the commit is reachable from.
|
||||
|
||||
Equivalent to `git rev-list --left-right --count <commit1> <commit2>`.
|
||||
"""
|
||||
function revcount(repo::GitRepo, commit1::AbstractString, commit2::AbstractString)
|
||||
commit1_id = revparseid(repo, commit1)
|
||||
commit2_id = revparseid(repo, commit2)
|
||||
base_id = merge_base(repo, string(commit1_id), string(commit2_id))
|
||||
fc = with(GitRevWalker(repo)) do walker
|
||||
count((i,r)->i!=base_id, walker, oid=commit1_id, by=Consts.SORT_TOPOLOGICAL)
|
||||
end
|
||||
sc = with(GitRevWalker(repo)) do walker
|
||||
count((i,r)->i!=base_id, walker, oid=commit2_id, by=Consts.SORT_TOPOLOGICAL)
|
||||
end
|
||||
return (fc-1, sc-1)
|
||||
end
|
||||
|
||||
"""
|
||||
merge!(repo::GitRepo; kwargs...) -> Bool
|
||||
|
||||
Perform a git merge on the repository `repo`, merging commits
|
||||
with diverging history into the current branch. Returns `true`
|
||||
if the merge succeeded, `false` if not.
|
||||
|
||||
The keyword arguments are:
|
||||
* `committish::AbstractString=""`: Merge the named commit(s) in `committish`.
|
||||
* `branch::AbstractString=""`: Merge the branch `branch` and all its commits
|
||||
since it diverged from the current branch.
|
||||
* `fastforward::Bool=false`: If `fastforward` is `true`, only merge if the
|
||||
merge is a fast-forward (the current branch head is an ancestor of the
|
||||
commits to be merged), otherwise refuse to merge and return `false`.
|
||||
This is equivalent to the git CLI option `--ff-only`.
|
||||
* `merge_opts::MergeOptions=MergeOptions()`: `merge_opts` specifies options
|
||||
for the merge, such as merge strategy in case of conflicts.
|
||||
* `checkout_opts::CheckoutOptions=CheckoutOptions()`: `checkout_opts` specifies
|
||||
options for the checkout step.
|
||||
|
||||
Equivalent to `git merge [--ff-only] [<committish> | <branch>]`.
|
||||
|
||||
!!! note
|
||||
If you specify a `branch`, this must be done in reference format, since
|
||||
the string will be turned into a `GitReference`. For example, if you
|
||||
wanted to merge branch `branch_a`, you would call
|
||||
`merge!(repo, branch="refs/heads/branch_a")`.
|
||||
"""
|
||||
function merge!(repo::GitRepo;
|
||||
committish::AbstractString = "",
|
||||
branch::AbstractString = "",
|
||||
fastforward::Bool = false,
|
||||
merge_opts::MergeOptions = MergeOptions(),
|
||||
checkout_opts::CheckoutOptions = CheckoutOptions())
|
||||
# merge into head branch
|
||||
upst_anns = if !isempty(committish) # merge committish into HEAD
|
||||
if committish == Consts.FETCH_HEAD # merge FETCH_HEAD
|
||||
fheads = fetchheads(repo)
|
||||
filter!(fh->fh.ismerge, fheads)
|
||||
if isempty(fheads)
|
||||
throw(GitError(Error.Merge, Error.ERROR,
|
||||
"There is no fetch reference for this branch."))
|
||||
end
|
||||
map(fh->GitAnnotated(repo,fh), fheads)
|
||||
else # merge commitish
|
||||
[GitAnnotated(repo, committish)]
|
||||
end
|
||||
else
|
||||
if !isempty(branch) # merge provided branch into HEAD
|
||||
with(GitReference(repo, branch)) do brn_ref
|
||||
[GitAnnotated(repo, brn_ref)]
|
||||
end
|
||||
else # try to get tracking remote branch for the head
|
||||
if !isattached(repo)
|
||||
throw(GitError(Error.Merge, Error.ERROR,
|
||||
"Repository HEAD is detached. Remote tracking branch cannot be used."))
|
||||
end
|
||||
if isorphan(repo)
|
||||
# this isn't really a merge, but really moving HEAD
|
||||
# https://github.com/libgit2/libgit2/issues/2135#issuecomment-35997764
|
||||
# try to figure out remote tracking of orphan head
|
||||
|
||||
m = with(GitReference(repo, Consts.HEAD_FILE)) do head_sym_ref
|
||||
match(r"refs/heads/(.*)", fullname(head_sym_ref))
|
||||
end
|
||||
if m === nothing
|
||||
throw(GitError(Error.Merge, Error.ERROR,
|
||||
"Unable to determine name of orphan branch."))
|
||||
end
|
||||
branchname = m.captures[1]
|
||||
remotename = with(GitConfig, repo) do cfg
|
||||
LibGit2.get(String, cfg, "branch.$branchname.remote")
|
||||
end
|
||||
oid = with(GitReference(repo, "refs/remotes/$remotename/$branchname")) do ref
|
||||
LibGit2.GitHash(ref)
|
||||
end
|
||||
with(GitCommit(repo, oid)) do cmt
|
||||
LibGit2.create_branch(repo, branchname, cmt)
|
||||
end
|
||||
return true
|
||||
else
|
||||
with(head(repo)) do head_ref
|
||||
tr_brn_ref = upstream(head_ref)
|
||||
if isnull(tr_brn_ref)
|
||||
throw(GitError(Error.Merge, Error.ERROR,
|
||||
"There is no tracking information for the current branch."))
|
||||
end
|
||||
try
|
||||
[GitAnnotated(repo, Base.get(tr_brn_ref))]
|
||||
finally
|
||||
close(Base.get(tr_brn_ref))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
try
|
||||
merge!(repo, upst_anns, fastforward,
|
||||
merge_opts=merge_opts,
|
||||
checkout_opts=checkout_opts)
|
||||
finally
|
||||
map(close, upst_anns)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.rebase!(repo::GitRepo, upstream::AbstractString="", newbase::AbstractString="")
|
||||
|
||||
Attempt an automatic merge rebase of the current branch, from `upstream` if provided, or
|
||||
otherwise from the upstream tracking branch.
|
||||
`newbase` is the branch to rebase onto. By default this is `upstream`.
|
||||
|
||||
If any conflicts arise which cannot be automatically resolved, the rebase will abort,
|
||||
leaving the repository and working tree in its original state, and the function will throw
|
||||
a `GitError`. This is roughly equivalent to the following command line statement:
|
||||
|
||||
git rebase --merge [<upstream>]
|
||||
if [ -d ".git/rebase-merge" ]; then
|
||||
git rebase --abort
|
||||
fi
|
||||
|
||||
"""
|
||||
function rebase!(repo::GitRepo, upstream::AbstractString="", newbase::AbstractString="")
|
||||
with(head(repo)) do head_ref
|
||||
head_ann = GitAnnotated(repo, head_ref)
|
||||
upst_ann = if isempty(upstream)
|
||||
brn_ref = LibGit2.upstream(head_ref)
|
||||
if isnull(brn_ref)
|
||||
throw(GitError(Error.Rebase, Error.ERROR,
|
||||
"There is no tracking information for the current branch."))
|
||||
end
|
||||
try
|
||||
GitAnnotated(repo, Base.get(brn_ref))
|
||||
finally
|
||||
close(brn_ref)
|
||||
end
|
||||
else
|
||||
GitAnnotated(repo, upstream)
|
||||
end
|
||||
onto_ann = Nullable{GitAnnotated}(isempty(newbase) ? nothing : GitAnnotated(repo, newbase))
|
||||
try
|
||||
sig = default_signature(repo)
|
||||
try
|
||||
rbs = GitRebase(repo, head_ann, upst_ann, onto=onto_ann)
|
||||
try
|
||||
while (rbs_op = next(rbs)) !== nothing
|
||||
commit(rbs, sig)
|
||||
end
|
||||
finish(rbs, sig)
|
||||
catch err
|
||||
abort(rbs)
|
||||
rethrow(err)
|
||||
finally
|
||||
close(rbs)
|
||||
end
|
||||
finally
|
||||
#!isnull(onto_ann) && close(get(onto_ann))
|
||||
close(sig)
|
||||
end
|
||||
finally
|
||||
if !isempty(newbase)
|
||||
close(Base.get(onto_ann))
|
||||
end
|
||||
close(upst_ann)
|
||||
close(head_ann)
|
||||
end
|
||||
end
|
||||
return head_oid(repo)
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
authors(repo::GitRepo) -> Vector{Signature}
|
||||
|
||||
Returns all authors of commits to the `repo` repository.
|
||||
|
||||
# Example
|
||||
|
||||
```julia
|
||||
repo = LibGit2.GitRepo(repo_path)
|
||||
repo_file = open(joinpath(repo_path, test_file), "a")
|
||||
|
||||
println(repo_file, commit_msg)
|
||||
flush(repo_file)
|
||||
LibGit2.add!(repo, test_file)
|
||||
sig = LibGit2.Signature("TEST", "TEST@TEST.COM", round(time(), 0), 0)
|
||||
commit_oid1 = LibGit2.commit(repo, "commit1"; author=sig, committer=sig)
|
||||
println(repo_file, randstring(10))
|
||||
flush(repo_file)
|
||||
LibGit2.add!(repo, test_file)
|
||||
commit_oid2 = LibGit2.commit(repo, "commit2"; author=sig, committer=sig)
|
||||
|
||||
# will be a Vector of [sig, sig]
|
||||
auths = LibGit2.authors(repo)
|
||||
```
|
||||
"""
|
||||
function authors(repo::GitRepo)
|
||||
return with(GitRevWalker(repo)) do walker
|
||||
map((oid,repo)->with(GitCommit(repo, oid)) do cmt
|
||||
author(cmt)::Signature
|
||||
end,
|
||||
walker) #, by = Consts.SORT_TIME)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
snapshot(repo::GitRepo) -> State
|
||||
|
||||
Take a snapshot of the current state of the repository `repo`,
|
||||
storing the current HEAD, index, and any uncommitted work.
|
||||
The output `State` can be used later during a call to [`restore`](@ref)
|
||||
to return the repository to the snapshotted state.
|
||||
"""
|
||||
function snapshot(repo::GitRepo)
|
||||
head = GitHash(repo, Consts.HEAD_FILE)
|
||||
index = with(GitIndex, repo) do idx; write_tree!(idx) end
|
||||
work = try
|
||||
with(GitIndex, repo) do idx
|
||||
if length(readdir(path(repo))) > 1
|
||||
add!(idx, ".")
|
||||
write!(idx)
|
||||
end
|
||||
write_tree!(idx)
|
||||
end
|
||||
finally
|
||||
# restore index
|
||||
with(GitIndex, repo) do idx
|
||||
read_tree!(idx, index)
|
||||
write!(idx)
|
||||
end
|
||||
end
|
||||
State(head, index, work)
|
||||
end
|
||||
|
||||
"""
|
||||
restore(s::State, repo::GitRepo)
|
||||
|
||||
Return a repository `repo` to a previous `State` `s`, for
|
||||
example the HEAD of a branch before a merge attempt. `s`
|
||||
can be generated using the [`snapshot`](@ref) function.
|
||||
"""
|
||||
function restore(s::State, repo::GitRepo)
|
||||
head = reset!(repo, Consts.HEAD_FILE, "*") # unstage everything
|
||||
with(GitIndex, repo) do idx
|
||||
read_tree!(idx, s.work) # move work tree to index
|
||||
opts = CheckoutOptions(
|
||||
checkout_strategy = Consts.CHECKOUT_FORCE | # check the index out to work
|
||||
Consts.CHECKOUT_REMOVE_UNTRACKED) # remove everything else
|
||||
checkout_index(repo, Nullable(idx), options = opts)
|
||||
|
||||
read_tree!(idx, s.index) # restore index
|
||||
end
|
||||
reset!(repo, s.head, Consts.RESET_SOFT) # restore head
|
||||
end
|
||||
|
||||
function transact(f::Function, repo::GitRepo)
|
||||
state = snapshot(repo)
|
||||
try f(repo) catch
|
||||
restore(state, repo)
|
||||
rethrow()
|
||||
finally
|
||||
close(repo)
|
||||
end
|
||||
end
|
||||
|
||||
function set_ssl_cert_locations(cert_loc)
|
||||
cert_file = isfile(cert_loc) ? cert_loc : Cstring(C_NULL)
|
||||
cert_dir = isdir(cert_loc) ? cert_loc : Cstring(C_NULL)
|
||||
cert_file == C_NULL && cert_dir == C_NULL && return
|
||||
# TODO FIX https://github.com/libgit2/libgit2/pull/3935#issuecomment-253910017
|
||||
#ccall((:git_libgit2_opts, :libgit2), Cint,
|
||||
# (Cint, Cstring, Cstring),
|
||||
# Cint(Consts.SET_SSL_CERT_LOCATIONS), cert_file, cert_dir)
|
||||
ENV["SSL_CERT_FILE"] = cert_file
|
||||
ENV["SSL_CERT_DIR"] = cert_dir
|
||||
end
|
||||
|
||||
function __init__()
|
||||
# Look for OpenSSL env variable for CA bundle (linux only)
|
||||
# windows and macOS use the OS native security backends
|
||||
old_ssl_cert_dir = Base.get(ENV, "SSL_CERT_DIR", nothing)
|
||||
old_ssl_cert_file = Base.get(ENV, "SSL_CERT_FILE", nothing)
|
||||
@static if is_linux()
|
||||
cert_loc = if "SSL_CERT_DIR" in keys(ENV)
|
||||
ENV["SSL_CERT_DIR"]
|
||||
elseif "SSL_CERT_FILE" in keys(ENV)
|
||||
ENV["SSL_CERT_FILE"]
|
||||
else
|
||||
# If we have a bundled ca cert file, point libgit2 at that so SSL connections work.
|
||||
abspath(ccall(:jl_get_julia_home, Any, ()),Base.DATAROOTDIR,"julia","cert.pem")
|
||||
end
|
||||
set_ssl_cert_locations(cert_loc)
|
||||
end
|
||||
|
||||
err = ccall((:git_libgit2_init, :libgit2), Cint, ())
|
||||
err > 0 || throw(ErrorException("error initializing LibGit2 module"))
|
||||
REFCOUNT[] = 1
|
||||
|
||||
atexit() do
|
||||
if Threads.atomic_sub!(REFCOUNT, UInt(1)) == 1
|
||||
# refcount zero, no objects to be finalized
|
||||
ccall((:git_libgit2_shutdown, :libgit2), Cint, ())
|
||||
end
|
||||
end
|
||||
|
||||
@static if is_linux()
|
||||
if old_ssl_cert_dir != Base.get(ENV, "SSL_CERT_DIR", "")
|
||||
if old_ssl_cert_dir === nothing
|
||||
delete!(ENV, "SSL_CERT_DIR")
|
||||
else
|
||||
ENV["SSL_CERT_DIR"] = old_ssl_cert_dir
|
||||
end
|
||||
end
|
||||
if old_ssl_cert_file != Base.get(ENV, "SSL_CERT_FILE", "")
|
||||
if old_ssl_cert_file === nothing
|
||||
delete!(ENV, "SSL_CERT_FILE")
|
||||
else
|
||||
ENV["SSL_CERT_FILE"] = old_ssl_cert_file
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end # module
|
||||
154
julia-0.6.2/share/julia/base/libgit2/merge.jl
Normal file
154
julia-0.6.2/share/julia/base/libgit2/merge.jl
Normal file
@@ -0,0 +1,154 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function GitAnnotated(repo::GitRepo, commit_id::GitHash)
|
||||
ann_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_annotated_commit_lookup, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{GitHash}),
|
||||
ann_ptr_ptr, repo.ptr, Ref(commit_id))
|
||||
return GitAnnotated(repo, ann_ptr_ptr[])
|
||||
end
|
||||
|
||||
function GitAnnotated(repo::GitRepo, ref::GitReference)
|
||||
ann_ref_ref = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_annotated_commit_from_ref, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{Void}),
|
||||
ann_ref_ref, repo.ptr, ref.ptr)
|
||||
return GitAnnotated(repo, ann_ref_ref[])
|
||||
end
|
||||
|
||||
function GitAnnotated(repo::GitRepo, fh::FetchHead)
|
||||
ann_ref_ref = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_annotated_commit_from_fetchhead, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cstring, Cstring, Ptr{GitHash}),
|
||||
ann_ref_ref, repo.ptr, fh.name, fh.url, Ref(fh.oid))
|
||||
return GitAnnotated(repo, ann_ref_ref[])
|
||||
end
|
||||
|
||||
function GitAnnotated(repo::GitRepo, comittish::AbstractString)
|
||||
obj = GitObject(repo, comittish)
|
||||
cmt = peel(GitCommit, obj)
|
||||
return GitAnnotated(repo, GitHash(cmt))
|
||||
end
|
||||
|
||||
function GitHash(ann::GitAnnotated)
|
||||
unsafe_load(ccall((:git_annotated_commit_id, :libgit2), Ptr{GitHash}, (Ptr{Void},), ann.ptr))
|
||||
end
|
||||
|
||||
function merge_analysis(repo::GitRepo, anns::Vector{GitAnnotated})
|
||||
analysis = Ref{Cint}(0)
|
||||
preference = Ref{Cint}(0)
|
||||
anns_ref = Ref(map(a->a.ptr, anns))
|
||||
anns_size = Csize_t(length(anns))
|
||||
@check ccall((:git_merge_analysis, :libgit2), Cint,
|
||||
(Ptr{Cint}, Ptr{Cint}, Ptr{Void}, Ptr{Ptr{Void}}, Csize_t),
|
||||
analysis, preference, repo.ptr, anns_ref, anns_size)
|
||||
return analysis[], preference[]
|
||||
end
|
||||
|
||||
"""Fastforward merge changes into current head """
|
||||
function ffmerge!(repo::GitRepo, ann::GitAnnotated)
|
||||
cmt = GitCommit(repo, GitHash(ann))
|
||||
|
||||
checkout_tree(repo, cmt)
|
||||
with(head(repo)) do head_ref
|
||||
cmt_oid = GitHash(cmt)
|
||||
msg = "libgit2.merge: fastforward $(string(cmt_oid)) into $(name(head_ref))"
|
||||
new_head_ref = if reftype(head_ref) == Consts.REF_OID
|
||||
target!(head_ref, cmt_oid, msg=msg)
|
||||
else
|
||||
GitReference(repo, cmt_oid, fullname(head_ref), msg=msg)
|
||||
end
|
||||
close(new_head_ref)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
""" Merge changes into current head """
|
||||
function merge!(repo::GitRepo, anns::Vector{GitAnnotated};
|
||||
merge_opts::MergeOptions = MergeOptions(),
|
||||
checkout_opts::CheckoutOptions = CheckoutOptions())
|
||||
anns_size = Csize_t(length(anns))
|
||||
@check ccall((:git_merge, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{Ptr{Void}}, Csize_t,
|
||||
Ptr{MergeOptions}, Ptr{CheckoutOptions}),
|
||||
repo.ptr, map(x->x.ptr, anns), anns_size,
|
||||
Ref(merge_opts), Ref(checkout_opts))
|
||||
info("Review and commit merged changes.")
|
||||
return true
|
||||
end
|
||||
|
||||
"""Internal implementation of merge.
|
||||
Returns `true` if merge was successful, otherwise `false`
|
||||
"""
|
||||
function merge!(repo::GitRepo, anns::Vector{GitAnnotated}, fastforward::Bool;
|
||||
merge_opts::MergeOptions = MergeOptions(),
|
||||
checkout_opts::CheckoutOptions = CheckoutOptions())
|
||||
ma, mp = merge_analysis(repo, anns)
|
||||
if isset(ma, Cint(Consts.MERGE_ANALYSIS_UP_TO_DATE))
|
||||
return true # no merge - everything is up to date
|
||||
end
|
||||
|
||||
ffpref = if fastforward
|
||||
Consts.MERGE_PREFERENCE_FASTFORWARD_ONLY
|
||||
elseif isset(mp, Cint(Consts.MERGE_PREFERENCE_NONE))
|
||||
Consts.MERGE_PREFERENCE_NONE
|
||||
elseif isset(mp, Cint(Consts.MERGE_PREFERENCE_NO_FASTFORWARD))
|
||||
Consts.MERGE_PREFERENCE_NO_FASTFORWARD
|
||||
elseif isset(mp, Cint(Consts.MERGE_PREFERENCE_FASTFORWARD_ONLY))
|
||||
Consts.MERGE_PREFERENCE_FASTFORWARD_ONLY
|
||||
else
|
||||
throw(ArgumentError("unknown merge preference: $(mp)."))
|
||||
end
|
||||
|
||||
merge_result = if ffpref == Consts.MERGE_PREFERENCE_NONE
|
||||
if isset(ma, Cint(Consts.MERGE_ANALYSIS_FASTFORWARD))
|
||||
if length(anns) > 1
|
||||
warn("Unable to perform Fast-Forward merge with mith multiple merge heads.")
|
||||
false
|
||||
else
|
||||
ffmerge!(repo, anns[1])
|
||||
end
|
||||
elseif isset(ma, Cint(Consts.MERGE_ANALYSIS_NORMAL))
|
||||
merge!(repo, anns,
|
||||
merge_opts=merge_opts,
|
||||
checkout_opts=checkout_opts)
|
||||
end
|
||||
elseif ffpref == Consts.MERGE_PREFERENCE_FASTFORWARD_ONLY
|
||||
if isset(ma, Cint(Consts.MERGE_ANALYSIS_FASTFORWARD))
|
||||
if length(anns) > 1
|
||||
warn("Unable to perform Fast-Forward merge with mith multiple merge heads.")
|
||||
false
|
||||
else
|
||||
ffmerge!(repo, anns[1])
|
||||
end
|
||||
else
|
||||
warn("Cannot perform fast-forward merge.")
|
||||
false
|
||||
end
|
||||
elseif ffpref == Consts.MERGE_PREFERENCE_NO_FASTFORWARD
|
||||
if isset(ma, Cint(Consts.MERGE_ANALYSIS_NORMAL))
|
||||
merge!(repo, anns,
|
||||
merge_opts=merge_opts,
|
||||
checkout_opts=checkout_opts)
|
||||
end
|
||||
else
|
||||
throw(ArgumentError("unknown merge analysis result: $(ma)"))
|
||||
end
|
||||
return merge_result
|
||||
end
|
||||
|
||||
function merge_base(repo::GitRepo, one::AbstractString, two::AbstractString)
|
||||
oid1_ptr = Ref(GitHash(one))
|
||||
oid2_ptr = Ref(GitHash(two))
|
||||
moid_ptr = Ref(GitHash())
|
||||
moid = try
|
||||
@check ccall((:git_merge_base, :libgit2), Cint,
|
||||
(Ptr{GitHash}, Ptr{Void}, Ptr{GitHash}, Ptr{GitHash}),
|
||||
moid_ptr, repo.ptr, oid1_ptr, oid2_ptr)
|
||||
moid_ptr[]
|
||||
catch e
|
||||
#warn("Pkg:",path(repo),"=>",e.msg)
|
||||
GitHash()
|
||||
end
|
||||
return moid
|
||||
end
|
||||
106
julia-0.6.2/share/julia/base/libgit2/oid.jl
Normal file
106
julia-0.6.2/share/julia/base/libgit2/oid.jl
Normal file
@@ -0,0 +1,106 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function GitHash(ptr::Ptr{UInt8})
|
||||
if ptr == C_NULL
|
||||
throw(ArgumentError("NULL pointer passed to GitHash() constructor"))
|
||||
end
|
||||
oid_ptr = Ref(GitHash())
|
||||
ccall((:git_oid_fromraw, :libgit2), Void, (Ptr{GitHash}, Ptr{UInt8}), oid_ptr, ptr)
|
||||
return oid_ptr[]
|
||||
end
|
||||
|
||||
function GitHash(id::Array{UInt8,1})
|
||||
if length(id) != OID_RAWSZ
|
||||
throw(ArgumentError("invalid raw buffer size"))
|
||||
end
|
||||
return GitHash(pointer(id))
|
||||
end
|
||||
|
||||
function GitHash(id::AbstractString)
|
||||
bstr = String(id)
|
||||
len = sizeof(bstr)
|
||||
if len < OID_HEXSZ
|
||||
throw(ArgumentError("Input string is too short, use `GitShortHash` for partial hashes"))
|
||||
end
|
||||
oid_ptr = Ref{GitHash}()
|
||||
@check ccall((:git_oid_fromstrn, :libgit2), Cint,
|
||||
(Ptr{GitHash}, Ptr{UInt8}, Csize_t), oid_ptr, bstr, len)
|
||||
return oid_ptr[]
|
||||
end
|
||||
function GitShortHash(id::AbstractString)
|
||||
bstr = String(id)
|
||||
len = sizeof(bstr)
|
||||
oid_ptr = Ref{GitHash}()
|
||||
@check ccall((:git_oid_fromstrn, :libgit2), Cint,
|
||||
(Ptr{GitHash}, Ptr{UInt8}, Csize_t), oid_ptr, bstr, len)
|
||||
GitShortHash(oid_ptr[], len)
|
||||
end
|
||||
|
||||
macro githash_str(id)
|
||||
bstr = String(id)
|
||||
if sizeof(bstr) < OID_HEXSZ
|
||||
GitShortHash(id)
|
||||
else
|
||||
GitHash(id)
|
||||
end
|
||||
end
|
||||
function GitHash(ref::GitReference)
|
||||
isempty(ref) && return GitHash()
|
||||
reftype(ref) != Consts.REF_OID && return GitHash()
|
||||
oid_ptr = ccall((:git_reference_target, :libgit2), Ptr{UInt8}, (Ptr{Void},), ref.ptr)
|
||||
oid_ptr == C_NULL && return GitHash()
|
||||
return GitHash(oid_ptr)
|
||||
end
|
||||
|
||||
function GitHash(repo::GitRepo, ref_name::AbstractString)
|
||||
isempty(repo) && return GitHash()
|
||||
oid_ptr = Ref(GitHash())
|
||||
@check ccall((:git_reference_name_to_id, :libgit2), Cint,
|
||||
(Ptr{GitHash}, Ptr{Void}, Cstring),
|
||||
oid_ptr, repo.ptr, ref_name)
|
||||
return oid_ptr[]
|
||||
end
|
||||
|
||||
function GitHash(obj::GitObject)
|
||||
GitHash(ccall((:git_object_id, :libgit2), Ptr{UInt8}, (Ptr{Void},), obj.ptr))
|
||||
end
|
||||
|
||||
Base.hex(id::GitHash) = join([hex(i,2) for i in id.val])
|
||||
Base.hex(id::GitShortHash) = hex(id.hash)[1:id.len]
|
||||
|
||||
raw(id::GitHash) = collect(id.val)
|
||||
|
||||
Base.string(id::AbstractGitHash) = hex(id)
|
||||
|
||||
Base.show(io::IO, id::GitHash) = print(io, "GitHash(\"$(string(id))\")")
|
||||
Base.show(io::IO, id::GitShortHash) = print(io, "GitShortHash(\"$(string(id))\")")
|
||||
|
||||
Base.hash(id::GitHash, h::UInt) = hash(id.val, h)
|
||||
|
||||
function Base.cmp(id1::GitHash, id2::GitHash)
|
||||
Int(ccall((:git_oid_cmp, :libgit2), Cint,
|
||||
(Ptr{GitHash}, Ptr{GitHash}),
|
||||
Ref(id1), Ref(id2)))
|
||||
end
|
||||
function Base.cmp(id1::GitShortHash, id2::GitShortHash)
|
||||
# shortened hashes appear at the beginning of the order, i.e.
|
||||
# 000 < 01 < 010 < 011 < 0112
|
||||
c = Int(ccall((:git_oid_ncmp, :libgit2), Cint,
|
||||
(Ptr{GitHash}, Ptr{GitHash}, Csize_t),
|
||||
Ref(id1.hash), Ref(id2.hash), min(id1.len, id2.len)))
|
||||
return c == 0 ? cmp(id1.len, id2.len) : c
|
||||
end
|
||||
Base.cmp(id1::GitHash, id2::GitShortHash) = cmp(GitShortHash(id1, OID_HEXSZ), id2)
|
||||
Base.cmp(id1::GitShortHash, id2::GitHash) = cmp(id1, GitShortHash(id2, OID_HEXSZ))
|
||||
|
||||
==(id1::GitHash, id2::GitHash) = cmp(id1, id2) == 0
|
||||
Base.isless(id1::AbstractGitHash, id2::AbstractGitHash) = cmp(id1, id2) < 0
|
||||
|
||||
function iszero(id::GitHash)
|
||||
for i in 1:OID_RAWSZ
|
||||
id.val[i] != zero(UInt8) && return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
Base.zero(::Type{GitHash}) = GitHash()
|
||||
81
julia-0.6.2/share/julia/base/libgit2/rebase.jl
Normal file
81
julia-0.6.2/share/julia/base/libgit2/rebase.jl
Normal file
@@ -0,0 +1,81 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function GitRebase(repo::GitRepo, branch::GitAnnotated, upstream::GitAnnotated;
|
||||
onto::Nullable{GitAnnotated}=Nullable{GitAnnotated}(),
|
||||
opts::RebaseOptions = RebaseOptions())
|
||||
rebase_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_rebase_init, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{Void}, Ptr{Void},
|
||||
Ptr{Void}, Ptr{RebaseOptions}),
|
||||
rebase_ptr_ptr, repo.ptr, branch.ptr, upstream.ptr,
|
||||
isnull(onto) ? C_NULL : Base.get(onto).ptr, Ref(opts))
|
||||
return GitRebase(repo, rebase_ptr_ptr[])
|
||||
end
|
||||
|
||||
function Base.count(rb::GitRebase)
|
||||
return ccall((:git_rebase_operation_entrycount, :libgit2), Csize_t, (Ptr{Void},), rb.ptr)
|
||||
end
|
||||
|
||||
function current(rb::GitRebase)
|
||||
return ccall((:git_rebase_operation_current, :libgit2), Csize_t, (Ptr{Void},), rb.ptr)
|
||||
end
|
||||
|
||||
function Base.getindex(rb::GitRebase, i::Integer)
|
||||
if !(1 <= i <= count(rb))
|
||||
throw(BoundsError(rb, (i,)))
|
||||
end
|
||||
rb_op_ptr = ccall((:git_rebase_operation_byindex, :libgit2),
|
||||
Ptr{RebaseOperation},
|
||||
(Ptr{Void}, Csize_t), rb.ptr, i-1)
|
||||
return unsafe_load(rb_op_ptr)
|
||||
end
|
||||
|
||||
function Base.next(rb::GitRebase)
|
||||
rb_op_ptr_ptr = Ref{Ptr{RebaseOperation}}(C_NULL)
|
||||
try
|
||||
@check ccall((:git_rebase_next, :libgit2), Cint,
|
||||
(Ptr{Ptr{RebaseOperation}}, Ptr{Void}),
|
||||
rb_op_ptr_ptr, rb.ptr)
|
||||
catch err
|
||||
err.code == Error.ITEROVER && return nothing
|
||||
rethrow(err)
|
||||
end
|
||||
return unsafe_load(rb_op_ptr_ptr[])
|
||||
end
|
||||
|
||||
function Base.show(io::IO, rb::GitRebase)
|
||||
println(io, "GitRebase:")
|
||||
println(io, "Number: ", count(rb))
|
||||
println(io, "Currently performing operation: ", current(rb)+1)
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.commit(rb::GitRebase, sig::GitSignature)
|
||||
|
||||
Commits the current patch to the rebase `rb`, using `sig` as the committer. Is silent if
|
||||
the commit has already been applied.
|
||||
"""
|
||||
function commit(rb::GitRebase, sig::GitSignature)
|
||||
oid_ptr = Ref(GitHash())
|
||||
try
|
||||
@check ccall((:git_rebase_commit, :libgit2), Error.Code,
|
||||
(Ptr{GitHash}, Ptr{Void}, Ptr{SignatureStruct}, Ptr{SignatureStruct}, Ptr{UInt8}, Ptr{UInt8}),
|
||||
oid_ptr, rb.ptr, C_NULL, sig.ptr, C_NULL, C_NULL)
|
||||
catch err
|
||||
# TODO: return current HEAD instead
|
||||
err.code == Error.EAPPLIED && return nothing
|
||||
rethrow(err)
|
||||
end
|
||||
return oid_ptr[]
|
||||
end
|
||||
|
||||
function abort(rb::GitRebase)
|
||||
return ccall((:git_rebase_abort, :libgit2), Csize_t,
|
||||
(Ptr{Void},), rb.ptr)
|
||||
end
|
||||
|
||||
function finish(rb::GitRebase, sig::GitSignature)
|
||||
return ccall((:git_rebase_finish, :libgit2), Csize_t,
|
||||
(Ptr{Void}, Ptr{SignatureStruct}),
|
||||
rb.ptr, sig.ptr)
|
||||
end
|
||||
347
julia-0.6.2/share/julia/base/libgit2/reference.jl
Normal file
347
julia-0.6.2/share/julia/base/libgit2/reference.jl
Normal file
@@ -0,0 +1,347 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function GitReference(repo::GitRepo, refname::AbstractString)
|
||||
ref_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_reference_lookup, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cstring),
|
||||
ref_ptr_ptr, repo.ptr, refname)
|
||||
return GitReference(repo, ref_ptr_ptr[])
|
||||
end
|
||||
|
||||
function GitReference(repo::GitRepo, obj_oid::GitHash, refname::AbstractString = Consts.HEAD_FILE;
|
||||
force::Bool=false, msg::AbstractString="")
|
||||
ref_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_reference_create, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{UInt8}, Ptr{GitHash}, Cint, Cstring),
|
||||
ref_ptr_ptr, repo.ptr, refname, Ref(obj_oid), Cint(force),
|
||||
isempty(msg) ? C_NULL : msg)
|
||||
return GitReference(repo, ref_ptr_ptr[])
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.isorphan(repo::GitRepo)
|
||||
|
||||
Checks if the current branch is an "orphan" branch, i.e. has no commits. The first commit
|
||||
to this branch will have no parents.
|
||||
"""
|
||||
function isorphan(repo::GitRepo)
|
||||
r = @check ccall((:git_repository_head_unborn, :libgit2), Cint,
|
||||
(Ptr{Void},), repo.ptr)
|
||||
r != 0
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.head(repo::GitRepo) -> GitReference
|
||||
|
||||
Returns a `GitReference` to the current HEAD of `repo`.
|
||||
"""
|
||||
function head(repo::GitRepo)
|
||||
head_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_repository_head, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}), head_ptr_ptr, repo.ptr)
|
||||
return GitReference(repo, head_ptr_ptr[])
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.shortname(ref::GitReference)
|
||||
|
||||
Returns a shortened version of the name of `ref` that's
|
||||
"human-readable".
|
||||
|
||||
```julia-repl
|
||||
julia> repo = LibGit2.GitRepo(path_to_repo);
|
||||
|
||||
julia> branch_ref = LibGit2.head(repo);
|
||||
|
||||
julia> LibGit2.name(branch_ref)
|
||||
"refs/heads/master"
|
||||
|
||||
julia> LibGit2.shortname(branch_ref)
|
||||
"master"
|
||||
```
|
||||
"""
|
||||
function shortname(ref::GitReference)
|
||||
isempty(ref) && return ""
|
||||
name_ptr = ccall((:git_reference_shorthand, :libgit2), Cstring, (Ptr{Void},), ref.ptr)
|
||||
name_ptr == C_NULL && return ""
|
||||
return unsafe_string(name_ptr)
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.reftype(ref::GitReference) -> Cint
|
||||
|
||||
Returns a `Cint` corresponding to the type of `ref`:
|
||||
* `0` if the reference is invalid
|
||||
* `1` if the reference is an object id
|
||||
* `2` if the reference is symbolic
|
||||
"""
|
||||
function reftype(ref::GitReference)
|
||||
return ccall((:git_reference_type, :libgit2), Cint, (Ptr{Void},), ref.ptr)
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.fullname(ref::GitReference)
|
||||
|
||||
Return the name of the reference pointed to by the
|
||||
symbolic reference `ref`. If `ref` is not a symbolic
|
||||
reference, returns an empty string.
|
||||
"""
|
||||
function fullname(ref::GitReference)
|
||||
isempty(ref) && return ""
|
||||
reftype(ref) == Consts.REF_OID && return ""
|
||||
rname = ccall((:git_reference_symbolic_target, :libgit2), Cstring, (Ptr{Void},), ref.ptr)
|
||||
rname == C_NULL && return ""
|
||||
return unsafe_string(rname)
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.name(ref::GitReference)
|
||||
|
||||
Return the full name of `ref`.
|
||||
"""
|
||||
function name(ref::GitReference)
|
||||
isempty(ref) && return ""
|
||||
name_ptr = ccall((:git_reference_name, :libgit2), Cstring, (Ptr{Void},), ref.ptr)
|
||||
name_ptr == C_NULL && return ""
|
||||
return unsafe_string(name_ptr)
|
||||
end
|
||||
|
||||
function branch(ref::GitReference)
|
||||
isempty(ref) && return ""
|
||||
str_ptr_ptr = Ref{Cstring}()
|
||||
@check ccall((:git_branch_name, :libgit2), Cint,
|
||||
(Ptr{Cstring}, Ptr{Void},), str_ptr_ptr, ref.ptr)
|
||||
return unsafe_string(str_ptr_ptr[])
|
||||
end
|
||||
|
||||
function ishead(ref::GitReference)
|
||||
isempty(ref) && return false
|
||||
err = ccall((:git_branch_is_head, :libgit2), Cint,
|
||||
(Ptr{Void},), ref.ptr)
|
||||
return err == 1
|
||||
end
|
||||
|
||||
function isbranch(ref::GitReference)
|
||||
isempty(ref) && return false
|
||||
err = ccall((:git_reference_is_branch, :libgit2), Cint,
|
||||
(Ptr{Void},), ref.ptr)
|
||||
return err == 1
|
||||
end
|
||||
|
||||
function istag(ref::GitReference)
|
||||
isempty(ref) && return false
|
||||
err = ccall((:git_reference_is_tag, :libgit2), Cint,
|
||||
(Ptr{Void},), ref.ptr)
|
||||
return err == 1
|
||||
end
|
||||
|
||||
function isremote(ref::GitReference)
|
||||
isempty(ref) && return false
|
||||
err = ccall((:git_reference_is_remote, :libgit2), Cint,
|
||||
(Ptr{Void},), ref.ptr)
|
||||
return err == 1
|
||||
end
|
||||
|
||||
function Base.show(io::IO, ref::GitReference)
|
||||
println(io, "GitReference:")
|
||||
if isremote(ref)
|
||||
println(io, "Remote with name ", name(ref))
|
||||
elseif isbranch(ref)
|
||||
println(io, "Branch with name ", name(ref))
|
||||
if ishead(ref)
|
||||
println(io, "Branch is HEAD.")
|
||||
else
|
||||
println(io, "Branch is not HEAD.")
|
||||
end
|
||||
elseif istag(ref)
|
||||
println(io, "Tag with name ", name(ref))
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
peel([T,] ref::GitReference)
|
||||
|
||||
Recursively peel `ref` until an object of type `T` is obtained. If no `T` is provided,
|
||||
then `ref` will be peeled until an object other than a [`GitTag`](@ref) is obtained.
|
||||
|
||||
- A `GitTag` will be peeled to the object it references.
|
||||
- A [`GitCommit`](@ref) will be peeled to a [`GitTree`](@ref).
|
||||
|
||||
!!! note
|
||||
Only annotated tags can be peeled to `GitTag` objects. Lightweight tags (the default)
|
||||
are references under `refs/tags/` which point directly to `GitCommit` objects.
|
||||
"""
|
||||
function peel{T<:GitObject}(::Type{T}, ref::GitReference)
|
||||
obj_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_reference_peel, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cint), obj_ptr_ptr, ref.ptr, Consts.OBJECT(T))
|
||||
return T(ref.owner, obj_ptr_ptr[])
|
||||
end
|
||||
peel(ref::GitReference) = peel(GitObject, ref)
|
||||
|
||||
"""
|
||||
LibGit2.ref_list(repo::GitRepo) -> Vector{String}
|
||||
|
||||
Get a list of all reference names in the `repo` repository.
|
||||
"""
|
||||
function ref_list(repo::GitRepo)
|
||||
sa_ref = Ref(StrArrayStruct())
|
||||
@check ccall((:git_reference_list, :libgit2), Cint,
|
||||
(Ptr{StrArrayStruct}, Ptr{Void}), sa_ref, repo.ptr)
|
||||
res = convert(Vector{String}, sa_ref[])
|
||||
free(sa_ref)
|
||||
res
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.create_branch(repo::GitRepo, bname::AbstractString, commit_obj::GitCommit; force::Bool=false)
|
||||
|
||||
Create a new branch in the repository `repo` with name `bname`, which
|
||||
points to commit `commit_obj` (which has to be part of `repo`). If
|
||||
`force` is `true`, overwrite an existing branch named `bname` if it
|
||||
exists. If `force` is `false` and a branch already exists named `bname`,
|
||||
this function will throw an error.
|
||||
"""
|
||||
function create_branch(repo::GitRepo,
|
||||
bname::AbstractString,
|
||||
commit_obj::GitCommit;
|
||||
force::Bool=false)
|
||||
ref_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_branch_create, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cstring, Ptr{Void}, Cint),
|
||||
ref_ptr_ptr, repo.ptr, bname, commit_obj.ptr, Cint(force))
|
||||
return GitReference(repo, ref_ptr_ptr[])
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.delete_branch(branch::GitReference)
|
||||
|
||||
Delete the branch pointed to by `branch`.
|
||||
"""
|
||||
function delete_branch(branch::GitReference)
|
||||
@check ccall((:git_branch_delete, :libgit2), Cint, (Ptr{Void},), branch.ptr)
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.head!(repo::GitRepo, ref::GitReference) -> GitReference
|
||||
|
||||
Set the HEAD of `repo` to the object pointed to by `ref`.
|
||||
"""
|
||||
function head!(repo::GitRepo, ref::GitReference)
|
||||
ref_name = name(ref)
|
||||
@check ccall((:git_repository_set_head, :libgit2), Cint,
|
||||
(Ptr{Void}, Cstring), repo.ptr, ref_name)
|
||||
return ref
|
||||
end
|
||||
|
||||
"""
|
||||
lookup_branch(repo::GitRepo, branch_name::AbstractString, remote::Bool=false) -> Nullable{GitReference}
|
||||
|
||||
Determine if the branch specified by `branch_name` exists in the repository `repo`.
|
||||
If `remote` is `true`, `repo` is assumed to be a remote git repository. Otherwise, it
|
||||
is part of the local filesystem.
|
||||
|
||||
`lookup_branch` returns a [`Nullable`](@ref), which will be null if the requested branch does
|
||||
not exist yet. If the branch does exist, the `Nullable` contains a `GitReference` to
|
||||
the branch.
|
||||
"""
|
||||
function lookup_branch(repo::GitRepo,
|
||||
branch_name::AbstractString,
|
||||
remote::Bool=false)
|
||||
ref_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
branch_type = remote ? Consts.BRANCH_REMOTE : Consts.BRANCH_LOCAL
|
||||
err = ccall((:git_branch_lookup, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{UInt8}, Cint),
|
||||
ref_ptr_ptr, repo.ptr, branch_name, branch_type)
|
||||
if err != Int(Error.GIT_OK)
|
||||
if err == Int(Error.ENOTFOUND)
|
||||
return Nullable{GitReference}()
|
||||
end
|
||||
if ref_ptr_ptr[] != C_NULL
|
||||
close(GitReference(repo, ref_ptr_ptr[]))
|
||||
end
|
||||
throw(Error.GitError(err))
|
||||
end
|
||||
return Nullable{GitReference}(GitReference(repo, ref_ptr_ptr[]))
|
||||
end
|
||||
|
||||
"""
|
||||
upstream(ref::GitReference) -> Nullable{GitReference}
|
||||
|
||||
Determine if the branch containing `ref` has a specified upstream branch.
|
||||
|
||||
`upstream` returns a [`Nullable`](@ref), which will be null if the requested branch does
|
||||
not have an upstream counterpart. If the upstream branch does exist, the `Nullable`
|
||||
contains a `GitReference` to the upstream branch.
|
||||
"""
|
||||
function upstream(ref::GitReference)
|
||||
isempty(ref) && return nothing
|
||||
ref_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
err = ccall((:git_branch_upstream, :libgit2), Cint,
|
||||
(Ref{Ptr{Void}}, Ptr{Void},), ref_ptr_ptr, ref.ptr)
|
||||
if err != Int(Error.GIT_OK)
|
||||
if err == Int(Error.ENOTFOUND)
|
||||
return Nullable{GitReference}()
|
||||
end
|
||||
if ref_ptr_ptr[] != C_NULL
|
||||
close(GitReference(ref.owner, ref_ptr_ptr[]))
|
||||
end
|
||||
throw(Error.GitError(err))
|
||||
end
|
||||
return Nullable{GitReference}(GitReference(ref.owner, ref_ptr_ptr[]))
|
||||
end
|
||||
|
||||
repository(ref::GitReference) = ref.owner
|
||||
|
||||
function target!(ref::GitReference, new_oid::GitHash; msg::AbstractString="")
|
||||
ref_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_reference_set_target, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{GitHash}, Cstring),
|
||||
ref_ptr_ptr, ref.ptr, Ref(new_oid), isempty(msg) ? C_NULL : msg)
|
||||
return GitReference(ref.owner, ref_ptr_ptr[])
|
||||
end
|
||||
|
||||
function GitBranchIter(repo::GitRepo, flags::Cint=Cint(Consts.BRANCH_LOCAL))
|
||||
bi_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_branch_iterator_new, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cint), bi_ptr, repo.ptr, flags)
|
||||
return GitBranchIter(repo, bi_ptr[])
|
||||
end
|
||||
|
||||
function Base.start(bi::GitBranchIter)
|
||||
ref_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
btype = Ref{Cint}()
|
||||
err = ccall((:git_branch_next, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Cint}, Ptr{Void}),
|
||||
ref_ptr_ptr, btype, bi.ptr)
|
||||
err != Int(Error.GIT_OK) && return (nothing, -1, true)
|
||||
return (GitReference(bi.owner, ref_ptr_ptr[]), btype[], false)
|
||||
end
|
||||
|
||||
Base.done(bi::GitBranchIter, state) = Bool(state[3])
|
||||
|
||||
function Base.next(bi::GitBranchIter, state)
|
||||
ref_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
btype = Ref{Cint}()
|
||||
err = ccall((:git_branch_next, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Cint}, Ptr{Void}),
|
||||
ref_ptr_ptr, btype, bi.ptr)
|
||||
err != Int(Error.GIT_OK) && return (state[1:2], (nothing, -1, true))
|
||||
return (state[1:2], (GitReference(bi.owner, ref_ptr_ptr[]), btype[], false))
|
||||
end
|
||||
|
||||
Base.iteratorsize(::Type{GitBranchIter}) = Base.SizeUnknown()
|
||||
|
||||
function Base.map(f::Function, bi::GitBranchIter)
|
||||
res = nothing
|
||||
s = start(bi)
|
||||
while !done(bi, s)
|
||||
val = f(s[1:2])
|
||||
if res === nothing
|
||||
res = Vector{typeof(val)}(0)
|
||||
end
|
||||
push!(res, val)
|
||||
val, s = next(bi, s)
|
||||
end
|
||||
return res
|
||||
end
|
||||
254
julia-0.6.2/share/julia/base/libgit2/remote.jl
Normal file
254
julia-0.6.2/share/julia/base/libgit2/remote.jl
Normal file
@@ -0,0 +1,254 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
"""
|
||||
GitRemote(repo::GitRepo, rmt_name::AbstractString, rmt_url::AbstractString) -> GitRemote
|
||||
|
||||
Look up a remote git repository using its name and URL. Uses the default fetch refspec.
|
||||
|
||||
# Example
|
||||
|
||||
```julia
|
||||
repo = LibGit2.init(repo_path)
|
||||
remote = LibGit2.GitRemote(repo, "upstream", repo_url)
|
||||
```
|
||||
"""
|
||||
function GitRemote(repo::GitRepo, rmt_name::AbstractString, rmt_url::AbstractString)
|
||||
rmt_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_remote_create, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cstring, Cstring),
|
||||
rmt_ptr_ptr, repo.ptr, rmt_name, rmt_url)
|
||||
return GitRemote(repo, rmt_ptr_ptr[])
|
||||
end
|
||||
|
||||
"""
|
||||
GitRemote(repo::GitRepo, rmt_name::AbstractString, rmt_url::AbstractString, fetch_spec::AbstractString) -> GitRemote
|
||||
|
||||
Look up a remote git repository using the repository's name and URL,
|
||||
as well as specifications for how to fetch from the remote
|
||||
(e.g. which remote branch to fetch from).
|
||||
|
||||
# Example
|
||||
|
||||
```julia
|
||||
repo = LibGit2.init(repo_path)
|
||||
refspec = "+refs/heads/mybranch:refs/remotes/origin/mybranch"
|
||||
remote = LibGit2.GitRemote(repo, "upstream", repo_url, refspec)
|
||||
```
|
||||
"""
|
||||
function GitRemote(repo::GitRepo, rmt_name::AbstractString, rmt_url::AbstractString, fetch_spec::AbstractString)
|
||||
rmt_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_remote_create_with_fetchspec, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cstring, Cstring, Cstring),
|
||||
rmt_ptr_ptr, repo.ptr, rmt_name, rmt_url, fetch_spec)
|
||||
return GitRemote(repo, rmt_ptr_ptr[])
|
||||
end
|
||||
|
||||
"""
|
||||
GitRemoteAnon(repo::GitRepo, url::AbstractString) -> GitRemote
|
||||
|
||||
Look up a remote git repository using only its URL, not its name.
|
||||
|
||||
# Example
|
||||
|
||||
```julia
|
||||
repo = LibGit2.init(repo_path)
|
||||
remote = LibGit2.GitRemoteAnon(repo, repo_url)
|
||||
```
|
||||
"""
|
||||
function GitRemoteAnon(repo::GitRepo, url::AbstractString)
|
||||
rmt_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_remote_create_anonymous, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cstring),
|
||||
rmt_ptr_ptr, repo.ptr, url)
|
||||
return GitRemote(repo, rmt_ptr_ptr[])
|
||||
end
|
||||
|
||||
function get(::Type{GitRemote}, repo::GitRepo, rmt_name::AbstractString)
|
||||
rmt_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_remote_lookup, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cstring),
|
||||
rmt_ptr_ptr, repo.ptr, rmt_name)
|
||||
return GitRemote(repo, rmt_ptr_ptr[])
|
||||
end
|
||||
|
||||
"""
|
||||
url(rmt::GitRemote)
|
||||
|
||||
Get the fetch URL of a remote git repository.
|
||||
|
||||
# Example
|
||||
|
||||
```julia-repl
|
||||
julia> repo_url = "https://github.com/JuliaLang/Example.jl";
|
||||
|
||||
julia> repo = LibGit2.init(mktempdir());
|
||||
|
||||
julia> remote = LibGit2.GitRemote(repo, "origin", repo_url);
|
||||
|
||||
julia> LibGit2.url(remote)
|
||||
"https://github.com/JuliaLang/Example.jl"
|
||||
```
|
||||
"""
|
||||
function url(rmt::GitRemote)
|
||||
url_ptr = ccall((:git_remote_url, :libgit2), Cstring, (Ptr{Void},), rmt.ptr)
|
||||
url_ptr == C_NULL && return ""
|
||||
return unsafe_string(url_ptr)
|
||||
end
|
||||
|
||||
"""
|
||||
push_url(rmt::GitRemote)
|
||||
|
||||
Get the push URL of a remote git repository.
|
||||
"""
|
||||
function push_url(rmt::GitRemote)
|
||||
url_ptr = ccall((:git_remote_pushurl, :libgit2), Cstring, (Ptr{Void},), rmt.ptr)
|
||||
url_ptr == C_NULL && return ""
|
||||
return unsafe_string(url_ptr)
|
||||
end
|
||||
|
||||
"""
|
||||
name(rmt::GitRemote)
|
||||
|
||||
Get the name of a remote repository, for instance `"origin"`.
|
||||
If the remote is anonymous (see [`GitRemoteAnon`](@ref))
|
||||
the name will be an empty string `""`.
|
||||
|
||||
# Example
|
||||
|
||||
```julia-repl
|
||||
julia> repo_url = "https://github.com/JuliaLang/Example.jl";
|
||||
|
||||
julia> repo = LibGit2.clone(cache_repo, "test_directory");
|
||||
|
||||
julia> remote = LibGit2.GitRemote(repo, "origin", repo_url);
|
||||
|
||||
julia> name(remote)
|
||||
"origin"
|
||||
```
|
||||
"""
|
||||
function name(rmt::GitRemote)
|
||||
name_ptr = ccall((:git_remote_name, :libgit2), Cstring, (Ptr{Void},), rmt.ptr)
|
||||
name_ptr == C_NULL && return ""
|
||||
return unsafe_string(name_ptr)
|
||||
end
|
||||
|
||||
"""
|
||||
fetch_refspecs(rmt::GitRemote) -> Vector{String}
|
||||
|
||||
Get the *fetch* refspecs for the specified `rmt`. These refspecs contain
|
||||
information about which branch(es) to fetch from.
|
||||
"""
|
||||
function fetch_refspecs(rmt::GitRemote)
|
||||
sa_ref = Ref(StrArrayStruct())
|
||||
@check ccall((:git_remote_get_fetch_refspecs, :libgit2), Cint,
|
||||
(Ptr{StrArrayStruct}, Ptr{Void}), sa_ref, rmt.ptr)
|
||||
res = convert(Vector{String}, sa_ref[])
|
||||
free(sa_ref)
|
||||
res
|
||||
end
|
||||
|
||||
"""
|
||||
push_refspecs(rmt::GitRemote) -> Vector{String}
|
||||
|
||||
Get the *push* refspecs for the specified `rmt`. These refspecs contain
|
||||
information about which branch(es) to push to.
|
||||
"""
|
||||
function push_refspecs(rmt::GitRemote)
|
||||
sa_ref = Ref(StrArrayStruct())
|
||||
@check ccall((:git_remote_get_push_refspecs, :libgit2), Cint,
|
||||
(Ptr{StrArrayStruct}, Ptr{Void}), sa_ref, rmt.ptr)
|
||||
res = convert(Vector{String}, sa_ref[])
|
||||
free(sa_ref)
|
||||
res
|
||||
end
|
||||
|
||||
"""
|
||||
add_fetch!(repo::GitRepo, rmt::GitRemote, fetch_spec::String)
|
||||
|
||||
Add a *fetch* refspec for the specified `rmt`. This refspec will contain
|
||||
information about which branch(es) to fetch from.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> LibGit2.add_fetch!(repo, remote, "upstream");
|
||||
|
||||
julia> LibGit2.fetch_refspecs(remote)
|
||||
String["+refs/heads/*:refs/remotes/upstream/*"]
|
||||
```
|
||||
"""
|
||||
function add_fetch!(repo::GitRepo, rmt::GitRemote, fetch_spec::String)
|
||||
@check ccall((:git_remote_add_fetch, :libgit2), Cint,
|
||||
(Ptr{Void}, Cstring, Cstring), repo.ptr,
|
||||
name(rmt), fetch_spec)
|
||||
end
|
||||
|
||||
"""
|
||||
add_push!(repo::GitRepo, rmt::GitRemote, push_spec::String)
|
||||
|
||||
Add a *push* refspec for the specified `rmt`. This refspec will contain
|
||||
information about which branch(es) to push to.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> LibGit2.add_push!(repo, remote, "refs/heads/master");
|
||||
|
||||
julia> remote = LibGit2.get(LibGit2.GitRemote, repo, branch);
|
||||
|
||||
julia> LibGit2.push_refspecs(remote)
|
||||
String["refs/heads/master"]
|
||||
```
|
||||
|
||||
!!! note
|
||||
You may need to [`close`](@ref) and reopen the `GitRemote`
|
||||
in question after updating its push refspecs in order for
|
||||
the change to take effect and for calls to [`push`](@ref)
|
||||
to work.
|
||||
"""
|
||||
function add_push!(repo::GitRepo, rmt::GitRemote, push_spec::String)
|
||||
@check ccall((:git_remote_add_push, :libgit2), Cint,
|
||||
(Ptr{Void}, Cstring, Cstring), repo.ptr,
|
||||
name(rmt), push_spec)
|
||||
end
|
||||
|
||||
"""
|
||||
fetch(rmt::GitRemote, refspecs; options::FetchOptions=FetchOptions(), msg="")
|
||||
|
||||
Fetch from the specified `rmt` remote git repository, using `refspecs` to
|
||||
determine which remote branch(es) to fetch.
|
||||
The keyword arguments are:
|
||||
* `options`: determines the options for the fetch, e.g. whether to prune afterwards.
|
||||
* `msg`: a message to insert into the reflogs.
|
||||
"""
|
||||
function fetch(rmt::GitRemote, refspecs::Vector{<:AbstractString};
|
||||
options::FetchOptions = FetchOptions(),
|
||||
msg::AbstractString="")
|
||||
msg = "libgit2.fetch: $msg"
|
||||
@check ccall((:git_remote_fetch, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{StrArrayStruct}, Ptr{FetchOptions}, Cstring),
|
||||
rmt.ptr, isempty(refspecs) ? C_NULL : refspecs, Ref(options), msg)
|
||||
end
|
||||
|
||||
"""
|
||||
push(rmt::GitRemote, refspecs; force::Bool=false, options::PushOptions=PushOptions())
|
||||
|
||||
Push to the specified `rmt` remote git repository, using `refspecs` to
|
||||
determine which remote branch(es) to push to.
|
||||
The keyword arguments are:
|
||||
* `force`: if `true`, a force-push will occur, disregarding conflicts.
|
||||
* `options`: determines the options for the push, e.g. which proxy headers to use.
|
||||
|
||||
!!! note
|
||||
You can add information about the push refspecs in two other ways: by setting
|
||||
an option in the repository's `GitConfig` (with `push.default` as the key) or
|
||||
by calling [`add_push!`](@ref). Otherwise you will need to explicitly specify
|
||||
a push refspec in the call to `push` for it to have any effect, like so:
|
||||
`LibGit2.push(repo, refspecs=["refs/heads/master"])`.
|
||||
"""
|
||||
function push(rmt::GitRemote, refspecs::Vector{<:AbstractString};
|
||||
force::Bool = false, options::PushOptions = PushOptions())
|
||||
@check ccall((:git_remote_push, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{StrArrayStruct}, Ptr{PushOptions}),
|
||||
rmt.ptr, isempty(refspecs) ? C_NULL : refspecs, Ref(options))
|
||||
end
|
||||
|
||||
Base.show(io::IO, rmt::GitRemote) = print(io, "GitRemote:\nRemote name: ", name(rmt), " url: ", url(rmt))
|
||||
309
julia-0.6.2/share/julia/base/libgit2/repository.jl
Normal file
309
julia-0.6.2/share/julia/base/libgit2/repository.jl
Normal file
@@ -0,0 +1,309 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
"""
|
||||
LibGit2.GitRepo(path::AbstractString)
|
||||
|
||||
Opens a git repository at `path`.
|
||||
"""
|
||||
function GitRepo(path::AbstractString)
|
||||
repo_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_repository_open, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Cstring), repo_ptr_ptr, path)
|
||||
return GitRepo(repo_ptr_ptr[])
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.GitRepoExt(path::AbstractString, flags::Cuint = Cuint(Consts.REPOSITORY_OPEN_DEFAULT))
|
||||
|
||||
Opens a git repository at `path` with extended controls (for instance, if the current
|
||||
user must be a member of a special access group to read `path`).
|
||||
"""
|
||||
function GitRepoExt(path::AbstractString, flags::Cuint = Cuint(Consts.REPOSITORY_OPEN_DEFAULT))
|
||||
separator = @static is_windows() ? ";" : ":"
|
||||
repo_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_repository_open_ext, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Cstring, Cuint, Cstring),
|
||||
repo_ptr_ptr, path, flags, separator)
|
||||
return GitRepo(repo_ptr_ptr[])
|
||||
end
|
||||
|
||||
function cleanup(r::GitRepo)
|
||||
if r.ptr != C_NULL
|
||||
ccall((:git_repository__cleanup, :libgit2), Void, (Ptr{Void},), r.ptr)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.init(path::AbstractString, bare::Bool=false) -> GitRepo
|
||||
|
||||
Opens a new git repository at `path`. If `bare` is `false`,
|
||||
the working tree will be created in `path/.git`. If `bare`
|
||||
is `true`, no working directory will be created.
|
||||
"""
|
||||
function init(path::AbstractString, bare::Bool=false)
|
||||
repo_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_repository_init, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Cstring, Cuint), repo_ptr_ptr, path, bare)
|
||||
return GitRepo(repo_ptr_ptr[])
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.head_oid(repo::GitRepo) -> GitHash
|
||||
|
||||
Lookup the object id of the current HEAD of git
|
||||
repository `repo`.
|
||||
"""
|
||||
function head_oid(repo::GitRepo)
|
||||
head_ref = head(repo)
|
||||
try
|
||||
return GitHash(head_ref)
|
||||
finally
|
||||
close(head_ref)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.headname(repo::GitRepo)
|
||||
|
||||
Lookup the name of the current HEAD of git
|
||||
repository `repo`. If `repo` is currently
|
||||
detached, returns the name of the HEAD it's
|
||||
detached from.
|
||||
"""
|
||||
function headname(repo::GitRepo)
|
||||
with(head(repo)) do href
|
||||
if isattached(repo)
|
||||
shortname(href)
|
||||
else
|
||||
"(detached from $(string(GitHash(href))[1:7]))"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function isbare(repo::GitRepo)
|
||||
return ccall((:git_repository_is_bare, :libgit2), Cint, (Ptr{Void},), repo.ptr) == 1
|
||||
end
|
||||
|
||||
function isattached(repo::GitRepo)
|
||||
ccall((:git_repository_head_detached, :libgit2), Cint, (Ptr{Void},), repo.ptr) != 1
|
||||
end
|
||||
|
||||
@doc """
|
||||
GitObject(repo::GitRepo, hash::AbstractGitHash)
|
||||
GitObject(repo::GitRepo, spec::AbstractString)
|
||||
|
||||
Return the specified object ([`GitCommit`](@ref), [`GitBlob`](@ref), [`GitTree`](@ref) or [`GitTag`](@ref)) from `repo`
|
||||
specified by `hash`/`spec`.
|
||||
|
||||
- `hash` is a full (`GitHash`) or partial (`GitShortHash`) hash.
|
||||
- `spec` is a textual specification: see [the git docs](https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions) for a full list.
|
||||
""" GitObject
|
||||
|
||||
for T in (:GitCommit, :GitBlob, :GitTree, :GitTag)
|
||||
@eval @doc $"""
|
||||
$T(repo::GitRepo, hash::AbstractGitHash)
|
||||
$T(repo::GitRepo, spec::AbstractString)
|
||||
|
||||
Return a `$T` object from `repo` specified by `hash`/`spec`.
|
||||
|
||||
- `hash` is a full (`GitHash`) or partial (`GitShortHash`) hash.
|
||||
- `spec` is a textual specification: see [the git docs](https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions) for a full list.
|
||||
""" $T
|
||||
end
|
||||
|
||||
function (::Type{T})(repo::GitRepo, spec::AbstractString) where T<:GitObject
|
||||
obj_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_revparse_single, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cstring), obj_ptr_ptr, repo.ptr, spec)
|
||||
# check object is of correct type
|
||||
if T != GitObject && T != GitUnknownObject
|
||||
t = Consts.OBJECT(obj_ptr_ptr[])
|
||||
t == Consts.OBJECT(T) || throw(GitError(Error.Object, Error.ERROR, "Expected object of type $T, received object of type $(objtype(t))"))
|
||||
end
|
||||
return T(repo, obj_ptr_ptr[])
|
||||
end
|
||||
|
||||
function (::Type{T})(repo::GitRepo, oid::GitHash) where T<:GitObject
|
||||
oid_ptr = Ref(oid)
|
||||
obj_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
|
||||
@check ccall((:git_object_lookup, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{GitHash}, Consts.OBJECT),
|
||||
obj_ptr_ptr, repo.ptr, oid_ptr, Consts.OBJECT(T))
|
||||
|
||||
return T(repo, obj_ptr_ptr[])
|
||||
end
|
||||
function (::Type{T})(repo::GitRepo, oid::GitShortHash) where T<:GitObject
|
||||
oid_ptr = Ref(oid.hash)
|
||||
obj_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
|
||||
@check ccall((:git_object_lookup_prefix, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{GitHash}, Csize_t, Consts.OBJECT),
|
||||
obj_ptr_ptr, repo.ptr, oid_ptr, oid.len, Consts.OBJECT(T))
|
||||
|
||||
return T(repo, obj_ptr_ptr[])
|
||||
end
|
||||
|
||||
# TODO: deprecate this function
|
||||
revparseid(repo::GitRepo, spec) = GitHash(GitUnknownObject(repo, spec))
|
||||
|
||||
"""
|
||||
LibGit2.gitdir(repo::GitRepo)
|
||||
|
||||
Returns the location of the "git" files of `repo`:
|
||||
|
||||
- for normal repositories, this is the location of the `.git` folder.
|
||||
- for bare repositories, this is the location of the repository itself.
|
||||
|
||||
See also [`workdir`](@ref), [`path`](@ref).
|
||||
"""
|
||||
function gitdir(repo::GitRepo)
|
||||
return unsafe_string(ccall((:git_repository_path, :libgit2), Cstring,
|
||||
(Ptr{Void},), repo.ptr))
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.workdir(repo::GitRepo)
|
||||
|
||||
The location of the working directory of `repo`. This will throw an error for bare
|
||||
repositories.
|
||||
|
||||
!!! note
|
||||
|
||||
This will typically be the parent directory of `gitdir(repo)`, but can be different in
|
||||
some cases: e.g. if either the `core.worktree` configuration variable or the
|
||||
`GIT_WORK_TREE` environment variable is set.
|
||||
|
||||
See also [`gitdir`](@ref), [`path`](@ref).
|
||||
"""
|
||||
function workdir(repo::GitRepo)
|
||||
sptr = ccall((:git_repository_workdir, :libgit2), Cstring,
|
||||
(Ptr{Void},), repo.ptr)
|
||||
sptr == C_NULL && throw(GitError(Error.Object, Error.ERROR, "No working directory found."))
|
||||
return unsafe_string(sptr)
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.path(repo::GitRepo)
|
||||
|
||||
The base file path of the repository `repo`.
|
||||
|
||||
- for normal repositories, this will typically be the parent directory of the ".git"
|
||||
directory (note: this may be different than the working directory, see `workdir` for
|
||||
more details).
|
||||
- for bare repositories, this is the location of the "git" files.
|
||||
|
||||
See also [`gitdir`](@ref), [`workdir`](@ref).
|
||||
"""
|
||||
function path(repo::GitRepo)
|
||||
d = gitdir(repo)
|
||||
if isdirpath(d)
|
||||
d = dirname(d) # strip trailing separator
|
||||
end
|
||||
if isbare(repo)
|
||||
return d
|
||||
else
|
||||
parent, base = splitdir(d)
|
||||
return base == ".git" ? parent : d
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
peel([T,] obj::GitObject)
|
||||
|
||||
Recursively peel `obj` until an object of type `T` is obtained. If no `T` is provided,
|
||||
then `obj` will be peeled until the type changes.
|
||||
|
||||
- A `GitTag` will be peeled to the object it references.
|
||||
- A `GitCommit` will be peeled to a `GitTree`.
|
||||
"""
|
||||
function peel(::Type{T}, obj::GitObject) where T<:GitObject
|
||||
new_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
|
||||
@check ccall((:git_object_peel, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Cint), new_ptr_ptr, obj.ptr, Consts.OBJECT(T))
|
||||
|
||||
return T(obj.owner, new_ptr_ptr[])
|
||||
end
|
||||
peel(obj::GitObject) = peel(GitObject, obj)
|
||||
|
||||
|
||||
function checkout_tree(repo::GitRepo, obj::GitObject;
|
||||
options::CheckoutOptions = CheckoutOptions())
|
||||
@check ccall((:git_checkout_tree, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{Void}, Ptr{CheckoutOptions}),
|
||||
repo.ptr, obj.ptr, Ref(options))
|
||||
end
|
||||
|
||||
function checkout_index(repo::GitRepo, idx::Nullable{GitIndex} = Nullable{GitIndex}();
|
||||
options::CheckoutOptions = CheckoutOptions())
|
||||
@check ccall((:git_checkout_index, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{Void}, Ptr{CheckoutOptions}),
|
||||
repo.ptr,
|
||||
isnull(idx) ? C_NULL : Base.get(idx).ptr,
|
||||
Ref(options))
|
||||
end
|
||||
|
||||
function checkout_head(repo::GitRepo; options::CheckoutOptions = CheckoutOptions())
|
||||
@check ccall((:git_checkout_head, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{CheckoutOptions}),
|
||||
repo.ptr, Ref(options))
|
||||
end
|
||||
|
||||
"""Updates some entries, determined by the `pathspecs`, in the index from the target commit tree."""
|
||||
function reset!(repo::GitRepo, obj::Nullable{<:GitObject}, pathspecs::AbstractString...)
|
||||
@check ccall((:git_reset_default, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{Void}, Ptr{StrArrayStruct}),
|
||||
repo.ptr,
|
||||
isnull(obj) ? C_NULL: Base.get(obj).ptr,
|
||||
collect(pathspecs))
|
||||
return head_oid(repo)
|
||||
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())
|
||||
@check ccall((:git_reset, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{Void}, Cint, Ptr{CheckoutOptions}),
|
||||
repo.ptr, obj.ptr, mode, Ref(checkout_opts))
|
||||
return head_oid(repo)
|
||||
end
|
||||
|
||||
function clone(repo_url::AbstractString, repo_path::AbstractString,
|
||||
clone_opts::CloneOptions)
|
||||
clone_opts_ref = Ref(clone_opts)
|
||||
repo_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_clone, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Cstring, Cstring, Ref{CloneOptions}),
|
||||
repo_ptr_ptr, repo_url, repo_path, clone_opts_ref)
|
||||
return GitRepo(repo_ptr_ptr[])
|
||||
end
|
||||
|
||||
function fetchheads(repo::GitRepo)
|
||||
fhr = Ref{Vector{FetchHead}}(FetchHead[])
|
||||
ffcb = fetchhead_foreach_cb()
|
||||
@check ccall((:git_repository_fetchhead_foreach, :libgit2), Cint,
|
||||
(Ptr{Void}, Ptr{Void}, Ptr{Void}),
|
||||
repo.ptr, ffcb, fhr)
|
||||
return fhr[]
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.remotes(repo::GitRepo)
|
||||
|
||||
Returns a vector of the names of the remotes of `repo`.
|
||||
"""
|
||||
function remotes(repo::GitRepo)
|
||||
sa_ref = Ref(StrArrayStruct())
|
||||
@check ccall((:git_remote_list, :libgit2), Cint,
|
||||
(Ptr{StrArrayStruct}, Ptr{Void}), sa_ref, repo.ptr)
|
||||
res = convert(Vector{String}, sa_ref[])
|
||||
free(sa_ref)
|
||||
return res
|
||||
end
|
||||
|
||||
function Base.show(io::IO, repo::GitRepo)
|
||||
print(io, "LibGit2.GitRepo(")
|
||||
show(io, path(repo))
|
||||
print(io, ")")
|
||||
end
|
||||
51
julia-0.6.2/share/julia/base/libgit2/signature.jl
Normal file
51
julia-0.6.2/share/julia/base/libgit2/signature.jl
Normal file
@@ -0,0 +1,51 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function Signature(ptr::Ptr{SignatureStruct})
|
||||
sig = unsafe_load(ptr)::SignatureStruct
|
||||
name = unsafe_string(sig.name)
|
||||
email = unsafe_string(sig.email)
|
||||
time = sig.when.time
|
||||
offset = sig.when.offset
|
||||
return Signature(name, email, time, offset)
|
||||
end
|
||||
Signature(sig::GitSignature) = Signature(sig.ptr)
|
||||
|
||||
function Signature(name::AbstractString, email::AbstractString)
|
||||
sig_ptr_ptr = Ref{Ptr{SignatureStruct}}(C_NULL)
|
||||
@check ccall((:git_signature_now, :libgit2), Cint,
|
||||
(Ptr{Ptr{SignatureStruct}}, Cstring, Cstring), sig_ptr_ptr, name, email)
|
||||
sig = GitSignature(sig_ptr_ptr[])
|
||||
s = Signature(sig.ptr)
|
||||
close(sig)
|
||||
return s
|
||||
end
|
||||
|
||||
function Signature(repo::GitRepo)
|
||||
sig = default_signature(repo)
|
||||
s = Signature(sig.ptr)
|
||||
close(sig)
|
||||
return s
|
||||
end
|
||||
|
||||
function Base.convert(::Type{GitSignature}, sig::Signature)
|
||||
sig_ptr_ptr = Ref{Ptr{SignatureStruct}}(C_NULL)
|
||||
@check ccall((:git_signature_new, :libgit2), Cint,
|
||||
(Ptr{Ptr{SignatureStruct}}, Cstring, Cstring, Int64, Cint),
|
||||
sig_ptr_ptr, sig.name, sig.email, sig.time, sig.time_offset)
|
||||
return GitSignature(sig_ptr_ptr[])
|
||||
end
|
||||
|
||||
function Base.show(io::IO, sig::Signature)
|
||||
print(io, "Name: ", sig.name, ", ")
|
||||
print(io, "Email: ", sig.email, ", ")
|
||||
print(io, "Time: ", Dates.unix2datetime(sig.time + 60*sig.time_offset))
|
||||
@printf(io, "%+03i:%02i", divrem(sig.time_offset, 60)...)
|
||||
end
|
||||
|
||||
"""Return signature object. Free it after use."""
|
||||
function default_signature(repo::GitRepo)
|
||||
sig_ptr_ptr = Ref{Ptr{SignatureStruct}}(C_NULL)
|
||||
@check ccall((:git_signature_default, :libgit2), Cint,
|
||||
(Ptr{Ptr{SignatureStruct}}, Ptr{Void}), sig_ptr_ptr, repo.ptr)
|
||||
return GitSignature(sig_ptr_ptr[])
|
||||
end
|
||||
50
julia-0.6.2/share/julia/base/libgit2/status.jl
Normal file
50
julia-0.6.2/share/julia/base/libgit2/status.jl
Normal file
@@ -0,0 +1,50 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
"""
|
||||
LibGit2.GitStatus(repo::GitRepo; status_opts=StatusOptions())
|
||||
|
||||
Collect information about the status of each file in the git
|
||||
repository `repo` (e.g. is the file modified, staged, etc.).
|
||||
`status_opts` can be used to set various options, for instance
|
||||
whether or not to look at untracked files or whether to include
|
||||
submodules or not.
|
||||
"""
|
||||
function GitStatus(repo::GitRepo; status_opts=StatusOptions())
|
||||
stat_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_status_list_new, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ptr{StatusOptions}),
|
||||
stat_ptr_ptr, repo.ptr, Ref(status_opts))
|
||||
return GitStatus(repo, stat_ptr_ptr[])
|
||||
end
|
||||
|
||||
function Base.length(status::GitStatus)
|
||||
return Int(ccall((:git_status_list_entrycount, :libgit2), Csize_t,
|
||||
(Ptr{Ptr{Void}},), status.ptr))
|
||||
end
|
||||
|
||||
function Base.getindex(status::GitStatus, i::Integer)
|
||||
1 <= i <= length(status) || throw(BoundsError())
|
||||
entry_ptr = ccall((:git_status_byindex, :libgit2),
|
||||
Ptr{StatusEntry},
|
||||
(Ptr{Void}, Csize_t),
|
||||
status.ptr, i-1)
|
||||
entry_ptr == C_NULL && throw(Error.GitError(Error.ERROR))
|
||||
return unsafe_load(entry_ptr)
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.status(repo::GitRepo, path::String)
|
||||
|
||||
Lookup the status of the file at `path` in the git
|
||||
repository `repo`. For instance, this can be used
|
||||
to check if the file at `path` has been modified
|
||||
and needs to be staged and committed.
|
||||
"""
|
||||
function status(repo::GitRepo, path::String)
|
||||
status_ptr = Ref{Cuint}(0)
|
||||
ret = ccall((:git_status_file, :libgit2), Cint,
|
||||
(Ref{Cuint}, Ptr{Void}, Cstring),
|
||||
status_ptr, repo.ptr, path)
|
||||
(ret == Cint(Error.ENOTFOUND) || ret == Cint(Error.EAMBIGUOUS)) && return Nullable{Cuint}()
|
||||
return Nullable(status_ptr[])
|
||||
end
|
||||
15
julia-0.6.2/share/julia/base/libgit2/strarray.jl
Normal file
15
julia-0.6.2/share/julia/base/libgit2/strarray.jl
Normal file
@@ -0,0 +1,15 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
|
||||
function Base.cconvert(::Type{Ptr{StrArrayStruct}}, x::Vector)
|
||||
str_ref = Base.cconvert(Ref{Cstring}, x)
|
||||
sa_ref = Ref(StrArrayStruct(Base.unsafe_convert(Ref{Cstring}, str_ref), length(x)))
|
||||
sa_ref, str_ref
|
||||
end
|
||||
function Base.unsafe_convert(::Type{Ptr{StrArrayStruct}}, rr::Tuple{Ref{StrArrayStruct}, Ref{Cstring}})
|
||||
Base.unsafe_convert(Ptr{StrArrayStruct}, first(rr))
|
||||
end
|
||||
|
||||
function Base.convert(::Type{Vector{String}}, sa::StrArrayStruct)
|
||||
[unsafe_string(unsafe_load(sa.strings, i)) for i = 1:sa.count]
|
||||
end
|
||||
77
julia-0.6.2/share/julia/base/libgit2/tag.jl
Normal file
77
julia-0.6.2/share/julia/base/libgit2/tag.jl
Normal file
@@ -0,0 +1,77 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
"""
|
||||
LibGit2.tag_list(repo::GitRepo) -> Vector{String}
|
||||
|
||||
Get a list of all tags in the git repository `repo`.
|
||||
"""
|
||||
function tag_list(repo::GitRepo)
|
||||
sa_ref = Ref(StrArrayStruct())
|
||||
@check ccall((:git_tag_list, :libgit2), Cint,
|
||||
(Ptr{StrArrayStruct}, Ptr{Void}), sa_ref, repo.ptr)
|
||||
res = convert(Vector{String}, sa_ref[])
|
||||
free(sa_ref)
|
||||
res
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.tag_delete(repo::GitRepo, tag::AbstractString)
|
||||
|
||||
Remove the git tag `tag` from the repository `repo`.
|
||||
"""
|
||||
function tag_delete(repo::GitRepo, tag::AbstractString)
|
||||
@check ccall((:git_tag_delete, :libgit2), Cint,
|
||||
(Ptr{Void}, Cstring), repo.ptr, tag)
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.tag_create(repo::GitRepo, tag::AbstractString, commit; kwargs...)
|
||||
|
||||
Create a new git tag `tag` (e.g. `"v0.5"`) in the repository `repo`, at
|
||||
the commit `commit`.
|
||||
|
||||
The keyword arguments are:
|
||||
* `msg::AbstractString=""`: the message for the tag.
|
||||
* `force::Bool=false`: if `true`, existing references will be overwritten.
|
||||
* `sig::Signature=Signature(repo)`: the tagger's signature.
|
||||
"""
|
||||
function tag_create(repo::GitRepo, tag::AbstractString, commit::Union{AbstractString,AbstractGitHash};
|
||||
msg::AbstractString = "",
|
||||
force::Bool = false,
|
||||
sig::Signature = Signature(repo))
|
||||
oid_ptr = Ref(GitHash())
|
||||
with(GitCommit(repo, commit)) do commit_obj
|
||||
commit_obj === nothing && return oid_ptr[] # return empty oid
|
||||
with(convert(GitSignature, sig)) do git_sig
|
||||
@check ccall((:git_tag_create, :libgit2), Cint,
|
||||
(Ptr{GitHash}, Ptr{Void}, Cstring, Ptr{Void}, Ptr{SignatureStruct}, Cstring, Cint),
|
||||
oid_ptr, repo.ptr, tag, commit_obj.ptr, git_sig.ptr, msg, Cint(force))
|
||||
end
|
||||
end
|
||||
return oid_ptr[]
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.name(tag::GitTag)
|
||||
|
||||
The name of `tag` (e.g. `"v0.5"`).
|
||||
"""
|
||||
function name(tag::GitTag)
|
||||
str_ptr = ccall((:git_tag_name, :libgit2), Cstring, (Ptr{Void},), tag.ptr)
|
||||
str_ptr == C_NULL && throw(Error.GitError(Error.ERROR))
|
||||
return unsafe_string(str_ptr)
|
||||
end
|
||||
|
||||
# should we return the actual object? i.e. git_tag_target?
|
||||
"""
|
||||
LibGit2.target(tag::GitTag)
|
||||
|
||||
The `GitHash` of the target object of `tag`.
|
||||
"""
|
||||
function target(tag::GitTag)
|
||||
oid_ptr = ccall((:git_tag_target_id, :libgit2), Ptr{GitHash}, (Ptr{Void},), tag.ptr)
|
||||
oid_ptr == C_NULL && throw(Error.GitError(Error.ERROR))
|
||||
return unsafe_load(oid_ptr)
|
||||
end
|
||||
|
||||
Base.show(io::IO, tag::GitTag) = print(io, "GitTag:\nTag name: $(name(tag)) target: $(target(tag))")
|
||||
76
julia-0.6.2/share/julia/base/libgit2/tree.jl
Normal file
76
julia-0.6.2/share/julia/base/libgit2/tree.jl
Normal file
@@ -0,0 +1,76 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
"""
|
||||
Traverse the entries in a tree and its subtrees in post or pre order.
|
||||
|
||||
Function parameter should have following signature:
|
||||
|
||||
(Cstring, Ptr{Void}, Ptr{Void}) -> Cint
|
||||
"""
|
||||
function treewalk(f::Function, tree::GitTree, payload=Any[], post::Bool = false)
|
||||
cbf = cfunction(f, Cint, Tuple{Cstring, Ptr{Void}, Ptr{Void}})
|
||||
cbf_payload = Ref{typeof(payload)}(payload)
|
||||
@check ccall((:git_tree_walk, :libgit2), Cint,
|
||||
(Ptr{Void}, Cint, Ptr{Void}, Ptr{Void}),
|
||||
tree.ptr, post, cbf, cbf_payload)
|
||||
return cbf_payload
|
||||
end
|
||||
|
||||
repository(tree::GitTree) = tree.owner
|
||||
repository(te::GitTreeEntry) = repository(te.owner)
|
||||
|
||||
function filename(te::GitTreeEntry)
|
||||
str = ccall((:git_tree_entry_name, :libgit2), Cstring, (Ptr{Void},), te.ptr)
|
||||
str != C_NULL && return unsafe_string(str)
|
||||
return nothing
|
||||
end
|
||||
|
||||
function filemode(te::GitTreeEntry)
|
||||
return ccall((:git_tree_entry_filemode, :libgit2), Cint, (Ptr{Void},), te.ptr)
|
||||
end
|
||||
|
||||
function entrytype(te::GitTreeEntry)
|
||||
otype = ccall((:git_tree_entry_type, :libgit2), Cint, (Ptr{Void},), te.ptr)
|
||||
return objtype(Consts.OBJECT(otype))
|
||||
end
|
||||
|
||||
function entryid(te::GitTreeEntry)
|
||||
oid_ptr = ccall((:git_tree_entry_id, :libgit2), Ptr{UInt8}, (Ptr{Void},), te.ptr)
|
||||
return GitHash(oid_ptr)
|
||||
end
|
||||
|
||||
function Base.count(tree::GitTree)
|
||||
return ccall((:git_tree_entrycount, :libgit2), Csize_t, (Ptr{Void},), tree.ptr)
|
||||
end
|
||||
|
||||
function Base.getindex(tree::GitTree, i::Integer)
|
||||
if i < 1 || i > count(tree)
|
||||
throw(BoundsError(tree, i))
|
||||
end
|
||||
te_ptr = ccall((:git_tree_entry_byindex, :libgit2),
|
||||
Ptr{Void},
|
||||
(Ptr{Void}, Csize_t), tree.ptr, i-1)
|
||||
return GitTreeEntry(tree, te_ptr, false)
|
||||
end
|
||||
|
||||
function (::Type{T})(te::GitTreeEntry) where T<:GitObject
|
||||
repo = repository(te)
|
||||
obj_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_tree_entry_to_object, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}, Ref{Void}),
|
||||
obj_ptr_ptr, repo.ptr, te.ptr)
|
||||
return T(repo, obj_ptr_ptr[])
|
||||
end
|
||||
|
||||
function Base.show(io::IO, te::GitTreeEntry)
|
||||
println(io, "GitTreeEntry:")
|
||||
println(io, "Entry name: ", filename(te))
|
||||
println(io, "Entry type: ", entrytype(te))
|
||||
println(io, "Entry OID: ", entryid(te))
|
||||
end
|
||||
|
||||
function Base.show(io::IO, tree::GitTree)
|
||||
println(io, "GitTree:")
|
||||
println(io, "Owner: ", repository(tree))
|
||||
println(io, "Number of entries: ", count(tree))
|
||||
end
|
||||
751
julia-0.6.2/share/julia/base/libgit2/types.jl
Normal file
751
julia-0.6.2/share/julia/base/libgit2/types.jl
Normal file
@@ -0,0 +1,751 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
import Base.@kwdef
|
||||
import .Consts: GIT_SUBMODULE_IGNORE, GIT_MERGE_FILE_FAVOR, GIT_MERGE_FILE
|
||||
|
||||
const OID_RAWSZ = 20
|
||||
const OID_HEXSZ = OID_RAWSZ * 2
|
||||
const OID_MINPREFIXLEN = 4
|
||||
|
||||
abstract type AbstractGitHash end
|
||||
|
||||
"""
|
||||
GitHash
|
||||
|
||||
A git object identifier, based on the sha-1 hash. It is a $OID_RAWSZ byte string
|
||||
($OID_HEXSZ hex digits) used to identify a `GitObject` in a repository.
|
||||
"""
|
||||
struct GitHash <: AbstractGitHash
|
||||
val::NTuple{OID_RAWSZ, UInt8}
|
||||
GitHash(val::NTuple{OID_RAWSZ, UInt8}) = new(val)
|
||||
end
|
||||
GitHash() = GitHash(ntuple(i->zero(UInt8), OID_RAWSZ))
|
||||
|
||||
"""
|
||||
GitShortHash
|
||||
|
||||
This is a shortened form of `GitHash`, which can be used to identify a git object when it
|
||||
is unique.
|
||||
|
||||
Internally it is stored as two fields: a full-size `GitHash` (`hash`) and a length
|
||||
(`len`). Only the initial `len` hex digits of `hash` are used.
|
||||
"""
|
||||
struct GitShortHash <: AbstractGitHash
|
||||
hash::GitHash # underlying hash: unused digits are ignored
|
||||
len::Csize_t # length in hex digits
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
LibGit2.TimeStruct
|
||||
|
||||
Time in a signature.
|
||||
Matches the [`git_time`](https://libgit2.github.com/libgit2/#HEAD/type/git_time) struct.
|
||||
"""
|
||||
struct TimeStruct
|
||||
time::Int64 # time in seconds from epoch
|
||||
offset::Cint # timezone offset in minutes
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.SignatureStruct
|
||||
|
||||
An action signature (e.g. for committers, taggers, etc).
|
||||
Matches the [`git_signature`](https://libgit2.github.com/libgit2/#HEAD/type/git_signature) struct.
|
||||
"""
|
||||
struct SignatureStruct
|
||||
name::Ptr{UInt8} # full name of the author
|
||||
email::Ptr{UInt8} # email of the author
|
||||
when::TimeStruct # time when the action happened
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.StrArrayStruct
|
||||
|
||||
A LibGit2 representation of an array of strings.
|
||||
Matches the [`git_strarray`](https://libgit2.github.com/libgit2/#HEAD/type/git_strarray) struct.
|
||||
|
||||
When fetching data from LibGit2, a typical usage would look like:
|
||||
```julia
|
||||
sa_ref = Ref(StrArrayStruct())
|
||||
@check ccall(..., (Ptr{StrArrayStruct},), sa_ref)
|
||||
res = convert(Vector{String}, sa_ref[])
|
||||
free(sa_ref)
|
||||
```
|
||||
In particular, note that `LibGit2.free` should be called afterward on the `Ref` object.
|
||||
|
||||
Conversely, when passing a vector of strings to LibGit2, it is generally simplest to rely
|
||||
on implicit conversion:
|
||||
```julia
|
||||
strs = String[...]
|
||||
@check ccall(..., (Ptr{StrArrayStruct},), strs)
|
||||
```
|
||||
Note that no call to `free` is required as the data is allocated by Julia.
|
||||
"""
|
||||
struct StrArrayStruct
|
||||
strings::Ptr{Cstring}
|
||||
count::Csize_t
|
||||
end
|
||||
StrArrayStruct() = StrArrayStruct(C_NULL, 0)
|
||||
|
||||
function free(sa_ref::Base.Ref{StrArrayStruct})
|
||||
ccall((:git_strarray_free, :libgit2), Void, (Ptr{StrArrayStruct},), sa_ref)
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.Buffer
|
||||
|
||||
A data buffer for exporting data from libgit2.
|
||||
Matches the [`git_buf`](https://libgit2.github.com/libgit2/#HEAD/type/git_buf) struct.
|
||||
|
||||
When fetching data from LibGit2, a typical usage would look like:
|
||||
```julia
|
||||
buf_ref = Ref(Buffer())
|
||||
@check ccall(..., (Ptr{Buffer},), buf_ref)
|
||||
# operation on buf_ref
|
||||
free(buf_ref)
|
||||
```
|
||||
In particular, note that `LibGit2.free` should be called afterward on the `Ref` object.
|
||||
"""
|
||||
struct Buffer
|
||||
ptr::Ptr{Cchar}
|
||||
asize::Csize_t
|
||||
size::Csize_t
|
||||
end
|
||||
Buffer() = Buffer(C_NULL, 0, 0)
|
||||
|
||||
function free(buf_ref::Base.Ref{Buffer})
|
||||
ccall((:git_buf_free, :libgit2), Void, (Ptr{Buffer},), buf_ref)
|
||||
end
|
||||
|
||||
"Abstract credentials payload"
|
||||
abstract type AbstractCredentials end
|
||||
|
||||
"Checks if credentials were used"
|
||||
checkused!(p::AbstractCredentials) = true
|
||||
checkused!(p::Void) = false
|
||||
"Resets credentials for another use"
|
||||
reset!(p::AbstractCredentials, cnt::Int=3) = nothing
|
||||
|
||||
"""
|
||||
LibGit2.CheckoutOptions
|
||||
|
||||
Matches the [`git_checkout_options`](https://libgit2.github.com/libgit2/#HEAD/type/git_checkout_options) struct.
|
||||
"""
|
||||
@kwdef struct CheckoutOptions
|
||||
version::Cuint = 1
|
||||
|
||||
checkout_strategy::Cuint = Consts.CHECKOUT_SAFE
|
||||
|
||||
disable_filters::Cint
|
||||
dir_mode::Cuint
|
||||
file_mode::Cuint
|
||||
file_open_flags::Cint
|
||||
|
||||
notify_flags::Cuint = Consts.CHECKOUT_NOTIFY_NONE
|
||||
notify_cb::Ptr{Void}
|
||||
notify_payload::Ptr{Void}
|
||||
|
||||
progress_cb::Ptr{Void}
|
||||
progress_payload::Ptr{Void}
|
||||
|
||||
paths::StrArrayStruct
|
||||
|
||||
baseline::Ptr{Void}
|
||||
baseline_index::Ptr{Void}
|
||||
|
||||
target_directory::Cstring
|
||||
ancestor_label::Cstring
|
||||
our_label::Cstring
|
||||
their_label::Cstring
|
||||
|
||||
perfdata_cb::Ptr{Void}
|
||||
perfdata_payload::Ptr{Void}
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.RemoteCallbacks
|
||||
|
||||
Callback settings.
|
||||
Matches the [`git_remote_callbacks`](https://libgit2.github.com/libgit2/#HEAD/type/git_remote_callbacks) struct.
|
||||
"""
|
||||
@kwdef struct RemoteCallbacks
|
||||
version::Cuint = 1
|
||||
sideband_progress::Ptr{Void}
|
||||
completion::Ptr{Void}
|
||||
credentials::Ptr{Void}
|
||||
certificate_check::Ptr{Void}
|
||||
transfer_progress::Ptr{Void}
|
||||
update_tips::Ptr{Void}
|
||||
pack_progress::Ptr{Void}
|
||||
push_transfer_progress::Ptr{Void}
|
||||
push_update_reference::Ptr{Void}
|
||||
push_negotiation::Ptr{Void}
|
||||
transport::Ptr{Void}
|
||||
payload::Ptr{Void}
|
||||
end
|
||||
|
||||
function RemoteCallbacks(credentials::Ptr{Void}, payload::Ref{Nullable{AbstractCredentials}})
|
||||
RemoteCallbacks(credentials=credentials_cb(), payload=pointer_from_objref(payload))
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.ProxyOptions
|
||||
|
||||
Options for connecting through a proxy.
|
||||
|
||||
Matches the [`git_proxy_options`](https://libgit2.github.com/libgit2/#HEAD/type/git_proxy_options) struct.
|
||||
"""
|
||||
@kwdef struct ProxyOptions
|
||||
version::Cuint = 1
|
||||
proxytype::Consts.GIT_PROXY = Consts.PROXY_AUTO
|
||||
url::Cstring
|
||||
credential_cb::Ptr{Void}
|
||||
certificate_cb::Ptr{Void}
|
||||
payload::Ptr{Void}
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
LibGit2.FetchOptions
|
||||
|
||||
Matches the [`git_fetch_options`](https://libgit2.github.com/libgit2/#HEAD/type/git_fetch_options) struct.
|
||||
"""
|
||||
@kwdef struct FetchOptions
|
||||
version::Cuint = 1
|
||||
callbacks::RemoteCallbacks
|
||||
prune::Cint = Consts.FETCH_PRUNE_UNSPECIFIED
|
||||
update_fetchhead::Cint = 1
|
||||
download_tags::Cint = Consts.REMOTE_DOWNLOAD_TAGS_AUTO
|
||||
@static if LibGit2.VERSION >= v"0.25.0"
|
||||
proxy_opts::ProxyOptions
|
||||
end
|
||||
@static if LibGit2.VERSION >= v"0.24.0"
|
||||
custom_headers::StrArrayStruct
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.CloneOptions
|
||||
|
||||
Matches the [`git_clone_options`](https://libgit2.github.com/libgit2/#HEAD/type/git_clone_options) struct.
|
||||
"""
|
||||
@kwdef struct CloneOptions
|
||||
version::Cuint = 1
|
||||
checkout_opts::CheckoutOptions
|
||||
fetch_opts::FetchOptions
|
||||
bare::Cint
|
||||
localclone::Cint = Consts.CLONE_LOCAL_AUTO
|
||||
checkout_branch::Cstring
|
||||
repository_cb::Ptr{Void}
|
||||
repository_cb_payload::Ptr{Void}
|
||||
remote_cb::Ptr{Void}
|
||||
remote_cb_payload::Ptr{Void}
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.DiffOptionsStruct
|
||||
|
||||
Matches the [`git_diff_options`](https://libgit2.github.com/libgit2/#HEAD/type/git_diff_options) struct.
|
||||
"""
|
||||
@kwdef struct DiffOptionsStruct
|
||||
version::Cuint = Consts.DIFF_OPTIONS_VERSION
|
||||
flags::UInt32 = Consts.DIFF_NORMAL
|
||||
|
||||
# options controlling which files are in the diff
|
||||
ignore_submodules::GIT_SUBMODULE_IGNORE = Consts.SUBMODULE_IGNORE_UNSPECIFIED
|
||||
pathspec::StrArrayStruct
|
||||
notify_cb::Ptr{Void}
|
||||
@static if LibGit2.VERSION >= v"0.24.0"
|
||||
progress_cb::Ptr{Void}
|
||||
end
|
||||
payload::Ptr{Void}
|
||||
|
||||
# options controlling how the diff text is generated
|
||||
context_lines::UInt32 = UInt32(3)
|
||||
interhunk_lines::UInt32
|
||||
id_abbrev::UInt16 = UInt16(7)
|
||||
max_size::Int64 = Int64(512*1024*1024) #512Mb
|
||||
old_prefix::Cstring
|
||||
new_prefix::Cstring
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.DiffFile
|
||||
|
||||
Description of one side of a delta.
|
||||
Matches the [`git_diff_file`](https://libgit2.github.com/libgit2/#HEAD/type/git_diff_file) struct.
|
||||
"""
|
||||
struct DiffFile
|
||||
id::GitHash
|
||||
path::Cstring
|
||||
size::Int64
|
||||
flags::UInt32
|
||||
mode::UInt16
|
||||
@static if LibGit2.VERSION >= v"0.25.0"
|
||||
id_abbrev::UInt16
|
||||
end
|
||||
end
|
||||
|
||||
function Base.show(io::IO, df::DiffFile)
|
||||
println(io, "DiffFile:")
|
||||
println(io, "Oid: $(df.id))")
|
||||
println(io, "Path: $(df.path)")
|
||||
println(io, "Size: $(df.size)")
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.DiffDelta
|
||||
|
||||
Description of changes to one entry.
|
||||
Matches the [`git_diff_delta`](https://libgit2.github.com/libgit2/#HEAD/type/git_diff_delta) struct.
|
||||
|
||||
The fields represent:
|
||||
* `status`: One of `Consts.DELTA_STATUS`, indicating whether the file has been added/modified/deleted.
|
||||
* `flags`: Flags for the delta and the objects on each side. Determines whether to treat the file(s)
|
||||
as binary/text, whether they exist on each side of the diff, and whether the object ids are known
|
||||
to be correct.
|
||||
* `similarity`: Used to indicate if a file has been renamed or copied.
|
||||
* `nfiles`: The number of files in the delta (for instance, if the delta
|
||||
was run on a submodule commit id, it may contain more than one file).
|
||||
* `old_file`: A [`DiffFile`](@ref) containing information about the file(s) before the changes.
|
||||
* `new_file`: A [`DiffFile`](@ref) containing information about the file(s) after the changes.
|
||||
"""
|
||||
struct DiffDelta
|
||||
status::Cint
|
||||
flags::UInt32
|
||||
similarity::UInt16
|
||||
nfiles::UInt16
|
||||
old_file::DiffFile
|
||||
new_file::DiffFile
|
||||
end
|
||||
|
||||
function Base.show(io::IO, dd::DiffDelta)
|
||||
println(io, "DiffDelta:")
|
||||
println(io, "Status: $(Consts.DELTA_STATUS(dd.status))")
|
||||
println(io, "Number of files: $(dd.nfiles)")
|
||||
println(io, "Old file:\n$(dd.old_file)")
|
||||
println(io, "New file:\n$(dd.new_file)")
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.MergeOptions
|
||||
|
||||
Matches the [`git_merge_options`](https://libgit2.github.com/libgit2/#HEAD/type/git_merge_options) struct.
|
||||
"""
|
||||
@kwdef struct MergeOptions
|
||||
version::Cuint = 1
|
||||
flags::Cint
|
||||
rename_threshold::Cuint = 50
|
||||
target_limit::Cuint = 200
|
||||
metric::Ptr{Void}
|
||||
@static if LibGit2.VERSION >= v"0.24.0"
|
||||
recursion_limit::Cuint
|
||||
end
|
||||
@static if LibGit2.VERSION >= v"0.25.0"
|
||||
default_driver::Cstring
|
||||
end
|
||||
file_favor::GIT_MERGE_FILE_FAVOR = Consts.MERGE_FILE_FAVOR_NORMAL
|
||||
file_flags::GIT_MERGE_FILE = Consts.MERGE_FILE_DEFAULT
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.PushOptions
|
||||
|
||||
Matches the [`git_push_options`](https://libgit2.github.com/libgit2/#HEAD/type/git_push_options) struct.
|
||||
"""
|
||||
@kwdef struct PushOptions
|
||||
version::Cuint = 1
|
||||
parallelism::Cint = 1
|
||||
callbacks::RemoteCallbacks
|
||||
@static if LibGit2.VERSION >= v"0.25.0"
|
||||
proxy_opts::ProxyOptions
|
||||
end
|
||||
@static if LibGit2.VERSION >= v"0.24.0"
|
||||
custom_headers::StrArrayStruct
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.IndexTime
|
||||
|
||||
Matches the [`git_index_time`](https://libgit2.github.com/libgit2/#HEAD/type/git_index_time) struct.
|
||||
"""
|
||||
struct IndexTime
|
||||
seconds::Int64
|
||||
nanoseconds::Cuint
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.IndexEntry
|
||||
|
||||
In-memory representation of a file entry in the index.
|
||||
Matches the [`git_index_entry`](https://libgit2.github.com/libgit2/#HEAD/type/git_index_entry) struct.
|
||||
"""
|
||||
struct IndexEntry
|
||||
ctime::IndexTime
|
||||
mtime::IndexTime
|
||||
|
||||
dev::UInt32
|
||||
ino::UInt32
|
||||
mode::UInt32
|
||||
uid::UInt32
|
||||
gid::UInt32
|
||||
file_size::Int64
|
||||
|
||||
id::GitHash
|
||||
|
||||
flags::UInt16
|
||||
flags_extended::UInt16
|
||||
|
||||
path::Ptr{UInt8}
|
||||
end
|
||||
Base.show(io::IO, ie::IndexEntry) = print(io, "IndexEntry($(string(ie.id)))")
|
||||
|
||||
"""
|
||||
LibGit2.RebaseOptions
|
||||
|
||||
Matches the `git_rebase_options` struct.
|
||||
"""
|
||||
@kwdef struct RebaseOptions
|
||||
version::Cuint = 1
|
||||
quiet::Cint = 1
|
||||
@static if LibGit2.VERSION >= v"0.24.0"
|
||||
inmemory::Cint
|
||||
end
|
||||
rewrite_notes_ref::Cstring
|
||||
@static if LibGit2.VERSION >= v"0.24.0"
|
||||
merge_opts::MergeOptions
|
||||
end
|
||||
checkout_opts::CheckoutOptions
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.RebaseOperation
|
||||
|
||||
Describes a single instruction/operation to be performed during the rebase.
|
||||
Matches the [`git_rebase_operation`](https://libgit2.github.com/libgit2/#HEAD/type/git_rebase_operation_t) struct.
|
||||
"""
|
||||
struct RebaseOperation
|
||||
optype::Cint
|
||||
id::GitHash
|
||||
exec::Cstring
|
||||
end
|
||||
function Base.show(io::IO, rbo::RebaseOperation)
|
||||
println(io, "RebaseOperation($(string(rbo.id)))")
|
||||
println(io, "Operation type: $(Consts.GIT_REBASE_OPERATION(rbo.optype))")
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.StatusOptions
|
||||
|
||||
Options to control how `git_status_foreach_ext()` will issue callbacks.
|
||||
Matches the [`git_status_opt_t`](https://libgit2.github.com/libgit2/#HEAD/type/git_status_opt_t) struct.
|
||||
"""
|
||||
@kwdef struct StatusOptions
|
||||
version::Cuint = 1
|
||||
show::Cint = Consts.STATUS_SHOW_INDEX_AND_WORKDIR
|
||||
flags::Cuint = Consts.STATUS_OPT_INCLUDE_UNTRACKED |
|
||||
Consts.STATUS_OPT_RECURSE_UNTRACKED_DIRS |
|
||||
Consts.STATUS_OPT_RENAMES_HEAD_TO_INDEX |
|
||||
Consts.STATUS_OPT_SORT_CASE_SENSITIVELY
|
||||
pathspec::StrArrayStruct
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.StatusEntry
|
||||
|
||||
Providing the differences between the file as it exists in HEAD and the index, and
|
||||
providing the differences between the index and the working directory.
|
||||
Matches the `git_status_entry` struct.
|
||||
"""
|
||||
struct StatusEntry
|
||||
status::Cuint
|
||||
head_to_index::Ptr{DiffDelta}
|
||||
index_to_workdir::Ptr{DiffDelta}
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.FetchHead
|
||||
|
||||
Contains the information about HEAD during a fetch, including the name and URL
|
||||
of the branch fetched from, the oid of the HEAD, and whether the fetched HEAD
|
||||
has been merged locally.
|
||||
"""
|
||||
struct FetchHead
|
||||
name::String
|
||||
url::String
|
||||
oid::GitHash
|
||||
ismerge::Bool
|
||||
end
|
||||
|
||||
function Base.show(io::IO, fh::FetchHead)
|
||||
println(io, "FetchHead:")
|
||||
println(io, "Name: $(fh.name)")
|
||||
println(io, "URL: $(fh.url)")
|
||||
print(io, "OID: ")
|
||||
show(io, fh.oid)
|
||||
println(io)
|
||||
println(io, "Merged: $(fh.ismerge)")
|
||||
end
|
||||
|
||||
# Abstract object types
|
||||
abstract type AbstractGitObject end
|
||||
Base.isempty(obj::AbstractGitObject) = (obj.ptr == C_NULL)
|
||||
|
||||
abstract type GitObject <: AbstractGitObject end
|
||||
|
||||
for (typ, owntyp, sup, cname) in [
|
||||
(:GitRepo, nothing, :AbstractGitObject, :git_repository),
|
||||
(:GitConfig, :(Nullable{GitRepo}), :AbstractGitObject, :git_config),
|
||||
(:GitIndex, :(Nullable{GitRepo}), :AbstractGitObject, :git_index),
|
||||
(:GitRemote, :GitRepo, :AbstractGitObject, :git_remote),
|
||||
(:GitRevWalker, :GitRepo, :AbstractGitObject, :git_revwalk),
|
||||
(:GitReference, :GitRepo, :AbstractGitObject, :git_reference),
|
||||
(:GitDiff, :GitRepo, :AbstractGitObject, :git_diff),
|
||||
(:GitDiffStats, :GitRepo, :AbstractGitObject, :git_diff_stats),
|
||||
(:GitAnnotated, :GitRepo, :AbstractGitObject, :git_annotated_commit),
|
||||
(:GitRebase, :GitRepo, :AbstractGitObject, :git_rebase),
|
||||
(:GitStatus, :GitRepo, :AbstractGitObject, :git_status_list),
|
||||
(:GitBranchIter, :GitRepo, :AbstractGitObject, :git_branch_iterator),
|
||||
(:GitUnknownObject, :GitRepo, :GitObject, :git_object),
|
||||
(:GitCommit, :GitRepo, :GitObject, :git_commit),
|
||||
(:GitBlob, :GitRepo, :GitObject, :git_blob),
|
||||
(:GitTree, :GitRepo, :GitObject, :git_tree),
|
||||
(:GitTag, :GitRepo, :GitObject, :git_tag),
|
||||
(:GitTreeEntry, :GitTree, :AbstractGitObject, :git_tree_entry),
|
||||
]
|
||||
|
||||
if owntyp === nothing
|
||||
@eval mutable struct $typ <: $sup
|
||||
ptr::Ptr{Void}
|
||||
function $typ(ptr::Ptr{Void}, fin::Bool=true)
|
||||
# fin=false should only be used when the pointer should not be free'd
|
||||
# e.g. from within callback functions which are passed a pointer
|
||||
@assert ptr != C_NULL
|
||||
obj = new(ptr)
|
||||
if fin
|
||||
Threads.atomic_add!(REFCOUNT, UInt(1))
|
||||
finalizer(obj, Base.close)
|
||||
end
|
||||
return obj
|
||||
end
|
||||
end
|
||||
else
|
||||
@eval mutable struct $typ <: $sup
|
||||
owner::$owntyp
|
||||
ptr::Ptr{Void}
|
||||
function $typ(owner::$owntyp, ptr::Ptr{Void}, fin::Bool=true)
|
||||
@assert ptr != C_NULL
|
||||
obj = new(owner, ptr)
|
||||
if fin
|
||||
Threads.atomic_add!(REFCOUNT, UInt(1))
|
||||
finalizer(obj, Base.close)
|
||||
end
|
||||
return obj
|
||||
end
|
||||
end
|
||||
if isa(owntyp, Expr) && owntyp.args[1] == :Nullable
|
||||
@eval begin
|
||||
$typ(ptr::Ptr{Void}, fin::Bool=true) = $typ($owntyp(), ptr, fin)
|
||||
$typ(owner::$(owntyp.args[2]), ptr::Ptr{Void}, fin::Bool=true) =
|
||||
$typ($owntyp(owner), ptr, fin)
|
||||
end
|
||||
end
|
||||
end
|
||||
@eval function Base.close(obj::$typ)
|
||||
if obj.ptr != C_NULL
|
||||
ccall(($(string(cname, :_free)), :libgit2), Void, (Ptr{Void},), obj.ptr)
|
||||
obj.ptr = C_NULL
|
||||
if Threads.atomic_sub!(REFCOUNT, UInt(1)) == 1
|
||||
# will the last finalizer please turn out the lights?
|
||||
ccall((:git_libgit2_shutdown, :libgit2), Cint, ())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
## Calling `GitObject(repo, ...)` will automatically resolve to the appropriate type.
|
||||
function GitObject(repo::GitRepo, ptr::Ptr{Void})
|
||||
T = objtype(Consts.OBJECT(ptr))
|
||||
T(repo, ptr)
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.GitSignature
|
||||
|
||||
This is a Julia wrapper around a pointer to a
|
||||
[`git_signature`](https://libgit2.github.com/libgit2/#HEAD/type/git_signature) object.
|
||||
"""
|
||||
mutable struct GitSignature <: AbstractGitObject
|
||||
ptr::Ptr{SignatureStruct}
|
||||
function GitSignature(ptr::Ptr{SignatureStruct})
|
||||
@assert ptr != C_NULL
|
||||
obj = new(ptr)
|
||||
finalizer(obj, Base.close)
|
||||
return obj
|
||||
end
|
||||
end
|
||||
function Base.close(obj::GitSignature)
|
||||
if obj.ptr != C_NULL
|
||||
ccall((:git_signature_free, :libgit2), Void, (Ptr{SignatureStruct},), obj.ptr)
|
||||
obj.ptr = C_NULL
|
||||
end
|
||||
end
|
||||
|
||||
# Structure has the same layout as SignatureStruct
|
||||
mutable struct Signature
|
||||
name::String
|
||||
email::String
|
||||
time::Int64
|
||||
time_offset::Cint
|
||||
end
|
||||
|
||||
""" Resource management helper function
|
||||
"""
|
||||
function with(f::Function, obj)
|
||||
try
|
||||
f(obj)
|
||||
finally
|
||||
close(obj)
|
||||
end
|
||||
end
|
||||
|
||||
with{T}(f::Function, ::Type{T}, args...) = with(f, T(args...))
|
||||
|
||||
function with_warn{T}(f::Function, ::Type{T}, args...)
|
||||
obj = T(args...)
|
||||
try
|
||||
with(f, obj)
|
||||
catch err
|
||||
warn("$(string(T)) thrown exception: $err")
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.Consts.OBJECT{T<:GitObject}(::Type{T})
|
||||
|
||||
The `OBJECT` enum value corresponding to type `T`.
|
||||
"""
|
||||
Consts.OBJECT(::Type{GitCommit}) = Consts.OBJ_COMMIT
|
||||
Consts.OBJECT(::Type{GitTree}) = Consts.OBJ_TREE
|
||||
Consts.OBJECT(::Type{GitBlob}) = Consts.OBJ_BLOB
|
||||
Consts.OBJECT(::Type{GitTag}) = Consts.OBJ_TAG
|
||||
Consts.OBJECT(::Type{GitUnknownObject}) = Consts.OBJ_ANY
|
||||
Consts.OBJECT(::Type{GitObject}) = Consts.OBJ_ANY
|
||||
|
||||
Consts.OBJECT(ptr::Ptr{Void}) =
|
||||
ccall((:git_object_type, :libgit2), Consts.OBJECT, (Ptr{Void},), ptr)
|
||||
|
||||
"""
|
||||
objtype(obj_type::Consts.OBJECT)
|
||||
|
||||
Returns the type corresponding to the enum value.
|
||||
"""
|
||||
function objtype(obj_type::Consts.OBJECT)
|
||||
if obj_type == Consts.OBJ_COMMIT
|
||||
GitCommit
|
||||
elseif obj_type == Consts.OBJ_TREE
|
||||
GitTree
|
||||
elseif obj_type == Consts.OBJ_BLOB
|
||||
GitBlob
|
||||
elseif obj_type == Consts.OBJ_TAG
|
||||
GitTag
|
||||
elseif obj_type == Consts.OBJ_ANY #this name comes from the header
|
||||
GitUnknownObject
|
||||
else
|
||||
throw(GitError(Error.Object, Error.ENOTFOUND, "Object type $obj_type is not supported"))
|
||||
end
|
||||
end
|
||||
|
||||
import Base.securezero!
|
||||
|
||||
"Credentials that support only `user` and `password` parameters"
|
||||
mutable struct UserPasswordCredentials <: AbstractCredentials
|
||||
user::String
|
||||
pass::String
|
||||
prompt_if_incorrect::Bool # Whether to allow interactive prompting if the credentials are incorrect
|
||||
count::Int # authentication failure protection count
|
||||
function UserPasswordCredentials(u::AbstractString,p::AbstractString,prompt_if_incorrect::Bool=false)
|
||||
c = new(u,p,prompt_if_incorrect,3)
|
||||
finalizer(c, securezero!)
|
||||
return c
|
||||
end
|
||||
UserPasswordCredentials(prompt_if_incorrect::Bool=false) = UserPasswordCredentials("","",prompt_if_incorrect)
|
||||
end
|
||||
|
||||
function securezero!(cred::UserPasswordCredentials)
|
||||
securezero!(cred.user)
|
||||
securezero!(cred.pass)
|
||||
cred.count = 0
|
||||
return cred
|
||||
end
|
||||
|
||||
function Base.:(==)(a::UserPasswordCredentials, b::UserPasswordCredentials)
|
||||
a.user == b.user && a.pass == b.pass
|
||||
end
|
||||
|
||||
"SSH credentials type"
|
||||
mutable struct SSHCredentials <: AbstractCredentials
|
||||
user::String
|
||||
pass::String
|
||||
prvkey::String
|
||||
pubkey::String
|
||||
usesshagent::String # used for ssh-agent authentication
|
||||
prompt_if_incorrect::Bool # Whether to allow interactive prompting if the credentials are incorrect
|
||||
count::Int
|
||||
function SSHCredentials(u::AbstractString,p::AbstractString,prvkey::AbstractString,pubkey::AbstractString,prompt_if_incorrect::Bool=false)
|
||||
c = new(u,p,prvkey,pubkey,"Y",prompt_if_incorrect,3)
|
||||
finalizer(c, securezero!)
|
||||
return c
|
||||
end
|
||||
SSHCredentials(u::AbstractString,p::AbstractString,prompt_if_incorrect::Bool=false) = SSHCredentials(u,p,"","",prompt_if_incorrect)
|
||||
SSHCredentials(prompt_if_incorrect::Bool=false) = SSHCredentials("","","","",prompt_if_incorrect)
|
||||
end
|
||||
|
||||
function securezero!(cred::SSHCredentials)
|
||||
securezero!(cred.user)
|
||||
securezero!(cred.pass)
|
||||
securezero!(cred.prvkey)
|
||||
securezero!(cred.pubkey)
|
||||
cred.count = 0
|
||||
return cred
|
||||
end
|
||||
|
||||
function Base.:(==)(a::SSHCredentials, b::SSHCredentials)
|
||||
a.user == b.user && a.pass == b.pass && a.prvkey == b.prvkey && a.pubkey == b.pubkey
|
||||
end
|
||||
|
||||
"Credentials that support caching"
|
||||
mutable struct CachedCredentials <: AbstractCredentials
|
||||
cred::Dict{String,AbstractCredentials}
|
||||
count::Int # authentication failure protection count
|
||||
CachedCredentials() = new(Dict{String,AbstractCredentials}(),3)
|
||||
end
|
||||
|
||||
"Checks if credentials were used or failed authentication, see `LibGit2.credentials_callback`"
|
||||
function checkused!(p::Union{UserPasswordCredentials, SSHCredentials})
|
||||
p.count <= 0 && return true
|
||||
p.count -= 1
|
||||
return false
|
||||
end
|
||||
reset!(p::Union{UserPasswordCredentials, SSHCredentials}, cnt::Int=3) = (p.count = cnt; p)
|
||||
reset!(p::CachedCredentials) = (foreach(reset!, values(p.cred)); p)
|
||||
|
||||
"Obtain the cached credentials for the given host+protocol (credid), or return and store the default if not found"
|
||||
get_creds!(collection::CachedCredentials, credid, default) = get!(collection.cred, credid, default)
|
||||
get_creds!(creds::AbstractCredentials, credid, default) = creds
|
||||
get_creds!(creds::Void, credid, default) = default
|
||||
function get_creds!(creds::Ref{Nullable{AbstractCredentials}}, credid, default)
|
||||
if isnull(creds[])
|
||||
creds[] = Nullable{AbstractCredentials}(default)
|
||||
return default
|
||||
else
|
||||
get_creds!(Base.get(creds[]), credid, default)
|
||||
end
|
||||
end
|
||||
|
||||
function securezero!(p::CachedCredentials)
|
||||
foreach(securezero!, values(p.cred))
|
||||
return p
|
||||
end
|
||||
67
julia-0.6.2/share/julia/base/libgit2/utils.jl
Normal file
67
julia-0.6.2/share/julia/base/libgit2/utils.jl
Normal file
@@ -0,0 +1,67 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# Parse "GIT URLs" syntax (URLs and a scp-like syntax). For details see:
|
||||
# https://git-scm.com/docs/git-clone#_git_urls_a_id_urls_a
|
||||
const URL_REGEX = r"""
|
||||
^(?:(?<scheme>ssh|git|https?)://)?
|
||||
(?:
|
||||
(?<user>.*?)
|
||||
(?:\:(?<password>.*?))?@
|
||||
)?
|
||||
(?<host>[A-Za-z0-9\-\.]+)
|
||||
(?(<scheme>)
|
||||
(?:\:(?<port>\d+))? # only parse port when not using SCP-like syntax
|
||||
|
|
||||
:?
|
||||
)
|
||||
(?<path>.*?)$
|
||||
"""x
|
||||
|
||||
function version()
|
||||
major = Ref{Cint}(0)
|
||||
minor = Ref{Cint}(0)
|
||||
patch = Ref{Cint}(0)
|
||||
ccall((:git_libgit2_version, :libgit2), Void,
|
||||
(Ptr{Cint}, Ptr{Cint}, Ptr{Cint}), major, minor, patch)
|
||||
return VersionNumber(major[], minor[], patch[])
|
||||
end
|
||||
const VERSION = version()
|
||||
|
||||
isset(val::Integer, flag::Integer) = (val & flag == flag)
|
||||
reset(val::Integer, flag::Integer) = (val &= ~flag)
|
||||
toggle(val::Integer, flag::Integer) = (val |= flag)
|
||||
|
||||
function prompt(msg::AbstractString; default::AbstractString="", password::Bool=false)
|
||||
if is_windows() && password
|
||||
error("Command line prompt not supported for password entry on windows. Use winprompt instead")
|
||||
end
|
||||
msg = !isempty(default) ? msg*" [$default]:" : msg*":"
|
||||
uinput = if password
|
||||
Base.getpass(msg)
|
||||
else
|
||||
print(msg)
|
||||
readline()
|
||||
end
|
||||
isempty(uinput) ? default : uinput
|
||||
end
|
||||
|
||||
function features()
|
||||
feat = ccall((:git_libgit2_features, :libgit2), Cint, ())
|
||||
res = Consts.GIT_FEATURE[]
|
||||
for f in instances(Consts.GIT_FEATURE)
|
||||
isset(feat, Cuint(f)) && push!(res, f)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
"""
|
||||
LibGit2.posixpath(path)
|
||||
|
||||
Standardise the path string `path` to use POSIX separators.
|
||||
"""
|
||||
function posixpath end
|
||||
if is_windows()
|
||||
posixpath(path) = replace(path,'\\','/')
|
||||
else is_unix()
|
||||
posixpath(path) = path
|
||||
end
|
||||
102
julia-0.6.2/share/julia/base/libgit2/walker.jl
Normal file
102
julia-0.6.2/share/julia/base/libgit2/walker.jl
Normal file
@@ -0,0 +1,102 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function GitRevWalker(repo::GitRepo)
|
||||
w_ptr = Ref{Ptr{Void}}(C_NULL)
|
||||
@check ccall((:git_revwalk_new, :libgit2), Cint,
|
||||
(Ptr{Ptr{Void}}, Ptr{Void}), w_ptr, repo.ptr)
|
||||
return GitRevWalker(repo, w_ptr[])
|
||||
end
|
||||
|
||||
function Base.start(w::GitRevWalker)
|
||||
id_ptr = Ref(GitHash())
|
||||
err = ccall((:git_revwalk_next, :libgit2), Cint,
|
||||
(Ptr{GitHash}, Ptr{Void}), id_ptr, w.ptr)
|
||||
err != Int(Error.GIT_OK) && return (nothing, true)
|
||||
return (id_ptr[], false)
|
||||
end
|
||||
|
||||
Base.done(w::GitRevWalker, state) = Bool(state[2])
|
||||
|
||||
function Base.next(w::GitRevWalker, state)
|
||||
id_ptr = Ref(GitHash())
|
||||
err = ccall((:git_revwalk_next, :libgit2), Cint,
|
||||
(Ptr{GitHash}, Ptr{Void}), id_ptr, w.ptr)
|
||||
err != Int(Error.GIT_OK) && return (state[1], (nothing, true))
|
||||
return (state[1], (id_ptr[], false))
|
||||
end
|
||||
|
||||
Base.iteratorsize(::Type{GitRevWalker}) = Base.SizeUnknown()
|
||||
|
||||
function push_head!(w::GitRevWalker)
|
||||
@check ccall((:git_revwalk_push_head, :libgit2), Cint, (Ptr{Void},), w.ptr)
|
||||
return w
|
||||
end
|
||||
|
||||
function Base.push!(w::GitRevWalker, cid::GitHash)
|
||||
@check ccall((:git_revwalk_push, :libgit2), Cint, (Ptr{Void}, Ptr{GitHash}), w.ptr, Ref(cid))
|
||||
return w
|
||||
end
|
||||
|
||||
function Base.push!(w::GitRevWalker, range::AbstractString)
|
||||
@check ccall((:git_revwalk_push_range, :libgit2), Cint, (Ptr{Void}, Ptr{UInt8}), w.ptr, range)
|
||||
return w
|
||||
end
|
||||
|
||||
function Base.sort!(w::GitRevWalker; by::Cint = Consts.SORT_NONE, rev::Bool=false)
|
||||
rev && (by |= Consts.SORT_REVERSE)
|
||||
ccall((:git_revwalk_sorting, :libgit2), Void, (Ptr{Void}, Cint), w.ptr, by)
|
||||
return w
|
||||
end
|
||||
|
||||
repository(w::GitRevWalker) = w.owner
|
||||
|
||||
function Base.map(f::Function, walker::GitRevWalker;
|
||||
oid::GitHash=GitHash(),
|
||||
range::AbstractString="",
|
||||
by::Cint = Consts.SORT_NONE,
|
||||
rev::Bool=false,
|
||||
count::Int=0)
|
||||
res = []
|
||||
sort!(walker, by=by, rev=rev)
|
||||
if !iszero(oid)
|
||||
push!(walker, oid)
|
||||
elseif !isempty(range)
|
||||
push!(walker, range)
|
||||
else
|
||||
push_head!(walker)
|
||||
end
|
||||
s = start(walker)
|
||||
|
||||
c = 0
|
||||
repo = repository(walker)
|
||||
while !done(walker, s)
|
||||
val = f(s[1], repo)
|
||||
push!(res, val)
|
||||
val, s = next(walker, s)
|
||||
c +=1
|
||||
count == c && break
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function Base.count(f::Function, walker::GitRevWalker;
|
||||
oid::GitHash=GitHash(),
|
||||
by::Cint = Consts.SORT_NONE,
|
||||
rev::Bool=false)
|
||||
c = 0
|
||||
sort!(walker, by=by, rev=rev)
|
||||
if !iszero(oid)
|
||||
push!(walker, oid)
|
||||
else
|
||||
push_head!(walker)
|
||||
end
|
||||
s = start(walker)
|
||||
|
||||
repo = repository(walker)
|
||||
while !done(walker, s)
|
||||
val = f(s[1], repo)
|
||||
_, s = next(walker, s)
|
||||
c += (val == true)
|
||||
end
|
||||
return c
|
||||
end
|
||||
Reference in New Issue
Block a user