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 Stockin152G

Blob @ resty-gitweb / pages / tree.lua

text/plain7699 bytesdownload raw
1-- resty-gitweb@pages/tree.lua
2-- Tree page builder
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 utils = require("utils/utils")
9local git = require("git/git")
10
11local builder = require("utils/builder")
12local tabulate = require("utils/tabulate")
13local nav = require("utils/nav")
14
15local _M = function(repo, repo_dir, branch, path)
16
17 -- Pre checks
18 if path ~= "" then -- make sure path exists
19 local path_tree = git.list_tree(repo_dir, branch.name, string.sub(path, 1, path:len() - 1))
20 if #path_tree.dirs == 0 then -- no path found
21 return nil
22 end
23 end
24
25 if branch.name == "" then
26 branch.name = branch.hash
27 end
28
29
30 local build = builder:new()
31
32 -- Breadcrumb navigation and repository description
33 local breadcrumb_nav = {
34 {string.format("/%s", repo.name), repo.name},
35 {string.format("/%s/tree/%s", repo.name, branch.name), branch.name},
36 }
37 build:add("<h2>"..nav(breadcrumb_nav, " / ").."</h2>")
38 build:add("<p>"..repo.description.."</p>")
39
40 -- Navigation links
41 local navlinks = {
42 {string.format("/%s/download", repo.name), "Download"},
43 {string.format("/%s/refs", repo.name), "Refs"},
44 {string.format("/%s/log/%s", repo.name, branch.name), "Commit Log"},
45 {string.format("/%s/tree/%s", repo.name, branch.name), "<b>Files</b>"}
46 }
47
48 for _, special in pairs(repo.specialfiles) do -- create nav items for special files
49 local split = string.split(special, " ")
50 table.insert(navlinks, {
51 string.format("/%s/blob/%s/%s", repo.name, branch.name, split[2]),
52 split[1]
53 })
54 end
55
56 build:add([[<div class="nav">]])
57 build:add(nav(navlinks))
58 build:add("</div>")
59
60 -- Latest Commit table
61 build:add("<h3>Latest Commit</h3>")
62
63 local commit = git.log(repo_dir, branch.name, path.."/", 1, 0, true)[1]
64
65 local commits_table_data = {}
66 commits_table_data.class = "log"
67 commits_table_data.headers = {
68 {"count", [[<span class="q" title="Commit number/count">{#}</span>]]},
69 {"timestamp", "Time"},
70 {"shorthash", "Hash"},
71 {"subject", "Subject"},
72 {"author", "Author"},
73 {"changed_files", [[<span class="q" title="# of files changed">#</span>]]},
74 {"changed_plus", [[<span class="q" title="Insertions">(+)</span>]]},
75 {"changed_minus", [[<span class="q" title="Deletions">(-)</span>]]},
76 {"gpggood", [[<span class="q" title="GPG signature status
77
78G: Good (valid) signature
79B: Bad signature
80U: Good signature with unknown validity
81X: Good signature that has expired
82Y: Good signature made by an expired key
83R: Good signature made by a revoked key
84E: Signature can't be checked (e.g. missing key)
85N: No signature">GPG?</span>]]}
86 }
87 commits_table_data.rows = {}
88
89 table.insert(commits_table_data.rows, {
90 git.count(repo_dir, commit.hash),
91 utils.iso8601(commit.timestamp),
92 string.format([[<a href="/%s/commit/%s">%s</a>]], repo.name, commit.hash, commit.shorthash),
93 utils.html_sanitize(commit.subject),
94 string.format([[<a href="mailto:%s">%s</a>]], commit.email, utils.html_sanitize(commit.author)),
95 commit.diff.num,
96 commit.diff.plus,
97 commit.diff.minus,
98 commit.gpggood
99 })
100
101 build:add(tabulate(commits_table_data))
102
103 -- Tree/files table
104 local title = builder:new()
105
106 if path == "" then
107 title:add("<h3>Tree</h3>")
108 else -- build path with hyperlinks for section header
109 title:add("<h3>Tree")
110 local split = string.split(path, "/")
111 table.remove(split, #split)
112 local base = "/"..repo.name.."/tree/"..branch.name
113 title:add(string.format([[ @ <a href="%s">%s</a>]], base, repo.name))
114 local build = ""
115 for _, part in pairs(split) do
116 build = build.."/"..part
117 title:add(string.format([[ / <a href="%s%s">%s</a>]], base, build, part))
118 end
119 title:add("</h3>")
120 end
121
122 build:add(title.body)
123
124 local files = git.list_tree(repo_dir, branch.name, path)
125
126 local files_table_data = {}
127 files_table_data.class = "files"
128 files_table_data.headers = {
129 {"object", "Object"},
130 {"subject", "Latest Commit Subject"},
131 {"timestamp", "Time"},
132 {"shorthash", "Hash"}}
133 files_table_data.rows = {}
134
135 local file_icon = [[<img style="width:1em;height:1em;vertical-align:middle;margin-right:0.5em;" src="https://joshuas3.s3.amazonaws.com/svg/file.svg"/>]]
136 local folder_icon = [[<img style="width:1em;height:1em;vertical-align:middle;margin-right:0.5em;fill:#ffe9a2;" src="https://joshuas3.s3.amazonaws.com/svg/folder.svg"/>]]
137
138 -- .. directory
139 if path ~= "" then
140 local split = string.split(string.sub(path, 1, path:len() - 1), "/")
141 table.remove(split, #split)
142 if #split > 0 then -- deeper than 1 directory
143 table.insert(files_table_data.rows, {
144 string.format([[%s<a href="/%s/tree/%s/%s">..</a>]], folder_icon, repo.name, branch.name, table.concat(split, "/")),
145 "","",""
146 })
147 else -- only one directory deep
148 table.insert(files_table_data.rows, {
149 string.format([[%s<a href="/%s/tree/%s">..</a>]], folder_icon, repo.name, branch.name),
150 "","",""
151 })
152 end
153 end
154
155 -- Regular directories
156 for _, dir in pairs(files.dirs) do
157 local lastedit = git.log(repo_dir, branch.name.." -1", dir, 1, 0, false)[1]
158 local split = string.split(dir, "/")
159 local name = split[#split]
160 table.insert(files_table_data.rows, {
161 string.format([[%s<a href="/%s/tree/%s/%s">%s</a>]], folder_icon, repo.name, branch.name, dir, name),
162 utils.html_sanitize(lastedit.subject),
163 utils.iso8601(lastedit.timestamp),
164 string.format([[<a href="/%s/commit/%s">%s</a>]], repo.name, lastedit.hash, lastedit.shorthash)
165 })
166 end
167
168 -- Regular files
169 for _, file in pairs(files.files) do
170 local lastedit = git.log(repo_dir, branch.name.." -1", file, 1, 0, false)[1]
171 local split = string.split(file, "/")
172 local name = split[#split]
173 table.insert(files_table_data.rows, {
174 string.format([[%s<a href="/%s/blob/%s/%s">%s</a>]], file_icon, repo.name, branch.name, file, name),
175 utils.html_sanitize(lastedit.subject),
176 utils.iso8601(lastedit.timestamp),
177 string.format([[<a href="/%s/commit/%s">%s</a>]], repo.name, lastedit.hash, lastedit.shorthash)
178 })
179 end
180
181 build:add(tabulate(files_table_data))
182
183 -- Look for and render README if it exists
184 for _, file in pairs(files.files) do
185 local split = string.split(file, "/")
186 local l = split[#split]:lower()
187 if l:match("^readme") then
188 build:add("<h3>README</h3>")
189 local success, repo = git.repo.open(repo_dir)
190 if not success then break end
191 local text = git.read_blob(repo, branch.name, file)
192 git.repo.free(repo)
193 local s = l:len()
194 local body = builder:new()
195 if string.sub(l, s-2, s) == ".md" then
196 body:add([[<div class="markdown">]]..utils.markdown(text).."</div>")
197 else
198 body:add("<pre><code>"..text.."</code></pre>")
199 end
200 build:add(body.body)
201 break
202 end
203 end
204
205 return build
206end
207
208return _M
209