Skip to content

Commit c24b82b

Browse files
committed
Add Git LFS support via package extension
1 parent f588510 commit c24b82b

File tree

4 files changed

+77
-2
lines changed

4 files changed

+77
-2
lines changed

Project.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
name = "Git"
22
uuid = "d7ba0133-e1db-5d97-8f8c-041e4b3a1eb2"
3-
version = "1.4.0"
43
authors = ["Dilum Aluthge", "contributors"]
4+
version = "1.4.0"
55

66
[deps]
77
Git_jll = "f8c6e375-362e-5223-8a59-34ff63f689eb"
88
JLLWrappers = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
99
OpenSSH_jll = "9bd350c2-7e96-507f-8002-3f2e150b4e1b"
1010

11+
[weakdeps]
12+
Git_LFS_jll = "020c3dae-16b3-5ae5-87b3-4cb189e250b2"
13+
1114
[compat]
15+
Git_LFS_jll = "3"
1216
Git_jll = "2.44"
1317
JLLWrappers = "1.1"
1418
OpenSSH_jll = "9, 10"
1519
julia = "1.6"
1620

21+
[extensions]
22+
GitLFSExt = "Git_LFS_jll"
23+
1724
[extras]
1825
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1926

ext/GitLFSExt.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module GitLFSExt
2+
using Git_LFS_jll
3+
4+
git_lfs_path() = Git_LFS_jll.PATH[]
5+
6+
end

src/git_function.jl

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ julia> run(git(["clone", "https://github.com/JuliaRegistries/General"]))
2020
2121
to bypass the parsing of the command string.
2222
"""
23-
function git(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true)
23+
function git(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true, lfs::Bool = false)
2424
git_cmd = @static if Sys.iswindows()
2525
Git_jll.git(; adjust_PATH, adjust_LIBPATH)::Cmd
2626
else
@@ -67,6 +67,13 @@ function git(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true)
6767
git_cmd = addenv(git_cmd, "PATH" => join(path, pathsep), LIBPATH_env => join(libpath, pathsep))
6868
end
6969

70+
# If the Git_LFS_jll is loaded _and_ the user has explicitly requested it, we'll enable
71+
# the support got `git lfs` subcommands (by modifying the PATH, so that Git could find
72+
# the subcommand from the other JLL).
73+
if lfs
74+
git_cmd = _push_git_lfs_to_path!(git_cmd)
75+
end
76+
7077
return git_cmd
7178
end
7279

@@ -75,3 +82,26 @@ function git(args::AbstractVector{<:AbstractString}; kwargs...)
7582
append!(cmd.exec, args)
7683
return cmd
7784
end
85+
86+
# This function is used to implement the LFS support
87+
function _push_git_lfs_to_path!(git_cmd::Cmd)
88+
GitLFSExt = Base.get_extension(@__MODULE__, :GitLFSExt)
89+
if isnothing(GitLFSExt)
90+
throw(GitLFSNotLoadedError())
91+
end
92+
93+
idx = findfirst(startswith("PATH="), git_cmd.env)
94+
path = if isnothing(idx)
95+
""
96+
else
97+
# dropping the `PATH=` part
98+
git_cmd.env[idx][6:end]
99+
end
100+
path = split(get(ENV, LIBPATH_env, ""), path)
101+
pushfirst!(path, GitLFSExt.git_lfs_path())
102+
103+
return addenv(git_cmd, "PATH" => join(path, pathsep))
104+
end
105+
106+
struct GitLFSNotLoadedError <: Exception end
107+
Base.showerror(io::IO, ::GitLFSNotLoadedError) = print(io, "GitLFSNotLoadedError: Unable to set up LFS support for Git: lfs=true, but Git_LFS_jll is not loaded.")

test/runtests.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,35 @@ end
107107
@test_skip false
108108
end # if
109109
end # testset
110+
111+
# This testset will only pass if the Git_LFS_jll has not been loaded
112+
@testset "Git LFS (not loaded)" begin
113+
@test_throws Git.GitLFSNotLoadedError Git.git(; lfs=true)
114+
end
115+
116+
# Ensure that we can call `git lfs`
117+
using Git_LFS_jll
118+
@testset "Git LFS" begin
119+
cmd = Git.git(; lfs=true)
120+
cmd = `$cmd lfs version`
121+
@test success(cmd)
122+
123+
version_output = read(cmd, String)
124+
# The output here will be something like
125+
#
126+
# git-lfs/3.7.0 (GitHub; linux amd64; go 1.24.0)\n
127+
#
128+
# So we'll match the first part. In case Git is unable to find `git lfs`, then
129+
# this should throw an error, since `git` will exit with a non-zero exit code.
130+
@test occursin(r"^git-lfs/\d+\.\d+\.\d+", version_output)
131+
132+
# If we set `lfs=false`, then `lfs` should not be available.
133+
cmd = Git.git(; lfs=false)
134+
cmd = `$cmd lfs version`
135+
@test success(cmd)
136+
137+
# And the same with the default value
138+
cmd = Git.git()
139+
cmd = `$cmd lfs version`
140+
@test !success(cmd)
141+
end

0 commit comments

Comments
 (0)