Compare commits

...

16 commits

Author SHA1 Message Date
John Kehayias
da04b3bb42
gnu: Add python-dotenv-0.13.0.
Old version just for docker-compose until it is updated.  Fixes build for
docker-compose

* gnu/packages/docker.scm (python-dotenv-0.13.0): New variable.
(docker-compose)[inputs]: Use it instead of python-dotenv.

Change-Id: I8efc30ad7d40601bb5ad88e7c56484edb36e328e
2025-09-26 16:57:40 -04:00
John Kehayias
3b55a14377
gnu: Add python-sh-1.
This is just for the old docker-compose we still ship (long pending an update
to Go version), via next commit for an older python-dotenv.

* gnu/packages/python-xyz.scm (python-sh-1): New variable.

Change-Id: Idb2b6d476bb9391d9fd8b71aa0184696f3b45aba
2025-09-26 16:54:38 -04:00
John Kehayias
f5d61ca686
gnu: python-websocket-client-0.59: Fix tests.
* gnu/packages/python-web.scm (python-websocket-client-0.59)[native-inputs]:
Add python-six.

Change-Id: I213b164858db5fe4e8aeea643daf1a1b98998835
2025-09-26 16:54:36 -04:00
Arun Isaac
bb2dacd811
gnu: mumi: Update to 0.14.0.
* gnu/packages/mail.scm (mumi): Update to 0.14.0.
2025-09-26 21:50:17 +01:00
Arun Isaac
3c422c6111
gnu: mumi: Update source URI.
* gnu/packages/mail.scm (mumi)[source]: Update URI.
2025-09-26 21:49:33 +01:00
Andy Tai
f2c9dabec8
gnu: gcal: Update to 4.2.0.
* gnu/packages/gcal.scm (gcal): Update to 4.2.0.
[argument]<#:configure-flags>: Add "-lm".
[native-inputs]: Add pkg-config and check.

Change-Id: Ia67f66b604ab428c8cbe546c47bbcdf7a52dd8de
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-09-26 21:55:09 +02:00
Martin Schitter
abc35bae81
gnu: guile-next: Use codeberg git repository.
Fetch code from the more reliable and faster repository at codeberg.org.

	modified:   gnu/packages/guile.scm

Change-Id: I9340e22abadf80931019acd566a8f4e9701988c0
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-09-26 21:53:39 +02:00
Alissa Istleyeva
8a69897b7e
home: services: Fix binding options in sway-service-type.
* gnu/home/services/sway.scm (keybinding-options?): Add to-code option.
(codebinding-options?): Remove to-code option.

Change-Id: I0a43ccb7d997bb1ba2ec334721a9a7bdd5e5ce91
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-09-26 21:46:19 +02:00
Ludovic Courtès
8f7837e104
gnu: guix-jupyter: Update to 0.3.1.
* gnu/packages/package-management.scm (guix-jupyter): Update to 0.3.1.

Change-Id: I784c1fe10006c587d32b0b0bb1cb0f3677335ca9
2025-09-26 21:43:16 +02:00
Rodion Goritskov
054aae7bb2
services: Add miniflux-service-type.
* doc/guix.texi: Document Miniflux service and configuration.
* gnu/services/web.scm: New service.
* gnu/services/web.scm: Define shepherd service and account roles.
* gnu/tests/web.scm: (%miniflux-create-admin-credentials,
miniflux-base-system, %test-miniflux-admin-string, %test-miniflux-admin-file,
%test-miniflux-socket): Add system tests for Miniflux service.

Change-Id: I4a336e677ec8b46aed632f0ded9cc11c2d38975f
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-09-26 21:39:40 +02:00
Ludovic Courtès
d411aff611
teams: Adjust team membership for myself.
* etc/teams.scm (civodul): Remove ‘home’, ‘bootstrap’ and ‘documentation’.
Add ‘hpc’.

Change-Id: I7946be1fc59fc292a7b92b92035ccaea722aadc9
2025-09-26 21:35:43 +02:00
Ludovic Courtès
e1038aee6d
gnu: shepherd@1.0: Build against Fibers 1.4.x.
This reinstates 2ba475d37a.

* gnu/packages/admin.scm (shepherd-1.0)[native-inputs, inputs]: Use
‘guile-fibers’.

Change-Id: I4dbbc2d32d114ed9d16a2da4efb831fc2044a314
2025-09-26 21:31:04 +02:00
Ludovic Courtès
55b39642e2
gnu: guile-fibers@1.4: Disable JIT for ‘make check’.
Fixes guix/guix#2474.

* gnu/packages/guile-xyz.scm (guile-fibers-1.4)[arguments]: Add ‘disable-jit’
phase on AArch64.

Change-Id: Idad1a5e1a84d29259bf1ed4a284f9981c50defb8
2025-09-26 21:31:04 +02:00
Sören Tempel
e10da6bff8
gnu: binsec: Enable support for z3-builtin solver.
This is much faster than an external solver as it doesn't rely on
forking an external solver and instead uses the API provided by
ocaml-z3.  This feature was added in binsec release 0.9.1.

