From 729f891eb5af3e8027ef9f69c2b63b3ea32a7f1b Mon Sep 17 00:00:00 2001 From: Curtis Vogt Date: Thu, 25 May 2017 15:01:59 -0500 Subject: [PATCH] Allow setting the remote push/fetch URL separately Changes include: - Creating `set_remote_fetch_url`, `set_remote_push_url`, `remote_delete`, and `lookup_remote` - Updating `set_remote_url` to use LibGit2 calls - Deprecate `set_remote_url` which uses keyword and reorder arguments to match order of `GitRemote` constructor. - Update all existing calls to `set_remote_url` --- base/deprecated.jl | 14 +++++ base/libgit2/libgit2.jl | 36 ------------ base/libgit2/remote.jl | 119 ++++++++++++++++++++++++++++++++++++++++ base/pkg/cache.jl | 2 +- base/pkg/dir.jl | 4 +- base/pkg/entry.jl | 2 +- base/pkg/write.jl | 2 +- test/libgit2.jl | 59 ++++++++++++++++++-- 8 files changed, 192 insertions(+), 46 deletions(-) diff --git a/base/deprecated.jl b/base/deprecated.jl index e882c3be8481a..550e4b655d879 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1348,6 +1348,20 @@ end @deprecate srand(filename::AbstractString, n::Integer=4) srand(read!(filename, Array{UInt32}(Int(n)))) @deprecate MersenneTwister(filename::AbstractString) srand(MersenneTwister(0), read!(filename, Array{UInt32}(Int(4)))) +# PR #22062 +function LibGit2.set_remote_url(repo::LibGit2.GitRepo, url::AbstractString; remote::AbstractString="origin") + Base.depwarn(string( + "`LibGit2.set_remote_url(repo, url; remote=remote)` is deprecated, use ", + "`LibGit2.set_remote_url(repo, remote, url)` instead."), :set_remote_url) + LibGit2.set_remote_url(repo, remote, url) +end +function LibGit2.set_remote_url(path::AbstractString, url::AbstractString; remote::AbstractString="origin") + Base.depwarn(string( + "`LibGit2.set_remote_url(path, url; remote=remote)` is deprecated, use ", + "`LibGit2.set_remote_url(path, remote, url)` instead."), :set_remote_url) + LibGit2.set_remote_url(path, remote, url) +end + # END 0.7 deprecations # BEGIN 1.0 deprecations diff --git a/base/libgit2/libgit2.jl b/base/libgit2/libgit2.jl index 8e5d64aa2e934..f1ab5ba72885a 100644 --- a/base/libgit2/libgit2.jl +++ b/base/libgit2/libgit2.jl @@ -240,42 +240,6 @@ function is_ancestor_of(a::AbstractString, b::AbstractString, repo::GitRepo) 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 diff --git a/base/libgit2/remote.jl b/base/libgit2/remote.jl index 6e4d4bb6ebb83..dbe4cd778236b 100644 --- a/base/libgit2/remote.jl +++ b/base/libgit2/remote.jl @@ -63,6 +63,27 @@ function GitRemoteAnon(repo::GitRepo, url::AbstractString) return GitRemote(repo, rmt_ptr_ptr[]) end +""" + lookup_remote(repo::GitRepo, remote_name::AbstractString) -> Nullable{GitRemote} + +Determine if the `remote_name` specified exists within the `repo`. Returns a +[`Nullable`](@ref), which will be null if the requested remote does not exist. If the remote +does exist, the `Nullable` contains a `GitRemote` to the remote name. +""" +function lookup_remote(repo::GitRepo, remote_name::AbstractString) + rmt_ptr_ptr = Ref{Ptr{Void}}(C_NULL) + err = ccall((:git_remote_lookup, :libgit2), Cint, + (Ptr{Ptr{Void}}, Ptr{Void}, Cstring), + rmt_ptr_ptr, repo.ptr, remote_name) + if err == Int(Error.GIT_OK) + return Nullable{GitRemote}(GitRemote(repo, rmt_ptr_ptr[])) + elseif err == Int(Error.ENOTFOUND) + return Nullable{GitRemote}() + else + throw(Error.GitError(err)) + end +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, @@ -99,6 +120,19 @@ end push_url(rmt::GitRemote) Get the push URL of a remote git repository. + +# Example + +```julia-repl +julia> repo_url = "https://github.com/JuliaLang/Example.jl"; + +julia> repo = LibGit2.init(mktempdir()); + +julia> LibGit2.set_remote_push_url(repo, "origin", repo_url); + +julia> LibGit2.push_url(LibGit2.get(LibGit2.GitRemote, repo, "origin")) +"https://github.com/JuliaLang/Example.jl" +``` """ function push_url(rmt::GitRemote) url_ptr = ccall((:git_remote_pushurl, :libgit2), Cstring, (Ptr{Void},), rmt.ptr) @@ -251,4 +285,89 @@ function push(rmt::GitRemote, refspecs::Vector{<:AbstractString}; rmt.ptr, isempty(refspecs) ? C_NULL : refspecs, Ref(options)) end +""" + remote_delete(repo::GitRepo, remote_name::AbstractString) -> Void + +Delete the `remote_name` from the git `repo`. +""" +function remote_delete(repo::GitRepo, remote_name::AbstractString) + @check ccall((:git_remote_delete, :libgit2), Cint, + (Ptr{Void}, Cstring), + repo.ptr, remote_name) +end + Base.show(io::IO, rmt::GitRemote) = print(io, "GitRemote:\nRemote name: ", name(rmt), " url: ", url(rmt)) + + +""" + set_remote_fetch_url(repo::GitRepo, remote_name, url) + set_remote_fetch_url(path::String, remote_name, url) + +Set the fetch `url` for the specified `remote_name` for the GitRepo or the git repository +located at `path`. Typically git repos use "origin" as the remote name. +""" +function set_remote_fetch_url end + +function set_remote_fetch_url(repo::GitRepo, remote_name::AbstractString, url::AbstractString) + @check ccall((:git_remote_set_url, :libgit2), Cint, + (Ptr{Void}, Cstring, Cstring), + repo.ptr, remote_name, url) +end + +function set_remote_fetch_url(path::AbstractString, remote_name::AbstractString, url::AbstractString) + with(GitRepo, path) do repo + set_remote_fetch_url(repo, remote_name, url) + end +end + + +""" + set_remote_push_url(repo::GitRepo, remote_name, url) + set_remote_push_url(path::String, remote_name, url) + +Set the push `url` for the specified `remote_name` for the GitRepo or the git repository +located at `path`. Typically git repos use "origin" as the remote name. +""" +function set_remote_push_url end + +function set_remote_push_url(repo::GitRepo, remote_name::AbstractString, url::AbstractString) +@check ccall((:git_remote_set_pushurl, :libgit2), Cint, + (Ptr{Void}, Cstring, Cstring), + repo.ptr, remote_name, url) +end + +function set_remote_push_url(path::AbstractString, remote_name::AbstractString, url::AbstractString) + with(GitRepo, path) do repo + set_remote_push_url(repo, remote_name, url) + end +end + + +""" + set_remote_url(repo::GitRepo, remote_name, url) + set_remote_url(repo::String, remote_name, url) + +Set both the fetch and push `url` for `remote_name` for the GitRepo or the git repository +located at `path`. Typically git repos use "origin" as the remote name. + +# Examples + +```julia +repo_path = joinpath(tempdir(), "Example") +repo = LibGit2.init(repo_path) +LibGit2.set_remote_url(repo, "upstream", "https://github.com/JuliaLang/Example.jl") +LibGit2.set_remote_url(repo_path, "upstream2", "https://github.com/JuliaLang/Example2.jl") +``` +""" +function set_remote_url end + +function set_remote_url(repo::GitRepo, remote_name::AbstractString, url::AbstractString) + set_remote_fetch_url(repo, remote_name, url) + set_remote_push_url(repo, remote_name, url) +end + +function set_remote_url(path::AbstractString, remote_name::AbstractString, url::AbstractString) + with(GitRepo, path) do repo + set_remote_url(repo, remote_name, url) + end +end diff --git a/base/pkg/cache.jl b/base/pkg/cache.jl index b4535579cd636..1a1a766f9cddc 100644 --- a/base/pkg/cache.jl +++ b/base/pkg/cache.jl @@ -57,7 +57,7 @@ function prefetch(pkg::AbstractString, url::AbstractString, sha1s::Vector) end end try - LibGit2.set_remote_url(repo, normalized_url) + LibGit2.set_remote_url(repo, "origin", normalized_url) in_cache = BitArray(map(sha1->LibGit2.iscommit(sha1, repo), sha1s)) if !all(in_cache) info("Updating cache of $pkg...") diff --git a/base/pkg/dir.jl b/base/pkg/dir.jl index 76b8b57d21bc4..4bcd8fcef7836 100644 --- a/base/pkg/dir.jl +++ b/base/pkg/dir.jl @@ -43,7 +43,7 @@ function init(meta::AbstractString=DEFAULT_META, branch::AbstractString=META_BRA metadata_dir = joinpath(dir, "METADATA") if isdir(metadata_dir) info("Package directory $dir is already initialized.") - LibGit2.set_remote_url(metadata_dir, meta) + LibGit2.set_remote_url(metadata_dir, "origin", meta) return end local temp_dir = "" @@ -53,7 +53,7 @@ function init(meta::AbstractString=DEFAULT_META, branch::AbstractString=META_BRA Base.cd(temp_dir) do info("Cloning METADATA from $meta") with(LibGit2.clone(meta, "METADATA", branch = branch)) do metadata_repo - LibGit2.set_remote_url(metadata_repo, meta) + LibGit2.set_remote_url(metadata_repo, "origin", meta) end touch("REQUIRE") touch("META_BRANCH") diff --git a/base/pkg/entry.jl b/base/pkg/entry.jl index 82bb1f5ab2fb9..91b03930e959d 100644 --- a/base/pkg/entry.jl +++ b/base/pkg/entry.jl @@ -193,7 +193,7 @@ function clone(url::AbstractString, pkg::AbstractString) ispath(pkg) && throw(PkgError("$pkg already exists")) try LibGit2.with(LibGit2.clone(url, pkg)) do repo - LibGit2.set_remote_url(repo, url) + LibGit2.set_remote_url(repo, "origin", url) end catch err isdir(pkg) && Base.rm(pkg, recursive=true) diff --git a/base/pkg/write.jl b/base/pkg/write.jl index 635ef6a677798..ffc2c6f84fb50 100644 --- a/base/pkg/write.jl +++ b/base/pkg/write.jl @@ -27,7 +27,7 @@ function fetch(repo::GitRepo, pkg::AbstractString, sha1::AbstractString) end function checkout(repo::GitRepo, pkg::AbstractString, sha1::AbstractString) - LibGit2.set_remote_url(repo, Cache.normalize_url(Read.url(pkg))) + LibGit2.set_remote_url(repo, "origin", Cache.normalize_url(Read.url(pkg))) LibGit2.checkout!(repo, sha1) end diff --git a/test/libgit2.jl b/test/libgit2.jl index 32bd6bc50d42e..be4f7d38712c7 100644 --- a/test/libgit2.jl +++ b/test/libgit2.jl @@ -257,13 +257,13 @@ mktempdir() do dir @test isa(remote, LibGit2.GitRemote) @test sprint(show, remote) == "GitRemote:\nRemote name: upstream url: $repo_url" @test LibGit2.isattached(repo) - LibGit2.set_remote_url(repo, "", remote="upstream") + LibGit2.set_remote_url(repo, "upstream", "unknown") remote = LibGit2.get(LibGit2.GitRemote, repo, branch) - @test LibGit2.url(remote) == "" - @test LibGit2.push_url(remote) == "" - @test sprint(show, remote) == "GitRemote:\nRemote name: upstream url: " + @test LibGit2.url(remote) == "unknown" + @test LibGit2.push_url(remote) == "unknown" + @test sprint(show, remote) == "GitRemote:\nRemote name: upstream url: unknown" close(remote) - LibGit2.set_remote_url(cache_repo, repo_url, remote="upstream") + LibGit2.set_remote_url(cache_repo, "upstream", repo_url) remote = LibGit2.get(LibGit2.GitRemote, repo, branch) @test LibGit2.url(remote) == repo_url @test LibGit2.push_url(remote) == repo_url @@ -1079,6 +1079,55 @@ mktempdir() do dir end end + @testset "Modify remote" begin + path = test_repo + repo = LibGit2.GitRepo(path) + try + remote_name = "test" + url = "https://test.com/repo" + + @test isnull(LibGit2.lookup_remote(repo, remote_name)) + + for r in (repo, path) + # Set just the fetch URL + LibGit2.set_remote_fetch_url(r, remote_name, url) + remote = get(LibGit2.lookup_remote(repo, remote_name)) + @test LibGit2.name(remote) == remote_name + @test LibGit2.url(remote) == url + @test LibGit2.push_url(remote) == "" + + LibGit2.remote_delete(repo, remote_name) + @test isnull(LibGit2.lookup_remote(repo, remote_name)) + + # Set just the push URL + LibGit2.set_remote_push_url(r, remote_name, url) + remote = get(LibGit2.lookup_remote(repo, remote_name)) + @test LibGit2.name(remote) == remote_name + @test LibGit2.url(remote) == "" + @test LibGit2.push_url(remote) == url + + LibGit2.remote_delete(repo, remote_name) + @test isnull(LibGit2.lookup_remote(repo, remote_name)) + + # Set the fetch and push URL + LibGit2.set_remote_url(r, remote_name, url) + remote = get(LibGit2.lookup_remote(repo, remote_name)) + @test LibGit2.name(remote) == remote_name + @test LibGit2.url(remote) == url + @test LibGit2.push_url(remote) == url + + LibGit2.remote_delete(repo, remote_name) + @test isnull(LibGit2.lookup_remote(repo, remote_name)) + end + + # Invalid remote name + @test_throws LibGit2.GitError LibGit2.set_remote_url(repo, "", url) + @test_throws LibGit2.GitError LibGit2.set_remote_url(repo, remote_name, "") + finally + close(repo) + end + end + @testset "rebase" begin repo = LibGit2.GitRepo(test_repo) try