Index

resty-gitweb / c69d6c0

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 Stockin12560G

Blob @ resty-gitweb / git / git.lua

text/plain7960 bytesdownload raw
1-- resty-gitweb@git/git_commands.lua
2-- git commands and parser functions
3
4-- Copyright (c) 2020 Joshua 'joshuas3' Stockin
5-- <https://git.joshstock.in/resty-gitweb>
6-- This software is licensed under the MIT License.
7
8local ffi = require("ffi")
9local utils = require("utils/utils")
10local git2_error = require("git/git2_error")
11
12local _M = {}
13
14local git = function(repo_dir, command)
15 local formatted_command = string.format(
16 "git --git-dir=%s %s",
17 repo_dir, command
18 )
19 return utils.process(formatted_command)
20end
21
22_M.get_head = function(repo_dir, ref_name)
23 local err = 0
24 ref_name = ref_name or "HEAD"
25
26 -- Open git repo
27 local repo_obj = ffi.new("git_repository*[1]")
28 err = git2.git_repository_open(ffi.cast("git_repository**", repo_obj), repo_dir)
29 git2_error(err, "Failed opening git repository")
30 repo_obj = repo_obj[0]
31
32 -- Get object/reference
33 local object = ffi.new("git_object*[1]")
34 local reference = ffi.new("git_reference*[1]")
35 err = git2.git_revparse_ext(ffi.cast("git_object**", object), ffi.cast("git_reference**", reference), repo_obj, ref_name)
36 git2_error(err, "Failed to find reference")
37 object = object[0]
38 reference = reference[0]
39
40 -- Get full name if intermediate reference exists
41 local name = ref_name
42 if reference ~= nil then
43 local ref_type = git2.git_reference_type(reference)
44 if ref_type == git2.GIT_REFERENCE_SYMBOLIC then
45 name = ffi.string(git2.git_reference_symbolic_target(reference))
46 else
47 name = ffi.string(git2.git_reference_name(reference))
48 end
49 end
50
51 -- Get OID
52 local oid = git2.git_object_id(object)
53
54 -- Format oid as SHA1 hash
55 local hash = ffi.new("char[41]") -- SHA1 length (40 chars) + \0
56 err = git2.git_oid_fmt(hash, oid)
57 git2_error(err, "Failed formatting OID")
58 hash = ffi.string(hash)
59
60 -- Free all
61 git2.git_object_free(object)
62 if reference ~= nil then
63 git2.git_reference_free(reference)
64 end
65 git2.git_repository_free(repo_obj)
66
67 -- Format
68 local ref = {}
69 ref.full = name
70 if name:match("^refs/heads/") then
71 ref.name = string.sub(name, 12, string.len(name))
72 elseif name:match("^refs/tags/") then
73 ref.name = string.sub(name, 11, string.len(name))
74 else
75 ref.name = ref_name -- just pass input as default output
76 end
77 ref.hash = hash
78 ref.shorthash = string.sub(hash, 1, 7)
79
80 return ref
81end
82
83_M.count = function(repo_dir, hash)
84 hash = hash or "@"
85 local output = git(repo_dir, "rev-list --count "..hash.." --")
86 return tonumber(string.trim(output))
87end
88
89_M.log = function(repo_dir, hash, file, number, skip, gpg)
90 hash = hash or "@"
91 file = file or ""
92 number = tostring(number or 25)
93 skip = tostring(skip or 0)
94 gpg = gpg or false
95 local output
96 if gpg then
97 output = git(repo_dir, "log --pretty=tformat:'%x00%x01%H%x00%cI%x00%cn%x00%ce%x00%s%x00%b%x00%G?%x00%GK%x00%GG%x00' --numstat -n "..number.." --skip "..skip.." "..hash.." -- "..file)
98 else
99 output = git(repo_dir, "log --pretty=tformat:'%x00%x01%H%x00%cI%x00%cn%x00%ce%x00%s%x00%b%x00' --numstat -n "..number.." --skip "..skip.." "..hash.." -- "..file)
100 end
101 local commits = {}
102 local a = string.split(output,"\0\1")
103 local f = false
104 for i,v in pairs(a) do
105 if f == true then
106 local commit = {}
107 local c = string.split(v, "\0")
108 commit.hash = c[1]
109 commit.shorthash = string.sub(c[1], 1,7)
110 commit.timestamp = c[2]
111 commit.author = c[3]
112 commit.email = c[4]
113 commit.subject = c[5]
114 commit.body = string.trim(c[6])
115 local diffs
116 if gpg then
117 commit.gpggood = c[7]
118 commit.gpgkey = c[8]
119 commit.gpgfull = string.trim(c[9])
120 diffs = string.trim(c[10])
121 else
122 diffs = string.trim(c[7])
123 end
124 commit.diff = {}
125 local b = string.split(diffs, "\n")
126 commit.diff.plus = 0
127 commit.diff.minus = 0
128 commit.diff.num = 0
129 commit.diff.files = {}
130 for i,v in pairs(b) do
131 local d = string.split(v,"\t")
132 local x = {}
133 x.plus = tonumber(d[1]) or 0
134 commit.diff.plus = commit.diff.plus + x.plus
135 x.minus = tonumber(d[2]) or 0
136 commit.diff.minus = commit.diff.minus + x.minus
137 commit.diff.files[d[3]] = x
138 commit.diff.num = commit.diff.num + 1
139 end
140 table.insert(commits, commit)
141 else
142 f = true
143 end
144 end
145 return commits
146end
147
148_M.commit = function(repo_dir, hash)
149 local commit = _M.log(repo_dir, hash, "", 1, 0, true)[1]
150 commit.count = _M.count(repo_dir, hash)
151 return commit
152end
153
154_M.list_refs = function(repo_dir)
155 -- Open git repo
156 local repo_obj = ffi.new("git_repository*[1]")
157 local err = git2.git_repository_open(ffi.cast("git_repository**", repo_obj), repo_dir)
158 repo_obj = repo_obj[0]
159
160 -- List refs
161 local refs = ffi.new("git_strarray")
162 local err = git2.git_reference_list(ffi.cast("git_strarray*", refs), repo_obj)
163
164 local ret = {}
165 ret.heads = {}
166 ret.tags = {}
167
168 for i = 0, tonumber(refs.count)-1 do
169
170 local name = ffi.string(refs.strings[i])
171
172 local dest
173 local prefix_len
174 if name:match("^refs/heads/") then
175 dest = ret.heads
176 prefix_len = 12
177 elseif name:match("^refs/tags/") then
178 dest = ret.tags
179 prefix_len = 11
180 end
181
182 if dest then
183 local oid = ffi.new("git_oid")
184 local err = git2.git_reference_name_to_id(ffi.cast("git_oid*", oid), repo_obj, refs.strings[i])
185
186 -- Format oid as SHA1 hash
187 local hash = ffi.new("char[41]") -- SHA1 length (40 chars) + \0
188 local err = git2.git_oid_fmt(hash, ffi.cast("git_oid*", oid))
189 hash = ffi.string(hash)
190
191 local ref = {}
192 ref.name = string.sub(name, prefix_len, string.len(name))
193 ref.full = name
194 ref.hash = hash
195 ref.shorthash = string.sub(hash, 1, 7)
196 table.insert(dest, ref)
197 end
198
199 end
200
201 if refs then
202 git2.git_strarray_free(ffi.cast("git_strarray*", refs))
203 end
204 if repo_obj then
205 git2.git_repository_free(ffi.cast("git_repository*", repo_obj))
206 end
207
208 return ret
209end
210
211local list_dirs = function(repo_dir, hash, path)
212 hash = hash or "@"
213 path = path or ""
214 local output = git(repo_dir, "ls-tree -d --name-only "..hash.." -- "..path)
215 local dirs = string.split(output, "\n")
216 table.remove(dirs, #dirs) -- remove trailing \n
217 return dirs
218end
219
220local list_all = function(repo_dir, hash, path)
221 hash = hash or "@"
222 path = path or ""
223 local output = git(repo_dir, "ls-tree --name-only "..hash.." -- "..path)
224 local all = string.split(output, "\n")
225 table.remove(all, #all) -- remove trailing \n
226 return all
227end
228
229_M.list_tree = function(repo_dir, hash, path)
230 hash = hash or "@"
231 path = path or ""
232 local files = list_all(repo_dir, hash, path)
233 local dirs = list_dirs(repo_dir, hash, path)
234 local ret = {}
235 ret.dirs = {}
236 ret.files = {}
237 for i,v in pairs(files) do -- iterate over all objects, separate directories from files
238 local not_dir = true
239 for _,d in pairs(dirs) do -- check if object is directory
240 if v == d then
241 not_dir = false
242 break
243 end
244 end
245 if not_dir then
246 table.insert(ret.files, v)
247 else
248 table.insert(ret.dirs, v)
249 end
250 end
251 return ret
252end
253
254_M.repo = require("git/repo")
255_M.read_blob = require("git/read_blob")
256return _M
257