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 Stockin1189146G

Blob @ resty-gitweb / app.lua

text/plain8352 bytesdownload raw
1-- resty-gitweb@app.lua
2-- Entry point for git HTTP site implementation
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")
12local parse_uri = require("utils/parse_uri")
13
14local parsed_uri = parse_uri()
15local view
16local content
17
18if parsed_uri.repo == nil then
19 content = require("pages/index")(yaml_config)
20else -- repo found
21 local repo
22 for _,r in pairs(yaml_config) do
23 if parsed_uri.repo == r.name then
24 repo = r
25 break
26 end
27 end
28 if repo then
29 local repo_dir = repo.location.dev
30 view = parsed_uri.parts[2] or "tree"
31 local branch
32
33 if pcall(function() -- if branch is real
34 branch = git.get_head(repo_dir, parsed_uri.parts[3]) -- if parts[3] is nil, defaults to "HEAD"
35 end) then
36 local res, status = pcall(function() -- effectively catch any errors, 404 if any
37 if view == "tree" then -- directory display (with automatic README rendering)
38 local path = parsed_uri.parts
39 table.remove(path, 3) -- branch
40 table.remove(path, 2) -- "tree"
41 table.remove(path, 1) -- repo
42 if #path > 0 then
43 path = table.concat(path, "/").."/"
44 else
45 path = ""
46 end
47
48 content = require("pages/tree")(repo, repo_dir, branch, path)
49 elseif view == "blob" then
50 local path = parsed_uri.parts
51 table.remove(path, 3) -- branch
52 table.remove(path, 2) -- "tree"
53 table.remove(path, 1) -- repo
54 if #path > 0 then
55 path = table.concat(path, "/")
56 else
57 path = ""
58 end
59
60 content = require("pages/blob")(repo, repo_dir, branch, path)
61 elseif view == "raw" then
62 local path = parsed_uri.parts
63 table.remove(path, 3) -- branch
64 table.remove(path, 2) -- "tree"
65 table.remove(path, 1) -- repo
66 if #path > 0 then
67 path = table.concat(path, "/")
68 else
69 path = ""
70 end
71
72 content, is_binary = require("pages/raw")(repo, repo_dir, branch, path)
73 if content then
74 if is_binary then
75 mimetype = puremagic.via_content(content.body, path)
76 content.type = mimetype
77 else
78 content.type = "text/plain"
79 end
80 end
81
82 elseif view == "log" then
83 content = require("pages/log")(repo, repo_dir, branch, ngx.var.arg_n, ngx.var.arg_skip)
84 elseif view == "refs" then
85 content = require("pages/refs")(repo, repo_dir, branch)
86 elseif view == "download" then
87 content = require("pages/download")(repo, repo_dir, branch)
88 elseif view == "commit" then
89 -- /repo/commit/[COMMIT HASH]
90 end
91 end) -- pcall
92
93 if res ~= true then
94 ngx.say(res)
95 ngx.say(status)
96 ngx.exit(ngx.HTTP_NOT_FOUND)
97 return
98 end
99 end
100 end
101end
102
103if content ~= nil then -- TODO: HTML templates from files, static serving
104 if view ~= "raw" then
105 ngx.header.content_type = "text/html"
106 ngx.say([[<style>
107 @import url('https://fonts.googleapis.com/css?family=Fira+Sans:400,400i,700,700i&display=swap');
108 *{
109 box-sizing:border-box;
110 }
111 body{
112 color: #212121;
113 font-family:'Fira Sans', sans-serif;
114 padding-bottom:200px;
115 line-height:1.4;
116 max-width:1000px;
117 margin:20px auto;
118 }
119 body>h2{
120 margin-top:5px;
121 margin-bottom:0;
122 }
123 h3{
124 margin-bottom:4px;
125 }
126 td,th{
127 padding:2px 5px;
128 border:1px solid #858585;
129 text-align:left;
130 vertical-align:top;
131 }
132 th{
133 border:1px solid #000;
134 }
135 table.files,table.log,table.blob{
136 width:100%;
137 max-width:100%;
138 }
139 table{
140 border-collapse:collapse;
141 overflow:auto;
142 font-family: monospace;
143 font-size:14px;
144 }
145 table.files td:first-child{
146 padding-right:calc(5px + 1em);
147 }
148 table.files td:not(:nth-child(2)), table.log td:not(:nth-child(4)){
149 width:1%;
150 white-space:nowrap;
151 }
152 span.q{
153 text-decoration:underline;
154 text-decoration-style:dotted;
155 }
156 .q:hover{
157 cursor:help;
158 }
159 th, tr:hover{ /*darker color for table head, hovered-over rows*/
160 background-color:#dedede;
161 }
162 div.markdown{
163 width:100%;
164 padding:20px 50px;
165 border:1px solid #858585;
166 border-radius:6px;
167 }
168 img{
169 max-width:100%;
170 }
171 pre{
172 background-color:#eee;
173 padding:15px;
174 overflow-x:auto;
175 border-radius:8px;
176 }
177 :not(pre)>code{
178 background-color:#eee;
179 padding:2.5px;
180 border-radius:4px;
181 }
182
183 div.blob {
184 border:1px solid #858585;
185 overflow-x: auto;
186 }
187 table.blob {
188 font-size:1em;
189 width:100%;
190 max-width:100%;
191 line-height:1;
192 }
193 table.blob tr:hover {
194 background-color: inherit;
195 }
196 table.blob td{
197 border:none;
198 padding:1px 5px;
199 }
200 table.blob.binary th {
201 max-width:100%;
202 }
203 table.blob.binary th span:not(:last-child){
204 margin-right:10px;
205 }
206 table.blob.binary tr, table.blob.binary td{
207 text-align:center;
208 padding: 0;
209 }
210 table.blob.binary td>img, table.blob.binary td>video{
211 max-width:100%;
212 max-height:600px;
213 }
214 table.blob.lines td:first-child{
215 text-align: right;
216 padding-left:20px;
217 user-select: none;
218 color:#858585;
219 max-width:1%;
220 white-space:nowrap;
221 }
222 table.blob.lines td:first-child:hover{
223 color: #454545;
224 }
225 table.blob.lines td:nth-child(2){
226 width:100%;
227 white-space:pre;
228 }
229
230 a{
231 text-decoration:none;
232 color: #0077aa;
233 display: inline-block;
234 }
235 a:hover{
236 text-decoration:underline;
237 }
238 .home-banner h1 {
239 margin-top:40px;
240 margin-bottom:0;
241 }
242 .home-banner p {
243 margin-top:8px;
244 margin-bottom:30px;
245 }
246 .repo-section .name {
247 margin-bottom:0;
248 }
249 .repo-section h3 {
250 margin-top:10px;
251 }
252 .repo-section .description {
253 margin-top:8px;
254 }
255 .repo-section .nav {
256 margin-top:10px;
257 }
258 hr {
259 margin: 20px 0;
260 }
261 </style>]])
262
263 if parsed_uri.repo then
264 local arrow_left_circle = [[<img style="width:1.2em;height:1.2em;vertical-align:middle;margin-right:0.2em" src="https://joshuas3.s3.amazonaws.com/svg/arrow-left.svg"/>]]
265 ngx.say("<a style=\"margin-left:-1.35em\" href=\"/\">"..arrow_left_circle.."<span style=\"vertical-align:middle\">Index</span></a>")
266 end
267 ngx.print(content:build())
268 else
269 ngx.header.content_type = content.type
270 ngx.print(content.body)
271 end
272 ngx.exit(ngx.HTTP_OK)
273 return
274else
275 ngx.exit(ngx.HTTP_NOT_FOUND) -- default behavior
276 return
277end
278