Index

resty-gitweb / 609d330

A git web interface for Lua/OpenResty (you're on it right now!)

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
703 Jan 2021 10:11609d330libgit2 binding updates, README updatesJosh Stockin1325G

Blob @ resty-gitweb / libgit.lua

text/plain6785 bytesdownload raw
1local ffi = require("ffi")
2
3ffi.include = function(header)
4 p = io.popen("echo '#include <"..header..">' | gcc -E -")
5 local c = {}
6 while true do
7 local line = p:read()
8 if line then
9 if not line:match("^#") then
10 table.insert(c, line)
11 end
12 else
13 break
14 end
15 end
16 p:close()
17 ffi.cdef(table.concat(c, "\n"))
18end
19
20ffi.include("git2.h")
21local git2 = ffi.load("git2")
22
23function git2_error(err, message)
24 if err < 0 then
25 local git2_error_message = ffi.string(git2.git_error_last().message)
26 error(string.format([[libgit2 Error - %s ("%s")]], message, git2_error_message))
27 end
28end
29
30function exists(repo_dir)
31 local err = git2.git_repository_open(nil, repo_dir)
32 return err == 0
33end
34
35function show(repo_dir, ref_name, file_path)
36 local err = 0
37
38 -- Open git repo
39 local repo_obj = ffi.new("git_repository*[1]")
40 err = git2.git_repository_open(ffi.cast("git_repository**", repo_obj), repo_dir)
41 git2_error(err, "Failed opening git repository")
42 repo_obj = repo_obj[0]
43
44 -- Get tree root
45 local tree = ffi.new("git_object*[1]")
46 err = git2.git_revparse_single(ffi.cast("git_object**", tree), repo_obj, ref_name)
47 git2_error(err, "Failed to look up tree from rev name")
48 tree = tree[0]
49
50 -- Get tree entry object (blob)
51 local blob = ffi.new("git_object*[1]")
52 err = git2.git_object_lookup_bypath(ffi.cast("git_object**", blob), tree, file_path, git2.GIT_OBJECT_BLOB)
53 git2_error(err, "Failed to look up blob")
54 blob = ffi.cast("git_blob*", blob[0])
55
56 -- Get blob content
57 local buf = ffi.new("git_buf")
58 err = git2.git_blob_filter(buf, blob, file_path, nil)
59 git2_error(err, "Failed to filter blob")
60 local raw = ffi.string(buf.ptr)
61
62 -- Free everything
63 git2.git_buf_free(buf)
64 git2.git_blob_free(blob)
65 git2.git_object_free(tree)
66 git2.git_repository_free(repo_obj)
67
68 return raw
69end
70
71function get_ref(repo_dir, ref_name)
72 local err = 0
73 ref_name = ref_name or "HEAD"
74
75 -- Open git repo
76 local repo_obj = ffi.new("git_repository*[1]")
77 err = git2.git_repository_open(ffi.cast("git_repository**", repo_obj), repo_dir)
78 git2_error(err, "Failed opening git repository")
79 repo_obj = repo_obj[0]
80
81 -- Get object/reference
82 local object = ffi.new("git_object*[1]")
83 local reference = ffi.new("git_reference*[1]")
84 err = git2.git_revparse_ext(ffi.cast("git_object**", object), ffi.cast("git_reference**", reference), repo_obj, ref_name)
85 git2_error(err, "Failed to find reference")
86 object = object[0]
87 reference = reference[0]
88
89 -- Get full name if intermediate reference exists
90 local name = ref_name
91 if reference ~= nil then
92 local ref_type = git2.git_reference_type(reference)
93 if ref_type == git2.GIT_REFERENCE_SYMBOLIC then
94 name = ffi.string(git2.git_reference_symbolic_target(reference))
95 else
96 name = ffi.string(git2.git_reference_name(reference))
97 end
98 end
99
100 -- Get OID
101 local oid = git2.git_object_id(object)
102
103 -- Format oid as SHA1 hash
104 local hash = ffi.new("char[41]") -- SHA1 length (40 chars) + \0
105 err = git2.git_oid_fmt(hash, oid)
106 git2_error(err, "Failed formatting OID")
107 hash = ffi.string(hash)
108
109 -- Free all
110 git2.git_object_free(object)
111 if reference ~= nil then
112 git2.git_reference_free(reference)
113 end
114 git2.git_repository_free(repo_obj)
115
116 -- Format
117 local ref = {}
118 ref.full = name
119 if name:match("^refs/heads/") then
120 ref.name = string.sub(name, 12, string.len(name))
121 elseif name:match("^refs/tags/") then
122 ref.name = string.sub(name, 11, string.len(name))
123 else
124 ref.name = ref_name -- just pass input as default output
125 end
126 ref.hash = hash
127 ref.shorthash = string.sub(hash, 1, 7)
128
129 return ref
130end
131
132function list_refs(repo_dir)
133 -- Open git repo
134 local repo_obj = ffi.new("git_repository*[1]")
135 local err = git2.git_repository_open(ffi.cast("git_repository**", repo_obj), repo_dir)
136 repo_obj = repo_obj[0]
137
138 -- List refs
139 local refs = ffi.new("git_strarray")
140 local err = git2.git_reference_list(refs, repo_obj)
141
142 local ret = {}
143 ret.heads = {}
144 ret.tags = {}
145
146 for i = 0, tonumber(refs.count)-1 do
147
148 local name = ffi.string(refs.strings[i])
149
150 local dest
151 local prefix_len
152 if name:match("^refs/heads/") then
153 dest = ret.heads
154 prefix_len = 12
155 elseif name:match("^refs/tags/") then
156 dest = ret.tags
157 prefix_len = 11
158 end
159
160 if dest then
161 local oid = ffi.new("git_oid")
162 local err = git2.git_reference_name_to_id(oid, repo_obj, refs.strings[i])
163
164 -- Format oid as SHA1 hash
165 local hash = ffi.new("char[41]") -- SHA1 length (40 chars) + \0
166 local err = git2.git_oid_fmt(hash, oid)
167 hash = ffi.string(hash)
168
169 local ref = {}
170 ref.name = string.sub(name, prefix_len, string.len(name))
171 ref.full = name
172 ref.hash = hash
173 ref.shorthash = string.sub(hash, 1, 7)
174 table.insert(dest, ref)
175 end
176
177 end
178
179 if refs ~= nil then
180 git2.git_strarray_free(refs)
181 end
182 if repo_obj ~= nil then
183 git2.git_repository_free(repo_obj)
184 end
185
186 return ret
187end
188
189local t = {
190 "/home/josh/repos/ncurses-minesweeper",
191}
192
193git2.git_libgit2_init()
194
195function serializeTable(val, name, skipnewlines, depth)
196 skipnewlines = skipnewlines or false
197 depth = depth or 0
198
199 local tmp = string.rep(" ", depth)
200
201 if name then tmp = tmp .. name .. " = " end
202
203 if type(val) == "table" then
204 tmp = tmp .. "{" .. (not skipnewlines and "\n" or "")
205
206 for k, v in pairs(val) do
207 tmp = tmp .. serializeTable(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and "\n" or "")
208 end
209
210 tmp = tmp .. string.rep(" ", depth) .. "}"
211 elseif type(val) == "number" then
212 tmp = tmp .. tostring(val)
213 elseif type(val) == "string" then
214 tmp = tmp .. string.format("%q", val)
215 elseif type(val) == "boolean" then
216 tmp = tmp .. (val and "true" or "false")
217 else
218 tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
219 end
220
221 return tmp
222end
223
224
225for _, r in pairs(t) do
226 if exists(r) then
227 print(r)
228 local refs = list_refs(r)
229 local head = get_ref(r)
230 print(serializeTable(head))
231 print()
232 end
233end
234
235git2.git_libgit2_shutdown()
236
237collectgarbage()
238collectgarbage()
239collectgarbage()
240collectgarbage()
241collectgarbage()
242collectgarbage()
243collectgarbage()
244collectgarbage()
245collectgarbage()
246