* gnu/packages/ocaml.scm (binsec)[propagated-inputs]: Add ocaml-z3.
* gnu/packages/ocaml.scm (binsec)[native-inputs]: Add z3.

Change-Id: I246fd1a13e8c9d6a6764608281a2bea5ac0a054b
Signed-off-by: Julien Lepiller <julien@lepiller.eu>
2025-09-26 21:26:41 +02:00
jgart
67f5f23c88
gnu: trealla: Update to 2.83.9.
* gnu/packages/prolog.scm (trealla): Update to 2.83.9.

Change-Id: I8ca5daedef142f6f88a9f22283a7c0e9a518320a
2025-09-26 11:30:07 -05:00
Sharlatan Hellseher
d4c1dc6df5
gnu: python-argparse-manpage: Update to 4.7.
* gnu/packages/python-xyz.scm (python-argparse-manpage): Update to 4.7.
[source]: Fix uri name as seen in PyPI archive.
[arguments] <test-flags>: Skip tests requiring pip.
[native-inputs]: Remove python-pip, python-tomli, and python-wheel.

Fixes: guix/guix#3015
Change-Id: I10b31aa295bd97673071ecaaecb9895cd4d8a6b0
2025-09-26 17:16:06 +01:00
16 changed files with 576 additions and 31 deletions

View file

@ -144,6 +144,7 @@ Copyright @copyright{} 2024 Evgeny Pisemsky@*
Copyright @copyright{} 2025 jgart@* Copyright @copyright{} 2025 jgart@*
Copyright @copyright{} 2025 Artur Wroblewski@* Copyright @copyright{} 2025 Artur Wroblewski@*
Copyright @copyright{} 2025 Edouard Klein@* Copyright @copyright{} 2025 Edouard Klein@*
Copyright @copyright{} 2025 Rodion Goritskov@*
Permission is granted to copy, distribute and/or modify this document Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or under the terms of the GNU Free Documentation License, Version 1.3 or
@ -35700,6 +35701,80 @@ The file which should store the logging output of Agate.
@end table @end table
@end deftp @end deftp
@subsubheading Miniflux
@cindex miniflux
The @uref{https://miniflux.app/, Miniflux} is a minimalist RSS feed reader
with a web interface.
Depending on the configuration, an initial administrator user can be pre-created
on startup. To enable this, @code{create-admin?} should be set to @code{#t}, and
both @code{admin-username-file} and @code{admin-password-file} should point to
files containing the username and password, respectively. However, it is
recommended to manually change the password to a secure one via the web
UI after the initial service startup.
@defvar miniflux-service-type
This is the type of the Miniflux service. Its value
must be a @code{miniflux-configuration} record as in this example:
@lisp
(service miniflux-service-type
(miniflux-configuration
(listen-address "0.0.0.0:8080")
(base-url "http://my-news-source.test")
(create-administrator-account? #t)
(administrator-account-name "/var/miniflux/initial-admin-username")
(administrator-account-password "/var/miniflux/initial-admin-password")))
@end lisp
The details of the @code{miniflux-configuration} record type are given below.
@end defvar
@deftp {Data Type} miniflux-configuration
Available @code{miniflux-configuration} fields are:
@table @asis
@item @code{listen-address} (default: @code{"127.0.0.1:8080"}) (type: string)
Address to listen on.
Use absolute path like @code{"/var/run/miniflux/miniflux.sock"} for a Unix socket.
@item @code{base-url} (default: @code{"http://127.0.0.1/"}) (type: string)
Base URL to generate HTML links and base path for cookies.
@item @code{create-administrator-account?} (default: @code{#f}) (type: boolean)
Create an initial administrator account.
@item @code{administrator-account-name} (type: maybe-string-or-file-path)
Initial administrator account name as a string or an absolute path
to a file with an account name inside.
@item @code{administrator-account-password} (type: maybe-string-or-file-path)
Initial administrator account password as a string or an absolute path
to a file with a password inside.
@item @code{run-migrations?} (default: @code{#t}) (type: boolean)
Run database migrations during application startup.
@item @code{database-url} (default: @code{"host=/var/run/postgresql"}) (type: string)
PostgreSQL connection string.
@item @code{user} (default: @code{"miniflux"}) (type: string)
User name for Postgresql and system account.
@item @code{group} (default: @code{"miniflux"}) (type: string)
Group for the system account.
@item @code{log-file} (default: @code{"/var/log/miniflux.log"}) (type: string)
Path to the log file.
@item @code{extra-settings} (type: maybe-list)
Extra configuration parameters as a list of strings.
@end table
@end deftp
@node High Availability Services @node High Availability Services
@subsection High Availability Services @subsection High Availability Services

View file

@ -1058,8 +1058,8 @@ the \"texlive\" importer."
(define-member (person "Ludovic Courtès" (define-member (person "Ludovic Courtès"
"ludo@gnu.org" "ludo@gnu.org"
"civodul") "civodul")
core home bootstrap core-packages installer core core-packages hpc installer
documentation mentors) mentors)
(define-member (person "Andreas Enge" (define-member (person "Andreas Enge"
"andreas@enge.fr" "andreas@enge.fr"

View file

@ -168,7 +168,7 @@
(lambda (e) (lambda (e)
(or (member e (or (member e
'("no-warn" "whole-window" "border" "exclude-titlebar" '("no-warn" "whole-window" "border" "exclude-titlebar"
"release" "locked" "inhibited" "no-repeat")) "release" "locked" "to-code" "inhibited" "no-repeat"))
(string-prefix? "input-device=" e))) (string-prefix? "input-device=" e)))
lst)) lst))
@ -177,7 +177,7 @@
(lambda (e) (lambda (e)
(or (member e (or (member e
'("no-warn" "whole-window" "border" "exclude-titlebar" '("no-warn" "whole-window" "border" "exclude-titlebar"
"release" "locked" "to-code" "inhibited" "no-repeat")) "release" "locked" "inhibited" "no-repeat"))
(string-prefix? "input-device=" e))) (string-prefix? "input-device=" e)))
lst)) lst))

View file

@ -601,8 +601,13 @@ interface and is based on GNU Guile.")
"/bin/gzip") "/bin/gzip")
(string-append "--with-zstd=" #$(this-package-input "zstd") (string-append "--with-zstd=" #$(this-package-input "zstd")
"/bin/zstd"))))) "/bin/zstd")))))
(inputs (modify-inputs (package-inputs shepherd-0.10) (native-inputs
(append gzip zstd))))) (modify-inputs (package-native-inputs shepherd-0.10)
(replace "guile-fibers" guile-fibers))) ;use latest guile-fibers available
(inputs
(modify-inputs (package-inputs shepherd-0.10)
(replace "guile-fibers" guile-fibers) ;use latest guile-fibers available
(append gzip zstd)))))
(define-public shepherd shepherd-0.10) (define-public shepherd shepherd-0.10)

