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 Stockin1299G

Blob @ resty-gitweb / pages / blob.lua

text/plain6313 bytesdownload raw
1-- resty-gitweb@pages/blob.lua
2-- File blob 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 puremagic = require("puremagic")
9
10local utils = require("utils/utils")
11local git = require("git/git")
12
13local builder = require("utils/builder")
14local tabulate = require("utils/tabulate")
15local nav = require("utils/nav")
16
17local _M = function(repo, repo_dir, branch, file_path)
18
19 -- Pre checks
20 if file_path ~= "" then -- make sure path exists
21 local path_tree = git.list_tree(repo_dir, branch.name, file_path)
22 if #path_tree.files == 0 then -- no path found
23 return nil
24 end
25 else
26 return nil
27 end
28
29 local build = builder:new()
30
31 -- Breadcrumb navigation and repository description
32 local breadcrumb_nav = {
33 {string.format("/%s", repo.name), repo.name},
34 {string.format("/%s/tree/%s", repo.name, branch.name), branch.name},
35 }
36 build:add("<h2>"..nav(breadcrumb_nav, " / ").."</h2>")
37 build:add("<p>"..repo.description.."</p>")
38
39 -- Navigation links
40 local navlinks = {
41 {string.format("/%s/download", repo.name), "Download"},
42 {string.format("/%s/refs", repo.name), "Refs"},
43 {string.format("/%s/log/%s", repo.name, branch.name), "Commit Log"},
44 {string.format("/%s/tree/%s", repo.name, branch.name), "<b>Files</b>"}
45 }
46
47 for _, special in pairs(repo.specialfiles) do -- create nav items for special files
48 local split = string.split(special, " ")
49 table.insert(navlinks, {
50 string.format("/%s/blob/%s/%s", repo.name, branch.name, split[2]),
51 split[1]
52 })
53 end
54
55 build:add([[<div class="nav">]])
56 build:add(nav(navlinks))
57 build:add("</div>")
58
59 -- Latest Commit table
60 build:add("<h3>Latest Commit</h3>")
61
62 local commit = git.log(repo_dir, branch.name, file_path, 1, 0, true)[1]
63
64 local commits_table_data = {}
65 commits_table_data.class = "log"
66 commits_table_data.headers = {
67 {"count", [[<span class="q" title="Commit number/count">{#}</span>]]},
68 {"timestamp", "Time"},
69 {"shorthash", "Hash"},
70 {"subject", "Subject"},
71 {"author", "Author"},
72 {"changed_files", [[<span class="q" title="# of files changed">#</span>]]},
73 {"changed_plus", [[<span class="q" title="Insertions">(+)</span>]]},
74 {"changed_minus", [[<span class="q" title="Deletions">(-)</span>]]},
75 {"gpggood", [[<span class="q" title="GPG signature status
76
77G: Good (valid) signature
78B: Bad signature
79U: Good signature with unknown validity
80X: Good signature that has expired
81Y: Good signature made by an expired key
82R: Good signature made by a revoked key
83E: Signature can't be checked (e.g. missing key)
84N: No signature">GPG?</span>]]}
85 }
86 commits_table_data.rows = {}
87
88 table.insert(commits_table_data.rows, {
89 git.count(repo_dir, commit.hash),
90 utils.iso8601(commit.timestamp),
91 string.format([[<a href="/%s/commit/%s">%s</a>]], repo.name, commit.hash, commit.shorthash),
92 utils.html_sanitize(commit.subject),
93 string.format([[<a href="mailto:%s">%s</a>]], commit.email, utils.html_sanitize(commit.author)),
94 commit.diff.num,
95 commit.diff.plus,
96 commit.diff.minus,
97 commit.gpggood
98 })
99
100 build:add(tabulate(commits_table_data))
101
102 -- Tree breadcrumb
103 build:add("<h3>Blob @ ")
104
105 local treelinks = {
106 {string.format("/%s/tree/%s", repo.name, branch.name), repo.name}
107 }
108
109 local base_path = treelinks[1][1] -- /repo/tree/branch
110
111 local path_string = ""
112 local path_split = string.split(file_path, "/")
113 local file_name = path_split[#path_split]
114 table.remove(path_split, #path_split)
115
116 for _, part in pairs(path_split) do
117 path_string = path_string.."/"..part
118 table.insert(treelinks, {base_path..path_string, part})
119 end
120 path_string = path_string.."/"..file_name
121 table.insert(treelinks, {
122 string.format("/%s/blob/%s"..path_string, repo.name, branch.name), file_name
123 })
124
125 build:add(nav(treelinks, " / "))
126 build:add("</h3>")
127
128 -- File
129 local success, repo_obj = git.repo.open(repo_dir)
130 local content, is_binary = git.read_blob(repo_obj, branch.name, file_path)
131 git.repo.free(repo_obj)
132
133 mimetype = puremagic.via_content(content, file_path)
134
135 build:add([[<div class="blob">]])
136
137 local text_table = {}
138 text_table.headers = {}
139 text_table.rows = {}
140 if not is_binary then
141 text_table.class = "blob lines"
142 for i, line in pairs(string.split(utils.highlight(content, file_name), "\n")) do
143 if line ~= "" then
144 local ftab = line:gsub("\t", " ")
145 table.insert(text_table.rows, {i, ftab})
146 else
147 table.insert(text_table.rows, {i, "\n"}) -- preserve newlines for copying/pasting
148 end
149 end
150 else
151 text_table.class = "blob binary"
152 table.insert(text_table.headers, {"blob", string.format([[<span>%s</span><span style="font-weight:normal">%d bytes</span><span style="float:inherit"><a href="/%s/raw/%s/%s">download raw</a></span>]], mimetype, string.len(content), repo.name, branch.name, file_path)})
153 if string.sub(mimetype, 1, 6) == "image/" then
154 table.insert(text_table.rows, {string.format([[<img src="/%s/raw/%s/%s">]], repo.name, branch.name, file_path)})
155 elseif string.sub(mimetype, 1, 6) == "video/" then
156 table.insert(text_table.rows, {string.format([[<video controls><source src="/%s/raw/%s/%s" type="%s"></audio>]], repo.name, branch.name, file_path, mimetype)})
157 elseif string.sub(mimetype, 1, 6) == "audio/" then
158 table.insert(text_table.rows, {string.format([[<audio controls><source src="/%s/raw/%s/%s" type="%s"></audio>]], repo.name, branch.name, file_path, mimetype)})
159 else
160 table.insert(text_table.rows, {string.format([[----- can't preview binary content -----]], repo.name, branch.name, file_path)})
161 end
162 end
163
164 build:add(tabulate(text_table))
165
166 build:add("</div>")
167
168 return build
169end
170
171return _M
172