diff --git a/Project.toml b/Project.toml index 2619f85..4c8710a 100644 --- a/Project.toml +++ b/Project.toml @@ -1,14 +1,16 @@ name = "Git" uuid = "d7ba0133-e1db-5d97-8f8c-041e4b3a1eb2" -version = "1.4.0" authors = ["Dilum Aluthge", "contributors"] +version = "1.5.0" [deps] +Git_LFS_jll = "020c3dae-16b3-5ae5-87b3-4cb189e250b2" Git_jll = "f8c6e375-362e-5223-8a59-34ff63f689eb" JLLWrappers = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" OpenSSH_jll = "9bd350c2-7e96-507f-8002-3f2e150b4e1b" [compat] +Git_LFS_jll = "3.7" Git_jll = "2.44" JLLWrappers = "1.1" OpenSSH_jll = "9, 10" diff --git a/README.md b/README.md index 337a302..e9d4866 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ not need to have Git installed on your computer, and neither do the users of your packages! Git.jl provides a Git binary via -[Git_jll.jl](https://github.com/JuliaBinaryWrappers/Git_jll.jl). +[Git_jll.jl](https://github.com/JuliaBinaryWrappers/Git_jll.jl) +and a Git LFS binary for large file support via +[Git_LFS_jll.jl](https://github.com/JuliaBinaryWrappers/Git_LFS_jll.jl). The latest version of Git.jl requires at least Julia 1.6. Git.jl is intended to work on any platform that supports Julia, diff --git a/src/git_function.jl b/src/git_function.jl index 1e34733..95e48b6 100644 --- a/src/git_function.jl +++ b/src/git_function.jl @@ -1,4 +1,5 @@ using OpenSSH_jll: OpenSSH_jll +using Git_LFS_jll: Git_LFS_jll using JLLWrappers: pathsep, LIBPATH_env """ @@ -21,9 +22,12 @@ julia> run(git(["clone", "https://github.com/JuliaRegistries/General"])) to bypass the parsing of the command string. """ function git(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true) - git_cmd = @static if Sys.iswindows() - Git_jll.git(; adjust_PATH, adjust_LIBPATH)::Cmd - else + git_cmd = Git_jll.git(; adjust_PATH, adjust_LIBPATH)::Cmd + env_mapping = Dict{String,String}( + "PATH" => _get_cmd_env(git_cmd, "PATH"), + LIBPATH_env => _get_cmd_env(git_cmd, LIBPATH_env), + ) + @static if !Sys.iswindows() root = Git_jll.artifact_dir libexec = joinpath(root, "libexec") @@ -35,7 +39,6 @@ function git(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true) ssl_cert = joinpath(dirname(Sys.BINDIR), "share", "julia", "cert.pem") - env_mapping = Dict{String,String}() env_mapping["GIT_EXEC_PATH"] = libexec_git_core env_mapping["GIT_SSL_CAINFO"] = ssl_cert env_mapping["GIT_TEMPLATE_DIR"] = share_git_core_templates @@ -46,15 +49,12 @@ function git(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true) # more details. env_mapping["JLL_DYLD_FALLBACK_LIBRARY_PATH"] = Git_jll.LIBPATH[] end - - original_cmd = Git_jll.git(; adjust_PATH, adjust_LIBPATH)::Cmd - addenv(original_cmd, env_mapping...)::Cmd end # Use OpenSSH from the JLL: . if !Sys.iswindows() && OpenSSH_jll.is_available() - path = split(get(ENV, "PATH", ""), pathsep) - libpath = split(get(ENV, LIBPATH_env, ""), pathsep) + path = split(get(env_mapping, "PATH", ""), pathsep) + libpath = split(get(env_mapping, LIBPATH_env, ""), pathsep) path = vcat(dirname(OpenSSH_jll.ssh_path), path) libpath = vcat(OpenSSH_jll.LIBPATH_list, libpath) @@ -64,10 +64,20 @@ function git(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true) unique!(filter!(!isempty, path)) unique!(filter!(!isempty, libpath)) - git_cmd = addenv(git_cmd, "PATH" => join(path, pathsep), LIBPATH_env => join(libpath, pathsep)) + env_mapping["PATH"] = join(path, pathsep) + env_mapping[LIBPATH_env] = join(libpath, pathsep) + end + + # Add git-lfs + if Git_LFS_jll.is_available() + env_mapping["PATH"] = string( + dirname(Git_LFS_jll.git_lfs_path), + pathsep, + get(env_mapping, "PATH", "") + ) end - return git_cmd + return addenv(git_cmd, env_mapping...)::Cmd end function git(args::AbstractVector{<:AbstractString}; kwargs...) @@ -75,3 +85,15 @@ function git(args::AbstractVector{<:AbstractString}; kwargs...) append!(cmd.exec, args) return cmd end + +# The .env field of a Cmd object is an array of strings in the format +# `$(key)=$(value)` for each environment variable. +function _get_cmd_env(cmd::Cmd, key::AbstractString) + idx = findfirst(startswith("$(key)="), cmd.env) + if isnothing(idx) + return "" + else + # dropping the `$(key)=` part + return cmd.env[idx][(ncodeunits(key)+2):end] + end +end diff --git a/test/runtests.jl b/test/runtests.jl index 1b1516f..75c61ea 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -34,6 +34,20 @@ end @test isdir("Git.jl") @test isfile(joinpath("Git.jl", "Project.toml")) end + + # git-lfs tests + withtempdir() do tmp_dir + rname = "repo-with-large-file-storage" + @test !isdir(rname) + @test !isfile(joinpath(rname, "LargeFile.zip")) + run(`$(git()) clone --quiet https://github.com/Apress/repo-with-large-file-storage`) + run(pipeline(`$(git()) -C $rname lfs install --local`; stdout=devnull)) + run(pipeline(`$(git()) -C $rname lfs pull`; stdout=devnull)) + @test isdir(rname) + @test isfile(joinpath(rname, "LargeFile.zip")) + # Test filesize to make sure we got real file and not small LFS pointer file + @test filesize(joinpath(rname, "LargeFile.zip")) > 10^6 + end end @testset "Safety" begin