handler.scm
1 | ;;;; Copyright (C) 2020 Julien Lepiller <julien@lepiller.eu> |
2 | ;;;; |
3 | ;;;; This library is free software; you can redistribute it and/or |
4 | ;;;; modify it under the terms of the GNU Lesser General Public |
5 | ;;;; License as published by the Free Software Foundation; either |
6 | ;;;; version 3 of the License, or (at your option) any later version. |
7 | ;;;; |
8 | ;;;; This library is distributed in the hope that it will be useful, |
9 | ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
11 | ;;;; Lesser General Public License for more details. |
12 | ;;;; |
13 | ;;;; You should have received a copy of the GNU Lesser General Public |
14 | ;;;; License along with this library; if not, write to the Free Software |
15 | ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
16 | ;;;; |
17 | |
18 | (define-module (gitile handler) |
19 | #:use-module (fibers web server) |
20 | #:use-module (git) |
21 | #:use-module (gitile config) |
22 | #:use-module (gitile pages) |
23 | #:use-module (ice-9 match) |
24 | #:use-module (rnrs bytevectors) |
25 | #:use-module (sxml simple) |
26 | #:use-module (web request) |
27 | #:use-module (web response) |
28 | #:use-module (web uri) |
29 | #:export (gitile-handler)) |
30 | |
31 | (define (request-path-components request) |
32 | (split-and-decode-uri-path (uri-path (request-uri request)))) |
33 | |
34 | (define (not-found request) |
35 | (format #t "Not found: ~a~%" (uri->string (request-uri request))) |
36 | (show (style `((p "Resource not found: " |
37 | ,(uri->string (request-uri request)))) |
38 | "" ""))) |
39 | |
40 | (define (style page project ref) |
41 | `(html |
42 | (head |
43 | (meta (@ (charset "UTF-8"))) |
44 | (meta (@ (name "viewport") (content "width=device-width, initial-scale=1"))) |
45 | (link (@ (rel "stylesheet") (href "/css/gitile.css"))) |
46 | (link (@ (rel "icon") (href "/images/icon.png") (sizes "32x32"))) |
47 | (script (@ (src "/js/gitile.js")) "") |
48 | (title ,project)) |
49 | (body |
50 | (header |
51 | (nav |
52 | (ul |
53 | (li (@ (class "first")) (a (@ (href "/")) "Projects")) |
54 | (li (a (@ (href "/" ,project)) "Repository")) |
55 | (li (a (@ (href "/" ,project "/tree/" ,ref)) "Files")) |
56 | (li (a (@ (href "/" ,project "/commits")) "Commits")) |
57 | (li (a (@ (href "/" ,project "/tags")) "Tags"))))) |
58 | (div (@ (id "content")) |
59 | ,@page) |
60 | (footer (p (a (@ (href "https://lepiller.eu")) "Who am I?")))))) |
61 | |
62 | (define* (show page #:key (code 200)) |
63 | (values (build-response #:code code #:headers '((content-type . (text/html)))) |
64 | (with-output-to-string (lambda _ (sxml->xml page))))) |
65 | |
66 | (define (show-raw page) |
67 | (values '((content-type . (text/plain))) |
68 | page)) |
69 | |
70 | (define (gitile-handler config) |
71 | (define (call-with-repo project-name callback) |
72 | (define (repo-404 content project-name ref) |
73 | (show (style content project-name ref) |
74 | #:code 404)) |
75 | (define (repo-500 content) |
76 | (show content #:code 500)) |
77 | (define (get-repo name) |
78 | (let ((repo (string-append (config-repositories config) |
79 | "/" name ".git"))) |
80 | (pk 'repo repo) |
81 | (pk 'exists (file-exists? (string-append repo "/git-daemon-export-ok"))) |
82 | (if (file-exists? (string-append repo "/git-daemon-export-ok")) |
83 | (repository-open repo) |
84 | #f))) |
85 | |
86 | (let ((repo (get-repo project-name))) |
87 | (if repo |
88 | (catch #t |
89 | (lambda _ |
90 | (callback repo)) |
91 | (lambda* (key . args) |
92 | (match key |
93 | ('not-found |
94 | (pk 'except key args) |
95 | (repo-404 (assoc-ref args 'content) |
96 | project-name |
97 | (or (assoc-ref args 'ref) "-"))) |
98 | (_ |
99 | (pk 'uncaught-exception key args) |
100 | (repo-500 `((p "Internal error"))))))) |
101 | (repo-404 `((p "Repository not found: " ,project-name)) project-name |
102 | "-")))) |
103 | (match config |
104 | (($ <config> port host database repositories) |
105 | (lambda (request body) |
106 | (pk 'request request) |
107 | (pk 'body (if body (utf8->string body) body)) |
108 | (match (request-path-components request) |
109 | ((project-name) |
110 | (call-with-repo project-name |
111 | (lambda (repo) |
112 | (show (style (project-index project-name repo) |
113 | project-name "-"))))) |
114 | ((project-name "tree" ref path ...) |
115 | (call-with-repo project-name |
116 | (lambda (repo) |
117 | (show (style (project-files project-name repo #:ref ref #:path path) |
118 | project-name ref))))) |
119 | ((project-name "raw" ref path ...) |
120 | (call-with-repo project-name |
121 | (lambda (repo) |
122 | (show-raw (project-file-raw repo path #:ref ref))))) |
123 | ((project-name "commits") |
124 | (call-with-repo project-name |
125 | (lambda (repo) |
126 | (show (style (project-commits project-name repo #f) |
127 | project-name "-"))))) |
128 | ((project-name "commits" ref) |
129 | (call-with-repo project-name |
130 | (lambda (repo) |
131 | (show (style (project-commits project-name repo ref) |
132 | project-name ref))))) |
133 | ((project-name "commit" ref) |
134 | (call-with-repo project-name |
135 | (lambda (repo) |
136 | (show (style (project-commit project-name repo ref) |
137 | project-name ref))))) |
138 | ((project-name "tags") |
139 | (call-with-repo project-name |
140 | (lambda (repo) |
141 | (show (style (project-tags project-name repo) |
142 | project-name "-"))))) |
143 | (_ (not-found request))))))) |
144 |