gnu: linux-libre: Update to 4.16.1.
[jackhill/guix/guix.git] / gnu / services / cgit.scm
CommitLineData
e1cf4fd2
OP
1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
3;;;
4;;; This file is part of GNU Guix.
5;;;
6;;; GNU Guix is free software; you can redistribute it and/or modify it
7;;; under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation; either version 3 of the License, or (at
9;;; your option) any later version.
10;;;
11;;; GNU Guix is distributed in the hope that it will be useful, but
12;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19(define-module (gnu services cgit)
20 #:use-module (gnu packages admin)
21 #:use-module (gnu packages version-control)
22 #:use-module (gnu services base)
23 #:use-module (gnu services configuration)
24 #:use-module (gnu services shepherd)
25 #:use-module (gnu services web)
26 #:use-module (gnu services)
27 #:use-module (gnu system shadow)
28 #:use-module (guix gexp)
29 #:use-module (guix packages)
30 #:use-module (guix records)
31 #:use-module (guix store)
32 #:use-module (ice-9 match)
33 #:use-module (srfi srfi-1)
34 #:use-module (srfi srfi-26)
35 #:export (repository-cgit-configuration
36 cgit-configuration
37 %cgit-configuration-nginx
38 cgit-configuration-nginx-config
39 opaque-cgit-configuration
40 cgit-service-type))
41
42;;; Commentary:
43;;;
44;;; This module provides a service definition for the Cgit a web frontend for
45;;; Git repositories written in C.
46;;;
47;;; Note: fields of <cgit-configuration> and <repository-cgit-configuration>
48;;; should be specified in the specific order.
49;;;
50;;; Code:
51
52(define %cgit-configuration-nginx
53 (nginx-server-configuration
54 (root cgit)
55 (locations
56 (list
57 (nginx-location-configuration
58 (uri "@cgit")
59 (body '("fastcgi_param SCRIPT_FILENAME $document_root/lib/cgit/cgit.cgi;"
60 "fastcgi_param PATH_INFO $uri;"
61 "fastcgi_param QUERY_STRING $args;"
62 "fastcgi_param HTTP_HOST $server_name;"
63 "fastcgi_pass 127.0.0.1:9000;")))))
64 (try-files (list "$uri" "@cgit"))
65 (listen '("80"))
66 (ssl-certificate #f)
67 (ssl-certificate-key #f)))
68
69\f
70;;;
71;;; Serialize <cgit-configuration>
72;;;
73
74(define (uglify-field-name field-name)
75 (let ((str (symbol->string field-name)))
76 (string-join (string-split (string-delete #\? str) #\-) "-")))
77
78(define (serialize-field field-name val)
79 (format #t "~a=~a\n" (uglify-field-name field-name) val))
80
81(define (serialize-string field-name val)
82 (if (string=? val "") "" (serialize-field field-name val)))
83
84(define (serialize-boolean field-name val)
85 (serialize-field field-name (if val 1 0)))
86
87(define (serialize-list field-name val)
88 (if (null? val) "" (serialize-field field-name (string-join val))))
89
90(define robots-list? list?)
91
92(define (serialize-robots-list field-name val)
93 (if (null? val) "" (serialize-field field-name (string-join val ", "))))
94
95(define (integer? val)
96 (exact-integer? val))
97
98(define (serialize-integer field-name val)
99 (serialize-field field-name val))
100
101(define (serialize-repository-cgit-configuration x)
102 (serialize-configuration x repository-cgit-configuration-fields))
103
104(define (repository-cgit-configuration-list? val)
105 (list? val))
106
107(define (serialize-repository-cgit-configuration-list field-name val)
108 (for-each serialize-repository-cgit-configuration val))
109
110\f
111;;;
112;;; Serialize <nginx-server-configuration>
113;;;
114
115(define (nginx-server-configuration-list? val)
116 (and (list? val) (and-map nginx-server-configuration? val)))
117
118(define (serialize-nginx-server-configuration-list field-name val)
119 #f)
120
121\f
122;;;
123;;; Serialize <repository-cgit-configuration>
124;;;
125
126(define (serialize-repo-field field-name val)
127 (format #t "repo.~a=~a\n" (uglify-field-name field-name) val))
128
129(define (serialize-repo-list field-name val)
130 (if (null? val) "" (serialize-repo-field field-name (string-join val))))
131
132(define repo-boolean? boolean?)
133
134(define (serialize-repo-boolean field-name val)
135 (serialize-repo-field field-name (if val 1 0)))
136
137(define (serialize-repo-integer field-name val)
138 (serialize-repo-field field-name val))
139
140(define repo-list? list?)
141
142(define repo-string? string?)
143
144(define (serialize-repo-string field-name val)
145 (if (string=? val "") "" (serialize-repo-field field-name val)))
146
147(define module-link-path? list?)
148
149(define (serialize-module-link-path field-name val)
150 (if (null? val) ""
151 (match val
152 ((path text)
153 (format #t "repo.~a.~a=~a\n"
154 (string-drop-right (uglify-field-name 'module-link-path)
155 (string-length "-path"))
156 path text)))))
157
158(define repository-directory? string?)
159
160(define (serialize-repository-directory _ val)
161 (if (string=? val "") "" (format #t "scan-path=~a\n" val)))
162
163(define mimetype-alist? list?)
164
165(define (serialize-mimetype-alist field-name val)
166 (format #t "# Mimetypes\n~a"
167 (string-join
168 (map (match-lambda
169 ((extension mimetype)
170 (format #f "mimetype.~a=~a"
171 (symbol->string extension) mimetype)))
172 val) "\n")))
173
174(define-configuration repository-cgit-configuration
175 (snapshots
176 (repo-list '())
177 "A mask of snapshot formats for this repo that cgit generates links for,
178restricted by the global @code{snapshots} setting.")
179 (source-filter
180 (repo-string "")
181 "Override the default @code{source-filter}.")
182 (url
183 (repo-string "")
184 "The relative URL used to access the repository.")
185 (about-filter
186 (repo-string "")
187 "Override the default @code{about-filter}.")
188 (branch-sort
189 (repo-string "")
190 "Flag which, when set to @samp{age}, enables date ordering in the branch
191ref list, and when set to @samp{name} enables ordering by branch name.")
192 (clone-url
193 (repo-list '())
194 "A list of URLs which can be used to clone repo.")
195 (commit-filter
196 (repo-string "")
197 "Override the default @code{commit-filter}.")
198 (commit-sort
199 (repo-string "")
200 "Flag which, when set to @samp{date}, enables strict date ordering in the
201commit log, and when set to @samp{topo} enables strict topological ordering.")
202 (defbranch
203 (repo-string "")
204 "The name of the default branch for this repository. If no such branch
205exists in the repository, the first branch name (when sorted) is used as
206default instead. By default branch pointed to by HEAD, or \"master\" if there
207is no suitable HEAD.")
208 (desc
209 (repo-string "")
210 "The value to show as repository description.")
211 (homepage
212 (repo-string "")
213 "The value to show as repository homepage.")
214 (email-filter
215 (repo-string "")
216 "Override the default @code{email-filter}.")
217 (enable-commit-graph?
218 (repo-boolean #f)
219 "A flag which can be used to disable the global setting
220@code{enable-commit-graph?}.")
221 (enable-log-filecount?
222 (repo-boolean #f)
223 "A flag which can be used to disable the global setting
224@code{enable-log-filecount?}.")
225 (enable-log-linecount?
226 (repo-boolean #f)
227 "A flag which can be used to disable the global setting
228@code{enable-log-linecount?}.")
229 (enable-remote-branches?
230 (repo-boolean #f)
231 "Flag which, when set to @code{#t}, will make cgit display remote
232branches in the summary and refs views.")
233 (enable-subject-links?
234 (repo-boolean #f)
235 "A flag which can be used to override the global setting
236@code{enable-subject-links?}.")
237 (enable-html-serving?
238 (repo-boolean #f)
239 "A flag which can be used to override the global setting
240@code{enable-html-serving?}.")
241 (hide?
242 (repo-boolean #f)
243 "Flag which, when set to @code{#t}, hides the repository from the
244repository index.")
245 (ignore?
246 (repo-boolean #f)
247 "Flag which, when set to @samp{#t}, ignores the repository.")
248 (logo
249 (repo-string "")
250 "URL which specifies the source of an image which will be used as a
251logo on this repo’s pages.")
252 (logo-link
253 (repo-string "")
254 "URL loaded when clicking on the cgit logo image.")
255 (owner-filter
256 (repo-string "")
257 "Override the default @code{owner-filter}.")
258 (module-link
259 (repo-string "")
260 "Text which will be used as the formatstring for a hyperlink when a
261submodule is printed in a directory listing. The arguments for the
262formatstring are the path and SHA1 of the submodule commit.")
263 (module-link-path
264 (module-link-path '())
265 "Text which will be used as the formatstring for a hyperlink when a
266submodule with the specified subdirectory path is printed in a directory
267listing.")
268 (max-stats
269 (repo-string "")
270 "Override the default maximum statistics period.")
271 (name
272 (repo-string "")
273 "The value to show as repository name.")
274 (owner
275 (repo-string "")
276 "A value used to identify the owner of the repository.")
277 (path
278 (repo-string "")
279 "An absolute path to the repository directory.")
280 (readme
281 (repo-string "")
282 "A path (relative to repo) which specifies a file to include verbatim
283as the \"About\" page for this repo.")
284 (section
285 (repo-string "")
286 "The name of the current repository section - all repositories defined
287after this option will inherit the current section name.")
288 (extra-options
289 (repo-list '())
290 "Extra options will be appended to cgitrc file."))
291
292;; Generate a <cgit-configuration> record, which may include a list of
293;; <repository-cgit-configuration>, <nginx-server-configuration>, <package>.
294(define-configuration cgit-configuration
295 (package
296 (package cgit)
297 "The CGIT package.")
298 (nginx
299 (nginx-server-configuration-list (list %cgit-configuration-nginx))
300 "NGINX configuration.")
301 (about-filter
302 (string "")
303 "Specifies a command which will be invoked to format the content of about
304pages (both top-level and for each repository).")
305 (agefile
306 (string "")
307 "Specifies a path, relative to each repository path, which can be used to
308specify the date and time of the youngest commit in the repository.")
309 (auth-filter
310 (string "")
311 "Specifies a command that will be invoked for authenticating repository
312access.")
313 (branch-sort
314 (string "name")
315 "Flag which, when set to @samp{age}, enables date ordering in the branch
316ref list, and when set @samp{name} enables ordering by branch name.")
317 (cache-root
318 (string "/var/cache/cgit")
319 "Path used to store the cgit cache entries.")
320 (cache-static-ttl
321 (integer -1)
322 "Number which specifies the time-to-live, in minutes, for the cached
323version of repository pages accessed with a fixed SHA1.")
324 (cache-dynamic-ttl
325 (integer 5)
326 "Number which specifies the time-to-live, in minutes, for the cached
327version of repository pages accessed without a fixed SHA1.")
328 (cache-repo-ttl
329 (integer 5)
330 "Number which specifies the time-to-live, in minutes, for the cached
331version of the repository summary page.")
332 (cache-root-ttl
333 (integer 5)
334 "Number which specifies the time-to-live, in minutes, for the cached
335version of the repository index page.")
336 (cache-scanrc-ttl
337 (integer 15)
338 "Number which specifies the time-to-live, in minutes, for the result of
339scanning a path for Git repositories.")
340 (cache-about-ttl
341 (integer 15)
342 "Number which specifies the time-to-live, in minutes, for the cached
343version of the repository about page.")
344 (cache-snapshot-ttl
345 (integer 5)
346 "Number which specifies the time-to-live, in minutes, for the cached
347version of snapshots.")
348 (cache-size
349 (integer 0)
350 "The maximum number of entries in the cgit cache. When set to
351@samp{0}, caching is disabled.")
352 (case-sensitive-sort?
353 (boolean #t)
354 "Sort items in the repo list case sensitively.")
355 (clone-prefix
356 (list '())
357 "List of common prefixes which, when combined with a repository URL,
358generates valid clone URLs for the repository.")
359 (clone-url
360 (list '())
361 "List of @code{clone-url} templates.")
362 (commit-filter
363 (string "")
364 "Command which will be invoked to format commit messages.")
365 (commit-sort
366 (string "git log")
367 "Flag which, when set to @samp{date}, enables strict date ordering in the
368commit log, and when set to @samp{topo} enables strict topological
369ordering.")
370 (css
371 (string "/share/cgit/cgit.css")
372 "URL which specifies the css document to include in all cgit pages.")
373 (email-filter
374 (string "")
375 "Specifies a command which will be invoked to format names and email
376address of committers, authors, and taggers, as represented in various
377places throughout the cgit interface.")
378 (embedded?
379 (boolean #f)
380 "Flag which, when set to @samp{#t}, will make cgit generate a HTML
381fragment suitable for embedding in other HTML pages.")
382 (enable-commit-graph?
383 (boolean #f)
384 "Flag which, when set to @samp{#t}, will make cgit print an ASCII-art
385commit history graph to the left of the commit messages in the
386repository log page.")
387 (enable-filter-overrides?
388 (boolean #f)
389 "Flag which, when set to @samp{#t}, allows all filter settings to be
390overridden in repository-specific cgitrc files.")
391 (enable-follow-links?
392 (boolean #f)
393 "Flag which, when set to @samp{#t}, allows users to follow a file in the
394log view.")
395 (enable-http-clone?
396 (boolean #t)
397 "If set to @samp{#t}, cgit will act as an dumb HTTP endpoint for Git
398clones.")
399 (enable-index-links?
400 (boolean #f)
401 "Flag which, when set to @samp{#t}, will make cgit generate extra links
402\"summary\", \"commit\", \"tree\" for each repo in the repository index.")
403 (enable-index-owner?
404 (boolean #t)
405 "Flag which, when set to @samp{#t}, will make cgit display the owner of
406each repo in the repository index.")
407 (enable-log-filecount?
408 (boolean #f)
409 "Flag which, when set to @samp{#t}, will make cgit print the number of
410modified files for each commit on the repository log page.")
411 (enable-log-linecount?
412 (boolean #f)
413 "Flag which, when set to @samp{#t}, will make cgit print the number of
414added and removed lines for each commit on the repository log page.")
415 (enable-remote-branches?
416 (boolean #f)
417 "Flag which, when set to @code{#t}, will make cgit display remote
418branches in the summary and refs views.")
419 (enable-subject-links?
420 (boolean #f)
421 "Flag which, when set to @code{1}, will make cgit use the subject of
422the parent commit as link text when generating links to parent commits
423in commit view.")
424 (enable-html-serving?
425 (boolean #f)
426 "Flag which, when set to @samp{#t}, will make cgit use the subject of the
427parent commit as link text when generating links to parent commits in
428commit view.")
429 (enable-tree-linenumbers?
430 (boolean #t)
431 "Flag which, when set to @samp{#t}, will make cgit generate linenumber
432links for plaintext blobs printed in the tree view.")
433 (enable-git-config?
434 (boolean #f)
435 "Flag which, when set to @samp{#f}, will allow cgit to use Git config to
436set any repo specific settings.")
437 (favicon
438 (string "/favicon.ico")
439 "URL used as link to a shortcut icon for cgit.")
440 (footer
441 (string "")
442 "The content of the file specified with this option will be included
443verbatim at the bottom of all pages (i.e. it replaces the standard
444\"generated by...\" message).")
445 (head-include
446 (string "")
447 "The content of the file specified with this option will be included
448verbatim in the HTML HEAD section on all pages.")
449 (header
450 (string "")
451 "The content of the file specified with this option will be included
452verbatim at the top of all pages.")
453 (include
454 (string "")
455 "Name of a configfile to include before the rest of the current config-
456file is parsed.")
457 (index-header
458 (string "")
459 "The content of the file specified with this option will be included
460verbatim above the repository index.")
461 (index-info
462 (string "")
463 "The content of the file specified with this option will be included
464verbatim below the heading on the repository index page.")
465 (local-time?
466 (boolean #f)
467 "Flag which, if set to @samp{#t}, makes cgit print commit and tag times
468in the servers timezone.")
469 (logo
470 (string "/share/cgit/cgit.png")
471 "URL which specifies the source of an image which will be used as a logo
472on all cgit pages.")
473 (logo-link
474 (string "")
475 "URL loaded when clicking on the cgit logo image.")
476 (owner-filter
477 (string "")
478 "Command which will be invoked to format the Owner column of the main
479page.")
480 (max-atom-items
481 (integer 10)
482 "Number of items to display in atom feeds view.")
483 (max-commit-count
484 (integer 50)
485 "Number of entries to list per page in \"log\" view.")
486 (max-message-length
487 (integer 80)
488 "Number of commit message characters to display in \"log\" view.")
489 (max-repo-count
490 (integer 50)
491 "Specifies the number of entries to list per page on the repository index
492page.")
493 (max-repodesc-length
494 (integer 80)
495 "Specifies the maximum number of repo description characters to display
496on the repository index page.")
497 (max-blob-size
498 (integer 0)
499 "Specifies the maximum size of a blob to display HTML for in KBytes.")
500 (max-stats
501 (string "")
502 "Maximum statistics period. Valid values are @samp{week},@samp{month},
503@samp{quarter} and @samp{year}.")
504 (mimetype
505 (mimetype-alist '((gif "image/gif")
506 (html "text/html")
507 (jpg "image/jpeg")
508 (jpeg "image/jpeg")
509 (pdf "application/pdf")
510 (png "image/png")
511 (svg "image/svg+xml")))
512 "Mimetype for the specified filename extension.")
513 (mimetype-file
514 (string "")
515 "Specifies the file to use for automatic mimetype lookup.")
516 (module-link
517 (string "")
518 "Text which will be used as the formatstring for a hyperlink when a
519submodule is printed in a directory listing.")
520 (nocache?
521 (boolean #f)
522 "If set to the value @samp{#t} caching will be disabled.")
523 (noplainemail?
524 (boolean #f)
525 "If set to @samp{#t} showing full author email addresses will be
526disabled.")
527 (noheader?
528 (boolean #f)
529 "Flag which, when set to @samp{#t}, will make cgit omit the standard
530header on all pages.")
531 ;; TODO: cgit expects a file name
532 ;; that should be created from a list of strings provided by the user.
533 ;;
534 ;; (project-list
535 ;; (string "")
536 ;; "A list of subdirectories inside of @code{repository-directory},
537 ;; relative to it, that should loaded as Git repositories.")
538 (readme
539 (string "")
540 "Text which will be used as default value for @code{cgit-repo-readme}.")
541 (remove-suffix?
542 (boolean #f)
543 "If set to @code{#t} and @code{repository-directory} is enabled, if any
544repositories are found with a suffix of @code{.git}, this suffix will be
545removed for the URL and name.")
546 (renamelimit
547 (integer -1)
548 "Maximum number of files to consider when detecting renames.")
549 (repository-sort
550 (string "")
551 "The way in which repositories in each section are sorted.")
552 (robots
553 (robots-list (list "noindex" "nofollow"))
554 "Text used as content for the @code{robots} meta-tag.")
555 (root-desc
556 (string "a fast webinterface for the git dscm")
557 "Text printed below the heading on the repository index page.")
558 (root-readme
559 (string "")
560 "The content of the file specified with this option will be included
561verbatim below thef \"about\" link on the repository index page.")
562 (root-title
563 (string "")
564 "Text printed as heading on the repository index page.")
565 (scan-hidden-path
566 (boolean #f)
567 "If set to @samp{#t} and repository-directory is enabled,
568repository-directory will recurse into directories whose name starts with a
569period. Otherwise, repository-directory will stay away from such directories,
570considered as \"hidden\". Note that this does not apply to the \".git\"
571directory in non-bare repos.")
572 (snapshots
573 (list '())
574 "Text which specifies the default set of snapshot formats that cgit
575generates links for.")
576 (repository-directory
577 (repository-directory "/srv/git")
578 "Name of the directory to scan for repositories (represents
579@code{scan-path}).")
580 (section
581 (string "")
582 "The name of the current repository section - all repositories defined
583after this option will inherit the current section name.")
584 (section-sort
585 (string "")
586 "Flag which, when set to @samp{1}, will sort the sections on the repository
587listing by name.")
588 (section-from-path
589 (integer 0)
590 "A number which, if defined prior to repository-directory, specifies how
591many path elements from each repo path to use as a default section name.")
592 (side-by-side-diffs?
593 (boolean #f)
594 "If set to @samp{#t} shows side-by-side diffs instead of unidiffs per
595default.")
596 (source-filter
597 (string "")
598 "Specifies a command which will be invoked to format plaintext blobs in the
599tree view.")
600 (summary-branches
601 (integer 10)
602 "Specifies the number of branches to display in the repository \"summary\"
603view.")
604 (summary-log
605 (integer 10)
606 "Specifies the number of log entries to display in the repository
607\"summary\" view.")
608 (summary-tags
609 (integer 10)
610 "Specifies the number of tags to display in the repository \"summary\"
611view.")
612 (strict-export
613 (string "")
614 "Filename which, if specified, needs to be present within the repository
615for cgit to allow access to that repository.")
616 (virtual-root
617 (string "/")
618 "URL which, if specified, will be used as root for all cgit links.")
619 (repositories
620 (repository-cgit-configuration-list '())
621 "A list of @dfn{cgit-repo} records to use with config.")
622 (extra-options
623 (list '())
624 "Extra options will be appended to cgitrc file."))
625
626(define-configuration opaque-cgit-configuration
627 (cgit
628 (package cgit)
629 "The cgit package.")
630 (cgitrc
631 (string (configuration-missing-field 'opaque-cgit-configuration 'cgitrc))
632 "The contents of the @code{cgitrc} to use.")
633 (cache-root
634 (string "/var/cache/cgit")
635 "Path used to store the cgit cache entries.")
636 (nginx
637 (nginx-server-configuration-list (list %cgit-configuration-nginx))
638 "NGINX configuration."))
639
640(define (cgit-activation config)
641 "Return the activation gexp for CONFIG."
642 (let* ((opaque-config? (opaque-cgit-configuration? config))
643 (config-str
644 (if opaque-config?
645 (opaque-cgit-configuration-cgitrc config)
646 (with-output-to-string
647 (lambda ()
648 (serialize-configuration config
649 cgit-configuration-fields))))))
650 #~(begin
651 (use-modules (guix build utils))
652 (mkdir-p #$(if opaque-config?
653 (opaque-cgit-configuration-cache-root config)
654 (cgit-configuration-cache-root config)))
655 (copy-file #$(plain-file "cgitrc" config-str) "/etc/cgitrc"))))
656
657(define (cgit-configuration-nginx-config config)
658 (if (opaque-cgit-configuration? config)
659 (opaque-cgit-configuration-nginx config)
660 (cgit-configuration-nginx config)))
661
662(define cgit-service-type
663 (service-type
664 (name 'cgit)
665 (extensions
666 (list (service-extension activation-service-type
667 cgit-activation)
668 (service-extension nginx-service-type
669 cgit-configuration-nginx-config)
670
671 ;; Make sure fcgiwrap is instantiated.
672 (service-extension fcgiwrap-service-type
673 (const #t))))
674 (default-value (cgit-configuration))
675 (description
676 "Run the cgit web interface, which allows users to browse Git
677repositories.")))
678
679(define (generate-cgit-documentation)
680 (generate-documentation
681 `((cgit-configuration
682 ,cgit-configuration-fields
683 (repositories repository-cgit-configuration))
684 (repository-cgit-configuration
685 ,repository-cgit-configuration-fields))
686 'cgit-configuration))