View file

@ -211,7 +211,7 @@ client.")
python-docker-5 python-docker-5
python-dockerpty python-dockerpty
python-docopt python-docopt
python-dotenv python-dotenv-0.13.0
python-jsonschema-3 python-jsonschema-3
python-pyyaml python-pyyaml
python-requests python-requests

View file

@ -1,5 +1,6 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2013, 2018 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2013, 2018 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2025 Andy Tai <atai@atai.org>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -20,19 +21,22 @@
#:use-module (guix packages) #:use-module (guix packages)
#:use-module (guix download) #:use-module (guix download)
#:use-module (guix build-system gnu) #:use-module (guix build-system gnu)
#:use-module (guix licenses)) #:use-module (guix licenses)
#:use-module (gnu packages check)
#:use-module (gnu packages pkg-config))
(define-public gcal (define-public gcal
(package (package
(name "gcal") (name "gcal")
(version "4.1") (version "4.2.0")
(source (origin (source (origin
(method url-fetch) (method url-fetch)
(uri (string-append "mirror://gnu/gcal/gcal-" (uri (string-append "https://www.alteholz.dev/gnu/gcal-"
version ".tar.xz")) version ".tar.xz"))
(sha256 (sha256
(base32 (base32
"1av11zkfirbixn05hyq4xvilin0ncddfjqzc4zd9pviyp506rdci")) "1p3q6his31bxs24nsgpfavw3nlhalqf0zak4f3b530p725s2vgfq"))
(modules '((guix build utils))) (modules '((guix build utils)))
(snippet (snippet
'(begin '(begin
@ -50,6 +54,8 @@
"/* BSD stdio derived implementations"))) "/* BSD stdio derived implementations")))
#t)))) #t))))
(build-system gnu-build-system) (build-system gnu-build-system)
(native-inputs (list check pkg-config))
(arguments `(#:configure-flags '("LDFLAGS=-lm")))
(home-page "https://www.gnu.org/software/gcal/") (home-page "https://www.gnu.org/software/gcal/")
(synopsis "Calculating and printing a wide variety of calendars") (synopsis "Calculating and printing a wide variety of calendars")
(description (description

View file

@ -1189,7 +1189,20 @@ is not available for Guile 2.0.")
(base32 (base32
"15ynxr3pfjscd6mz641zagv6i84jh9y65i5dnbb3j3q72j6bbvnb")) "15ynxr3pfjscd6mz641zagv6i84jh9y65i5dnbb3j3q72j6bbvnb"))
(patches '()))) (patches '())))
(arguments '()))) (arguments
(if (target-aarch64?)
(list #:phases
#~(modify-phases %standard-phases
(add-before 'check 'disable-jit
(lambda _
;; XXX: Due to a JIT bug in Guile 3.0.9 on AArch64,
;; some tests would hang:
;; <https://codeberg.org/fibers/fibers/issues/83>.
;; Disable JIT for now; re-enable it when Guile 3.0.10+
;; is used. (Note: The Shepherd disables JIT on
;; AArch64 so it can safely use Fibers.)
(setenv "GUILE_JIT_THRESHOLD" "-1")))))
'()))))
(define-public guile-fibers guile-fibers-1.4) (define-public guile-fibers guile-fibers-1.4)

View file

@ -502,7 +502,7 @@ without requiring the source code to be rewritten.")
;; The main goal here is to allow for '--with-branch'. ;; The main goal here is to allow for '--with-branch'.
(method git-fetch) (method git-fetch)
(uri (git-reference (uri (git-reference
(url "https://git.savannah.gnu.org/git/guile.git") (url "https://codeberg.org/guile/guile.git")
(commit commit))) (commit commit)))
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (sha256

View file

@ -4353,16 +4353,16 @@ It is a replacement for the @command{urlview} program.")
(define-public mumi (define-public mumi
(package (package
(name "mumi") (name "mumi")
(version "0.13.0") (version "0.14.0")
(source (origin (source (origin
(method git-fetch) (method git-fetch)
(uri (git-reference (uri (git-reference
(url "https://git.savannah.gnu.org/git/guix/mumi.git/") (url "https://codeberg.org/guix/mumi.git")
(commit version))) (commit version)))
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (sha256
(base32 (base32
"04mcd1xkdpvxlvpf4k4mvnwi06sdy8vy1di6gxxsr9msgdb366ir")))) "1v5gjzh8idz926518c0bv0qsmyggr6lvqn5vksf5j0qdh6r6dar7"))))
(build-system gnu-build-system) (build-system gnu-build-system)
(arguments (arguments
(list (list

View file

@ -1470,14 +1470,15 @@ Knuths LR(1) parser construction technique.")
(wrap-program (string-append #$output "/bin/" "binsec") (wrap-program (string-append #$output "/bin/" "binsec")
`("OCAMLPATH" ":" prefix ,ocamlpath)))))))) `("OCAMLPATH" ":" prefix ,ocamlpath))))))))
(inputs (list bash-minimal)) (inputs (list bash-minimal))
(native-inputs (list gmp ocaml-qcheck ocaml-ounit2)) (native-inputs (list gmp ocaml-qcheck ocaml-ounit2 z3))
(propagated-inputs (list dune-site (propagated-inputs (list dune-site
ocaml-base ocaml-base
ocaml-menhir ocaml-menhir
ocaml-graph ocaml-graph
ocaml-zarith ocaml-zarith
ocaml-grain-dypgen ocaml-grain-dypgen
ocaml-toml)) ocaml-toml
ocaml-z3))
(synopsis "Binary-level analysis platform") (synopsis "Binary-level analysis platform")
(description (description
"BINSEC is a binary analysis platform which implements analysis "BINSEC is a binary analysis platform which implements analysis

View file

@ -1931,7 +1931,7 @@ This package just includes the agent component.")))
(define-public guix-jupyter (define-public guix-jupyter
(package (package
(name "guix-jupyter") (name "guix-jupyter")
(version "0.3.0") (version "0.3.1")
(home-page "https://codeberg.org/guix-science/guix-jupyter") (home-page "https://codeberg.org/guix-science/guix-jupyter")
(source (origin (source (origin
(method git-fetch) (method git-fetch)
@ -1939,7 +1939,7 @@ This package just includes the agent component.")))
(commit (string-append "v" version)))) (commit (string-append "v" version))))
(sha256 (sha256
(base32 (base32
"0cvjxv60la2bqmwb7m2bfpvjy8hx1hmjk2qy9wfzaffcabgr0x44")) "1yvrmaj4qcb9vn2nfjz1q0cil830hvmxpp8cgi76aylbnv36aask"))
(file-name (string-append "guix-jupyter-" version "-checkout")))) (file-name (string-append "guix-jupyter-" version "-checkout"))))
(build-system gnu-build-system) (build-system gnu-build-system)
(arguments (arguments

View file

@ -185,7 +185,7 @@ it.")
(define-public trealla (define-public trealla
(package (package
(name "trealla") (name "trealla")
(version "2.83.8") (version "2.83.9")
(source (source
(origin (origin
(method git-fetch) (method git-fetch)
@ -194,7 +194,7 @@ it.")
(url "https://github.com/trealla-prolog/trealla") (url "https://github.com/trealla-prolog/trealla")
(commit (string-append "v" version)))) (commit (string-append "v" version))))
(sha256 (sha256
(base32 "1bpfzrwsgbmjl1maiaw5b8ixkgh548gw1lkiznsjgkjm7dxr4ns4")) (base32 "01gxml7g6qf185pa51v8vrsv1m42b3dz5rcnyqf7ic041s6p9bwl"))
(file-name (git-file-name name version)))) (file-name (git-file-name name version))))
(build-system gnu-build-system) (build-system gnu-build-system)
(native-inputs (native-inputs

View file

@ -5294,7 +5294,10 @@ WebSocket usage in Python programs.")
(method url-fetch) (method url-fetch)
(uri (pypi-uri "websocket-client" version)) (uri (pypi-uri "websocket-client" version))
(sha256 (sha256
(base32 "0p0cz2mdissq7iw1n7jrmsfir0jfmgs1dvnpnrx477ffx9hbsxnk")))))) (base32 "0p0cz2mdissq7iw1n7jrmsfir0jfmgs1dvnpnrx477ffx9hbsxnk"))))
(native-inputs
(modify-inputs (package-native-inputs python-websocket-client)
(append python-six)))))
(define-public python-purl (define-public python-purl
(package (package

View file

@ -4809,6 +4809,31 @@ Unicode-to-LaTeX conversion.")
@code{subprocess} feature.") @code{subprocess} feature.")
(license license:expat))) (license license:expat)))
;; Old version just for python-dotenv-0.13.0 for docker-compose; remove once
;; that is updated.
(define-public python-sh-1
(package
(inherit python-sh)
(version "1.14.2")
(source
(origin
(method url-fetch)
(uri (pypi-uri "sh" version))
(sha256
(base32
"03gyss1rhj4in7pgysg4q0hxp3230whinlpy1532ljs99lrx0ywx"))))
;(build-system python-build-system)
(arguments
'(#:phases
(modify-phases %standard-phases
(replace 'check
(lambda _
;; XXX: A Python 2 test fails when HOME=/homeless-shelter.
(setenv "HOME" "/tmp")
(invoke "python" "sh.py" "test"))))))
(native-inputs
(list python-setuptools))))
(define-public python-cftime (define-public python-cftime
(package (package
(name "python-cftime") (name "python-cftime")
@ -20156,18 +20181,22 @@ and dataclasses.")
(define-public python-argparse-manpage (define-public python-argparse-manpage
(package (package
(name "python-argparse-manpage") (name "python-argparse-manpage")
(version "4.5") (version "4.7")
(source (source
(origin (origin
(method url-fetch) (method url-fetch)
(uri (pypi-uri "argparse-manpage" version)) (uri (pypi-uri "argparse_manpage" version))
(sha256 (sha256
(base32 (base32 "0clb20scp408gxac675v731vnj89pk9d5fb7pcy7bj1a45mvgshx"))))
"1nq4sq1zk1xzdsqq61hd27jhj978ys136aba1zjg02x1g0c0cg11"))))
(build-system pyproject-build-system) (build-system pyproject-build-system)
(arguments
(list
#:test-flags
;; Tests require PIP.
#~(list "--ignore=tests/test_examples.py")))
(native-inputs (native-inputs
(list python-pip python-pytest python-setuptools python-tomli (list python-pytest
python-wheel)) python-setuptools))
(home-page "https://github.com/praiskup/argparse-manpage") (home-page "https://github.com/praiskup/argparse-manpage")
(synopsis "Build manual page from Python's ArgumentParser object") (synopsis "Build manual page from Python's ArgumentParser object")
(description (description
@ -36879,6 +36908,35 @@ systems in Python.")
key-value pairs from a @code{.env} file and set them as environment variables.") key-value pairs from a @code{.env} file and set them as environment variables.")
(license license:bsd-3))) (license license:bsd-3)))
;; Old version just for docker-compose; remove once that is updated.
(define-public python-dotenv-0.13.0
(package (inherit python-dotenv)
(name "python-dotenv")
(version "0.13.0")
(source
(origin
(method url-fetch)
(uri (pypi-uri "python-dotenv" version))
(sha256
(base32
"0x5dagmfn31phrbxlwacw3s4w5vibv8fxqc62nqcdvdhjsy0k69v"))))
(arguments
`(#:phases
(modify-phases %standard-phases
(replace 'check
(lambda* (#:key tests? inputs outputs #:allow-other-keys)
(when tests?
(add-installed-pythonpath inputs outputs)
(setenv "PATH" (string-append (getenv "PATH") ":"
(assoc-ref outputs "out") "/bin"))
;; Skip the ipython tests.
(delete-file "tests/test_ipython.py")
(invoke "python" "-m" "pytest")))))))
(native-inputs
(modify-inputs (package-native-inputs python-dotenv)
(append python-mock)
(replace "python-sh" python-sh-1)))))
(define-public date2name (define-public date2name
(let ((commit "6c8f37277e8ec82aa50f90b8921422be30c4e798") (let ((commit "6c8f37277e8ec82aa50f90b8921422be30c4e798")
(revision "1")) (revision "1"))

View file

@ -19,6 +19,7 @@
;;; Copyright © 2023 Miguel Ángel Moreno <mail@migalmoreno.com> ;;; Copyright © 2023 Miguel Ángel Moreno <mail@migalmoreno.com>
;;; Copyright © 2024 Leo Nikkilä <hello@lnikki.la> ;;; Copyright © 2024 Leo Nikkilä <hello@lnikki.la>
;;; Copyright © 2025 Maxim Cournoyer <maxim.cournoyer@gmail.com> ;;; Copyright © 2025 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2025 Rodion Goritskov <rodion@goritskov.com>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -40,8 +41,10 @@
#:use-module (gnu services shepherd) #:use-module (gnu services shepherd)
#:use-module (gnu services admin) #:use-module (gnu services admin)
#:use-module (gnu services configuration) #:use-module (gnu services configuration)
#:use-module (gnu services databases)
#:use-module (gnu services getmail) #:use-module (gnu services getmail)
#:use-module (gnu services mail) #:use-module (gnu services mail)
#:use-module (gnu system file-systems)
#:use-module (gnu system pam) #:use-module (gnu system pam)
#:use-module (gnu system shadow) #:use-module (gnu system shadow)
#:use-module (gnu packages admin) #:use-module (gnu packages admin)
@ -59,7 +62,9 @@
#:use-module (gnu packages mail) #:use-module (gnu packages mail)
#:use-module (gnu packages rust-apps) #:use-module (gnu packages rust-apps)
#:autoload (guix i18n) (G_) #:autoload (guix i18n) (G_)
#:autoload (gnu build linux-container) (%namespaces)
#:use-module (guix diagnostics) #:use-module (guix diagnostics)
#:use-module (guix least-authority)
#:use-module (guix packages) #:use-module (guix packages)
#:use-module (guix records) #:use-module (guix records)
#:use-module (guix modules) #:use-module (guix modules)
@ -74,6 +79,7 @@
#:use-module (srfi srfi-34) #:use-module (srfi srfi-34)
#:use-module (ice-9 match) #:use-module (ice-9 match)
#:use-module (ice-9 format) #:use-module (ice-9 format)
#:use-module (ice-9 regex)
#:export (httpd-configuration #:export (httpd-configuration
httpd-configuration? httpd-configuration?
httpd-configuration-package httpd-configuration-package
@ -328,7 +334,23 @@
agate-configuration-group agate-configuration-group
agate-configuration-log-file agate-configuration-log-file
agate-service-type)) agate-service-type
miniflux-configuration
miniflux-configuration?
miniflux-configuration-listen-address
miniflux-configuration-base-url
miniflux-configuration-create-administrator-account?
miniflux-configuration-administrator-account-name
miniflux-configuration-administrator-account-password
miniflux-configuration-run-migrations?
miniflux-configuration-database-url
miniflux-configuration-user
miniflux-configuration-group
miniflux-configuration-log-file
miniflux-configuration-extra-settings
miniflux-service-type))
;;; Commentary: ;;; Commentary:
;;; ;;;
@ -2279,3 +2301,173 @@ root=/srv/gemini
(default-value (agate-configuration)) (default-value (agate-configuration))
(description "Run Agate, a simple Gemini protocol server written in (description "Run Agate, a simple Gemini protocol server written in
Rust."))) Rust.")))
(define (serialize-string field-name val)
(format #f "~a=~a\n" field-name val))
(define (string-or-file-path? val)
(string? val))
(define (serialize-string-or-file-path field-name val)
(serialize-string (if (absolute-file-name? val)
(format #f "~a_FILE" field-name) field-name) val))
(define-maybe string-or-file-path)
(define (serialize-list field-name val)
(string-append (string-join val "\n") "\n"))
(define-maybe list)
(define (serialize-boolean field-name val)
(if val (serialize-string field-name "1") (serialize-string field-name "0")))
(define-configuration/no-serialization miniflux-configuration
(listen-address
(string "127.0.0.1:8080")
"Address to listen on.
Use absolute path like @code{\"/var/run/miniflux/miniflux.sock\"} for a Unix socket.")
(base-url
(string "http://127.0.0.1/")
"Base URL to generate HTML links and base path for cookies.")
(create-administrator-account?
(boolean #f)
"Create an initial administrator account.")
(administrator-account-name
maybe-string-or-file-path
"Initial administrator account name as a string or an absolute path to a file with a account name inside.")
(administrator-account-password
maybe-string-or-file-path
"Initial administrator account password as a string or an absolute path to a file with a password inside.")
(run-migrations?
(boolean #t)
"Run database migrations during application startup.")
(database-url
(string "host=/var/run/postgresql")
"PostgreSQL connection string.")
(user
(string "miniflux")
"User name for Postgresql and system account.")
(group
(string "miniflux")
"Group for the system account.")
(log-file
(string "/var/log/miniflux.log")
"Path to the log file.")
(extra-settings
maybe-list
"Extra configuration parameters as a list of strings."))
(define (miniflux-serialize-configuration config)
(match-record config <miniflux-configuration>
(listen-address base-url create-administrator-account?
administrator-account-name administrator-account-password
run-migrations? database-url extra-settings)
(string-append (serialize-string "LISTEN_ADDR" listen-address)
(serialize-string "BASE_URL" base-url)
(serialize-boolean "CREATE_ADMIN" create-administrator-account?)
(serialize-maybe-string-or-file-path "ADMIN_USERNAME" administrator-account-name)
(serialize-maybe-string-or-file-path "ADMIN_PASSWORD" administrator-account-password)
(serialize-boolean "RUN_MIGRATIONS" run-migrations?)
(serialize-string "DATABASE_URL" database-url)
(serialize-maybe-list #f extra-settings))))
(define (miniflux-configuration-file config)
(mixed-text-file "miniflux.conf" (miniflux-serialize-configuration config)))
(define (pair->file-system-mapping pair previous)
(if (pair? pair)
(let ((path (car pair))
(writable (cdr pair)))
(if (or (and (string? path)
(absolute-file-name? path))
(computed-file? path))
(append previous (list (file-system-mapping
(source path)
(target source)
(writable? writable))))
previous))
previous))
(define (miniflux-shepherd-service config)
(match-record config <miniflux-configuration>
(user group log-file database-url listen-address
administrator-account-name administrator-account-password)
(let ((config-file (miniflux-configuration-file config)))
(list (shepherd-service
(documentation "Run Miniflux server")
(provision '(miniflux))
(requirement '(postgres networking))
(start #~(make-forkexec-constructor
(list #$(least-authority-wrapper
(file-append miniflux "/bin/miniflux")
#:name "miniflux"
#:user user
#:group group
#:preserved-environment-variables
(append %default-preserved-environment-variables
'("SSL_CERT_FILE"))
#:mappings
(fold pair->file-system-mapping
'()
`((,log-file . #t)
(,config-file . #f)
("/etc/ssl/certs/ca-certificates.crt" . #f)
(,administrator-account-name . #f)
(,administrator-account-password . #f)
(,(dirname listen-address) . #t)
,(let* ((db-socket-match (string-match ".*host=(/[^ ]*).*" database-url))
(db-socket (if db-socket-match (match:substring db-socket-match 1) #f)))
(if db-socket
`(,db-socket . #t)))))
#:namespaces
(fold delq %namespaces '(net user)))
"-config-file"
#$config-file)
#:log-file #$log-file))
(stop #~(make-kill-destructor)))))))
(define (miniflux-accounts config)
(match-record config <miniflux-configuration>
(user group)
`(,(user-group
(name group)
(system? #t))
,(user-account
(name user)
(group group)
(system? #t)
(comment "miniflux server user")
(home-directory "/var/empty")
(shell (file-append shadow "/sbin/nologin"))))))
(define (miniflux-postgresql-role config)
(list (postgresql-role
(name (miniflux-configuration-user config))
(create-database? #t))))
(define (miniflux-log-files config)
(list (miniflux-configuration-log-file config)))
(define (miniflux-activation-service-type config)
(match-record config <miniflux-configuration>
(user listen-address)
#~(begin
(use-modules (gnu build activation))
(let ((user (getpwnam #$user)))
(if (absolute-file-name? #$listen-address)
(mkdir-p/perms (dirname #$listen-address) user #o755))))))
(define miniflux-service-type
(service-type
(name 'miniflux)
(default-value (miniflux-configuration))
(extensions
(list (service-extension account-service-type
miniflux-accounts)
(service-extension postgresql-role-service-type
miniflux-postgresql-role)
(service-extension shepherd-root-service-type
miniflux-shepherd-service)
(service-extension log-rotation-service-type
miniflux-log-files)
(service-extension activation-service-type
miniflux-activation-service-type)))
(description "Run Miniflux, minimalist feed reader")))

View file

@ -5,6 +5,7 @@
;;; Copyright © 2018 Pierre-Antoine Rouby <pierre-antoine.rouby@inria.fr> ;;; Copyright © 2018 Pierre-Antoine Rouby <pierre-antoine.rouby@inria.fr>
;;; Copyright © 2018 Marius Bakke <mbakke@fastmail.com> ;;; Copyright © 2018 Marius Bakke <mbakke@fastmail.com>
;;; Copyright © 2024 Maxim Cournoyer <maxim@guixotic.coop> ;;; Copyright © 2024 Maxim Cournoyer <maxim@guixotic.coop>
;;; Copyright © 2025 Rodion Goritskov <rodion@goritskov.com>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -37,6 +38,7 @@
#:use-module (gnu packages base) #:use-module (gnu packages base)
#:use-module (gnu packages databases) #:use-module (gnu packages databases)
#:use-module (gnu packages guile-xyz) #:use-module (gnu packages guile-xyz)
#:use-module (gnu packages gnupg)
#:use-module (gnu packages patchutils) #:use-module (gnu packages patchutils)
#:use-module (gnu packages python) #:use-module (gnu packages python)
#:use-module (gnu packages tls) #:use-module (gnu packages tls)
@ -56,7 +58,10 @@
%test-hpcguix-web %test-hpcguix-web
%test-anonip %test-anonip
%test-patchwork %test-patchwork
%test-agate)) %test-agate
%test-miniflux-admin-string
%test-miniflux-admin-file
%test-miniflux-socket))
(define %index.html-contents (define %index.html-contents
;; Contents of the /index.html file. ;; Contents of the /index.html file.
@ -848,3 +853,190 @@ HTTP-PORT."
(name "agate") (name "agate")
(description "Connect to a running Agate service.") (description "Connect to a running Agate service.")
(value (run-agate-test name %agate-os %index.gmi-contents)))) (value (run-agate-test name %agate-os %index.gmi-contents))))
;;;
;;; Miniflux
;;;
(define %miniflux-create-admin-credentials
#~(begin
(mkdir "/var/miniflux")
(call-with-output-file "/var/miniflux/admin-username"
(lambda (port)
(display "test" port)))
(call-with-output-file "/var/miniflux/admin-password"
(lambda (port)
(display "testpassword" port)))))
(define miniflux-base-system
(lambda (miniflux-config)
(simple-operating-system
(simple-service 'create-admin-credentials
activation-service-type
%miniflux-create-admin-credentials)
(service dhcpcd-service-type)
(service postgresql-service-type
(postgresql-configuration
(postgresql postgresql-13)))
(service miniflux-service-type
miniflux-config))))
(define %miniflux-with-admin-as-string
(miniflux-base-system
(miniflux-configuration
(listen-address "0.0.0.0:8080")
(create-administrator-account? #t)
(administrator-account-name "test")
(administrator-account-password "testpassword"))))
(define %miniflux-with-admin-as-file
(miniflux-base-system
(miniflux-configuration
(listen-address "0.0.0.0:8080")
(create-administrator-account? #t)
(administrator-account-name "/var/miniflux/admin-username")
(administrator-account-password "/var/miniflux/admin-password"))))
(define %miniflux-with-socket
(miniflux-base-system
(miniflux-configuration
(listen-address "/var/run/miniflux/miniflux.sock"))))
(define* (run-miniflux-test name test-os)
(define os
(marionette-operating-system
test-os
#:imported-modules '((gnu services herd)
(guix combinators))))
(define forwarded-port 8080)
(define vm
(virtual-machine
(operating-system os)
(memory-size 512)
(port-forwardings `((8080 . ,forwarded-port)))))
(define test
(with-extensions (list guile-gcrypt)
(with-imported-modules '((gnu build marionette))
#~(begin
(use-modules (srfi srfi-64)
(srfi srfi-11)
(gnu build marionette)
(web client)
(web uri)
(web response)
(ice-9 match)
(ice-9 iconv)
(gcrypt base64))
(define marionette
(make-marionette (list #$vm)))
(test-runner-current (system-test-runner #$output))
(test-begin #$name)
(test-assert "Check Miniflux service is running"
(begin
(#$retry-on-error
(lambda ()
(marionette-eval
'(begin
(use-modules (gnu services herd))
(match (start-service '#$(string->symbol "miniflux"))
(#f #f)
(('service response-parts ...)
(match (assq-ref response-parts 'running)
(#f #f)
((running) #t)))))
marionette))
#:delay 1
#:times 10)))
(test-assert "Miniflux TCP port ready, IPv4"
(wait-for-tcp-port #$forwarded-port marionette))
(test-assert "Miniflux login page is opened"
(begin
(wait-for-tcp-port #$forwarded-port marionette)
(#$retry-on-error
(lambda ()
(let-values (((_ text)
(http-get
#$(format #f "http://localhost:~A/" forwarded-port)
#:decode-body? #t)))
(string-contains text "<title>Sign In - Miniflux</title>")))
#:times 10
#:delay 2)))
(define authorization-header
(let ((encoded (base64-encode (string->bytevector "test:testpassword" "utf-8"))))
`(authorization . (basic . ,encoded))))
(test-equal "Miniflux initial admin API call is successful"
200
(begin
(wait-for-tcp-port #$forwarded-port marionette)
(#$retry-on-error
(lambda ()
(let-values (((response _)
(http-get #$(format #f "http://localhost:~A/v1/me" forwarded-port)
#:headers (list authorization-header)
#:decode-body? #t)))
(response-code response)))
#:times 10
#:delay 2)))
(test-end)))))
(gexp->derivation (string-append name "-test") test))
(define* (run-miniflux-socket-test name test-os)
(define os
(marionette-operating-system
test-os
#:imported-modules '((gnu services herd)
(guix combinators))))
(define vm
(virtual-machine
(operating-system os)
(memory-size 512)))
(define test
(with-imported-modules '((gnu build marionette))
#~(begin
(use-modules (srfi srfi-64)
(gnu build marionette))
(define marionette
(make-marionette (list #$vm)))
(test-runner-current (system-test-runner #$output))
(test-begin #$name)
(test-assert "Check socket file is created"
(wait-for-unix-socket "/var/run/miniflux/miniflux.sock" marionette))
(test-end))))
(gexp->derivation (string-append name "-test") test))
(define %test-miniflux-admin-string
(system-test
(name "miniflux-admin-string")
(description "Run Miniflux with initial admin credentials as string.")
(value (run-miniflux-test name %miniflux-with-admin-as-string))))
(define %test-miniflux-admin-file
(system-test
(name "miniflux-admin-file")
(description "Run Miniflux with initial admin credentials as file.")
(value (run-miniflux-test name %miniflux-with-admin-as-file))))
(define %test-miniflux-socket
(system-test
(name "miniflux-socket")
(description "Run Miniflux on unix socket.")
(value (run-miniflux-socket-test name %miniflux-with-socket))))