diff options
| author | Nguyễn Gia Phong <mcsinyx@disroot.org> | 2025-11-17 15:46:53 +0900 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2026-03-11 18:27:46 +0100 |
| commit | 3433fb987bbc826a585a0d4d0a80e1f5369769a3 (patch) | |
| tree | 404bf5c6a53dd084bc4ab26506455077e9a8eef3 | |
| parent | 6eb6971f4d721fc8d648323f0dbd52d0697b2a7b (diff) | |
services: Add fossil-service-type.
* gnu/services/version-control.scm
(fossil-service-type, fossil-configuration): New public variables.
* gnu/tests/version-control.scm (%test-fossil): Add system tests.
* doc/guix.texi (Version Control Services): Add Fossil documentation.
Change-Id: I84e09fe8c11e161ed7c4bdba42b0ae38ef4c2096
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
| -rw-r--r-- | doc/guix.texi | 150 | ||||
| -rw-r--r-- | gnu/services/version-control.scm | 257 | ||||
| -rw-r--r-- | gnu/tests/version-control.scm | 75 |
3 files changed, 480 insertions, 2 deletions
diff --git a/doc/guix.texi b/doc/guix.texi index 9924f4771f2..8841a483a8d 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -149,6 +149,7 @@ Copyright @copyright{} 2025 Rodion Goritskov@* | |||
| 149 | Copyright @copyright{} 2025 dan@* | 149 | Copyright @copyright{} 2025 dan@* |
| 150 | Copyright @copyright{} 2025 Noé Lopez@* | 150 | Copyright @copyright{} 2025 Noé Lopez@* |
| 151 | Copyright @copyright{} 2026 David Elsing@* | 151 | Copyright @copyright{} 2026 David Elsing@* |
| 152 | Copyright @copyright{} 2026 Nguyễn Gia Phong@* | ||
| 152 | 153 | ||
| 153 | Permission is granted to copy, distribute and/or modify this document | 154 | Permission is granted to copy, distribute and/or modify this document |
| 154 | under the terms of the GNU Free Documentation License, Version 1.3 or | 155 | under the terms of the GNU Free Documentation License, Version 1.3 or |
| @@ -43773,6 +43774,155 @@ like to serve. | |||
| 43773 | @end table | 43774 | @end table |
| 43774 | @end deftp | 43775 | @end deftp |
| 43775 | 43776 | ||
| 43777 | @anchor{fossil-service-type} | ||
| 43778 | @subsubheading Fossil Service | ||
| 43779 | |||
| 43780 | @cindex Fossil service | ||
| 43781 | @cindex Fossil, forge | ||
| 43782 | @uref{https://fossil-scm.org, Fossil} is a distributed | ||
| 43783 | software configuration management system. In addition to version control | ||
| 43784 | like Git, Fossil also supports bug tracking, wiki, forum, chat, etc., | ||
| 43785 | all accessible via its built-in web interface. | ||
| 43786 | |||
| 43787 | Fossil is highly reliable thanks to its robust file format based on SQLite | ||
| 43788 | with atomic transactions. Its server is CPU, memory and bandwidth efficient | ||
| 43789 | enough run comfortably on a cheap VPS or single board computer, | ||
| 43790 | and be accessed over suboptimal connections. | ||
| 43791 | |||
| 43792 | The following example will configure Fossil to listen on a unix socket | ||
| 43793 | behind a reverse proxy and serve repositories from a custom location. | ||
| 43794 | |||
| 43795 | @lisp | ||
| 43796 | (service fossil-service-type | ||
| 43797 | (fossil-configuration | ||
| 43798 | (repository "/srv/museum") | ||
| 43799 | (repo-list? #t) | ||
| 43800 | (base-url "https://museum.example") | ||
| 43801 | (socket-file "/var/run/fossil.sock") | ||
| 43802 | (compress? #f))) | ||
| 43803 | @end lisp | ||
| 43804 | |||
| 43805 | @deftp {Data Type} fossil-configuration | ||
| 43806 | Available @code{fossil-configuration} fields are: | ||
| 43807 | |||
| 43808 | @table @asis | ||
| 43809 | @item @code{package} (default: @code{fossil}) (type: package) | ||
| 43810 | The Fossil package to use. | ||
| 43811 | |||
| 43812 | @item @code{user} (default: @code{"fossil"}) (type: string) | ||
| 43813 | The user running the Fossil server. | ||
| 43814 | |||
| 43815 | @item @code{group} (default: @code{"fossil"}) (type: string) | ||
| 43816 | The user group running the Fossil server. | ||
| 43817 | |||
| 43818 | @item @code{log-file} (default: @code{"/var/log/fossil.log"}) (type: string) | ||
| 43819 | The path to the server's log. | ||
| 43820 | |||
| 43821 | @item @code{repository} (default: @code{"/var/lib/fossil"}) (type: string) | ||
| 43822 | The name of the Fossil repository to be served, or a directory | ||
| 43823 | containing one or more repositories with names ending in @code{.fossil}. | ||
| 43824 | In the latter case, a prefix of the URL pathname is used to search the | ||
| 43825 | directory for an appropriate repository. Files not matching the pattern | ||
| 43826 | @code{*.fossil*} will be served as static content. Invoke | ||
| 43827 | @command{fossil server --help} for more information. | ||
| 43828 | |||
| 43829 | @item @code{acme?} (default: @code{#f}) (type: boolean) | ||
| 43830 | Deliver files from the @code{.well-known} subdirectory. | ||
| 43831 | |||
| 43832 | @item @code{base-url} (type: maybe-string) | ||
| 43833 | The URL used as the base (useful for reverse proxies) | ||
| 43834 | |||
| 43835 | @item @code{chroot} (type: maybe-string) | ||
| 43836 | The directory to use for chroot instead of @code{repository}. | ||
| 43837 | |||
| 43838 | @item @code{ckout-alias} (type: maybe-string) | ||
| 43839 | The @var{name} for @code{/doc/@var{name}/...} to be treated as | ||
| 43840 | @code{/doc/ckout/...}. | ||
| 43841 | |||
| 43842 | @item @code{compress?} (default: @code{#t}) (type: boolean) | ||
| 43843 | Compress HTTP response. | ||
| 43844 | |||
| 43845 | @item @code{create?} (default: @code{#f}) (type: boolean) | ||
| 43846 | Create a new @code{repository} if it does not already exist. | ||
| 43847 | |||
| 43848 | @item @code{error-log-file} (type: maybe-string) | ||
| 43849 | The path for HTTP error log. | ||
| 43850 | |||
| 43851 | @item @code{ext-root} (type: maybe-string) | ||
| 43852 | The document root for the /ext extension mechanism. | ||
| 43853 | |||
| 43854 | @item @code{files} (type: maybe-list-of-strings) | ||
| 43855 | The glob patterns for static files. | ||
| 43856 | |||
| 43857 | @item @code{from} (type: maybe-string) | ||
| 43858 | The path to be used as the diff baseline for the /ckout page. | ||
| 43859 | |||
| 43860 | @item @code{jail?} (default: @code{#t}) (type: boolean) | ||
| 43861 | Whether to enter the chroot jail after dropping root privileges. | ||
| 43862 | |||
| 43863 | @item @code{js-mode} (type: maybe-fossil-js-mode) | ||
| 43864 | How JavaScript is delivered with pages, either @code{'inline} at the end | ||
| 43865 | of the HTML file, as @code{'separate} HTTP requests, or one single HTTP | ||
| 43866 | request for all JavaScript @code{'bundled} together. Depending on the | ||
| 43867 | needs of any given page, @code{'inline} and @code{'bundled} modes might | ||
| 43868 | result in a single amalgamated script or several, but both approaches | ||
| 43869 | result in fewer HTTP requests than the @code{'separate} mode. | ||
| 43870 | |||
| 43871 | @item @code{https?} (default: @code{#f}) (type: boolean) | ||
| 43872 | Indicate that the requests are coming through a reverse proxy that has | ||
| 43873 | already translated HTTPS into HTTP. | ||
| 43874 | |||
| 43875 | @item @code{ip} (type: maybe-string) | ||
| 43876 | The IP for the server to listen on. | ||
| 43877 | |||
| 43878 | @item @code{local-authentication?} (default: @code{#f}) (type: boolean) | ||
| 43879 | Enable automatic login for requests from localhost. | ||
| 43880 | |||
| 43881 | @item @code{localhost?} (default: @code{#f}) (type: boolean) | ||
| 43882 | Listen on @code{127.0.0.1} only. | ||
| 43883 | |||
| 43884 | @item @code{main-menu} (type: maybe-string) | ||
| 43885 | The file whose contents is to override the repository's @code{mainmenu} | ||
| 43886 | setting. | ||
| 43887 | |||
| 43888 | @item @code{max-latency} (type: maybe-number) | ||
| 43889 | The maximum latency in seconds for a single HTTP request. | ||
| 43890 | |||
| 43891 | @item @code{port} (default: @code{8080}) (type: port-number) | ||
| 43892 | The port number for the server to listen on. | ||
| 43893 | |||
| 43894 | @item @code{list-repositories?} (default: @code{#f}) (type: boolean) | ||
| 43895 | If @code{repository} is dir, URL @code{/} lists repos. | ||
| 43896 | |||
| 43897 | @item @code{redirect-to-https?} (default: @code{#t}) (type: boolean) | ||
| 43898 | If set to @code{#f}, do not force redirects to HTTPS regardless of the | ||
| 43899 | repository setting @code{redirect-to-https}. | ||
| 43900 | |||
| 43901 | @item @code{scgi?} (default: @code{#f}) (type: boolean) | ||
| 43902 | Accept SCGI rather than HTTP. | ||
| 43903 | |||
| 43904 | @item @code{skin} (type: maybe-string) | ||
| 43905 | The skin label to use, overriding repository settings. | ||
| 43906 | |||
| 43907 | @item @code{socket-file} (type: maybe-string) | ||
| 43908 | The unix-domain socket to use instead of TCP/IP. | ||
| 43909 | |||
| 43910 | @item @code{socket-mode} (default: @code{0o640}) (type: mode-number) | ||
| 43911 | The file permissions to set for the unix socket. | ||
| 43912 | |||
| 43913 | @item @code{th-trace?} (default: @code{#f}) (type: boolean) | ||
| 43914 | Trace TH1 execution (for debugging purposes). | ||
| 43915 | |||
| 43916 | @item @code{tls-certificate} (type: maybe-string) | ||
| 43917 | The certicate file (@file{fullchain.pem}) with which to enable TLS | ||
| 43918 | (HTTPS) encryption. | ||
| 43919 | |||
| 43920 | @item @code{tls-private-key} (type: maybe-string) | ||
| 43921 | The file storing the TLS private key. | ||
| 43922 | |||
| 43923 | @end table | ||
| 43924 | |||
| 43925 | @end deftp | ||
| 43776 | 43926 | ||
| 43777 | @node Game Services | 43927 | @node Game Services |
| 43778 | @subsection Game Services | 43928 | @subsection Game Services |
diff --git a/gnu/services/version-control.scm b/gnu/services/version-control.scm index a7f40812a6c..dba38faa460 100644 --- a/gnu/services/version-control.scm +++ b/gnu/services/version-control.scm | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | ;;; Copyright © 2021 Julien Lepiller <julien@lepiller.eu> | 7 | ;;; Copyright © 2021 Julien Lepiller <julien@lepiller.eu> |
| 8 | ;;; Copyright © 2025 Tomas Volf <~@wolfsden.cz> | 8 | ;;; Copyright © 2025 Tomas Volf <~@wolfsden.cz> |
| 9 | ;;; Copyright © 2025 Evgeny Pisemsky <mail@pisemsky.site> | 9 | ;;; Copyright © 2025 Evgeny Pisemsky <mail@pisemsky.site> |
| 10 | ;;; Copyright © 2026 Nguyễn Gia Phong <cnx@loang.net> | ||
| 10 | ;;; | 11 | ;;; |
| 11 | ;;; This file is part of GNU Guix. | 12 | ;;; This file is part of GNU Guix. |
| 12 | ;;; | 13 | ;;; |
| @@ -26,12 +27,14 @@ | |||
| 26 | (define-module (gnu services version-control) | 27 | (define-module (gnu services version-control) |
| 27 | #:use-module (gnu services) | 28 | #:use-module (gnu services) |
| 28 | #:use-module (gnu services base) | 29 | #:use-module (gnu services base) |
| 30 | #:use-module (gnu services configuration) | ||
| 29 | #:use-module (gnu services shepherd) | 31 | #:use-module (gnu services shepherd) |
| 30 | #:use-module (gnu services web) | 32 | #:use-module (gnu services web) |
| 31 | #:use-module (gnu system shadow) | 33 | #:use-module (gnu system shadow) |
| 32 | #:use-module (gnu packages version-control) | 34 | #:use-module (gnu packages version-control) |
| 33 | #:use-module (gnu packages admin) | 35 | #:use-module (gnu packages admin) |
| 34 | #:use-module (guix deprecation) | 36 | #:use-module (guix deprecation) |
| 37 | #:use-module (guix packages) | ||
| 35 | #:use-module (guix records) | 38 | #:use-module (guix records) |
| 36 | #:use-module (guix gexp) | 39 | #:use-module (guix gexp) |
| 37 | #:use-module (guix store) | 40 | #:use-module (guix store) |
| @@ -93,7 +96,44 @@ | |||
| 93 | gitile-configuration-footer | 96 | gitile-configuration-footer |
| 94 | gitile-configuration-nginx | 97 | gitile-configuration-nginx |
| 95 | 98 | ||
| 96 | gitile-service-type)) | 99 | gitile-service-type |
| 100 | |||
| 101 | fossil-configuration | ||
| 102 | fossil-configuration-fields | ||
| 103 | fossil-configuration? | ||
| 104 | fossil-configuration-package | ||
| 105 | fossil-configuration-user | ||
| 106 | fossil-configuration-group | ||
| 107 | fossil-configuration-log-file | ||
| 108 | fossil-configuration-repository | ||
| 109 | fossil-configuration-acme? | ||
| 110 | fossil-configuration-base-url | ||
| 111 | fossil-configuration-chroot | ||
| 112 | fossil-configuration-ckout-alias | ||
| 113 | fossil-configuration-compress? | ||
| 114 | fossil-configuration-create? | ||
| 115 | fossil-configuration-error-log-file | ||
| 116 | fossil-configuration-ext-root | ||
| 117 | fossil-configuration-files | ||
| 118 | fossil-configuration-from | ||
| 119 | fossil-configuration-jail? | ||
| 120 | fossil-configuration-js-mode | ||
| 121 | fossil-configuration-https? | ||
| 122 | fossil-configuration-ip | ||
| 123 | fossil-configuration-local-authentication? | ||
| 124 | fossil-configuration-main-menu | ||
| 125 | fossil-configuration-max-latency | ||
| 126 | fossil-configuration-port | ||
| 127 | fossil-configuration-list-repositories? | ||
| 128 | fossil-configuration-redirect-to-https? | ||
| 129 | fossil-configuration-skin | ||
| 130 | fossil-configuration-socket-file | ||
| 131 | fossil-configuration-socket-mode | ||
| 132 | fossil-configuration-th-trace? | ||
| 133 | fossil-configuration-tls-certificate | ||
| 134 | fossil-configuration-tls-private-key | ||
| 135 | |||
| 136 | fossil-service-type)) | ||
| 97 | 137 | ||
| 98 | ;;; Commentary: | 138 | ;;; Commentary: |
| 99 | ;;; | 139 | ;;; |
| @@ -603,3 +643,218 @@ on the web.") | |||
| 603 | gitile-shepherd-service) | 643 | gitile-shepherd-service) |
| 604 | (service-extension nginx-service-type | 644 | (service-extension nginx-service-type |
| 605 | gitile-nginx-server-block))))) | 645 | gitile-nginx-server-block))))) |
| 646 | |||
| 647 | |||
| 648 | ;;; | ||
| 649 | ;;; Fossil HTTP server. | ||
| 650 | ;;; | ||
| 651 | |||
| 652 | (define (port-number? n) | ||
| 653 | (and (integer? n) | ||
| 654 | (> n 0) | ||
| 655 | (< n (expt 2 16)))) | ||
| 656 | |||
| 657 | (define (mode-number? n) | ||
| 658 | (and (integer? n) | ||
| 659 | (>= n 0) | ||
| 660 | (<= n #o777))) | ||
| 661 | |||
| 662 | (define (fossil-js-mode? x) | ||
| 663 | (and (memq x '(inline separate bundled)) | ||
| 664 | #t)) | ||
| 665 | |||
| 666 | (define-maybe/no-serialization number) | ||
| 667 | (define-maybe/no-serialization string) | ||
| 668 | (define-maybe/no-serialization list-of-strings) | ||
| 669 | (define-maybe/no-serialization fossil-js-mode) | ||
| 670 | |||
| 671 | (define-configuration/no-serialization fossil-configuration | ||
| 672 | (package (package fossil) | ||
| 673 | "The Fossil package to use.") | ||
| 674 | (user (string "fossil") | ||
| 675 | "The user running the Fossil server.") | ||
| 676 | (group (string "fossil") | ||
| 677 | "The user group running the Fossil server.") | ||
| 678 | (log-file (string "/var/log/fossil.log") | ||
| 679 | "The path to the server's log.") | ||
| 680 | (repository (string "/var/lib/fossil") | ||
| 681 | "The name of the Fossil repository to be served, or a directory | ||
| 682 | containing one or more repositories with names ending in @code{.fossil}. | ||
| 683 | |||
| 684 | In the latter case, a prefix of the URL pathname is used | ||
| 685 | to search the directory for an appropriate repository. | ||
| 686 | Files not matching the pattern @code{*.fossil*} | ||
| 687 | will be served as static content. Invoke @command{fossil server --help} | ||
| 688 | for more information.") | ||
| 689 | (acme? (boolean #f) | ||
| 690 | "Deliver files from the @code{.well-known} subdirectory.") | ||
| 691 | (base-url maybe-string | ||
| 692 | "The URL used as the base (useful for reverse proxies)") | ||
| 693 | (chroot maybe-string | ||
| 694 | "The directory to use for chroot instead of @code{repository}.") | ||
| 695 | (ckout-alias maybe-string | ||
| 696 | "The @var{name} for @code{/doc/@var{name}/...} | ||
| 697 | to be treated as @code{/doc/ckout/...}.") | ||
| 698 | (compress? (boolean #t) "Compress HTTP response.") | ||
| 699 | (create? (boolean #f) | ||
| 700 | "Create a new @code{repository} if it does not already exist.") | ||
| 701 | (error-log-file maybe-string "The path for HTTP error log.") | ||
| 702 | (ext-root maybe-string "The document root for the /ext extension mechanism.") | ||
| 703 | (files maybe-list-of-strings "The glob patterns for static files.") | ||
| 704 | (from maybe-string | ||
| 705 | "The path to be used as the diff baseline for the /ckout page.") | ||
| 706 | (jail? (boolean #t) | ||
| 707 | "Whether to enter the chroot jail after dropping root privileges.") | ||
| 708 | (js-mode maybe-fossil-js-mode | ||
| 709 | "How JavaScript is delivered with pages, either @code{'inline} | ||
| 710 | at the end of the HTML file, as @code{'separate} HTTP requests, | ||
| 711 | or one single HTTP request for all JavaScript @code{'bundled} together. | ||
| 712 | |||
| 713 | Depending on the needs of any given page, @code{'inline} | ||
| 714 | and @code{'bundled} modes might result in a single amalgamated script | ||
| 715 | or several, but both approaches result in fewer HTTP requests | ||
| 716 | than the @code{'separate} mode.") | ||
| 717 | (https? (boolean #f) | ||
| 718 | "Indicate that the requests are coming through a reverse proxy | ||
| 719 | that has already translated HTTPS into HTTP.") | ||
| 720 | (ip maybe-string "The IP for the server to listen on.") | ||
| 721 | (local-authentication? (boolean #f) | ||
| 722 | "Enable automatic login for requests from localhost.") | ||
| 723 | (localhost? (boolean #f) "Listen on @code{127.0.0.1} only.") | ||
| 724 | (main-menu maybe-string ;TODO: structure | ||
| 725 | "The file whose contents is to override | ||
| 726 | the repository's @code{mainmenu} setting.") | ||
| 727 | (max-latency maybe-number | ||
| 728 | "The maximum latency in seconds for a single HTTP request.") | ||
| 729 | (port (port-number 8080) "The port number for the server to listen on.") | ||
| 730 | (list-repositories? (boolean #f) | ||
| 731 | "If @code{repository} is dir, URL @code{/} lists repos.") | ||
| 732 | (redirect-to-https? (boolean #t) | ||
| 733 | "If set to @code{#f}, do not force redirects to HTTPS | ||
| 734 | regardless of the repository setting @code{redirect-to-https}.") | ||
| 735 | (scgi? (boolean #f) "Accept SCGI rather than HTTP.") | ||
| 736 | (skin maybe-string "The skin label to use, overriding repository settings.") | ||
| 737 | (socket-file maybe-string | ||
| 738 | "The unix-domain socket to use instead of TCP/IP.") | ||
| 739 | (socket-mode (mode-number #o640) | ||
| 740 | "The file permissions to set for the unix socket.") | ||
| 741 | (th-trace? (boolean #f) | ||
| 742 | "Trace TH1 execution (for debugging purposes).") | ||
| 743 | (tls-certificate maybe-string | ||
| 744 | "The certicate file (@file{fullchain.pem}) | ||
| 745 | with which to enable TLS (HTTPS) encryption.") | ||
| 746 | (tls-private-key maybe-string "The file storing the TLS private key.")) | ||
| 747 | |||
| 748 | (define (fossil-accounts config) | ||
| 749 | (match-record config <fossil-configuration> (user group) | ||
| 750 | (list (user-group (name group) | ||
| 751 | (system? #t)) | ||
| 752 | (user-account (name user) | ||
| 753 | (group group) | ||
| 754 | (system? #t) | ||
| 755 | (comment "Fossil server user") | ||
| 756 | (home-directory "/var/empty") | ||
| 757 | (shell (file-append shadow "/sbin/nologin")))))) | ||
| 758 | |||
| 759 | (define (fossil-activation config) | ||
| 760 | (match-record config <fossil-configuration> (user create? repository) | ||
| 761 | (with-imported-modules '((guix build utils)) | ||
| 762 | #~(begin | ||
| 763 | (use-modules (guix build utils)) | ||
| 764 | (let* ((pw (getpwnam #$user)) | ||
| 765 | (uid (passwd:uid pw)) | ||
| 766 | (gid (passwd:gid pw))) | ||
| 767 | (unless #$create? (chown #$repository uid gid))))))) | ||
| 768 | |||
| 769 | (define (fossil-shepherd-service config) | ||
| 770 | (match-record config <fossil-configuration> | ||
| 771 | (package user group log-file repository acme? base-url | ||
| 772 | chroot ckout-alias compress? create? error-log-file ext-root | ||
| 773 | files from https? ip jail? js-mode list-repositories? | ||
| 774 | local-authentication? localhost? main-menu max-latency port | ||
| 775 | redirect-to-https? scgi? skin socket-file socket-mode | ||
| 776 | th-trace? tls-certificate tls-private-key) | ||
| 777 | (shepherd-service | ||
| 778 | (provision '(fossil)) | ||
| 779 | (requirement '(user-processes networking)) | ||
| 780 | (start #~(make-forkexec-constructor | ||
| 781 | (list #$(file-append package "/bin/fossil") | ||
| 782 | "server" | ||
| 783 | #$@(if acme? '("--acme") '()) | ||
| 784 | #$@(if (maybe-value-set? base-url) | ||
| 785 | (list "--baseurl" base-url) | ||
| 786 | '()) | ||
| 787 | #$@(if (maybe-value-set? chroot) | ||
| 788 | (list "--chroot" chroot) | ||
| 789 | '()) | ||
| 790 | #$@(if (maybe-value-set? ckout-alias) | ||
| 791 | (list "--ckout-alias" ckout-alias) | ||
| 792 | '()) | ||
| 793 | #$@(if compress? '() '("--nocompress")) | ||
| 794 | #$@(if create? '("--create") '()) | ||
| 795 | #$@(if (maybe-value-set? error-log-file) | ||
| 796 | (list "--errorlog" error-log-file) | ||
| 797 | '()) | ||
| 798 | #$@(if (maybe-value-set? ext-root) | ||
| 799 | (list "--extroot" ext-root) | ||
| 800 | '()) | ||
| 801 | #$@(if (maybe-value-set? files) | ||
| 802 | (list "--files" (string-join files ",")) | ||
| 803 | '()) | ||
| 804 | #$@(if (maybe-value-set? from) (list "--from" from) '()) | ||
| 805 | #$@(if https? '("--https") '()) | ||
| 806 | #$@(if jail? '() '("--nojail")) | ||
| 807 | #$@(if (maybe-value-set? js-mode) | ||
| 808 | (list "--jsmode" (symbol->string js-mode)) | ||
| 809 | '()) | ||
| 810 | #$@(if local-authentication? '("--localauth") '()) | ||
| 811 | #$@(if localhost? '("--localhost") '()) | ||
| 812 | #$@(if (maybe-value-set? main-menu) | ||
| 813 | (list "--mainmenu" main-menu) | ||
| 814 | '()) | ||
| 815 | #$@(if (maybe-value-set? max-latency) | ||
| 816 | (list "--max-latency" | ||
| 817 | (number->string max-latency)) | ||
| 818 | '()) | ||
| 819 | #$@(if redirect-to-https? '() '("--nossl")) | ||
| 820 | #$@(if scgi? '("--scgi") '()) | ||
| 821 | #$@(if list-repositories? '("--repolist") '()) | ||
| 822 | #$@(if (maybe-value-set? skin) (list "--skin" skin) '()) | ||
| 823 | #$@(if (maybe-value-set? socket-file) | ||
| 824 | (list "--socket-name" socket-file | ||
| 825 | "--socket-mode" socket-mode | ||
| 826 | "--socket-owner" | ||
| 827 | (simple-format #f "~a:~a" user group)) | ||
| 828 | (list "--port" | ||
| 829 | (if (maybe-value-set? ip) | ||
| 830 | (simple-format #f "~a:~a" ip port) | ||
| 831 | (number->string port)))) | ||
| 832 | #$@(if th-trace? '("--th-trace") '()) | ||
| 833 | #$@(if (maybe-value-set? tls-certificate) | ||
| 834 | (list "--cert" tls-certificate) | ||
| 835 | '()) | ||
| 836 | #$@(if (maybe-value-set? tls-private-key) | ||
| 837 | (list "--pkey" tls-private-key) | ||
| 838 | '()) | ||
| 839 | "--user" #$user | ||
| 840 | #$repository) | ||
| 841 | #:user #$user | ||
| 842 | #:group #$group | ||
| 843 | #:log-file #$log-file)) | ||
| 844 | (stop #~(make-kill-destructor)) | ||
| 845 | (documentation | ||
| 846 | "Run the HTTP server | ||
| 847 | for the Fossil software configuration management system.")))) | ||
| 848 | |||
| 849 | (define fossil-service-type | ||
| 850 | (service-type | ||
| 851 | (name 'fossil) | ||
| 852 | (extensions | ||
| 853 | (list (service-extension account-service-type fossil-accounts) | ||
| 854 | (service-extension activation-service-type fossil-activation) | ||
| 855 | (service-extension shepherd-root-service-type | ||
| 856 | (compose list fossil-shepherd-service)))) | ||
| 857 | (description | ||
| 858 | "Run the HTTP server for the Fossil software configuration management | ||
| 859 | system. In addition to distributed version control, Fossil also supports | ||
| 860 | bug tracking, wiki, forum, email alerts, chat, and technotes."))) | ||
diff --git a/gnu/tests/version-control.scm b/gnu/tests/version-control.scm index 8426555a18f..9df3aa9dbd4 100644 --- a/gnu/tests/version-control.scm +++ b/gnu/tests/version-control.scm | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | ;;; Copyright © 2017-2018, 2020-2022 Ludovic Courtès <ludo@gnu.org> | 3 | ;;; Copyright © 2017-2018, 2020-2022 Ludovic Courtès <ludo@gnu.org> |
| 4 | ;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org> | 4 | ;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org> |
| 5 | ;;; Copyright © 2018 Christopher Baines <mail@cbaines.net> | 5 | ;;; Copyright © 2018 Christopher Baines <mail@cbaines.net> |
| 6 | ;;; Copyright © 2026 Nguyễn Gia Phong <cnx@loang.net> | ||
| 6 | ;;; | 7 | ;;; |
| 7 | ;;; This file is part of GNU Guix. | 8 | ;;; This file is part of GNU Guix. |
| 8 | ;;; | 9 | ;;; |
| @@ -39,7 +40,8 @@ | |||
| 39 | #:export (%test-cgit | 40 | #:export (%test-cgit |
| 40 | %test-git-http | 41 | %test-git-http |
| 41 | %test-gitolite | 42 | %test-gitolite |
| 42 | %test-gitile)) | 43 | %test-gitile |
| 44 | %test-fossil)) | ||
| 43 | 45 | ||
| 44 | (define README-contents | 46 | (define README-contents |
| 45 | "Hello! This is what goes inside the 'README' file.") | 47 | "Hello! This is what goes inside the 'README' file.") |
| @@ -519,3 +521,74 @@ HTTP-PORT." | |||
| 519 | (name "gitile") | 521 | (name "gitile") |
| 520 | (description "Connect to a running Gitile server.") | 522 | (description "Connect to a running Gitile server.") |
| 521 | (value (run-gitile-test)))) | 523 | (value (run-gitile-test)))) |
| 524 | |||
| 525 | |||
| 526 | ;;; | ||
| 527 | ;;; Fossil server. | ||
| 528 | ;;; | ||
| 529 | |||
| 530 | (define %test-fossil | ||
| 531 | (system-test | ||
| 532 | (name "fossil") | ||
| 533 | (description "Connect to a running Fossil server.") | ||
| 534 | (value | ||
| 535 | (gexp->derivation | ||
| 536 | (string-append name "-test") | ||
| 537 | (let* ((port 8080) | ||
| 538 | (base-url (simple-format #f "http://localhost:~a" port)) | ||
| 539 | (index-url (string-append base-url "/index")) | ||
| 540 | (os (marionette-operating-system | ||
| 541 | (simple-operating-system | ||
| 542 | (service dhcpcd-service-type) | ||
| 543 | (service fossil-service-type | ||
| 544 | (fossil-configuration | ||
| 545 | (repository "/tmp/test.fossil") | ||
| 546 | (base-url base-url) | ||
| 547 | (create? #t) | ||
| 548 | (port port)))))) | ||
| 549 | (vm (virtual-machine (operating-system os) | ||
| 550 | (port-forwardings (list (cons port port)))))) | ||
| 551 | (with-imported-modules '((gnu build marionette) | ||
| 552 | (guix build utils)) | ||
| 553 | #~(begin | ||
| 554 | (use-modules (gnu build marionette) | ||
| 555 | (guix build utils) | ||
| 556 | (srfi srfi-64) | ||
| 557 | (srfi srfi-71) | ||
| 558 | (web client) | ||
| 559 | (web response)) | ||
| 560 | (define marionette (make-marionette (list #$vm))) | ||
| 561 | (test-runner-current (system-test-runner #$output)) | ||
| 562 | (test-begin #$name) | ||
| 563 | |||
| 564 | (test-assert "server running" | ||
| 565 | (wait-for-tcp-port #$port marionette)) | ||
| 566 | |||
| 567 | (test-assert "server log file" | ||
| 568 | (wait-for-file "/var/log/fossil.log" marionette)) | ||
| 569 | |||
| 570 | (test-assert "cloning" | ||
| 571 | (begin | ||
| 572 | (setenv "HOME" #$output) ; fossil writes to $HOME | ||
| 573 | (invoke/quiet #$(file-append fossil "/bin/fossil") "clone" | ||
| 574 | "--admin-user" "alice" | ||
| 575 | "--httptrace" | ||
| 576 | "--verbose" | ||
| 577 | #$base-url | ||
| 578 | (string-append #$output "/test.fossil")))) | ||
| 579 | |||
| 580 | (test-assert "index redirect" | ||
| 581 | (let ((response text | ||
| 582 | (http-get #$base-url #:decode-body? #t))) | ||
| 583 | (and (= 302 (response-code response)) | ||
| 584 | (string-contains text #$index-url)))) | ||
| 585 | |||
| 586 | (test-equal "index page" | ||
| 587 | 200 (response-code (http-get #$index-url))) | ||
| 588 | |||
| 589 | (test-equal "tarball download" | ||
| 590 | 200 (response-code | ||
| 591 | (http-get (string-append #$base-url | ||
| 592 | "/tarball/test.tar.gz")))) | ||
| 593 | |||
| 594 | (test-end)))))))) | ||
