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 |
|
8 | local utils = require("utils/utils") |
9 |
|
10 | local _M = {} |
11 |
|
12 | local git = function(repo_dir, command) |
13 | local formatted_command = string.format( |
14 | "git --git-dir=%s %s", |
15 | repo_dir, command |
16 | ) |
17 | return utils.process(formatted_command) |
18 | end |
19 |
|
20 | _M.show_file = function(repo_dir, hash, filename) |
21 | hash = hash or "@" |
22 | filename = filename or "" |
23 | local output = git(repo_dir, "show "..hash..":"..filename) |
24 | return output |
25 | end |
26 |
|
27 | _M.get_head = function(repo_dir, head_name) |
28 | head_name = head_name or "HEAD" |
29 | local head = {} |
30 | local name = string.trim(git(repo_dir, "rev-parse --abbrev-ref "..head_name)) |
31 | if name ~= "" then |
32 | local output = git(repo_dir, "show-ref --heads --tags "..name) |
33 | local a = string.split(string.trim(output), " ") |
34 | head.hash = a[1] |
35 | head.shorthash = string.sub(a[1], 1, 7) |
36 | head.full = a[2] |
37 | head.name = name |
38 | else -- no ref, default to hash |
39 | head.hash = head_name |
40 | head.shorthash = string.sub(head_name, 1, 7) |
41 | head.full = head_name |
42 | head.name = head_name |
43 | end |
44 | return head |
45 | end |
46 |
|
47 | _M.count = function(repo_dir, hash) |
48 | hash = hash or "@" |
49 | local output = git(repo_dir, "rev-list --count "..hash.." --") |
50 | return tonumber(string.trim(output)) |
51 | end |
52 |
|
53 | _M.log = function(repo_dir, hash, file, number, skip, gpg) |
54 | hash = hash or "@" |
55 | file = file or "" |
56 | number = tostring(number or 25) |
57 | skip = tostring(skip or 0) |
58 | gpg = gpg or false |
59 | local output |
60 | if gpg then |
61 | 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) |
62 | else |
63 | 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) |
64 | end |
65 | local commits = {} |
66 | local a = string.split(output,"\0\1") |
67 | local f = false |
68 | for i,v in pairs(a) do |
69 | if f == true then |
70 | local commit = {} |
71 | local c = string.split(v, "\0") |
72 | commit.hash = c[1] |
73 | commit.shorthash = string.sub(c[1], 1,7) |
74 | commit.timestamp = c[2] |
75 | commit.author = c[3] |
76 | commit.email = c[4] |
77 | commit.subject = c[5] |
78 | commit.body = string.trim(c[6]) |
79 | local diffs |
80 | if gpg then |
81 | commit.gpggood = c[7] |
82 | commit.gpgkey = c[8] |
83 | commit.gpgfull = string.trim(c[9]) |
84 | diffs = string.trim(c[10]) |
85 | else |
86 | diffs = string.trim(c[7]) |
87 | end |
88 | commit.diff = {} |
89 | local b = string.split(diffs, "\n") |
90 | commit.diff.plus = 0 |
91 | commit.diff.minus = 0 |
92 | commit.diff.num = 0 |
93 | commit.diff.files = {} |
94 | for i,v in pairs(b) do |
95 | local d = string.split(v,"\t") |
96 | local x = {} |
97 | x.plus = tonumber(d[1]) or 0 |
98 | commit.diff.plus = commit.diff.plus + x.plus |
99 | x.minus = tonumber(d[2]) or 0 |
100 | commit.diff.minus = commit.diff.minus + x.minus |
101 | commit.diff.files[d[3]] = x |
102 | commit.diff.num = commit.diff.num + 1 |
103 | end |
104 | table.insert(commits, commit) |
105 | else |
106 | f = true |
107 | end |
108 | end |
109 | return commits |
110 | end |
111 |
|
112 | _M.commit = function(repo_dir, hash) |
113 | local commit = _M.log(repo_dir, hash, "", 1, 0, true)[1] |
114 | commit.count = _M.count(repo_dir, hash) |
115 | return commit |
116 | end |
117 |
|
118 | local heads = function(repo_dir) |
119 | local output = git(repo_dir, "show-ref --heads") |
120 | local a = string.split(output, "\n") |
121 | table.remove(a,#a) |
122 | local heads = {} |
123 | for i,v in pairs(a) do |
124 | local b = string.split(v, " ") |
125 | local head = {} |
126 | head.hash = b[1] |
127 | head.shorthash = string.sub(b[1], 1, 7) |
128 | head.full = b[2] |
129 | head.name = string.split(b[2], "/")[3] |
130 | table.insert(heads, head) |
131 | end |
132 | return heads |
133 | end |
134 |
|
135 | local tags = function(repo_dir) |
136 | local output = git(repo_dir, "show-ref --tags") |
137 | local a = string.split(output, "\n") |
138 | table.remove(a,#a) |
139 | local tags = {} |
140 | for i,v in pairs(a) do |
141 | local b = string.split(v, " ") |
142 | local tag = {} |
143 | tag.hash = b[1] |
144 | tag.shorthash = string.sub(b[1], 1, 7) |
145 | tag.full = b[2] |
146 | tag.name = string.split(b[2], "/")[3] |
147 | table.insert(tags, tag) |
148 | end |
149 | return tags |
150 | end |
151 |
|
152 | _M.list_refs = function(repo_dir) |
153 | local refs = {} |
154 | refs.heads = heads(repo_dir) |
155 | refs.tags = tags(repo_dir) |
156 | return refs |
157 | end |
158 |
|
159 | local list_dirs = function(repo_dir, hash, path) |
160 | hash = hash or "@" |
161 | path = path or "" |
162 | local output = git(repo_dir, "ls-tree -d --name-only "..hash.." -- "..path) |
163 | local dirs = string.split(output, "\n") |
164 | table.remove(dirs, #dirs) -- remove trailing \n |
165 | return dirs |
166 | end |
167 |
|
168 | local list_all = function(repo_dir, hash, path) |
169 | hash = hash or "@" |
170 | path = path or "" |
171 | local output = git(repo_dir, "ls-tree --name-only "..hash.." -- "..path) |
172 | local all = string.split(output, "\n") |
173 | table.remove(all, #all) -- remove trailing \n |
174 | return all |
175 | end |
176 |
|
177 | _M.list_tree = function(repo_dir, hash, path) |
178 | hash = hash or "@" |
179 | path = path or "" |
180 | local files = list_all(repo_dir, hash, path) |
181 | local dirs = list_dirs(repo_dir, hash, path) |
182 | local ret = {} |
183 | ret.dirs = {} |
184 | ret.files = {} |
185 | for i,v in pairs(files) do -- iterate over all objects, separate directories from files |
186 | local not_dir = true |
187 | for _,d in pairs(dirs) do -- check if object is directory |
188 | if v == d then |
189 | not_dir = false |
190 | break |
191 | end |
192 | end |
193 | if not_dir then |
194 | table.insert(ret.files, v) |
195 | else |
196 | table.insert(ret.dirs, v) |
197 | end |
198 | end |
199 | return ret |
200 | end |
201 |
|
202 | return _M |
203 |
|