# This file is a part of Julia. License is MIT: https://julialang.org/license

module Cache

import ...LibGit2, ..Dir, ...Pkg.PkgError
using ..Types

rewrite_url_to = "https"

const GITHUB_REGEX =
    r"^(?:git@|git://|https://(?:[\w\.\+\-]+@)?)github.com[:/](([^/].+)/(.+?))(?:\.git)?$"i

path(pkg::AbstractString) = abspath(".cache", pkg)

function mkcachedir()
    cache = joinpath(realpath("."), ".cache")
    if isdir(cache)
        return
    end

    @static if is_unix()
        if Dir.isversioned(pwd())
            rootcache = joinpath(realpath(".."), ".cache")
            if !isdir(rootcache)
                mkdir(rootcache)
            end
            symlink(rootcache, cache)
            return
        end
    end
    mkdir(cache)
end

function prefetch(pkg::AbstractString, url::AbstractString, sha1s::Vector)
    isdir(".cache") || mkcachedir()

    cache = path(pkg)
    normalized_url = normalize_url(url)

    repo = if isdir(cache)
        LibGit2.GitRepo(cache) # open repo, free it at the end
    else
        info("Cloning cache of $pkg from $normalized_url")
        try
            # clone repo, free it at the end
            LibGit2.clone(normalized_url, cache, isbare = true, remote_cb = LibGit2.mirror_cb())
        catch err
            errmsg = if isa(err, LibGit2.Error.GitError)
                "Cannot clone $pkg from $normalized_url. $(err.msg)"
            elseif isa(err, InterruptException)
                "Package `$pkg` prefetching was interrupted."
            else
                "Unknown error: $err"
            end
            isdir(cache) && rm(cache, recursive=true)
            throw(PkgError(errmsg))
        end
    end
    try
        LibGit2.set_remote_url(repo, normalized_url)
        in_cache = BitArray(map(sha1->LibGit2.iscommit(sha1, repo), sha1s))
        if !all(in_cache)
            info("Updating cache of $pkg...")
            LibGit2.fetch(repo)
            in_cache = BitArray(map(sha1->LibGit2.iscommit(sha1, repo), sha1s))
        end
        sha1s[!in_cache]
    finally
        finalize(repo) # closing repo opened/created above
    end
end
prefetch(pkg::AbstractString, url::AbstractString, sha1::AbstractString...) =
    prefetch(pkg, url, AbstractString[sha1...])

function setprotocol!(proto::AbstractString)
    global rewrite_url_to

    if length(proto) == 0
        rewrite_url_to = nothing
    else
        rewrite_url_to = proto
    end
end

function normalize_url(url::AbstractString)
    global rewrite_url_to

    m = match(GITHUB_REGEX,url)
    (m === nothing || rewrite_url_to === nothing) ?
        url : "$rewrite_url_to://github.com/$(m.captures[1]).git"

end

end # module
