@@ -63,58 +63,38 @@ local lib = ffi.load(here .. (sep == "\\" and "git2.dll" or "libgit2.so"))
6363
6464lib .git_libgit2_init ()
6565
66- -- ffi.cdata* phantom types for LuaCATS
66+ -- ffi phantom types
6767
6868--- @class git2.ffi.Oid : ffi.cdata*
69- --- @field id number[]
70-
7169--- @class git2.ffi.Repository : ffi.cdata*
72-
7370--- @class git2.ffi.Commit : ffi.cdata*
74-
7571--- @class git2.ffi.Object : ffi.cdata*
76-
7772--- @class git2.ffi.Reference : ffi.cdata*
78-
7973--- @class git2.ffi.Index : ffi.cdata*
80-
8174--- @class git2.ffi.Remote : ffi.cdata*
82-
8375--- @class git2.ffi.Signature : ffi.cdata*
8476--- @field name string
8577--- @field email string
8678--- @field when_time integer
8779
88- -- Lua-land value types
80+ -- value types
8981
9082--- @class git2.Sig
9183--- @field name string
9284--- @field email string
93- --- @field time number Unix timestamp
85+ --- @field time number
9486
9587--- @class git2.Commit
96- --- @field id string 40-char hex SHA
97- --- @field message string Full commit message
98- --- @field summary string First line of message
88+ --- @field id string
89+ --- @field message string
90+ --- @field summary string
9991--- @field author git2.Sig
10092--- @field committer git2.Sig
101- --- @field time number Unix timestamp
93+ --- @field time number
10294--- @field parents string[]
10395
104- --- @class git2.Repo
105- --- @field path fun (): string Absolute path to the .git directory
106- --- @field workdir fun (): string | nil Working directory , nil for bare repos
107- --- @field isBare fun (): boolean
108- --- @field headUnborn fun (): boolean True when repo has no commits yet
109- --- @field head fun (): string SHA of HEAD commit
110- --- @field commitLookup fun ( sha : string ): git2.Commit
111- --- @field revparse fun ( spec : string ): string Resolve any refspec to a SHA
112- --- @field indexAdd fun ( relpath : string )
113- --- @field indexRemove fun ( relpath : string )
114- --- @field indexWrite fun ()
115- --- @field indexWriteTree fun (): string Tree SHA
116- --- @field fetch fun ( remote : string )
117- --- @field free fun ()
96+ -- helpers
97+
11898local sigLayout = ffi .typeof (" struct { char *name; char *email; int64_t when_time; int when_offset; } *" )
11999
120100--- @param code integer
@@ -158,121 +138,136 @@ local function wrapCommit(c)
158138 }
159139end
160140
161- --- @param path string
162- --- @param bare boolean ?
163- --- @return git2.Repo
164- local function openRepo (path , bare )
165- local rp = ffi .new (" git_repository*[1]" )
166- if bare ~= nil then
167- check (lib .git_repository_init (rp , path , bare and 1 or 0 ))
168- else
169- check (lib .git_repository_open (rp , path ))
170- end
171- --- @type git2.ffi.Repository
172- local repo = rp [0 ]
173-
174- --- @type git2.Repo
175- local M = {}
141+ -- Repo class
176142
177- --- @return string
178- function M .path () return ffi .string (lib .git_repository_path (repo )) end
143+ --- @class git2.Repo
144+ --- @field _repo git2.ffi.Repository
145+ local Repo = {}
146+ Repo .__index = Repo
179147
180- --- @return string | nil
181- function M . workdir ()
182- local p = lib . git_repository_workdir (repo )
183- return p ~= nil and ffi . string ( p ) or nil
184- end
148+ --- @param repo git2.ffi.Repository
149+ --- @return git2.Repo
150+ function Repo . new (repo )
151+ return setmetatable ({ _repo = repo }, Repo )
152+ end
185153
186- --- @return boolean
187- function M .isBare () return lib .git_repository_is_bare (repo ) == 1 end
154+ --- @return string
155+ function Repo :path ()
156+ return ffi .string (lib .git_repository_path (self ._repo ))
157+ end
188158
189- --- @return boolean
190- function M .headUnborn () return lib .git_repository_head_unborn (repo ) == 1 end
159+ --- @return string | nil
160+ function Repo :workdir ()
161+ local p = lib .git_repository_workdir (self ._repo )
162+ return p ~= nil and ffi .string (p ) or nil
163+ end
191164
192- --- @return string
193- function M .head ()
194- local ref = ffi .new (" git_reference*[1]" )
195- check (lib .git_repository_head (ref , repo ))
196- local sha = oidStr (lib .git_reference_target (ref [0 ]))
197- lib .git_reference_free (ref [0 ])
198- return sha
199- end
165+ --- @return boolean
166+ function Repo :isBare ()
167+ return lib .git_repository_is_bare (self ._repo ) == 1
168+ end
200169
201- --- @param sha string
202- --- @return git2.Commit
203- function M .commitLookup (sha )
204- local oid = ffi .new (" git_oid" )
205- check (lib .git_oid_fromstr (oid , sha ))
206- local cp = ffi .new (" git_commit*[1]" )
207- check (lib .git_commit_lookup (cp , repo , oid ))
208- local info = wrapCommit (cp [0 ])
209- lib .git_commit_free (cp [0 ])
210- return info
211- end
170+ --- @return boolean
171+ function Repo :headUnborn ()
172+ return lib .git_repository_head_unborn (self ._repo ) == 1
173+ end
212174
213- --- @param spec string
214- --- @return string
215- function M .revparse (spec )
216- local op = ffi .new (" git_object*[1]" )
217- check (lib .git_revparse_single (op , repo , spec ))
218- local sha = oidStr (lib .git_object_id (op [0 ]))
219- lib .git_object_free (op [0 ])
220- return sha
221- end
175+ --- @return string
176+ function Repo :head ()
177+ local ref = ffi .new (" git_reference*[1]" )
178+ check (lib .git_repository_head (ref , self ._repo ))
179+ local sha = oidStr (lib .git_reference_target (ref [0 ]))
180+ lib .git_reference_free (ref [0 ])
181+ return sha
182+ end
222183
223- --- @generic T
224- --- @param fn fun ( idx : git2.ffi.Index ): T
225- --- @return T
226- local function withIndex (fn )
227- local ip = ffi .new (" git_index*[1]" )
228- check (lib .git_repository_index (ip , repo ))
229- local result = fn (ip [0 ])
230- lib .git_index_free (ip [0 ])
231- return result
232- end
184+ --- @param sha string
185+ --- @return git2.Commit
186+ function Repo :commitLookup (sha )
187+ local oid = ffi .new (" git_oid" )
188+ check (lib .git_oid_fromstr (oid , sha ))
189+ local cp = ffi .new (" git_commit*[1]" )
190+ check (lib .git_commit_lookup (cp , self ._repo , oid ))
191+ local info = wrapCommit (cp [0 ])
192+ lib .git_commit_free (cp [0 ])
193+ return info
194+ end
233195
234- --- @param relpath string
235- function M .indexAdd (relpath ) withIndex (function (i ) check (lib .git_index_add_bypath (i , relpath )) end ) end
196+ --- @param spec string
197+ --- @return string
198+ function Repo :revparse (spec )
199+ local op = ffi .new (" git_object*[1]" )
200+ check (lib .git_revparse_single (op , self ._repo , spec ))
201+ local sha = oidStr (lib .git_object_id (op [0 ]))
202+ lib .git_object_free (op [0 ])
203+ return sha
204+ end
236205
237- --- @param relpath string
238- function M .indexRemove (relpath ) withIndex (function (i ) check (lib .git_index_remove_bypath (i , relpath )) end ) end
206+ --- @param relpath string
207+ function Repo :indexAdd (relpath )
208+ local ip = ffi .new (" git_index*[1]" )
209+ check (lib .git_repository_index (ip , self ._repo ))
210+ check (lib .git_index_add_bypath (ip [0 ], relpath ))
211+ lib .git_index_free (ip [0 ])
212+ end
239213
240- function M .indexWrite () withIndex (function (i ) check (lib .git_index_write (i )) end ) end
214+ --- @param relpath string
215+ function Repo :indexRemove (relpath )
216+ local ip = ffi .new (" git_index*[1]" )
217+ check (lib .git_repository_index (ip , self ._repo ))
218+ check (lib .git_index_remove_bypath (ip [0 ], relpath ))
219+ lib .git_index_free (ip [0 ])
220+ end
241221
242- --- @return string
243- function M .indexWriteTree ()
244- return withIndex (function (i )
245- local oid = ffi .new (" git_oid" )
246- check (lib .git_index_write_tree (oid , i ))
247- return oidStr (oid )
248- end )
249- end
222+ function Repo :indexWrite ()
223+ local ip = ffi .new (" git_index*[1]" )
224+ check (lib .git_repository_index (ip , self ._repo ))
225+ check (lib .git_index_write (ip [0 ]))
226+ lib .git_index_free (ip [0 ])
227+ end
250228
251- --- @param remoteName string
252- function M .fetch (remoteName )
253- local rmt = ffi .new (" git_remote*[1]" )
254- check (lib .git_remote_lookup (rmt , repo , remoteName ))
255- check (lib .git_remote_fetch (rmt [0 ], nil , nil , nil ))
256- lib .git_remote_free (rmt [0 ])
257- end
229+ --- @return string
230+ function Repo :indexWriteTree ()
231+ local ip = ffi .new (" git_index*[1]" )
232+ check (lib .git_repository_index (ip , self ._repo ))
233+ local oid = ffi .new (" git_oid" )
234+ check (lib .git_index_write_tree (oid , ip [0 ]))
235+ lib .git_index_free (ip [0 ])
236+ return oidStr (oid )
237+ end
258238
259- function M .free () lib .git_repository_free (repo ) end
239+ --- @param remoteName string
240+ function Repo :fetch (remoteName )
241+ local rmt = ffi .new (" git_remote*[1]" )
242+ check (lib .git_remote_lookup (rmt , self ._repo , remoteName ))
243+ check (lib .git_remote_fetch (rmt [0 ], nil , nil , nil ))
244+ lib .git_remote_free (rmt [0 ])
245+ end
260246
261- return M
247+ function Repo :free ()
248+ lib .git_repository_free (self ._repo )
262249end
263250
251+ -- module
252+
264253--- @class git2
265254local git2 = {}
266255
267- --- Open an existing repository.
268256--- @param path string
269257--- @return git2.Repo
270- function git2 .open (path ) return openRepo (path ) end
258+ function git2 .open (path )
259+ local rp = ffi .new (" git_repository*[1]" )
260+ check (lib .git_repository_open (rp , path ))
261+ return Repo .new (rp [0 ])
262+ end
271263
272- --- Initialise a new repository.
273264--- @param path string
274265--- @param bare boolean ?
275266--- @return git2.Repo
276- function git2 .init (path , bare ) return openRepo (path , bare or false ) end
267+ function git2 .init (path , bare )
268+ local rp = ffi .new (" git_repository*[1]" )
269+ check (lib .git_repository_init (rp , path , bare and 1 or 0 ))
270+ return Repo .new (rp [0 ])
271+ end
277272
278273return git2
0 commit comments