1 | -- app.lua |
2 | -- Entry point for git HTTP site implementation |
3 |
|
4 | -- Copyright (c) 2020 Joshua 'joshuas3' Stockin |
5 | -- <https://joshstock.in> |
6 |
|
7 | local utils = require("utils/utils") |
8 | local git = require("git/git_commands") |
9 | local parse_uri = require("utils/parse_uri") |
10 |
|
11 | local parsed_uri = parse_uri() |
12 | local content |
13 |
|
14 | if parsed_uri.repo == nil then |
15 | content = require("pages/index")(yaml_config) |
16 | else -- repo found |
17 | local repo |
18 | for _,r in pairs(yaml_config) do |
19 | if parsed_uri.repo == r.name then |
20 | repo = r |
21 | break |
22 | end |
23 | end |
24 | if repo then |
25 | local repo_dir = repo.location.dev |
26 | local view = parsed_uri.parts[2] or "tree" |
27 | local branch |
28 |
|
29 | if pcall(function() -- if branch is real |
30 | branch = git.get_head(repo_dir, parsed_uri.parts[3]) -- if parts[3] is nil, defaults to "HEAD" |
31 | end) then |
32 | if pcall(function() -- effectively catch any errors, 404 if any |
33 | if view == "tree" then -- directory display (with automatic README rendering) |
34 | local path = parsed_uri.parts |
35 | table.remove(path, 3) -- branch |
36 | table.remove(path, 2) -- "tree" |
37 | table.remove(path, 1) -- repo |
38 | if #path > 0 then |
39 | path = table.concat(path, "/").."/" |
40 | else |
41 | path = "" |
42 | end |
43 |
|
44 | content = require("pages/tree")(repo, repo_dir, branch, path) |
45 | elseif view == "blob" then |
46 | -- /repo/blob/branch/[FILE PATH] |
47 | elseif view == "raw" then |
48 | -- /repo/raw/branch/[FILE PATH] |
49 | elseif view == "log" then |
50 | content = require("pages/log")(repo, repo_dir, branch, ngx.var.arg_n, ngx.var.arg_skip) |
51 | elseif view == "refs" then |
52 | content = require("pages/refs")(repo, repo_dir, branch) |
53 | elseif view == "download" then |
54 | content = require("pages/download")(repo, repo_dir, branch) |
55 | elseif view == "commit" then |
56 | -- /repo/commit/[COMMIT HASH] |
57 | end |
58 | end) ~= true then |
59 | ngx.exit(ngx.HTTP_NOT_FOUND) |
60 | return |
61 | end |
62 | end |
63 | end |
64 | end |
65 |
|
66 | if content ~= nil then -- TODO: HTML templates from files, static serving |
67 | ngx.say([[<style> |
68 | @import url('https://fonts.googleapis.com/css?family=Fira+Sans:400,400i,700,700i&display=swap'); |
69 | *{ |
70 | box-sizing:border-box; |
71 | } |
72 | body{ |
73 | font-family:'Fira Sans', sans-serif; |
74 | padding-bottom:200px; |
75 | line-height:1.4; |
76 | max-width:1000px; |
77 | margin:20px auto; |
78 | } |
79 | body>h2{ |
80 | margin-top:5px; |
81 | margin-bottom:0; |
82 | } |
83 | h3{ |
84 | margin-bottom:4px; |
85 | } |
86 | td,th{ |
87 | padding:2px 5px; |
88 | border:1px solid #858585; |
89 | text-align:left; |
90 | vertical-align:top; |
91 | } |
92 | th{ |
93 | border:1px solid #000; |
94 | } |
95 | table.files,table.log{ |
96 | width:100%; |
97 | max-width:100%; |
98 | } |
99 | table{ |
100 | border-collapse:collapse; |
101 | overflow:auto; |
102 | font-family: monospace; |
103 | font-size:14px; |
104 | } |
105 | table.tree td:not(:nth-child(2)), table.log td:not(:nth-child(4)){ |
106 | max-width:1%; |
107 | white-space:nowrap; |
108 | } |
109 | span.q{ |
110 | text-decoration:underline; |
111 | text-decoration-style:dotted; |
112 | } |
113 | .q:hover{ |
114 | cursor:help; |
115 | } |
116 | tr:hover,th{ /*darker color for table head, hovered-over rows*/ |
117 | background-color:#dedede; |
118 | } |
119 | div.markdown{ |
120 | width:100%; |
121 | padding:20px 50px; |
122 | border:1px solid #858585; |
123 | border-radius:6px; |
124 | } |
125 | img{ |
126 | max-width:100%; |
127 | } |
128 | pre{ |
129 | background-color:#eee; |
130 | padding:15px; |
131 | overflow-x:auto; |
132 | border-radius:8px; |
133 | } |
134 | :not(pre)>code{ |
135 | background-color:#eee; |
136 | padding:2.5px; |
137 | border-radius:4px; |
138 | } |
139 | a{ |
140 | text-decoration:none; |
141 | color: #0077aa; |
142 | } |
143 | a:hover{ |
144 | text-decoration:underline; |
145 | } |
146 | .home-banner h1 { |
147 | margin-top:50px; |
148 | margin-bottom:0; |
149 | } |
150 | .home-banner p { |
151 | margin-top:8px; |
152 | margin-bottom:35px; |
153 | } |
154 | .repo-section .name { |
155 | margin-bottom:0; |
156 | } |
157 | .repo-section h3 { |
158 | margin-top:10px; |
159 | } |
160 | .repo-section .description { |
161 | margin-top:8px; |
162 | } |
163 | .repo-section .nav { |
164 | margin-top:10px; |
165 | } |
166 | hr { |
167 | margin: 25px 0; |
168 | } |
169 | </style>]]) |
170 |
|
171 | if parsed_uri.repo then |
172 | 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"/>]] |
173 | ngx.say("<a style=\"margin-left:-1.35em\" href=\"/\">"..arrow_left_circle.."<span style=\"vertical-align:middle\">Index</span></a>") |
174 | end |
175 | ngx.say(content:build()) |
176 | ngx.exit(ngx.HTTP_OK) |
177 | return |
178 | else |
179 | ngx.exit(ngx.HTTP_NOT_FOUND) -- default behavior |
180 | return |
181 | end |
182 |
|