forked from tribes/guix
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 89a8bd9257 | |||
| f99f4a2257 | |||
| 02874b2a43 |
+27
-50
@@ -6,33 +6,39 @@
|
||||
(sentence-end-double-space . t)
|
||||
|
||||
;; For use with 'bug-reference-prog-mode'.
|
||||
(bug-reference-url-format . "http://bugs.gnu.org/%s")
|
||||
(bug-reference-bug-regexp
|
||||
. "\\(<https?://\\bugs\\.gnu\\.org/\\([0-9]+\\)>\\)")
|
||||
(bug-reference-url-format . "https://bugs.gnu.org/%s")
|
||||
|
||||
(eval . (add-to-list 'completion-ignored-extensions ".go"))
|
||||
. "<https?://\\(debbugs\\|bugs\\)\\.gnu\\.org/\\([0-9]+\\)>")
|
||||
|
||||
;; Emacs-Guix
|
||||
(eval . (setq-local guix-directory
|
||||
(locate-dominating-file default-directory
|
||||
".dir-locals.el")))
|
||||
|
||||
;; YASnippet
|
||||
(eval . (with-eval-after-load
|
||||
'yasnippet
|
||||
(let ((guix-yasnippets
|
||||
(expand-file-name
|
||||
"etc/snippets/yas"
|
||||
(locate-dominating-file default-directory
|
||||
".dir-locals.el"))))
|
||||
(unless (member guix-yasnippets yas-snippet-dirs)
|
||||
(add-to-list 'yas-snippet-dirs guix-yasnippets)
|
||||
(yas-reload-all)))))
|
||||
|
||||
;; Geiser
|
||||
;; This allows automatically setting the `geiser-guile-load-path'
|
||||
;; variable when using various Guix checkouts (e.g., via git worktrees).
|
||||
(geiser-repl-per-project-p . t)))
|
||||
(eval . (let ((root-dir-unexpanded (locate-dominating-file
|
||||
default-directory ".dir-locals.el")))
|
||||
;; While Guix should in theory always have a .dir-locals.el
|
||||
;; (we are reading this file, after all) there seems to be a
|
||||
;; strange problem where this code "escapes" to some other buffers,
|
||||
;; at least vc-mode. See:
|
||||
;; https://lists.gnu.org/archive/html/guix-devel/2020-11/msg00296.html
|
||||
;; Upstream report: <https://bugs.gnu.org/44698>
|
||||
;; Hence the following "when", which might otherwise be unnecessary;
|
||||
;; it prevents causing an error when root-dir-unexpanded is nil.
|
||||
(when root-dir-unexpanded
|
||||
(let* ((root-dir (expand-file-name root-dir-unexpanded))
|
||||
;; Workaround for bug https://issues.guix.gnu.org/43818.
|
||||
(root-dir* (directory-file-name root-dir)))
|
||||
|
||||
(unless (boundp 'geiser-guile-load-path)
|
||||
(defvar geiser-guile-load-path '()))
|
||||
(make-local-variable 'geiser-guile-load-path)
|
||||
(require 'cl-lib)
|
||||
(cl-pushnew root-dir* geiser-guile-load-path
|
||||
:test #'string-equal)))))))
|
||||
|
||||
(c-mode . ((c-file-style . "gnu")))
|
||||
(scheme-mode
|
||||
@@ -41,7 +47,7 @@
|
||||
(eval . (put 'eval-when 'scheme-indent-function 1))
|
||||
(eval . (put 'call-with-prompt 'scheme-indent-function 1))
|
||||
(eval . (put 'test-assert 'scheme-indent-function 1))
|
||||
(eval . (put 'test-assertm 'scheme-indent-function 2))
|
||||
(eval . (put 'test-assertm 'scheme-indent-function 1))
|
||||
(eval . (put 'test-equalm 'scheme-indent-function 1))
|
||||
(eval . (put 'test-equal 'scheme-indent-function 1))
|
||||
(eval . (put 'test-eq 'scheme-indent-function 1))
|
||||
@@ -50,11 +56,7 @@
|
||||
(eval . (put 'guard 'scheme-indent-function 1))
|
||||
(eval . (put 'lambda* 'scheme-indent-function 1))
|
||||
(eval . (put 'substitute* 'scheme-indent-function 1))
|
||||
(eval . (put 'match-record 'scheme-indent-function 3))
|
||||
(eval . (put 'match-record-lambda 'scheme-indent-function 2))
|
||||
|
||||
;; TODO: Contribute these to Emacs' scheme-mode.
|
||||
(eval . (put 'let-keywords 'scheme-indent-function 3))
|
||||
(eval . (put 'match-record 'scheme-indent-function 2))
|
||||
|
||||
;; 'modify-inputs' and its keywords.
|
||||
(eval . (put 'modify-inputs 'scheme-indent-function 1))
|
||||
@@ -78,6 +80,7 @@
|
||||
(eval . (put 'origin 'scheme-indent-function 0))
|
||||
(eval . (put 'build-system 'scheme-indent-function 0))
|
||||
(eval . (put 'bag 'scheme-indent-function 0))
|
||||
(eval . (put 'gexp->derivation 'scheme-indent-function 1))
|
||||
(eval . (put 'graft 'scheme-indent-function 0))
|
||||
(eval . (put 'operating-system 'scheme-indent-function 0))
|
||||
(eval . (put 'file-system 'scheme-indent-function 0))
|
||||
@@ -115,11 +118,9 @@
|
||||
(eval . (put 'munless 'scheme-indent-function 1))
|
||||
(eval . (put 'mlet* 'scheme-indent-function 2))
|
||||
(eval . (put 'mlet 'scheme-indent-function 2))
|
||||
(eval . (put 'mparameterize 'scheme-indent-function 2))
|
||||
(eval . (put 'run-with-store 'scheme-indent-function 1))
|
||||
(eval . (put 'run-with-state 'scheme-indent-function 1))
|
||||
(eval . (put 'wrap-program 'scheme-indent-function 1))
|
||||
(eval . (put 'wrap-script 'scheme-indent-function 1))
|
||||
(eval . (put 'with-imported-modules 'scheme-indent-function 1))
|
||||
(eval . (put 'with-extensions 'scheme-indent-function 1))
|
||||
(eval . (put 'with-parameters 'scheme-indent-function 1))
|
||||
@@ -154,31 +155,7 @@
|
||||
;; preceding symbol is one of these.
|
||||
(eval . (modify-syntax-entry ?~ "'"))
|
||||
(eval . (modify-syntax-entry ?$ "'"))
|
||||
(eval . (modify-syntax-entry ?+ "'"))
|
||||
|
||||
;; Emacs 28 changed the behavior of 'lisp-fill-paragraph', which causes the
|
||||
;; first line of package descriptions to extrude past 'fill-column', and
|
||||
;; somehow that is deemed more correct upstream (see:
|
||||
;; https://issues.guix.gnu.org/56197).
|
||||
(eval . (progn
|
||||
(require 'lisp-mode)
|
||||
(defun emacs27-lisp-fill-paragraph (&optional justify)
|
||||
(interactive "P")
|
||||
(or (fill-comment-paragraph justify)
|
||||
(let ((paragraph-start
|
||||
(concat paragraph-start
|
||||
"\\|\\s-*\\([(;\"]\\|\\s-:\\|`(\\|#'(\\)"))
|
||||
(paragraph-separate
|
||||
(concat paragraph-separate "\\|\\s-*\".*[,\\.]$"))
|
||||
(fill-column (if (and (integerp emacs-lisp-docstring-fill-column)
|
||||
(derived-mode-p 'emacs-lisp-mode))
|
||||
emacs-lisp-docstring-fill-column
|
||||
fill-column)))
|
||||
(fill-paragraph justify))
|
||||
;; Never return nil.
|
||||
t))
|
||||
(setq-local fill-paragraph-function #'emacs27-lisp-fill-paragraph)))))
|
||||
|
||||
(eval . (modify-syntax-entry ?+ "'"))))
|
||||
(emacs-lisp-mode . ((indent-tabs-mode . nil)))
|
||||
(texinfo-mode . ((indent-tabs-mode . nil)
|
||||
(fill-column . 72))))
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*.{c,h,cpp,hpp,el,scm,ac,am,m4,po}{,.in}]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{c,h,cpp,hpp,ac,am,m4,el,scm}{,.in}]
|
||||
max_line_length = 85
|
||||
|
||||
[*.{c,h,cpp,hpp,ac,m4,el,scm}{,.in}]
|
||||
indent_style = space
|
||||
|
||||
[*.{c,h,cpp,hpp}{,.in}]
|
||||
indent_size = 4
|
||||
@@ -68,7 +68,6 @@
|
||||
/doc/version.texi
|
||||
/doc/version-*.texi
|
||||
/etc/committer.scm
|
||||
/etc/teams.scm
|
||||
/etc/gnu-store.mount
|
||||
/etc/guix-daemon.cil
|
||||
/etc/guix-daemon.conf
|
||||
@@ -158,5 +157,3 @@ tmp
|
||||
/gnu/packages/bootstrap
|
||||
/gnu/packages/aux-files/guile-guile-launcher.o
|
||||
/guile
|
||||
.DS_Store
|
||||
.mumi/current-issue
|
||||
+21
-20
@@ -4,13 +4,12 @@
|
||||
(authorizations
|
||||
(version 0)
|
||||
|
||||
(;; primary: "D963 A5A3 8A80 3D52 4461 F914 7483 0A27 6C32 8EC2"
|
||||
("2841 9AC6 5038 7440 C7E9 2FFA 2208 D209 58C1 DEB0"
|
||||
(name "abcdw"))
|
||||
(("AD17 A21E F8AE D8F1 CC02 DBD9 F7D5 C9BF 765C 61E3"
|
||||
(name "andreas"))
|
||||
("4FB9 9F49 2B12 A365 7997 E664 8246 0C08 2A0E E98F"
|
||||
(name "alezost"))
|
||||
("50F3 3E2E 5B0C 3D90 0424 ABE8 9BDC F497 A4BB CC7F"
|
||||
(name "ambrevar"))
|
||||
("AD17 A21E F8AE D8F1 CC02 DBD9 F7D5 C9BF 765C 61E3"
|
||||
(name "andreas"))
|
||||
("27D5 86A4 F890 0854 329F F09F 1260 E464 82E6 3562"
|
||||
(name "apteryx"))
|
||||
("7F73 0343 F2F0 9F3C 77BF 79D3 2E25 EE8B 6180 2BB3"
|
||||
@@ -18,6 +17,9 @@
|
||||
(;; primary: "34FF 38BC D151 25A6 E340 A0B5 3453 2F9F AFCA 8B8E"
|
||||
"A3A4 B419 0074 087C A7DE 5698 BC45 CA67 E2F8 D007"
|
||||
(name "bavier"))
|
||||
(;; primary: "8929 BBC5 73CD 9206 3DDD 979D 3D36 CAA0 116F 0F99"
|
||||
"1C9B F005 1A1A 6A44 5257 599A A949 03A1 66A1 8FAE"
|
||||
(name "bricewge"))
|
||||
(;; primary: "0401 7A2A 6D9A 0CCD C81D 8EC2 96AB 007F 1A7E D999"
|
||||
"09CD D25B 5244 A376 78F6 EEA8 0CC5 2153 1979 91A5"
|
||||
(name "carl"))
|
||||
@@ -30,16 +32,15 @@
|
||||
(;; primary: "295A F991 6F46 F8A1 34B0 29DA 8086 3842 F0FE D83B"
|
||||
"76CE C6B1 7274 B465 C02D B3D9 E71A 3554 2C30 BAA5"
|
||||
(name "dannym"))
|
||||
("8CCB A7F5 52B9 CBEA E1FB 2915 8328 C747 0FF1 D807"
|
||||
(name "dthompson"))
|
||||
("B3C0 DB4D AD73 BA5D 285E 19AE 5143 0234 CEFD 87C3"
|
||||
(name "davexunit"))
|
||||
("8CCB A7F5 52B9 CBEA E1FB 2915 8328 C747 0FF1 D807" ;FIXME: to be confirmed!
|
||||
(name "davexunit (2nd)"))
|
||||
("A28B F40C 3E55 1372 662D 14F7 41AA E7DC CA3D 8351"
|
||||
(name "efraim"))
|
||||
(;; primary: "2453 02B1 BAB1 F867 FDCA 96BC 8F3F 861F 82EB 7A9A"
|
||||
"CBC5 9C66 EC27 B971 7940 6B3E 6BE8 208A DF21 FE3F"
|
||||
(name "glv"))
|
||||
(;; primary: "220F 98D9 5E86 204C 0036 DA7B 6DEC 4360 408B 4185"
|
||||
"F4C2 D1DF 3FDE EA63 D1D3 0776 ACC6 6D09 CA52 8292"
|
||||
(name "hako"))
|
||||
("2219 43F4 9E9F 276F 9499 3382 BF28 6CB6 593E 5FFD"
|
||||
(name "hoebjo"))
|
||||
("B943 509D 633E 80DD 27FC 4EED 634A 8DFF D3F6 31DF"
|
||||
@@ -49,22 +50,22 @@
|
||||
(name "iyzsong"))
|
||||
("1A85 8392 E331 EAFD B8C2 7FFB F3C1 A0D9 C1D6 5273"
|
||||
(name "janneke"))
|
||||
("3B1D 7F19 E36B B60C 0F5B 2CA9 A52A A2B4 77B6 DD35"
|
||||
(name "jgart"))
|
||||
(;; primary: "1BA4 08C5 8BF2 0EA7 3179 635A 865D C0A3 DED9 B5D0"
|
||||
"E31D 9DDE EBA5 4A14 8A20 4550 DA45 97F9 47B4 1025"
|
||||
(name "jlicht"))
|
||||
("8141 6036 E81A 5CF7 8F80 1071 ECFC 8398 8B4E 4B9F"
|
||||
(name "jonsger"))
|
||||
("3924 8CD8 41C6 3CC3 36DC AF2F 505E 40B9 1617 1A8A"
|
||||
(name "jpoiret"))
|
||||
("017D 74E2 7F58 5696 3801 781D F663 943E 08D8 092A"
|
||||
(name "lbraun"))
|
||||
("CA4F 8CF4 37D7 478F DA05 5FD4 4213 7701 1A37 8446"
|
||||
(name "lbraun (professional)"))
|
||||
("ACC2 3BA0 59F7 CCF4 08F0 43AD 442A 84B8 C70E 2F87"
|
||||
(name "lilyp"))
|
||||
(;; primary: "4F71 6F9A 8FA2 C80E F1B5 E1BA 5E35 F231 DE1A C5E0"
|
||||
"B051 5948 F1E7 D3C1 B980 38A0 2646 FA30 BACA 7F08"
|
||||
(name "lfam"))
|
||||
("CBF5 9755 CBE7 E7EF EF18 3FB1 DD40 9A15 D822 469D"
|
||||
(name "marusich"))
|
||||
("BBB0 2DDF 2CEA F6A8 0D1D E643 A2A0 6DF2 A33A 54FA"
|
||||
(name "mbakke"))
|
||||
("D919 0965 CE03 199E AF28 B3BE 7CEF 2984 7562 C516"
|
||||
@@ -76,6 +77,8 @@
|
||||
(;; primary: "F5BC 5534 C36F 0087 B39D 36EF 1C9D C4FE B9DB 7C4B"
|
||||
"F5DA 2032 4B87 3D0B 7A38 7672 0DB0 FF88 4F55 6D79"
|
||||
(name "nckx"))
|
||||
("E576 BFB2 CF6E B13D F571 33B9 E315 A758 4613 1564"
|
||||
(name "niedzejkob"))
|
||||
("ED0E F1C8 E126 BA83 1B48 5FE9 DA00 B4F0 48E9 2F2D"
|
||||
(name "ngz"))
|
||||
("CEF4 CB91 4856 BA38 0A20 A7E2 3008 88CB 39C6 3817"
|
||||
@@ -83,9 +86,9 @@
|
||||
(;; primary: "41CA 12EA DE0C F33F 6885 A58F 5719 6E37 E00B 77FD"
|
||||
"72D5 3D81 8CB6 F4A1 7258 374C A8FC 9E44 7F4F 7D54"
|
||||
(name "planglois"))
|
||||
(;; primary: "7E9F 5BF6 1680 4367 127B 7A87 F9E6 9FB8 5A75 54F1"
|
||||
"A420 7B56 C255 109F 2CB3 157E 4990 97AE 5EA8 15D9"
|
||||
(name "podiki"))
|
||||
(;; primary: "B68B DF22 73F9 DA0E 63C1 8A32 515B F416 9242 D600"
|
||||
"C699 ED09 E51B CE89 FD1D A078 AAC7 E891 896B 568A"
|
||||
(name "pgarlick"))
|
||||
("CD2D 5EAA A98C CB37 DA91 D6B0 5F58 1664 7F8B E551"
|
||||
(name "raghavgururajan"))
|
||||
("BCA6 89B6 3655 3801 C3C6 2150 197A 5888 235F ACAC"
|
||||
@@ -107,6 +110,4 @@
|
||||
(name "vagrantc"))
|
||||
(;; primary: "C955 CC5D C048 7FB1 7966 40A9 199A F6A3 67E9 4ABB"
|
||||
"7238 7123 8EAC EB63 4548 5857 167F 8EA5 001A FA9C"
|
||||
(name "wigust"))
|
||||
("705A 29B7 01EE 410E B6F9 236E 92F1 D22C 608E E7E5"
|
||||
(name "zimoun"))))
|
||||
(name "wigust"))))
|
||||
|
||||
@@ -39,7 +39,6 @@ Joshua Grant <tadni@riseup.net> <gzg@riseup.net>
|
||||
Joshua Grant <tadni@riseup.net> <jgrant@parenthetical.io>
|
||||
Joshua Grant <tadni@riseup.net> <tadnimi@gmail.com>
|
||||
Joshua Grant <tadni@riseup.net> <youlysses@riseup.net>
|
||||
Juliana Sims <juli@incana.org> <jtsims@protonmail.com>
|
||||
Kei Kebreau <kkebreau@posteo.net>
|
||||
Leo Famulari <leo@famulari.name> <lfamular@gmail.com>
|
||||
Liliana Marie Prikler <liliana.prikler@gmail.com>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
((debbugs-host . "debbugs.gnu.org")
|
||||
(patch-email-address . "guix-patches@gnu.org")
|
||||
(mumi-host . "issues.guix.gnu.org"))
|
||||
@@ -1,10 +0,0 @@
|
||||
# This config file allows for Patchwork integration with
|
||||
# https://patches.guix-patches.cbaines.net/.
|
||||
|
||||
[settings]
|
||||
project: guix-patches
|
||||
patchwork_url: https://patches.guix-patches.cbaines.net
|
||||
add_signoff: False
|
||||
# TODO: enable check_patch
|
||||
check_patch: False
|
||||
ignore_bad_tags: True
|
||||
+59
-183
@@ -1,5 +1,5 @@
|
||||
# GNU Guix --- Functional package management for GNU
|
||||
# Copyright © 2012-2023 Ludovic Courtès <ludo@gnu.org>
|
||||
# Copyright © 2012-2022 Ludovic Courtès <ludo@gnu.org>
|
||||
# Copyright © 2013 Andreas Enge <andreas@enge.fr>
|
||||
# Copyright © 2015, 2017 Alex Kost <alezost@gmail.com>
|
||||
# Copyright © 2016, 2018 Mathieu Lirzin <mthl@gnu.org>
|
||||
@@ -7,14 +7,13 @@
|
||||
# Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
|
||||
# Copyright © 2017 Leo Famulari <leo@famulari.name>
|
||||
# Copyright © 2017 Ricardo Wurmus <rekado@elephly.net>
|
||||
# Copyright © 2017, 2020, 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
|
||||
# Copyright © 2017, 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||
# Copyright © 2017 Arun Isaac <arunisaac@systemreboot.net>
|
||||
# Copyright © 2018 Nikita <nikita@n0.is>
|
||||
# Copyright © 2018 Julien Lepiller <julien@lepiller.eu>
|
||||
# Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
|
||||
# Copyright © 2018 Alex Vong <alexvong1995@gmail.com>
|
||||
# Copyright © 2019 Efraim Flashner <efraim@flashner.co.il>
|
||||
# Copyright © 2020, 2021, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
# Copyright © 2021 Chris Marusich <cmmarusich@gmail.com>
|
||||
# Copyright © 2021 Andrew Tropin <andrew@trop.in>
|
||||
#
|
||||
@@ -98,6 +97,7 @@ MODULES = \
|
||||
guix/discovery.scm \
|
||||
guix/android-repo-download.scm \
|
||||
guix/bzr-download.scm \
|
||||
guix/extracting-download.scm \
|
||||
guix/git-download.scm \
|
||||
guix/hg-download.scm \
|
||||
guix/hash.scm \
|
||||
@@ -112,7 +112,6 @@ MODULES = \
|
||||
guix/derivations.scm \
|
||||
guix/grafts.scm \
|
||||
guix/repl.scm \
|
||||
guix/rpm.scm \
|
||||
guix/transformations.scm \
|
||||
guix/inferior.scm \
|
||||
guix/describe.scm \
|
||||
@@ -131,27 +130,16 @@ MODULES = \
|
||||
guix/cache.scm \
|
||||
guix/cve.scm \
|
||||
guix/workers.scm \
|
||||
guix/least-authority.scm \
|
||||
guix/read-print.scm \
|
||||
guix/ipfs.scm \
|
||||
guix/platform.scm \
|
||||
guix/platforms/arm.scm \
|
||||
guix/platforms/mips.scm \
|
||||
guix/platforms/powerpc.scm \
|
||||
guix/platforms/riscv.scm \
|
||||
guix/platforms/x86.scm \
|
||||
guix/build-system.scm \
|
||||
guix/build-system/agda.scm \
|
||||
guix/build-system/android-ndk.scm \
|
||||
guix/build-system/ant.scm \
|
||||
guix/build-system/cargo.scm \
|
||||
guix/build-system/channel.scm \
|
||||
guix/build-system/chicken.scm \
|
||||
guix/build-system/clojure.scm \
|
||||
guix/build-system/cmake.scm \
|
||||
guix/build-system/dub.scm \
|
||||
guix/build-system/dune.scm \
|
||||
guix/build-system/elm.scm \
|
||||
guix/build-system/emacs.scm \
|
||||
guix/build-system/font.scm \
|
||||
guix/build-system/go.scm \
|
||||
@@ -170,7 +158,6 @@ MODULES = \
|
||||
guix/build-system/maven.scm \
|
||||
guix/build-system/node.scm \
|
||||
guix/build-system/perl.scm \
|
||||
guix/build-system/pyproject.scm \
|
||||
guix/build-system/python.scm \
|
||||
guix/build-system/renpy.scm \
|
||||
guix/build-system/ocaml.scm \
|
||||
@@ -178,11 +165,9 @@ MODULES = \
|
||||
guix/build-system/waf.scm \
|
||||
guix/build-system/r.scm \
|
||||
guix/build-system/rakudo.scm \
|
||||
guix/build-system/rebar.scm \
|
||||
guix/build-system/ruby.scm \
|
||||
guix/build-system/scons.scm \
|
||||
guix/build-system/texlive.scm \
|
||||
guix/build-system/tree-sitter.scm \
|
||||
guix/build-system/trivial.scm \
|
||||
guix/ftp-client.scm \
|
||||
guix/http-client.scm \
|
||||
@@ -197,7 +182,6 @@ MODULES = \
|
||||
guix/diagnostics.scm \
|
||||
guix/ui.scm \
|
||||
guix/status.scm \
|
||||
guix/build/agda-build-system.scm \
|
||||
guix/build/android-ndk-build-system.scm \
|
||||
guix/build/ant-build-system.scm \
|
||||
guix/build/download.scm \
|
||||
@@ -208,7 +192,6 @@ MODULES = \
|
||||
guix/build/cmake-build-system.scm \
|
||||
guix/build/dub-build-system.scm \
|
||||
guix/build/dune-build-system.scm \
|
||||
guix/build/elm-build-system.scm \
|
||||
guix/build/emacs-build-system.scm \
|
||||
guix/build/meson-build-system.scm \
|
||||
guix/build/minify-build-system.scm \
|
||||
@@ -229,22 +212,18 @@ MODULES = \
|
||||
guix/build/minetest-build-system.scm \
|
||||
guix/build/node-build-system.scm \
|
||||
guix/build/perl-build-system.scm \
|
||||
guix/build/pyproject-build-system.scm \
|
||||
guix/build/python-build-system.scm \
|
||||
guix/build/ocaml-build-system.scm \
|
||||
guix/build/qt-build-system.scm \
|
||||
guix/build/r-build-system.scm \
|
||||
guix/build/renpy-build-system.scm \
|
||||
guix/build/rakudo-build-system.scm \
|
||||
guix/build/rebar-build-system.scm \
|
||||
guix/build/ruby-build-system.scm \
|
||||
guix/build/scons-build-system.scm \
|
||||
guix/build/texlive-build-system.scm \
|
||||
guix/build/tree-sitter-build-system.scm \
|
||||
guix/build/waf-build-system.scm \
|
||||
guix/build/haskell-build-system.scm \
|
||||
guix/build/julia-build-system.scm \
|
||||
guix/build/kconfig.scm \
|
||||
guix/build/linux-module-build-system.scm \
|
||||
guix/build/store-copy.scm \
|
||||
guix/build/json.scm \
|
||||
@@ -278,7 +257,6 @@ MODULES = \
|
||||
guix/import/cran.scm \
|
||||
guix/import/crate.scm \
|
||||
guix/import/egg.scm \
|
||||
guix/import/elm.scm \
|
||||
guix/import/elpa.scm \
|
||||
guix/import/gem.scm \
|
||||
guix/import/git.scm \
|
||||
@@ -287,7 +265,6 @@ MODULES = \
|
||||
guix/import/gnu.scm \
|
||||
guix/import/go.scm \
|
||||
guix/import/hackage.scm \
|
||||
guix/import/hexpm.scm \
|
||||
guix/import/json.scm \
|
||||
guix/import/kde.scm \
|
||||
guix/import/launchpad.scm \
|
||||
@@ -296,7 +273,6 @@ MODULES = \
|
||||
guix/import/print.scm \
|
||||
guix/import/pypi.scm \
|
||||
guix/import/stackage.scm \
|
||||
guix/import/test.scm \
|
||||
guix/import/texlive.scm \
|
||||
guix/import/utils.scm \
|
||||
guix/scripts.scm \
|
||||
@@ -306,7 +282,6 @@ MODULES = \
|
||||
guix/scripts/archive.scm \
|
||||
guix/scripts/import.scm \
|
||||
guix/scripts/package.scm \
|
||||
guix/scripts/locate.scm \
|
||||
guix/scripts/install.scm \
|
||||
guix/scripts/remove.scm \
|
||||
guix/scripts/upgrade.scm \
|
||||
@@ -324,25 +299,20 @@ MODULES = \
|
||||
guix/scripts/describe.scm \
|
||||
guix/scripts/style.scm \
|
||||
guix/scripts/system.scm \
|
||||
guix/scripts/system/edit.scm \
|
||||
guix/scripts/system/reconfigure.scm \
|
||||
guix/scripts/system/search.scm \
|
||||
guix/scripts/system/reconfigure.scm \
|
||||
guix/scripts/home.scm \
|
||||
guix/scripts/home/edit.scm \
|
||||
guix/scripts/home/import.scm \
|
||||
guix/scripts/lint.scm \
|
||||
guix/scripts/challenge.scm \
|
||||
guix/scripts/import/crate.scm \
|
||||
guix/scripts/import/cpan.scm \
|
||||
guix/scripts/import/cran.scm \
|
||||
guix/scripts/import/egg.scm \
|
||||
guix/scripts/import/elm.scm \
|
||||
guix/scripts/import/elpa.scm \
|
||||
guix/scripts/import/gem.scm \
|
||||
guix/scripts/import/gnu.scm \
|
||||
guix/scripts/import/go.scm \
|
||||
guix/scripts/import/hackage.scm \
|
||||
guix/scripts/import/hexpm.scm \
|
||||
guix/scripts/import/json.scm \
|
||||
guix/scripts/import/minetest.scm \
|
||||
guix/scripts/import/opam.scm \
|
||||
@@ -410,14 +380,10 @@ AUX_FILES = \
|
||||
gnu/packages/aux-files/chromium/master-preferences.json \
|
||||
gnu/packages/aux-files/emacs/guix-emacs.el \
|
||||
gnu/packages/aux-files/guix.vim \
|
||||
gnu/packages/aux-files/linux-libre/6.4-arm.conf \
|
||||
gnu/packages/aux-files/linux-libre/6.4-arm64.conf \
|
||||
gnu/packages/aux-files/linux-libre/6.4-i686.conf \
|
||||
gnu/packages/aux-files/linux-libre/6.4-x86_64.conf \
|
||||
gnu/packages/aux-files/linux-libre/6.1-arm.conf \
|
||||
gnu/packages/aux-files/linux-libre/6.1-arm64.conf \
|
||||
gnu/packages/aux-files/linux-libre/6.1-i686.conf \
|
||||
gnu/packages/aux-files/linux-libre/6.1-x86_64.conf \
|
||||
gnu/packages/aux-files/linux-libre/5.16-arm.conf \
|
||||
gnu/packages/aux-files/linux-libre/5.16-arm64.conf \
|
||||
gnu/packages/aux-files/linux-libre/5.16-i686.conf \
|
||||
gnu/packages/aux-files/linux-libre/5.16-x86_64.conf \
|
||||
gnu/packages/aux-files/linux-libre/5.15-arm.conf \
|
||||
gnu/packages/aux-files/linux-libre/5.15-arm64.conf \
|
||||
gnu/packages/aux-files/linux-libre/5.15-i686.conf \
|
||||
@@ -437,13 +403,15 @@ AUX_FILES = \
|
||||
gnu/packages/aux-files/linux-libre/4.14-arm.conf \
|
||||
gnu/packages/aux-files/linux-libre/4.14-i686.conf \
|
||||
gnu/packages/aux-files/linux-libre/4.14-x86_64.conf \
|
||||
gnu/packages/aux-files/linux-libre/4.9-i686.conf \
|
||||
gnu/packages/aux-files/linux-libre/4.9-x86_64.conf \
|
||||
gnu/packages/aux-files/linux-libre/4.4-i686.conf \
|
||||
gnu/packages/aux-files/linux-libre/4.4-x86_64.conf \
|
||||
gnu/packages/aux-files/pack-audit.c \
|
||||
gnu/packages/aux-files/python/sanity-check.py \
|
||||
gnu/packages/aux-files/python/sitecustomize.py \
|
||||
gnu/packages/aux-files/renpy/renpy.in \
|
||||
gnu/packages/aux-files/run-in-namespace.c \
|
||||
gnu/packages/aux-files/xml/patch-catalog-xml.xsl \
|
||||
gnu/packages/aux-files/xml/docbook-xml/catalog-4.1.2.xml
|
||||
gnu/packages/aux-files/run-in-namespace.c
|
||||
|
||||
# Templates, examples.
|
||||
EXAMPLES = \
|
||||
@@ -454,9 +422,6 @@ EXAMPLES = \
|
||||
gnu/system/examples/desktop.tmpl \
|
||||
gnu/system/examples/lightweight-desktop.tmpl \
|
||||
gnu/system/examples/docker-image.tmpl \
|
||||
gnu/system/examples/plasma.tmpl \
|
||||
gnu/system/examples/raspberry-pi-64.tmpl \
|
||||
gnu/system/examples/raspberry-pi-64-nfs-root.tmpl \
|
||||
gnu/system/examples/vm-image.tmpl
|
||||
|
||||
GOBJECTS = $(MODULES:%.scm=%.go) guix/config.go $(dist_noinst_DATA:%.scm=%.go)
|
||||
@@ -494,7 +459,6 @@ SCM_TESTS = \
|
||||
tests/boot-parameters.scm \
|
||||
tests/bournish.scm \
|
||||
tests/builders.scm \
|
||||
tests/build-emacs-utils.scm \
|
||||
tests/build-utils.scm \
|
||||
tests/cache.scm \
|
||||
tests/challenge.scm \
|
||||
@@ -510,7 +474,6 @@ SCM_TESTS = \
|
||||
tests/derivations.scm \
|
||||
tests/discovery.scm \
|
||||
tests/egg.scm \
|
||||
tests/elm.scm \
|
||||
tests/elpa.scm \
|
||||
tests/file-systems.scm \
|
||||
tests/gem.scm \
|
||||
@@ -524,7 +487,6 @@ SCM_TESTS = \
|
||||
tests/gremlin.scm \
|
||||
tests/hackage.scm \
|
||||
tests/home-import.scm \
|
||||
tests/home-services.scm \
|
||||
tests/http-client.scm \
|
||||
tests/import-git.scm \
|
||||
tests/import-github.scm \
|
||||
@@ -546,19 +508,14 @@ SCM_TESTS = \
|
||||
tests/profiles.scm \
|
||||
tests/publish.scm \
|
||||
tests/pypi.scm \
|
||||
tests/read-print.scm \
|
||||
tests/records.scm \
|
||||
tests/rpm.scm \
|
||||
tests/scripts.scm \
|
||||
tests/search-paths.scm \
|
||||
tests/services.scm \
|
||||
tests/services/file-sharing.scm \
|
||||
tests/services/configuration.scm \
|
||||
tests/services/lightdm.scm \
|
||||
tests/services/linux.scm \
|
||||
tests/services/pam-mount.scm \
|
||||
tests/services/telephony.scm \
|
||||
tests/services/vpn.scm \
|
||||
tests/sets.scm \
|
||||
tests/size.scm \
|
||||
tests/status.scm \
|
||||
@@ -599,24 +556,19 @@ SH_TESTS = \
|
||||
tests/guix-gc.sh \
|
||||
tests/guix-git-authenticate.sh \
|
||||
tests/guix-hash.sh \
|
||||
tests/guix-locate.sh \
|
||||
tests/guix-pack.sh \
|
||||
tests/guix-pack-localstatedir.sh \
|
||||
tests/guix-pack-relocatable.sh \
|
||||
tests/guix-package.sh \
|
||||
tests/guix-package-aliases.sh \
|
||||
tests/guix-package-net.sh \
|
||||
tests/guix-style.sh \
|
||||
tests/guix-system.sh \
|
||||
tests/guix-home.sh \
|
||||
tests/guix-archive.sh \
|
||||
tests/guix-authenticate.sh \
|
||||
tests/guix-environment.sh \
|
||||
tests/guix-environment-container.sh \
|
||||
tests/guix-refresh.sh \
|
||||
tests/guix-shell.sh \
|
||||
tests/guix-shell-export-manifest.sh \
|
||||
tests/guix-time-machine.sh \
|
||||
tests/guix-graph.sh \
|
||||
tests/guix-describe.sh \
|
||||
tests/guix-repl.sh \
|
||||
@@ -684,50 +636,48 @@ dist_fishcompletion_DATA = etc/completion/fish/guix.fish
|
||||
nodist_selinux_policy_DATA = etc/guix-daemon.cil
|
||||
|
||||
EXTRA_DIST += \
|
||||
.dir-locals.el \
|
||||
.guix-authorizations \
|
||||
.guix-channel \
|
||||
CODE-OF-CONDUCT \
|
||||
HACKING \
|
||||
ROADMAP \
|
||||
TODO \
|
||||
bootstrap \
|
||||
build-aux/build-self.scm \
|
||||
build-aux/check-channel-news.scm \
|
||||
build-aux/check-final-inputs-self-contained.scm \
|
||||
build-aux/compile-all.scm \
|
||||
build-aux/compile-as-derivation.scm \
|
||||
build-aux/config.rpath \
|
||||
build-aux/convert-xref.scm \
|
||||
build-aux/generate-authors.scm \
|
||||
build-aux/test-driver.scm \
|
||||
build-aux/update-NEWS.scm \
|
||||
build-aux/update-guix-package.scm \
|
||||
doc/build.scm \
|
||||
CODE-OF-CONDUCT \
|
||||
.dir-locals.el \
|
||||
.guix-authorizations \
|
||||
.guix-channel \
|
||||
scripts/guix.in \
|
||||
etc/disarchive-manifest.scm \
|
||||
etc/guix-install.sh \
|
||||
etc/historical-authorizations \
|
||||
etc/news.scm \
|
||||
etc/hurd-manifest.scm \
|
||||
etc/kernels-manifest.scm \
|
||||
etc/release-manifest.scm \
|
||||
etc/source-manifest.scm \
|
||||
etc/system-tests.scm \
|
||||
etc/time-travel-manifest.scm \
|
||||
scripts/guix.in \
|
||||
etc/historical-authorizations \
|
||||
build-aux/build-self.scm \
|
||||
build-aux/compile-all.scm \
|
||||
build-aux/cuirass/hurd-manifest.scm \
|
||||
build-aux/check-final-inputs-self-contained.scm \
|
||||
build-aux/check-channel-news.scm \
|
||||
build-aux/compile-as-derivation.scm \
|
||||
build-aux/convert-xref.scm \
|
||||
build-aux/generate-authors.scm \
|
||||
build-aux/test-driver.scm \
|
||||
build-aux/update-guix-package.scm \
|
||||
build-aux/update-NEWS.scm \
|
||||
tests/test.drv \
|
||||
tests/cve-sample.json \
|
||||
tests/keys/signing-key.pub \
|
||||
tests/keys/signing-key.sec \
|
||||
tests/keys/civodul.pub \
|
||||
tests/keys/rsa.pub \
|
||||
tests/keys/dsa.pub \
|
||||
tests/keys/ed25519.pub \
|
||||
tests/keys/ed25519.sec \
|
||||
tests/keys/ed25519-2.pub \
|
||||
tests/keys/ed25519-2.sec \
|
||||
tests/keys/ed25519-3.pub \
|
||||
tests/keys/ed25519-3.sec \
|
||||
tests/keys/ed25519.pub \
|
||||
tests/keys/ed25519.sec \
|
||||
tests/keys/rsa.pub \
|
||||
tests/keys/signing-key.pub \
|
||||
tests/keys/signing-key.sec \
|
||||
tests/test.drv \
|
||||
build-aux/config.rpath \
|
||||
bootstrap \
|
||||
doc/build.scm \
|
||||
$(TESTS)
|
||||
|
||||
if !BUILD_DAEMON_OFFLOAD
|
||||
@@ -776,70 +726,20 @@ endef
|
||||
# in <https://issues.guix.gnu.org/48963>. Each 'eval' call below creates a
|
||||
# 'make-*-go' phony target that builds the corresponding subset.
|
||||
|
||||
first_fifth := \
|
||||
gnu/packages/a% gnu/packages/b% gnu/packages/c%
|
||||
|
||||
second_fifth := \
|
||||
gnu/packages/d% gnu/packages/e% gnu/packages/f%
|
||||
|
||||
third_fifth := \
|
||||
gnu/packages/g% gnu/packages/h% gnu/packages/i%
|
||||
|
||||
fourth_fifth := \
|
||||
gnu/packages/j% gnu/packages/k% gnu/packages/l% gnu/packages/m% \
|
||||
gnu/packages/n% gnu/packages/o%
|
||||
|
||||
MODULES_CORE := guix.scm $(filter-out guix/scripts/%,$(filter guix/%,$(MODULES)))
|
||||
MODULES_PACKAGES1 := $(filter $(first_fifth),$(MODULES))
|
||||
MODULES_PACKAGES2 := $(filter $(second_fifth),$(MODULES))
|
||||
MODULES_PACKAGES3 := $(filter $(third_fifth),$(MODULES))
|
||||
MODULES_PACKAGES4 := $(filter $(fourth_fifth),$(MODULES))
|
||||
MODULES_PACKAGES5 := $(filter-out $(first_fifth) $(second_fifth) \
|
||||
$(third_fifth) $(fourth_fifth), \
|
||||
$(filter gnu/packages/%,$(MODULES)))
|
||||
MODULES_PACKAGES := $(MODULES_PACKAGES1) $(MODULES_PACKAGES2) \
|
||||
$(MODULES_PACKAGES3) $(MODULES_PACKAGES4) \
|
||||
$(MODULES_PACKAGES5)
|
||||
MODULES_SYSTEM := gnu.scm $(filter-out gnu/packages/%,$(filter gnu/%,$(MODULES)))
|
||||
MODULES_CLI := $(filter guix/scripts/%,$(MODULES))
|
||||
MODULES_PO := guix/build/po.scm
|
||||
MODULES_CORE = guix.scm $(filter-out guix/scripts/%,$(filter guix/%,$(MODULES)))
|
||||
MODULES_PACKAGES = $(filter gnu/packages/%,$(MODULES))
|
||||
MODULES_SYSTEM = gnu.scm $(filter-out gnu/packages/%,$(filter gnu/%,$(MODULES)))
|
||||
MODULES_CLI = $(filter guix/scripts/%,$(MODULES))
|
||||
MODULES_PO = guix/build/po.scm
|
||||
|
||||
$(eval $(call guile-compilation-rule,make-core-go, \
|
||||
$(MODULES_CORE) guix/config.scm $(dist_noinst_DATA), \
|
||||
0))
|
||||
.PHONY: make-core-go
|
||||
|
||||
$(eval $(call guile-compilation-rule,make-packages1-go, \
|
||||
$(MODULES_PACKAGES1) make-core-go, \
|
||||
$(eval $(call guile-compilation-rule,make-packages-go, \
|
||||
$(MODULES_PACKAGES) make-core-go, \
|
||||
$(words $(MODULES_CORE))))
|
||||
.PHONY: make-packages1-go
|
||||
|
||||
$(eval $(call guile-compilation-rule,make-packages2-go, \
|
||||
$(MODULES_PACKAGES2) make-core-go make-packages1-go, \
|
||||
$(words $(MODULES_CORE) $(MODULES_PACKAGES1))))
|
||||
.PHONY: make-packages2-go
|
||||
|
||||
$(eval $(call guile-compilation-rule,make-packages3-go, \
|
||||
$(MODULES_PACKAGES3) make-core-go make-packages1-go make-packages2-go, \
|
||||
$(words $(MODULES_CORE) $(MODULES_PACKAGES1) $(MODULES_PACKAGES2))))
|
||||
.PHONY: make-packages3-go
|
||||
|
||||
$(eval $(call guile-compilation-rule,make-packages4-go, \
|
||||
$(MODULES_PACKAGES4) make-core-go make-packages1-go make-packages2-go \
|
||||
make-packages3-go, \
|
||||
$(words $(MODULES_CORE) $(MODULES_PACKAGES1) $(MODULES_PACKAGES2) \
|
||||
$(MODULES_PACKAGES3))))
|
||||
.PHONY: make-packages4-go
|
||||
|
||||
$(eval $(call guile-compilation-rule,make-packages5-go, \
|
||||
$(MODULES_PACKAGES5) make-core-go make-packages1-go make-packages2-go \
|
||||
make-packages3-go make-packages4-go, \
|
||||
$(words $(MODULES_CORE) $(MODULES_PACKAGES1) $(MODULES_PACKAGES2) \
|
||||
$(MODULES_PACKAGES3) $(MODULES_PACKAGES4))))
|
||||
.PHONY: make-packages5-go
|
||||
|
||||
make-packages-go: make-packages1-go make-packages2-go \
|
||||
make-packages3-go make-packages4-go make-packages5-go
|
||||
.PHONY: make-packages-go
|
||||
|
||||
$(eval $(call guile-compilation-rule,make-system-go, \
|
||||
@@ -1055,21 +955,25 @@ release: dist-with-updated-version all
|
||||
mv "guix-binary.$$system.tar.xz" \
|
||||
"$(releasedir)/guix-binary-$(PACKAGE_VERSION).$$system.tar.xz" ; \
|
||||
done
|
||||
# Build 'current-guix' to speed things up for the next step.
|
||||
$(top_builddir)/pre-inst-env guix build \
|
||||
-e '((@ (gnu packages package-management) current-guix))' \
|
||||
# Bump the Guix package version and build it (again).
|
||||
GUIX_ALLOW_ME_TO_USE_PRIVATE_COMMIT=yes \
|
||||
$(top_builddir)/pre-inst-env "$(GUILE)" \
|
||||
$(top_srcdir)/build-aux/update-guix-package.scm \
|
||||
"`git rev-parse HEAD`"
|
||||
git add $(top_srcdir)/gnu/packages/package-management.scm
|
||||
git commit -m "gnu: guix: Update to `git rev-parse HEAD | cut -c1-7`."
|
||||
$(top_builddir)/pre-inst-env guix build guix \
|
||||
$(call system_flags,$(GUIX_SYSTEM_SUPPORTED_SYSTEMS)) \
|
||||
-v1 --no-grafts --fallback
|
||||
# Generate the ISO installation images.
|
||||
for system in $(GUIX_SYSTEM_SUPPORTED_SYSTEMS) ; do \
|
||||
GUIX_DISPLAYED_VERSION="`git describe --match=v* | sed -'es/^v//'`" ; \
|
||||
image=`$(top_builddir)/pre-inst-env \
|
||||
guix system image -t iso9660 \
|
||||
guix system image -t iso9660 \
|
||||
--label="GUIX_$${system}_$(VERSION)" \
|
||||
--system=$$system --fallback \
|
||||
gnu/system/install.scm` ; \
|
||||
if [ ! -f "$$image" ] ; then \
|
||||
echo "failed to produce Guix installation image for $$system" >&2 ; \
|
||||
echo "failed to produce Guix installation image for $$system" >&2 ; \
|
||||
exit 1 ; \
|
||||
fi ; \
|
||||
cp "$$image" "$(releasedir)/$(GUIX_SYSTEM_IMAGE_BASE).$$system.iso.tmp" ; \
|
||||
@@ -1078,7 +982,6 @@ release: dist-with-updated-version all
|
||||
done
|
||||
# Generate the VM images.
|
||||
for system in $(GUIX_SYSTEM_VM_SYSTEMS) ; do \
|
||||
GUIX_DISPLAYED_VERSION="`git describe --match=v* | sed -'es/^v//'`" ; \
|
||||
image=`$(top_builddir)/pre-inst-env \
|
||||
guix system image -t qcow2 $(GUIX_SYSTEM_VM_IMAGE_FLAGS) \
|
||||
--save-provenance \
|
||||
@@ -1156,19 +1059,6 @@ cuirass-jobs: $(GOBJECTS)
|
||||
.PHONY: clean-go make-go as-derivation authenticate
|
||||
.PHONY: update-guix-package update-NEWS cuirass-jobs release
|
||||
|
||||
# Git auto-configuration.
|
||||
.git/hooks/pre-push: etc/git/pre-push
|
||||
$(AM_V_at)if test -d .git; then \
|
||||
cp etc/git/pre-push .git/hooks/pre-push; \
|
||||
fi
|
||||
|
||||
.git/config: etc/git/gitconfig
|
||||
$(AM_V_at)if command -v git >/dev/null && test -d .git; then \
|
||||
git config --add include.path ../etc/git/gitconfig; \
|
||||
fi
|
||||
|
||||
nodist_noinst_DATA = .git/hooks/pre-push .git/config
|
||||
|
||||
# Downloading up-to-date PO files.
|
||||
|
||||
WEBLATE_REPO = https://framagit.org/tyreunom/guix-translations
|
||||
@@ -1179,35 +1069,21 @@ WEBLATE_REPO = https://framagit.org/tyreunom/guix-translations
|
||||
# form.
|
||||
download-po:
|
||||
dir=$$(mktemp -d); \
|
||||
git clone --depth 1 "$(WEBLATE_REPO)" "$$dir/translations" && \
|
||||
git clone --depth 1 "$(WEBLATE_REPO)" "$$dir/translations"; \
|
||||
for domain in po/doc po/guix po/packages; do \
|
||||
for po in "$$dir/translations/$$domain"/*.po; do \
|
||||
translated=$$(LANG=en_US.UTF-8 msgfmt --statistics "$$po" 2>&1 | cut -f1 -d' '); \
|
||||
untranslated=$$(LANG=en_US.UTF-8 msgfmt --statistics "$$po" 2>&1 | rev | cut -f3 -d' ' | rev); \
|
||||
untranslated=$${untranslated:-0}; \
|
||||
total=$$(($$translated+$$untranslated)); \
|
||||
target=$$(basename "$$po"); \
|
||||
target="$$domain/$$target"; \
|
||||
msgfmt -c "$$po"; \
|
||||
if msgfmt -c "$$po" && [ "$$translated" != "0" ] && ([ "$$domain" != "po/doc" ] || [ "$$translated" -gt $$(($$total/10)) ] || [ -f $$target ]); then \
|
||||
if msgfmt -c "$$po" && [ "$$translated" != "0" ]; then \
|
||||
msgfilter --no-wrap -i "$$po" cat > "$$po".tmp; \
|
||||
mv "$$po".tmp "$$target"; \
|
||||
echo "copied $$target."; \
|
||||
else \
|
||||
echo "WARN: $$target ($$translated translated messages ($$((translated/total*100))%)) was not added/updated."; \
|
||||
echo "WARN: $$target ($$translated translated messages) was not added/updated."; \
|
||||
fi; \
|
||||
done; \
|
||||
done; \
|
||||
for po in po/doc/*.po; do \
|
||||
translated=$$(LANG=en_US.UTF-8 msgfmt --statistics "$$po" 2>&1 | cut -f1 -d' '); \
|
||||
untranslated=$$(LANG=en_US.UTF-8 msgfmt --statistics "$$po" 2>&1 | rev | cut -f3 -d' ' | rev); \
|
||||
untranslated=$${untranslated:-0}; \
|
||||
total=$$(($$translated + $$untranslated)); \
|
||||
if [ "$$translated" -lt "$$(($$total/20))" ]; then \
|
||||
echo "WARN: $$po was removed because it is below the 5% threshold: $$((translated/total*100))%"; \
|
||||
rm $$po; \
|
||||
fi; \
|
||||
done; \
|
||||
rm -rf "$$dir"
|
||||
.PHONY: download-po
|
||||
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
#+TITLE: Guix NEWS – history of user-visible changes
|
||||
#+STARTUP: content hidestars
|
||||
|
||||
Copyright © 2013-2022 Ludovic Courtès <ludo@gnu.org>
|
||||
Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
|
||||
Copyright © 2016, 2017, 2018 Ricardo Wurmus <rekado@elephly.net>
|
||||
Copyright © 2021, 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
Copyright © 2022 Mathieu Othacehe <othacehe@gnu.org>
|
||||
Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
@@ -13,127 +12,26 @@ Copyright © 2022 Mathieu Othacehe <othacehe@gnu.org>
|
||||
|
||||
Please send Guix bug reports to bug-guix@gnu.org.
|
||||
|
||||
* Changes in 1.5.0 (since 1.4.0)
|
||||
** Package management
|
||||
*** New ‘rpm’ format for the ‘guix pack’ command
|
||||
* Changes in 1.4.0 (since 1.3.0)
|
||||
** Package management
|
||||
*** New ‘guix home’ command, for home environment management
|
||||
*** New ‘guix shell’ command, the successor to ‘guix environment’
|
||||
*** New ‘guix system edit’ command, to edit services
|
||||
*** New ‘deb’ format for the ‘guix pack’ command
|
||||
*** New ‘guix import minetest’ command, to import Minetest extensions
|
||||
*** New ‘guix import elm’ command, to import Elm packages
|
||||
*** New ‘guix import egg’ command, to import CHICKEN egg packages
|
||||
*** New ‘guix import hexpm’ command, to import Erlang and Elixir packages
|
||||
*** New 'guix style' command, to auto-format package definitions
|
||||
*** ‘guix import texlive’ rewritten to use the TLPDB as its source
|
||||
*** ‘guix import elpa’ now supports the non-GNU ELPA repository
|
||||
*** ‘guix import pypi’ can now import a specific version
|
||||
*** ‘guix import cran’ can now import a specific version
|
||||
*** New updater (see ‘guix refresh’): ‘generic-git’
|
||||
*** ‘guix graph’ has a new ‘--max-depth’ option
|
||||
*** ‘guix deploy’ has a new ‘--execute’ option
|
||||
*** ‘guix shell’ has a new ‘--emulate-fhs’ option
|
||||
*** ‘guix shell’ has a new ‘--symlink’ option
|
||||
*** ‘--with-commit’ option now accepts strings returned by ‘git describe’
|
||||
*** ‘--with-source’ option now applied recursively
|
||||
*** Align tabular data output by commands like ‘guix package --list-available’
|
||||
*** Improved ‘guix import go’ importer via a new PEG parser
|
||||
*** Improved Software Heritage downloader
|
||||
*** New 'web.archive.org’ download fall-back
|
||||
*** Various performance enhancements
|
||||
*** New ‘--tune’ package transformation option
|
||||
*** ‘guix refresh’ ‘-L’ option is repurposed to ‘load-path’ modification
|
||||
*** ‘guix system image’ supersedes the ‘docker-image’ sub-command
|
||||
|
||||
** Distribution
|
||||
*** The installation script can now enable local substitute servers discovery
|
||||
*** The installation script can now customize the Bash prompt for Guix
|
||||
*** More control over boot-time file system checks and repairs
|
||||
*** XFS file systems can be created by the installer and mounted by label/UUID
|
||||
*** New interface for declaring swap space
|
||||
*** GNOME is now at version 42
|
||||
*** TeX Live is now at version 2021
|
||||
*** Multiple TeX Live trees can now be used via GUIX_TEXMF
|
||||
*** Python modules are searched in GUIX_PYTHONPATH instead of PYTHONPATH
|
||||
*** Python is now faster thanks to being built with optimizations
|
||||
*** The Rust bootstrap now starts from 1.54 instead of 1.19
|
||||
*** Most Python 2 packages have been removed
|
||||
*** Guix now makes use of parallel xz compression
|
||||
*** Faster shared libraries discovery via a per-package dynamic linker cache
|
||||
*** Package inputs can now be plain package lists
|
||||
*** A package origin can now be a single file rather than an archive
|
||||
*** New sanity-check phase to detect Python packaging problems at build time
|
||||
*** Fetching sources can now fall-back to use Disarchive
|
||||
*** Improved CI and infrastructure
|
||||
*** Multiple cross-compilation tooling addition and fixes
|
||||
*** Many Qt 6 modules are now packaged
|
||||
*** Configuring setuid programs is now more flexible
|
||||
*** Add support for the XFS file system
|
||||
*** Add partial support for LUKS2 headers when using GRUB
|
||||
*** GDM now supports Wayland
|
||||
*** Guix System static networking support is improved
|
||||
*** The installer final configuration is prettified
|
||||
*** The installer external command handling is improved
|
||||
*** The installer now has a crash dump upload mechanism
|
||||
*** Emacs now supports native compilation
|
||||
*** GRUB bootloader now supports chain-loading
|
||||
*** The GNU Shepherd was upgraded to 0.9.3
|
||||
*** The init RAM disk honors more arguments—e.g. ‘root’ and ‘rootflags’
|
||||
*** ‘guix system image’ can now generate WSL images
|
||||
*** The mcron task scheduler logs now contain the jobs exit statuses
|
||||
*** Chromium extensions are now built in a deterministic fashion
|
||||
*** The ‘rsync’ service lets you specify individual “modules”
|
||||
*** New services
|
||||
|
||||
anonip, bitmask, fail2ban, gitile, greetd, jami, lightdm, log-cleanup,
|
||||
nar-herder, opendht, rasdaemon, samba, seatd, strongswan, wsdd
|
||||
|
||||
*** 5311 new packages
|
||||
|
||||
*** 6573 package updates
|
||||
|
||||
Noteworthy updates:
|
||||
bash 5.1.8, binutils 2.37, clojure 1.11.1, cups 2.3.3op2, emacs 28.2,
|
||||
enlightenment 0.25.4, gcc-toolchain 12.2.0, gdb 12.1, ghc 8.10.7,
|
||||
gimp 2.10.32, glibc 2.33, gnome 42.4, gnupg 2.2.32, go 1.19.1, guile 3.0.8,
|
||||
icecat 102.5.0-guix0-preview1, icedtea 3.19.0, inkscape 1.2.1, julia 1.6.7,
|
||||
libreoffice 7.4.3.2, linux-libre 6.0.10, ocaml 4.14.0, octave 7.2.0,
|
||||
openjdk 18, perl 5.34.0, python2 2.7.18, python 3.9.9, racket 8.7,
|
||||
rust 1.60.0, r 4.2.2, sbcl 2.2.10, shepherd 0.9.3, xorg-server 21.1.4
|
||||
|
||||
** Programming interfaces
|
||||
*** Package input fields can now be plain package lists
|
||||
*** G-expressions can now be used in build phases
|
||||
*** New ‘modify-inputs’ macro to ease customizing a list of package inputs
|
||||
*** New ‘this-package-input’ and ‘this-package-native-input’ macros
|
||||
*** Build phases are no longer required to return a boolean
|
||||
*** (guix records) now supports “field sanitizers”
|
||||
*** Various improvements to the helpers in (gnu service configuration)
|
||||
*** ‘texlive-union’ is now deprecated in favor of ‘texlive-updmap.cfg’
|
||||
*** New (guix cpu) module
|
||||
*** New (guix least-authority) module
|
||||
*** New (guix platform) module
|
||||
*** New (guix read-print) module
|
||||
|
||||
It provides a comment-preserving reader and a comment-preserving
|
||||
pretty-printer smarter than (ice-9 pretty-print).
|
||||
|
||||
*** New ‘channel-build-system’
|
||||
|
||||
This build system lets you build Guix instances from channel specifications,
|
||||
similar to how 'guix time-machine' would do it, as regular packages.
|
||||
|
||||
*** New ‘pyproject-build-system’
|
||||
|
||||
This is an extension of ‘python-build-system’ with support for PEP-517 and
|
||||
‘pyproject.toml’ files. It may eventually get merged back into
|
||||
‘python-build-system’.
|
||||
|
||||
*** New ‘elm-build-system’
|
||||
*** New ‘rebar-build-system’
|
||||
|
||||
** Noteworthy bug fixes
|
||||
*** Fall back to Software Heritage when cloning a channel
|
||||
(<https://issues.guix.gnu.org/44187>)
|
||||
@@ -145,42 +43,6 @@ This is an extension of ‘python-build-system’ with support for PEP-517 and
|
||||
(<https://issues.guix.gnu.org/24937>)
|
||||
*** File system flags are validated before system instantiation
|
||||
(<https://issues.guix.gnu.org/51425>)
|
||||
*** Fonts can now be discovered in any profile via XDG_DATA_DIRS
|
||||
(<https://issues.guix.gnu.org/31403>)
|
||||
*** Various Python reproducibility fixes
|
||||
*** The installer now supports MSDOS disk labels on UEFI systems
|
||||
(<https://issues.guix.gnu.org/47889>)
|
||||
*** The installer can now properly mount FAT16 partitions
|
||||
(<https://issues.guix.gnu.org/48419>)
|
||||
*** The installer no longer crashes when deleting a free space partition
|
||||
*** Emacs handles major upgrades better without a re-login
|
||||
(<https://issues.guix.gnu.org/47458>)
|
||||
*** The bootloader configuration now accepts multiple targets
|
||||
(<https://issues.guix.gnu.org/40997>)
|
||||
*** File system mount point is always created when ‘create?’ is true
|
||||
(<https://issues.guix.gnu.org/40158>)
|
||||
*** Build the man database only if ‘man-db’ is in the profile
|
||||
*** gdk-pixbuf now discovers pixbuf loaders via a search path
|
||||
(<https://issues.guix.gnu.org/50957>)
|
||||
*** Gitolite home directory permissions are fixed
|
||||
(https://issues.guix.gnu.org/56444)
|
||||
*** The man-db database is indexed via man pages names
|
||||
(https://issues.guix.gnu.org/38838)
|
||||
*** ‘chfn’ can now change the user's full name
|
||||
(https://issues.guix.gnu.org/52539)
|
||||
*** GNOME Settings Bluetooth panel is now working
|
||||
(https://issues.guix.gnu.org/32166)
|
||||
*** Inferiors are now caching store connections
|
||||
(https://issues.guix.gnu.org/48007)
|
||||
*** Retry downloads when a substitute has become unavailable
|
||||
(https://issues.guix.gnu.org/57978)
|
||||
*** The installer doesn't segfault when removing an extended partition
|
||||
*** The installer doesn't ship an older Guix revision
|
||||
(https://issues.guix.gnu.org/53210)
|
||||
*** The installer cannot proceed without any non-root user accounts
|
||||
(https://issues.guix.gnu.org/54666)
|
||||
*** <operating-system> compiler truly honors the 'system' argument
|
||||
(https://issues.guix.gnu.org/55951)
|
||||
|
||||
* Changes in 1.3.0 (since 1.2.0)
|
||||
** Package management
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2016-2018, 2020, 2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2016, 2017, 2018, 2020 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2017 Jan Nieuwenhuizen <janneke@gnu.org>
|
||||
;;; Copyright © 2021 Mathieu Othacehe <othacehe@gnu.org>
|
||||
;;;
|
||||
@@ -78,35 +78,28 @@
|
||||
;; up the evaluation speed as the evaluations can be performed
|
||||
;; concurrently. It also decreases the amount of memory needed per
|
||||
;; evaluation process.
|
||||
;;
|
||||
;; Fork inferior processes upfront before we have created any
|
||||
;; threads.
|
||||
(let ((inferiors (map (lambda _
|
||||
(open-inferior (derivation->output-path derivation)))
|
||||
%cuirass-supported-systems)))
|
||||
(n-par-for-each
|
||||
(min (length %cuirass-supported-systems)
|
||||
(current-processor-count))
|
||||
(lambda (system inferior)
|
||||
(with-store store
|
||||
(let ((channels (map channel-instance->sexp instances)))
|
||||
(inferior-eval '(use-modules (gnu ci)) inferior)
|
||||
(let ((jobs
|
||||
(inferior-eval-with-store
|
||||
inferior store
|
||||
`(lambda (store)
|
||||
(cuirass-jobs store
|
||||
'((subset . all)
|
||||
(systems . ,(list system))
|
||||
(channels . ,channels))))))
|
||||
(file
|
||||
(string-append directory "/jobs-" system ".scm")))
|
||||
(close-inferior inferior)
|
||||
(call-with-output-file file
|
||||
(lambda (port)
|
||||
(write jobs port)))))))
|
||||
%cuirass-supported-systems
|
||||
inferiors)))))))
|
||||
(n-par-for-each
|
||||
(/ (current-processor-count) 2)
|
||||
(lambda (system)
|
||||
(with-store store
|
||||
(let ((inferior
|
||||
(open-inferior (derivation->output-path derivation)))
|
||||
(channels (map channel-instance->sexp instances)))
|
||||
(inferior-eval '(use-modules (gnu ci)) inferior)
|
||||
(let ((jobs
|
||||
(inferior-eval-with-store
|
||||
inferior store
|
||||
`(lambda (store)
|
||||
(cuirass-jobs store
|
||||
'((subset . all)
|
||||
(systems . ,(list system))
|
||||
(channels . ,channels))))))
|
||||
(file
|
||||
(string-append directory "/jobs-" system ".scm")))
|
||||
(call-with-output-file file
|
||||
(lambda (port)
|
||||
(write jobs port)))))))
|
||||
%cuirass-supported-systems))))))
|
||||
(x
|
||||
(format (current-error-port) "Wrong command: ~a~%." x)
|
||||
(exit 1)))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2020, 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
|
||||
;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -31,7 +31,7 @@
|
||||
(srfi srfi-1))
|
||||
|
||||
(use-package-modules
|
||||
base bootloaders commencement compression file gawk gdb gettext guile
|
||||
base commencement compression file gawk gdb gettext guile
|
||||
hurd less m4 package-management python ssh version-control)
|
||||
|
||||
(define (input->package input)
|
||||
@@ -64,14 +64,11 @@
|
||||
|
||||
;; development packages
|
||||
gcc-toolchain gdb-minimal git-minimal gnu-make
|
||||
gettext-minimal python-minimal
|
||||
|
||||
;; ourselves!
|
||||
(package-without-tests guix)
|
||||
|
||||
;; system
|
||||
grub-minimal grub
|
||||
;; guix environment guix --without-tests=python-minimal --without-tests=gettext-minimal
|
||||
(package-without-tests gettext-minimal)
|
||||
(package-without-tests python-minimal)
|
||||
|
||||
(append
|
||||
guix-dependencies
|
||||
%base-packages/hurd)))
|
||||
(delete guile-3.0 %base-packages/hurd))))
|
||||
@@ -274,7 +274,6 @@ AC_CONFIG_FILES([Makefile
|
||||
guix/config.scm])
|
||||
|
||||
AC_CONFIG_FILES([etc/committer.scm], [chmod +x etc/committer.scm])
|
||||
AC_CONFIG_FILES([etc/teams.scm], [chmod +x etc/teams.scm])
|
||||
AC_CONFIG_FILES([test-env:build-aux/test-env.in], [chmod +x test-env])
|
||||
AC_CONFIG_FILES([pre-inst-env:build-aux/pre-inst-env.in],
|
||||
[chmod +x pre-inst-env])
|
||||
|
||||
+35
-50
@@ -1,7 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2019-2023 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2019-2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2020 Björn Höfling <bjoern.hoefling@bjoernhoefling.de>
|
||||
;;; Copyright © 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -31,7 +30,6 @@
|
||||
(guix gexp)
|
||||
(guix git)
|
||||
(guix git-download)
|
||||
(guix profiles)
|
||||
(guix utils)
|
||||
(git)
|
||||
(gnu packages base)
|
||||
@@ -64,19 +62,11 @@
|
||||
(or (getenv "GUIX_MANUAL")
|
||||
"guix"))
|
||||
|
||||
(define %manual-languages
|
||||
;; Available translations for the 'guix-manual' text domain.
|
||||
'("de" "en" "es" "fr" "pt_BR" "ru" "zh_CN"))
|
||||
|
||||
(define %cookbook-languages
|
||||
;; Available translations for the 'guix-cookbook' text domain.
|
||||
'("de" "en" "fr" "sk"))
|
||||
|
||||
(define %languages
|
||||
;; Available translations for the document being built.
|
||||
;; The cookbook is not translated in the same languages as the manual
|
||||
(if (string=? %manual "guix-cookbook")
|
||||
%cookbook-languages
|
||||
%manual-languages))
|
||||
'("de" "en" "fr" "sk")
|
||||
'("de" "en" "es" "fr" "ru" "zh_CN")))
|
||||
|
||||
(define (texinfo-manual-images source)
|
||||
"Return a directory containing all the images used by the user manual, taken
|
||||
@@ -284,9 +274,6 @@ actual file name."
|
||||
(loop rest))
|
||||
((('strong _ ...) _ ...)
|
||||
#t)
|
||||
((('span ('@ ('class "category")) ;raw Texinfo 6.8
|
||||
(? string-or-entity?) ...) rest ...)
|
||||
#t)
|
||||
((('span ('@ ('class "symbol-definition-category"))
|
||||
(? string-or-entity?) ...) rest ...)
|
||||
#t)
|
||||
@@ -314,9 +301,8 @@ actual file name."
|
||||
(define (html-files directory)
|
||||
;; Return the list of HTML files under DIRECTORY.
|
||||
(map (cut string-append directory "/" <>)
|
||||
(or (scandir #$manual (lambda (file)
|
||||
(string-suffix? ".html" file)))
|
||||
'())))
|
||||
(scandir #$manual (lambda (file)
|
||||
(string-suffix? ".html" file)))))
|
||||
|
||||
(define anchors
|
||||
(sort (concatenate
|
||||
@@ -510,16 +496,10 @@ its <pre class=\"lisp\"> blocks (as produced by 'makeinfo --html')."
|
||||
|
||||
;; Replace the ugly <strong> used for @deffn etc., which
|
||||
;; translate to <dt>, with more stylable markup.
|
||||
(('dt ('@ ('id id)) ;raw Texinfo 6.8
|
||||
('span ('@ ('class "category")) category ...)
|
||||
('span ('strong thing)
|
||||
anchor))
|
||||
(('dt (@ ('id id)) category ... ('strong thing))
|
||||
(highlight-definition id category thing '()))
|
||||
(('dt (@ ('id id))
|
||||
('span ('@ ('class "category")) category ...)
|
||||
('span ('strong thing)
|
||||
(? space?) ('em args ...)
|
||||
anchor))
|
||||
(('dt (@ ('id id)) category ... ('strong thing)
|
||||
(? space?) ('em args ...))
|
||||
(highlight-definition id category thing args))
|
||||
|
||||
((tag ('@ attributes ...) body ...)
|
||||
@@ -901,19 +881,14 @@ makeinfo OPTIONS."
|
||||
#:languages languages
|
||||
#:date date))
|
||||
|
||||
(define texinfo-profile
|
||||
(profile
|
||||
(content (packages->manifest
|
||||
;; texi2dvi requires various command line tools.
|
||||
(list coreutils
|
||||
diffutils
|
||||
gawk
|
||||
grep
|
||||
sed
|
||||
tar
|
||||
texinfo
|
||||
(texlive-updmap.cfg
|
||||
(list texlive-epsf texlive-texinfo)))))))
|
||||
;; FIXME: This union works, except for the table of contents of non-English
|
||||
;; manuals, which contains escape sequences like "^^ca^^fe" instead of
|
||||
;; accented letters.
|
||||
;;
|
||||
;; (define texlive
|
||||
;; (texlive-updmap.cfg (list texlive-tex-texinfo
|
||||
;; texlive-generic-epsf
|
||||
;; texlive-fonts-ec)))
|
||||
|
||||
(define build
|
||||
(with-imported-modules '((guix build utils))
|
||||
@@ -930,12 +905,21 @@ makeinfo OPTIONS."
|
||||
(string-downcase language)))
|
||||
|
||||
;; Install a UTF-8 locale so that 'makeinfo' is at ease.
|
||||
(setenv "GUIX_LOCPATH" #+(file-append glibc-utf8-locales
|
||||
"/lib/locale"))
|
||||
(setenv "GUIX_LOCPATH"
|
||||
#+(file-append glibc-utf8-locales "/lib/locale"))
|
||||
(setenv "LC_ALL" "en_US.utf8")
|
||||
(setenv "PATH" #+(file-append texinfo-profile "/bin"))
|
||||
(setenv "GUIX_TEXMF" #+(file-append texinfo-profile
|
||||
"/share/texmf-dist"))
|
||||
(setenv "PATH"
|
||||
(string-append #+(file-append texlive "/bin") ":"
|
||||
#+(file-append texinfo "/bin") ":"
|
||||
|
||||
;; Below are command-line tools needed by
|
||||
;; 'texi2dvi' and friends.
|
||||
#+(file-append sed "/bin") ":"
|
||||
#+(file-append grep "/bin") ":"
|
||||
#+(file-append coreutils "/bin") ":"
|
||||
#+(file-append gawk "/bin") ":"
|
||||
#+(file-append tar "/bin") ":"
|
||||
#+(file-append diffutils "/bin")))
|
||||
|
||||
(setvbuf (current-output-port) 'line)
|
||||
(setvbuf (current-error-port) 'line)
|
||||
@@ -985,8 +969,7 @@ PDF for language '~a'!~%~%"
|
||||
(computed-file (string-append manual "-pdf-manual") build
|
||||
#:local-build? #f))
|
||||
|
||||
(define* (guix-manual-text-domain source
|
||||
#:optional (languages %manual-languages))
|
||||
(define (guix-manual-text-domain source languages)
|
||||
"Return the PO files for LANGUAGES of the 'guix-manual' text domain taken
|
||||
from SOURCE."
|
||||
(define po-directory
|
||||
@@ -1059,7 +1042,9 @@ must be the Guix top-level source directory, from which PO files are taken."
|
||||
(define exp
|
||||
`(begin
|
||||
(bindtextdomain "guix-manual"
|
||||
#+(guix-manual-text-domain source))
|
||||
#+(guix-manual-text-domain
|
||||
source
|
||||
languages))
|
||||
(bindtextdomain "iso_639-3" ;language names
|
||||
#+(file-append iso-codes
|
||||
"/share/locale"))
|
||||
|
||||
+172
-596
@@ -26,10 +26,9 @@ choice.
|
||||
* Packaging Guidelines:: Growing the distribution.
|
||||
* Coding Style:: Hygiene of the contributor.
|
||||
* Submitting Patches:: Share your work.
|
||||
* Tracking Bugs and Changes:: Keeping it all organized.
|
||||
* Tracking Bugs and Patches:: Keeping it all organized.
|
||||
* Commit Access:: Pushing to the official repository.
|
||||
* Updating the Guix Package:: Updating the Guix package definition.
|
||||
* Writing Documentation:: Improving documentation in GNU Guix.
|
||||
* Translating Guix:: Make Guix speak your native language.
|
||||
@end menu
|
||||
|
||||
@@ -130,16 +129,14 @@ more information.
|
||||
Then, run:
|
||||
|
||||
@example
|
||||
./configure --localstatedir=/var --sysconfdir=/etc
|
||||
./configure --localstatedir=/var
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
... where @file{/var} is the normal @code{localstatedir} value
|
||||
(@pxref{The Store}, for information about this) and @file{/etc} is the
|
||||
normal @code{sysconfdir} value. Note that you will probably not run
|
||||
@command{make install} at the end (you don't have to) but it's still
|
||||
important to pass the right @code{localstatedir} and @code{sysconfdir}
|
||||
values, which get recorded in the @code{(guix config)} Guile module.
|
||||
(@pxref{The Store}, for information about this). Note that you will
|
||||
probably not run @command{make install} at the end (you don't have to)
|
||||
but it's still important to pass the right @code{localstatedir}.
|
||||
|
||||
Finally, you can build Guix and, if you feel so inclined, run the tests
|
||||
(@pxref{Running the Test Suite}):
|
||||
@@ -227,7 +224,8 @@ $ ./pre-inst-env guile -c '(use-modules (guix utils)) (pk (%current-system))'
|
||||
@noindent
|
||||
@cindex REPL
|
||||
@cindex read-eval-print loop
|
||||
@dots{} and for a REPL (@pxref{Using Guix Interactively}):
|
||||
@dots{} and for a REPL (@pxref{Using Guile Interactively,,, guile, Guile
|
||||
Reference Manual}):
|
||||
|
||||
@example
|
||||
$ ./pre-inst-env guile
|
||||
@@ -280,8 +278,8 @@ prepared Guile object (@file{.go}) files.
|
||||
|
||||
You can run @command{make} automatically as you work using
|
||||
@command{watchexec} from the @code{watchexec} package. For example,
|
||||
to build again each time you update a package file, run
|
||||
@samp{watchexec -w gnu/packages -- make -j4}.
|
||||
to build again each time you update a package file, you can run
|
||||
@samp{watchexec -w gnu/packages make -j4}.
|
||||
|
||||
@node The Perfect Setup
|
||||
@section The Perfect Setup
|
||||
@@ -293,17 +291,22 @@ Manual}). First, you need more than an editor, you need
|
||||
wonderful @url{https://nongnu.org/geiser/, Geiser}. To set that up, run:
|
||||
|
||||
@example
|
||||
guix install emacs guile emacs-geiser emacs-geiser-guile
|
||||
guix package -i emacs guile emacs-geiser emacs-geiser-guile
|
||||
@end example
|
||||
|
||||
Geiser allows for interactive and incremental development from within
|
||||
Emacs: code compilation and evaluation from within buffers, access to
|
||||
on-line documentation (docstrings), context-sensitive completion,
|
||||
@kbd{M-.} to jump to an object definition, a REPL to try out your code,
|
||||
and more (@pxref{Introduction,,, geiser, Geiser User Manual}). If you
|
||||
allow Emacs to load the @file{.dir-locals.el} file at the root of the
|
||||
project checkout, it will cause Geiser to automatically add the local
|
||||
Guix sources to the Guile load path.
|
||||
and more (@pxref{Introduction,,, geiser, Geiser User Manual}). For
|
||||
convenient Guix development, make sure to augment Guile’s load path so
|
||||
that it finds source files from your checkout:
|
||||
|
||||
@lisp
|
||||
;; @r{Assuming the Guix checkout is in ~/src/guix.}
|
||||
(with-eval-after-load 'geiser-guile
|
||||
(add-to-list 'geiser-guile-load-path "~/src/guix"))
|
||||
@end lisp
|
||||
|
||||
To actually edit the code, Emacs already has a neat Scheme mode. But in
|
||||
addition to that, you must not miss
|
||||
@@ -317,25 +320,15 @@ s-expression, etc.
|
||||
@cindex reducing boilerplate
|
||||
We also provide templates for common git commit messages and package
|
||||
definitions in the @file{etc/snippets} directory. These templates can
|
||||
be used to expand short trigger strings to interactive text snippets. If
|
||||
you use @url{https://joaotavora.github.io/yasnippet/, YASnippet}, you
|
||||
may want to add the @file{etc/snippets/yas} snippets directory to the
|
||||
@var{yas-snippet-dirs} variable. If you use
|
||||
@url{https://github.com/minad/tempel/, Tempel}, you may want to add the
|
||||
@file{etc/snippets/tempel/*} path to the @var{tempel-path} variable in
|
||||
be used with @url{https://joaotavora.github.io/yasnippet/, YASnippet} to
|
||||
expand short trigger strings to interactive text snippets. You may want
|
||||
to add the snippets directory to the @var{yas-snippet-dirs} variable in
|
||||
Emacs.
|
||||
|
||||
@lisp
|
||||
;; @r{Assuming the Guix checkout is in ~/src/guix.}
|
||||
;; @r{Yasnippet configuration}
|
||||
(with-eval-after-load 'yasnippet
|
||||
(add-to-list 'yas-snippet-dirs "~/src/guix/etc/snippets/yas"))
|
||||
;; @r{Tempel configuration}
|
||||
(with-eval-after-load 'tempel
|
||||
;; Ensure tempel-path is a list -- it may also be a string.
|
||||
(unless (listp 'tempel-path)
|
||||
(setq tempel-path (list tempel-path)))
|
||||
(add-to-list 'tempel-path "~/src/guix/etc/snippets/tempel/*"))
|
||||
(add-to-list 'yas-snippet-dirs "~/src/guix/etc/snippets"))
|
||||
@end lisp
|
||||
|
||||
The commit message snippets depend on @url{https://magit.vc/, Magit} to
|
||||
@@ -454,7 +447,6 @@ needed is to review and apply the patch.
|
||||
* Perl Modules:: Little pearls.
|
||||
* Java Packages:: Coffee break.
|
||||
* Rust Crates:: Beware of oxidation.
|
||||
* Elm Packages:: Trees of browser code
|
||||
* Fonts:: Fond of fonts.
|
||||
@end menu
|
||||
|
||||
@@ -612,7 +604,7 @@ A typical package definition may look like this:
|
||||
)))
|
||||
@end lisp
|
||||
|
||||
@deffn {Procedure} git-version @var{VERSION} @var{REVISION} @var{COMMIT}
|
||||
@deffn {Scheme Procedure} git-version @var{VERSION} @var{REVISION} @var{COMMIT}
|
||||
Return the version string for packages using @code{git-fetch}.
|
||||
|
||||
@lisp
|
||||
@@ -621,7 +613,7 @@ Return the version string for packages using @code{git-fetch}.
|
||||
@end lisp
|
||||
@end deffn
|
||||
|
||||
@deffn {Procedure} hg-version @var{VERSION} @var{REVISION} @var{CHANGESET}
|
||||
@deffn {Scheme Procedure} hg-version @var{VERSION} @var{REVISION} @var{CHANGESET}
|
||||
Return the version string for packages using @code{hg-fetch}. It works
|
||||
in the same way as @code{git-version}.
|
||||
@end deffn
|
||||
@@ -671,7 +663,7 @@ hyperlinks (@pxref{Overview,,, texinfo, GNU Texinfo}). However you
|
||||
should be careful when using some characters for example @samp{@@} and
|
||||
curly braces which are the basic special characters in Texinfo
|
||||
(@pxref{Special Characters,,, texinfo, GNU Texinfo}). User interfaces
|
||||
such as @command{guix show} take care of rendering it
|
||||
such as @command{guix package --show} take care of rendering it
|
||||
appropriately.
|
||||
|
||||
Synopses and descriptions are translated by volunteers
|
||||
@@ -773,8 +765,9 @@ the word @code{python}.
|
||||
Some modules are compatible with only one version of Python, others with
|
||||
both. If the package Foo is compiled with Python 3, we name it
|
||||
@code{python-foo}. If it is compiled with Python 2, we name it
|
||||
@code{python2-foo}. Python 2 packages are being removed from the
|
||||
distribution; please do no not submit any new Python 2 packages.
|
||||
@code{python2-foo}. Packages should be added when they are necessary;
|
||||
we don't add Python 2 variants of the package unless we are going to use
|
||||
them.
|
||||
|
||||
If a project already contains the word @code{python}, we drop this;
|
||||
for instance, the module python-dateutil is packaged under the names
|
||||
@@ -782,29 +775,12 @@ for instance, the module python-dateutil is packaged under the names
|
||||
starts with @code{py} (e.g.@: @code{pytz}), we keep it and prefix it as
|
||||
described above.
|
||||
|
||||
@quotation Note
|
||||
Currently there are two different build systems for Python packages in Guix:
|
||||
@var{python-build-system} and @var{pyproject-build-system}. For the
|
||||
longest time, Python packages were built from an informally specified
|
||||
@file{setup.py} file. That worked amazingly well, considering Python's
|
||||
success, but was difficult to build tooling around. As a result, a host
|
||||
of alternative build systems emerged and the community eventually settled on a
|
||||
@url{https://peps.python.org/pep-0517/, formal standard} for specifying build
|
||||
requirements. @var{pyproject-build-system} is Guix's implementation of this
|
||||
standard. It is considered ``experimental'' in that it does not yet support
|
||||
all the various PEP-517 @emph{build backends}, but you are encouraged to try
|
||||
it for new Python packages and report any problems. It will eventually be
|
||||
deprecated and merged into @var{python-build-system}.
|
||||
@end quotation
|
||||
|
||||
@subsubsection Specifying Dependencies
|
||||
@cindex inputs, for Python packages
|
||||
|
||||
Dependency information for Python packages is usually available in the
|
||||
package source tree, with varying degrees of accuracy: in the
|
||||
@file{pyproject.toml} file, the @file{setup.py} file, in
|
||||
@file{requirements.txt}, or in @file{tox.ini} (the latter mostly for
|
||||
test dependencies).
|
||||
@file{setup.py} file, in @file{requirements.txt}, or in @file{tox.ini}.
|
||||
|
||||
Your mission, when writing a recipe for a Python package, is to map
|
||||
these dependencies to the appropriate type of ``input'' (@pxref{package
|
||||
@@ -815,12 +791,10 @@ following check list to determine which dependency goes where.
|
||||
@itemize
|
||||
|
||||
@item
|
||||
We currently package Python with @code{setuptools} and @code{pip}
|
||||
installed per default. This is about to change, and users are encouraged
|
||||
to use @code{python-toolchain} if they want a build environment for Python.
|
||||
|
||||
@command{guix lint} will warn if @code{setuptools} or @code{pip} are
|
||||
added as native-inputs because they are generally not necessary.
|
||||
We currently package Python 2 with @code{setuptools} and @code{pip}
|
||||
installed like Python 3.4 has per default. Thus you don't need to
|
||||
specify either of these as an input. @command{guix lint} will warn you
|
||||
if you do.
|
||||
|
||||
@item
|
||||
Python dependencies required at run time go into
|
||||
@@ -829,10 +803,9 @@ Python dependencies required at run time go into
|
||||
@file{requirements.txt} file.
|
||||
|
||||
@item
|
||||
Python packages required only at build time---e.g., those listed under
|
||||
@code{build-system.requires} in @file{pyproject.toml} or with the
|
||||
@code{setup_requires} keyword in @file{setup.py}---or dependencies only
|
||||
for testing---e.g., those in @code{tests_require} or @file{tox.ini}---go into
|
||||
Python packages required only at build time---e.g., those listed with
|
||||
the @code{setup_requires} keyword in @file{setup.py}---or only for
|
||||
testing---e.g., those in @code{tests_require}---go into
|
||||
@code{native-inputs}. The rationale is that (1) they do not need to be
|
||||
propagated because they are not needed at run time, and (2) in a
|
||||
cross-compilation context, it's the ``native'' input that we'd want.
|
||||
@@ -925,87 +898,6 @@ developed for a different Operating System, depend on features from the Nightly
|
||||
Rust compiler, or the test suite may have atrophied since it was released.
|
||||
|
||||
|
||||
@node Elm Packages
|
||||
@subsection Elm Packages
|
||||
|
||||
@cindex Elm
|
||||
Elm applications can be named like other software: their names need not
|
||||
mention Elm.
|
||||
|
||||
Packages in the Elm sense (see @code{elm-build-system} under @ref{Build
|
||||
Systems}) are required use names of the format
|
||||
@var{author}@code{/}@var{project}, where both the @var{author} and the
|
||||
@var{project} may contain hyphens internally, and the @var{author} sometimes
|
||||
contains uppercase letters.
|
||||
|
||||
To form the Guix package name from the upstream name, we follow a convention
|
||||
similar to Python packages (@pxref{Python Modules}), adding an @code{elm-}
|
||||
prefix unless the name would already begin with @code{elm-}.
|
||||
|
||||
In many cases we can reconstruct an Elm package's upstream name heuristically,
|
||||
but, since conversion to a Guix-style name involves a loss of information,
|
||||
this is not always possible. Care should be taken to add the
|
||||
@code{'upstream-name} property when necessary so that @samp{guix import elm}
|
||||
will work correctly (@pxref{Invoking guix import}). The most notable scenarios
|
||||
when explicitly specifying the upstream name is necessary are:
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
When the @var{author} is @code{elm} and the @var{project} contains one or more
|
||||
hyphens, as with @code{elm/virtual-dom}; and
|
||||
|
||||
@item
|
||||
When the @var{author} contains hyphens or uppercase letters, as with
|
||||
@code{Elm-Canvas/raster-shapes}---unless the @var{author} is
|
||||
@code{elm-explorations}, which is handled as a special case, so packages like
|
||||
@code{elm-explorations/markdown} do @emph{not} need to use the
|
||||
@code{'upstream-name} property.
|
||||
@end enumerate
|
||||
|
||||
The module @code{(guix build-system elm)} provides the following utilities for
|
||||
working with names and related conventions:
|
||||
|
||||
@deffn {Procedure} elm-package-origin @var{elm-name} @var{version} @
|
||||
@var{hash}
|
||||
Returns a Git origin using the repository naming and tagging regime required
|
||||
for a published Elm package with the upstream name @var{elm-name} at version
|
||||
@var{version} with sha256 checksum @var{hash}.
|
||||
|
||||
For example:
|
||||
@lisp
|
||||
(package
|
||||
(name "elm-html")
|
||||
(version "1.0.0")
|
||||
(source
|
||||
(elm-package-origin
|
||||
"elm/html"
|
||||
version
|
||||
(base32 "15k1679ja57vvlpinpv06znmrxy09lbhzfkzdc89i01qa8c4gb4a")))
|
||||
...)
|
||||
@end lisp
|
||||
@end deffn
|
||||
|
||||
@deffn {Procedure} elm->package-name @var{elm-name}
|
||||
Returns the Guix-style package name for an Elm package with upstream name
|
||||
@var{elm-name}.
|
||||
|
||||
Note that there is more than one possible @var{elm-name} for which
|
||||
@code{elm->package-name} will produce a given result.
|
||||
@end deffn
|
||||
|
||||
@deffn {Procedure} guix-package->elm-name @var{package}
|
||||
Given an Elm @var{package}, returns the possibly-inferred upstream name, or
|
||||
@code{#f} the upstream name is not specified via the @code{'upstream-name}
|
||||
property and can not be inferred by @code{infer-elm-package-name}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Procedure} infer-elm-package-name @var{guix-name}
|
||||
Given the @var{guix-name} of an Elm package, returns the inferred upstream
|
||||
name, or @code{#f} if the upstream name can't be inferred. If the result is
|
||||
not @code{#f}, supplying it to @code{elm->package-name} would produce
|
||||
@var{guix-name}.
|
||||
@end deffn
|
||||
|
||||
@node Fonts
|
||||
@subsection Fonts
|
||||
|
||||
@@ -1085,16 +977,11 @@ and then to browse them ``by hand'' using @code{car}, @code{cdr},
|
||||
notably the fact that it is hard to read, error-prone, and a hindrance
|
||||
to proper type error reports.
|
||||
|
||||
@findex define-record-type*
|
||||
@findex match-record
|
||||
@cindex pattern matching
|
||||
Guix code should define appropriate data types (for instance, using
|
||||
@code{define-record-type*}) rather than abuse lists. In addition, it
|
||||
should use pattern matching, via Guile’s @code{(ice-9 match)} module,
|
||||
especially when matching lists (@pxref{Pattern Matching,,, guile, GNU
|
||||
Guile Reference Manual}); pattern matching for records is better done
|
||||
using @code{match-record} from @code{(guix records)}, which, unlike
|
||||
@code{match}, verifies field names at macro-expansion time.
|
||||
Guile Reference Manual}).
|
||||
|
||||
@node Formatting Code
|
||||
@subsection Formatting Code
|
||||
@@ -1149,37 +1036,36 @@ Development is done using the Git distributed version control system.
|
||||
Thus, access to the repository is not strictly necessary. We welcome
|
||||
contributions in the form of patches as produced by @code{git
|
||||
format-patch} sent to the @email{guix-patches@@gnu.org} mailing list
|
||||
(@pxref{Submitting patches to a project,,, git, Git User Manual}).
|
||||
Contributors are encouraged to take a moment to set some Git repository
|
||||
options (@pxref{Configuring Git}) first, which can improve the
|
||||
readability of patches. Seasoned Guix developers may also want to look
|
||||
at the section on commit access (@pxref{Commit Access}).
|
||||
(@pxref{submitting patches,, Submitting patches to a project, git, Git
|
||||
User Manual}). Contributors are encouraged to take a moment to set some
|
||||
Git repository options (@pxref{Configuring Git}) first, which can
|
||||
improve the readability of patches. Seasoned Guix developers may also
|
||||
want to look at the section on commit access (@pxref{Commit Access}).
|
||||
|
||||
This mailing list is backed by a Debbugs instance, which allows us to
|
||||
keep track of submissions (@pxref{Tracking Bugs and Changes}).
|
||||
Each message sent to that mailing list gets a new tracking number
|
||||
assigned; people can then follow up on the submission by sending email
|
||||
to @code{@var{ISSUE_NUMBER}@@debbugs.gnu.org}, where @var{ISSUE_NUMBER}
|
||||
is the tracking number (@pxref{Sending a Patch Series}).
|
||||
keep track of submissions (@pxref{Tracking Bugs and Patches}). Each
|
||||
message sent to that mailing list gets a new tracking number assigned;
|
||||
people can then follow up on the submission by sending email to
|
||||
@code{@var{NNN}@@debbugs.gnu.org}, where @var{NNN} is the tracking
|
||||
number (@pxref{Sending a Patch Series}).
|
||||
|
||||
Please write commit logs in the ChangeLog format (@pxref{Change Logs,,,
|
||||
standards, GNU Coding Standards}); you can check the commit history for
|
||||
examples.
|
||||
|
||||
You can help make the review process more efficient, and increase the
|
||||
chance that your patch will be reviewed quickly, by describing the
|
||||
context of your patch and the impact you expect it to have. For
|
||||
example, if your patch is fixing something that is broken, describe the
|
||||
problem and how your patch fixes it. Tell us how you have tested your
|
||||
patch. Will users of the code changed by your patch have to adjust
|
||||
their workflow at all? If so, tell us how. In general, try to imagine
|
||||
what questions a reviewer will ask, and answer those questions in
|
||||
advance.
|
||||
|
||||
Before submitting a patch that adds or modifies a package definition,
|
||||
please run through this check list:
|
||||
|
||||
@enumerate
|
||||
@cindex @code{git format-patch}
|
||||
@cindex @code{git-format-patch}
|
||||
@item
|
||||
When generating your patches with @code{git format-patch} or @code{git
|
||||
send-email}, we recommend using the option @code{--base=}, perhaps with
|
||||
the value @code{auto}. This option adds a note to the patch stating
|
||||
which commit the patch is based on. This helps reviewers understand how
|
||||
to apply and review your patches.
|
||||
|
||||
@item
|
||||
If the authors of the packaged software provide a cryptographic
|
||||
signature for the release tarball, make an effort to verify the
|
||||
@@ -1247,14 +1133,53 @@ Take a look at the profile reported by @command{guix size}
|
||||
(@pxref{Invoking guix size}). This will allow you to notice references
|
||||
to other packages unwillingly retained. It may also help determine
|
||||
whether to split the package (@pxref{Packages with Multiple Outputs}),
|
||||
and which optional dependencies should be used. In particular, avoid
|
||||
adding @code{texlive} as a dependency: because of its extreme size, use
|
||||
@code{texlive-updmap.cfg} procedure instead.
|
||||
and which optional dependencies should be used. In particular, avoid adding
|
||||
@code{texlive} as a dependency: because of its extreme size, use
|
||||
the @code{texlive-tiny} package or @code{texlive-union} procedure instead.
|
||||
|
||||
@item
|
||||
Check that dependent packages (if applicable) are not affected by the
|
||||
change; @code{guix refresh --list-dependent @var{package}} will help you
|
||||
do that (@pxref{Invoking guix refresh}).
|
||||
For important changes, check that dependent packages (if applicable) are
|
||||
not affected by the change; @code{guix refresh --list-dependent
|
||||
@var{package}} will help you do that (@pxref{Invoking guix refresh}).
|
||||
|
||||
@c See <https://lists.gnu.org/archive/html/guix-devel/2016-10/msg00933.html>.
|
||||
@cindex branching strategy
|
||||
@cindex rebuild scheduling strategy
|
||||
Depending on the number of dependent packages and thus the amount of
|
||||
rebuilding induced, commits go to different branches, along these lines:
|
||||
|
||||
@table @asis
|
||||
@item 300 dependent packages or less
|
||||
@code{master} branch (non-disruptive changes).
|
||||
|
||||
@item between 300 and 1,800 dependent packages
|
||||
@code{staging} branch (non-disruptive changes). This branch is intended
|
||||
to be merged in @code{master} every 6 weeks or so. Topical changes
|
||||
(e.g., an update of the GNOME stack) can instead go to a specific branch
|
||||
(say, @code{gnome-updates}). This branch is not expected to be
|
||||
buildable or usable until late in its development process.
|
||||
|
||||
@item more than 1,800 dependent packages
|
||||
@code{core-updates} branch (may include major and potentially disruptive
|
||||
changes). This branch is intended to be merged in @code{master} every
|
||||
6 months or so. This branch is not expected to be buildable or usable
|
||||
until late in its development process.
|
||||
@end table
|
||||
|
||||
All these branches are @uref{https://@value{SUBSTITUTE-SERVER-1},
|
||||
tracked by our build farm} and merged into @code{master} once
|
||||
everything has been successfully built. This allows us to fix issues
|
||||
before they hit users, and to reduce the window during which pre-built
|
||||
binaries are not available.
|
||||
|
||||
When we decide to start building the @code{staging} or
|
||||
@code{core-updates} branches, they will be forked and renamed with the
|
||||
suffix @code{-frozen}, at which time only bug fixes may be pushed to the
|
||||
frozen branches. The @code{core-updates} and @code{staging} branches
|
||||
will remain open to accept patches for the next cycle. Please ask on
|
||||
the mailing list or IRC if unsure where to place a patch.
|
||||
@c TODO: It would be good with badges on the website that tracks these
|
||||
@c branches. Or maybe even a status page.
|
||||
|
||||
@item
|
||||
@cindex determinism, of build processes
|
||||
@@ -1324,13 +1249,12 @@ guix pull --url=/path/to/your/checkout --profile=/tmp/guix.master
|
||||
When posting a patch to the mailing list, use @samp{[PATCH] @dots{}} as
|
||||
a subject, if your patch is to be applied on a branch other than
|
||||
@code{master}, say @code{core-updates}, specify it in the subject like
|
||||
@samp{[PATCH core-updates] @dots{}}.
|
||||
|
||||
You may use your email client or the @command{git send-email} command
|
||||
(@pxref{Sending a Patch Series}). We prefer to get patches in plain
|
||||
text messages, either inline or as MIME attachments. You are advised to
|
||||
pay attention if your email client changes anything like line breaks or
|
||||
indentation which could potentially break the patches.
|
||||
@samp{[PATCH core-updates] @dots{}}. You may use your email client or
|
||||
the @command{git send-email} command (@pxref{Sending a Patch Series}).
|
||||
We prefer to get patches in plain text messages, either inline or as
|
||||
MIME attachments. You are advised to pay attention if your email client
|
||||
changes anything like line breaks or indentation which could potentially
|
||||
break the patches.
|
||||
|
||||
Expect some delay when you submit your very first patch to
|
||||
@email{guix-patches@@gnu.org}. You have to wait until you get an
|
||||
@@ -1338,13 +1262,7 @@ acknowledgement with the assigned tracking number. Future acknowledgements
|
||||
should not be delayed.
|
||||
|
||||
When a bug is resolved, please close the thread by sending an email to
|
||||
@email{@var{ISSUE_NUMBER}-done@@debbugs.gnu.org}.
|
||||
|
||||
@menu
|
||||
* Configuring Git::
|
||||
* Sending a Patch Series::
|
||||
* Teams::
|
||||
@end menu
|
||||
@email{@var{NNN}-done@@debbugs.gnu.org}.
|
||||
|
||||
@node Configuring Git
|
||||
@subsection Configuring Git
|
||||
@@ -1359,192 +1277,51 @@ different name or email just for commits in this repository, you can
|
||||
use @command{git config --local}, or edit @file{.git/config} in the
|
||||
repository instead of @file{~/.gitconfig}.
|
||||
|
||||
Other important Git configuration will automatically be configured when
|
||||
building the project (@pxref{Building from Git}).
|
||||
We provide some default settings in @file{etc/git/gitconfig} which
|
||||
modify how patches are generated, making them easier to read and apply.
|
||||
These settings can be applied by manually copying them to
|
||||
@file{.git/config} in your checkout, or by telling Git to include the
|
||||
whole file:
|
||||
|
||||
@node Sending a Patch Series
|
||||
@subsection Sending a Patch Series
|
||||
@example
|
||||
git config --local include.path ../etc/git/gitconfig
|
||||
@end example
|
||||
|
||||
From then on, any changes to @file{etc/git/gitconfig} would
|
||||
automatically take effect.
|
||||
|
||||
Since the first patch in a series must be sent separately
|
||||
(@pxref{Sending a Patch Series}), it can also be helpful to tell
|
||||
@command{git format-patch} to handle the e-mail threading instead of
|
||||
@command{git send-email}:
|
||||
|
||||
@example
|
||||
git config --local format.thread shallow
|
||||
git config --local sendemail.thread no
|
||||
@end example
|
||||
|
||||
@unnumberedsubsec Sending a Patch Series
|
||||
@anchor{Sending a Patch Series}
|
||||
@cindex patch series
|
||||
@cindex @code{git send-email}
|
||||
@cindex @code{git format-patch}
|
||||
|
||||
@unnumberedsubsubsec Single Patches
|
||||
@anchor{Single Patches}
|
||||
The @command{git send-email} command is the best way to send both single
|
||||
patches and patch series (@pxref{Multiple Patches}) to the Guix mailing
|
||||
list. Sending patches as email attachments may make them difficult to
|
||||
review in some mail clients, and @command{git diff} does not store commit
|
||||
metadata.
|
||||
When sending a patch series (e.g., using @code{git send-email}), please
|
||||
first send one message to @email{guix-patches@@gnu.org}, and then send
|
||||
subsequent patches to @email{@var{NNN}@@debbugs.gnu.org} to make sure
|
||||
they are kept together. See
|
||||
@uref{https://debbugs.gnu.org/Advanced.html, the Debbugs documentation}
|
||||
for more information. You can install @command{git send-email} with
|
||||
@command{guix install git:send-email}.
|
||||
@c Debbugs bug: https://debbugs.gnu.org/db/15/15361.html
|
||||
|
||||
@quotation Note
|
||||
The @command{git send-email} command is provided by the @code{send-email}
|
||||
output of the @code{git} package, i.e. @code{git:send-email}.
|
||||
@end quotation
|
||||
@node Tracking Bugs and Patches
|
||||
@section Tracking Bugs and Patches
|
||||
|
||||
The following command will create a patch email from the latest commit,
|
||||
open it in your @var{EDITOR} or @var{VISUAL} for editing, and send it to
|
||||
the Guix mailing list to be reviewed and merged. Assuming you have
|
||||
already configured Git according to @xref{Configuring Git}, you can
|
||||
simply use:
|
||||
|
||||
@example
|
||||
$ git send-email --annotate -1
|
||||
@end example
|
||||
|
||||
@quotation Tip
|
||||
To add a prefix to the subject of your patch, you may use the
|
||||
@option{--subject-prefix} option. The Guix project uses this to
|
||||
specify that the patch is intended for a branch or repository
|
||||
other than the @code{master} branch of
|
||||
@url{https://git.savannah.gnu.org/cgit/guix.git}.
|
||||
|
||||
@example
|
||||
git send-email --annotate --subject-prefix='PATCH core-updates' -1
|
||||
@end example
|
||||
@end quotation
|
||||
|
||||
The patch email contains a three-dash separator line after the commit
|
||||
message. You may ``annotate'' the patch with explanatory text by adding
|
||||
it under this line. If you do not wish to annotate the email, you may
|
||||
drop the @option{--annotate} option.
|
||||
|
||||
If you need to send a revised patch, don't resend it like this or send
|
||||
a ``fix'' patch to be applied on top of the last one; instead, use
|
||||
@command{git commit --amend} or @url{https://git-rebase.io,
|
||||
@command{git rebase}} to modify the commit, and use the
|
||||
@email{@var{ISSUE_NUMBER}@@debbugs.gnu.org} address and the @option{-v}
|
||||
flag with @command{git send-email}.
|
||||
|
||||
@example
|
||||
$ git commit --amend
|
||||
$ git send-email --annotate -v@var{REVISION} \
|
||||
--to=@var{ISSUE_NUMBER}@@debbugs.gnu.org -1
|
||||
@end example
|
||||
|
||||
@quotation Note
|
||||
Due to an apparent bug in @command{git send-email},
|
||||
@option{-v @var{REVISION}} (with the space) will not work; you
|
||||
@emph{must} use @option{-v@var{REVISION}}.
|
||||
@end quotation
|
||||
|
||||
You can find out @var{ISSUE_NUMBER} either by searching on the mumi
|
||||
interface at @url{https://issues.guix.gnu.org} for the name of your patch or
|
||||
reading the acknowledgement email sent automatically by Debbugs in
|
||||
reply to incoming bugs and patches, which contains the bug number.
|
||||
|
||||
@unnumberedsubsubsec Notifying Teams
|
||||
@anchor{Notifying Teams}
|
||||
@cindex teams
|
||||
If your git checkout has been correctly configured (@pxref{Configuring
|
||||
Git}), the @command{git send-email} command will automatically notify
|
||||
the appropriate team members, based on the scope of your changes. This
|
||||
relies on the @file{etc/teams.scm} script, which can also be invoked
|
||||
manually if you do not use the preferred @command{git send-email}
|
||||
command to submit patches. To list the available actions of the script,
|
||||
you can invoke it via the @command{etc/teams.scm help} command. For
|
||||
more information regarding teams, see @xref{Teams}.
|
||||
|
||||
@unnumberedsubsubsec Multiple Patches
|
||||
@anchor{Multiple Patches}
|
||||
@cindex cover letter
|
||||
While @command{git send-email} alone will suffice for a single
|
||||
patch, an unfortunate flaw in Debbugs means you need to be more
|
||||
careful when sending multiple patches: if you send them all to the
|
||||
@email{guix-patches@@gnu.org} address, a new issue will be created
|
||||
for each patch!
|
||||
|
||||
When sending a series of patches, it's best to send a Git ``cover
|
||||
letter'' first, to give reviewers an overview of the patch series.
|
||||
We can create a directory called @file{outgoing} containing both
|
||||
our patch series and a cover letter called @file{0000-cover-letter.patch}
|
||||
with @command{git format-patch}.
|
||||
|
||||
@example
|
||||
$ git format-patch -@var{NUMBER_COMMITS} -o outgoing \
|
||||
--cover-letter --base=auto
|
||||
@end example
|
||||
|
||||
We can now send @emph{just} the cover letter to the
|
||||
@email{guix-patches@@gnu.org} address, which will create an issue
|
||||
that we can send the rest of the patches to.
|
||||
|
||||
@example
|
||||
$ git send-email outgoing/0000-cover-letter.patch --annotate
|
||||
$ rm outgoing/0000-cover-letter.patch # we don't want to resend it!
|
||||
@end example
|
||||
|
||||
Ensure you edit the email to add an appropriate subject line and
|
||||
blurb before sending it. Note the automatically generated shortlog
|
||||
and diffstat below the blurb.
|
||||
|
||||
Once the Debbugs mailer has replied to your cover letter email, you
|
||||
can send the actual patches to the newly-created issue address.
|
||||
|
||||
@example
|
||||
$ git send-email outgoing/*.patch --to=@var{ISSUE_NUMBER}@@debbugs.gnu.org
|
||||
$ rm -rf outgoing # we don't need these anymore
|
||||
@end example
|
||||
|
||||
Thankfully, this @command{git format-patch} dance is not necessary
|
||||
to send an amended patch series, since an issue already exists for
|
||||
the patchset.
|
||||
|
||||
@example
|
||||
$ git send-email -@var{NUMBER_COMMITS} -v@var{REVISION} \
|
||||
--to=@var{ISSUE_NUMBER}@@debbugs.gnu.org
|
||||
@end example
|
||||
|
||||
If need be, you may use @option{--cover-letter --annotate} to send
|
||||
another cover letter, e.g. for explaining what's changed since the last
|
||||
revision, and these changes are necessary.
|
||||
|
||||
@node Teams
|
||||
@subsection Teams
|
||||
@cindex teams
|
||||
|
||||
There are several teams mentoring different parts of the Guix source
|
||||
code. To list all those teams, you can run from a Guix checkout:
|
||||
|
||||
@example
|
||||
$ ./etc/teams.scm list-teams
|
||||
id: mentors
|
||||
name: Mentors
|
||||
description: A group of mentors who chaperone contributions by newcomers.
|
||||
members:
|
||||
+ Christopher Baines <mail@@cbaines.net>
|
||||
+ Ricardo Wurmus <rekado@@elephly.net>
|
||||
+ Mathieu Othacehe <othacehe@@gnu.org>
|
||||
+ jgart <jgart@@dismail.de>
|
||||
+ Ludovic Courtès <ludo@@gnu.org>
|
||||
@dots{}
|
||||
@end example
|
||||
|
||||
You can run the following command to have the @code{Mentors} team put in
|
||||
CC of a patch series:
|
||||
|
||||
@example
|
||||
$ git send-email --to=@var{ISSUE_NUMBER}@@debbugs.gnu.org \
|
||||
--header-cmd='etc/teams.scm cc-mentors-header-cmd' *.patch
|
||||
@end example
|
||||
|
||||
The appropriate team or teams can also be inferred from the modified
|
||||
files. For instance, if you want to send the two latest commits of the
|
||||
current Git repository to review, you can run:
|
||||
|
||||
@example
|
||||
$ guix shell -D guix
|
||||
[env]$ git send-email --to=@var{ISSUE_NUMBER}@@debbugs.gnu.org -2
|
||||
@end example
|
||||
|
||||
@node Tracking Bugs and Changes
|
||||
@section Tracking Bugs and Changes
|
||||
|
||||
This section describes how the Guix project tracks its bug reports,
|
||||
patch submissions and topic branches.
|
||||
This section describes how the Guix project tracks its bug reports and
|
||||
patch submissions.
|
||||
|
||||
@menu
|
||||
* The Issue Tracker:: The official bug and patch tracker.
|
||||
* Managing Patches and Branches:: How changes to Guix are managed.
|
||||
* Debbugs User Interfaces:: Ways to interact with Debbugs.
|
||||
* Debbugs Usertags:: Tag reports with custom labels.
|
||||
@end menu
|
||||
@@ -1563,71 +1340,9 @@ email to @email{bug-guix@@gnu.org}, while patch submissions are filed
|
||||
against the @code{guix-patches} package by sending email to
|
||||
@email{guix-patches@@gnu.org} (@pxref{Submitting Patches}).
|
||||
|
||||
@node Managing Patches and Branches
|
||||
@subsection Managing Patches and Branches
|
||||
@cindex branching strategy
|
||||
@cindex rebuild scheduling strategy
|
||||
|
||||
Changes should be posted to @email{guix-patches@@gnu.org}. This mailing
|
||||
list fills the patch-tracking database (@pxref{The Issue Tracker}). It
|
||||
also allows patches to be picked up and tested by the quality assurance
|
||||
tooling; the result of that testing eventually shows up on the dashboard
|
||||
at @indicateurl{https://qa.guix.gnu.org/issue/@var{ISSUE_NUMBER}}, where
|
||||
@var{ISSUE_NUMBER} is the number assigned by the issue tracker. Leave
|
||||
time for a review, without committing anything.
|
||||
|
||||
As an exception, some changes considered ``trivial'' or ``obvious'' may
|
||||
be pushed directly to the @code{master} branch. This includes changes
|
||||
to fix typos and reverting commits that caused immediate problems. This
|
||||
is subject to being adjusted, allowing individuals to commit directly on
|
||||
non-controversial changes on parts they’re familiar with.
|
||||
|
||||
Changes which affect more than 300 dependent packages (@pxref{Invoking
|
||||
guix refresh}) should first be pushed to a topic branch other than
|
||||
@code{master}; the set of changes should be consistent---e.g., ``GNOME
|
||||
update'', ``NumPy update'', etc. This allows for testing: the branch
|
||||
will automatically show up at
|
||||
@indicateurl{https://qa.guix.gnu.org/branch/@var{branch}}, with an
|
||||
indication of its build status on various platforms.
|
||||
|
||||
@cindex feature branches, coordination
|
||||
To help coordinate the merging of branches, you must create a new
|
||||
guix-patches issue each time you wish to merge a branch (@pxref{The
|
||||
Issue Tracker}). The title of the issue requesting to merge a branch
|
||||
should have the following format:
|
||||
|
||||
@cindex merge requests, template
|
||||
@example
|
||||
Request for merging "@var{name}" branch
|
||||
@end example
|
||||
|
||||
The @url{https://qa.guix.gnu.org/, QA infrastructure} recognizes such
|
||||
issues and lists the merge requests on its main page. Normally branches
|
||||
will be merged in a ``first come, first merged'' manner, tracked through
|
||||
the guix-patches issues.
|
||||
|
||||
If you agree on a different order with those involved, you can track
|
||||
this by updating which issues block@footnote{You can mark an issue as
|
||||
blocked by another by emailing @email{control@@debbugs.gnu.org} with the
|
||||
following line in the body of the email: @code{block XXXXX by YYYYY}.
|
||||
Where @code{XXXXX} is the number for the blocked issue, and @code{YYYYY}
|
||||
is the number for the issue blocking it.} which other issues.
|
||||
Therefore, to know which branch is at the front of the queue, look for
|
||||
the oldest issue, or the issue that isn't @dfn{blocked} by any other
|
||||
branch merges. An ordered list of branches with the open issues is
|
||||
available at @url{https://qa.guix.gnu.org}.
|
||||
|
||||
Once a branch is at the front of the queue, wait until sufficient time
|
||||
has passed for the build farms to have processed the changes, and for
|
||||
the necessary testing to have happened. For example, you can check
|
||||
@indicateurl{https://qa.guix.gnu.org/branch/@var{branch}} to see
|
||||
information on some builds and substitute availability.
|
||||
|
||||
@node Debbugs User Interfaces
|
||||
@subsection Debbugs User Interfaces
|
||||
|
||||
@subsubsection Web interface
|
||||
|
||||
A web interface (actually @emph{two} web interfaces!) are available to
|
||||
browse issues:
|
||||
|
||||
@@ -1649,88 +1364,6 @@ To view discussions related to issue number @var{n}, go to
|
||||
@indicateurl{https://issues.guix.gnu.org/@var{n}} or
|
||||
@indicateurl{https://bugs.gnu.org/@var{n}}.
|
||||
|
||||
@subsubsection Command-line interface
|
||||
|
||||
Mumi also comes with a command-line interface that can be used to search
|
||||
existing issues, open new issues and send patches. You do not need to
|
||||
use Emacs to use the mumi command-line client. You interact with it
|
||||
only on the command-line.
|
||||
|
||||
To use the mumi command-line interface, navigate to a local clone of the
|
||||
Guix git repository, and drop into a shell with mumi, git and
|
||||
git:send-email installed.
|
||||
|
||||
@example
|
||||
$ cd guix
|
||||
~/guix$ guix shell mumi git git:send-email
|
||||
@end example
|
||||
|
||||
To search for issues, say all open issues about "zig", run
|
||||
|
||||
@example
|
||||
~/guix [env]$ mumi search zig is:open
|
||||
|
||||
#60889 Add zig-build-system
|
||||
opened on 17 Jan 17:37 Z by Ekaitz Zarraga
|
||||
#61036 [PATCH 0/3] Update zig to 0.10.1
|
||||
opened on 24 Jan 09:42 Z by Efraim Flashner
|
||||
#39136 [PATCH] gnu: services: Add endlessh.
|
||||
opened on 14 Jan 2020 21:21 by Nicol? Balzarotti
|
||||
#60424 [PATCH] gnu: Add python-online-judge-tools
|
||||
opened on 30 Dec 2022 07:03 by gemmaro
|
||||
#45601 [PATCH 0/6] vlang 0.2 update
|
||||
opened on 1 Jan 2021 19:23 by Ryan Prior
|
||||
@end example
|
||||
|
||||
Pick an issue and make it the "current" issue.
|
||||
|
||||
@example
|
||||
~/guix [env]$ mumi current 61036
|
||||
|
||||
#61036 [PATCH 0/3] Update zig to 0.10.1
|
||||
opened on 24 Jan 09:42 Z by Efraim Flashner
|
||||
@end example
|
||||
|
||||
Once an issue is the current issue, you can easily create and send
|
||||
patches to it using
|
||||
|
||||
@example
|
||||
~/guix [env]$ git format-patch origin/master
|
||||
~/guix [env]$ mumi send-email foo.patch bar.patch
|
||||
@end example
|
||||
|
||||
Note that you do not have to pass in @samp{--to} or @samp{--cc}
|
||||
arguments to @command{git format-patch}. @command{mumi send-email} will
|
||||
put them in correctly when sending the patches.
|
||||
|
||||
To open a new issue, run
|
||||
|
||||
@example
|
||||
~/guix [env]$ mumi new
|
||||
@end example
|
||||
|
||||
and send patches
|
||||
|
||||
@example
|
||||
~/guix [env]$ mumi send-email foo.patch bar.patch
|
||||
@end example
|
||||
|
||||
@command{mumi send-email} is really a wrapper around @command{git
|
||||
send-email} that automates away all the nitty-gritty of sending patches.
|
||||
It uses the current issue state to automatically figure out the correct
|
||||
@samp{To} address to send to, other participants to @samp{Cc}, headers
|
||||
to add, etc.
|
||||
|
||||
Also note that, unlike @command{git send-email}, @command{mumi
|
||||
send-email} works perfectly well with single and multiple patches alike.
|
||||
It automates away the debbugs dance of sending the first patch, waiting
|
||||
for a response from debbugs and sending the remaining patches. It does
|
||||
so by sending the first patch, polling the server for a response, and
|
||||
then sending the remaining patches. This polling can unfortunately take
|
||||
a few minutes. So, please be patient.
|
||||
|
||||
@subsubsection Emacs interface
|
||||
|
||||
If you use Emacs, you may find it more convenient to interact with
|
||||
issues using @file{debbugs.el}, which you can install with:
|
||||
|
||||
@@ -1809,12 +1442,7 @@ project for at least 6 months. This ensures enough interactions with
|
||||
the contributor, which is essential for mentoring and assessing whether
|
||||
they are ready to become a committer. Commit access should not be
|
||||
thought of as a ``badge of honor'' but rather as a responsibility a
|
||||
contributor is willing to take to help the project. It is expected from
|
||||
all contributors, and even more so from committers, to help build
|
||||
consensus and make decisions based on consensus. To learn what
|
||||
consensus decision making means and understand its finer details, you
|
||||
are encouraged to read
|
||||
@url{https://www.seedsforchange.org.uk/consensus}.
|
||||
contributor is willing to take to help the project.
|
||||
|
||||
The following sections explain how to get commit access, how to be ready
|
||||
to push commits, and the policies and community expectations for commits
|
||||
@@ -1907,30 +1535,33 @@ git config commit.gpgsign true
|
||||
git config user.signingkey CABBA6EA1DC0FF33
|
||||
@end example
|
||||
|
||||
To check that commits are signed with correct key, use:
|
||||
You can prevent yourself from accidentally pushing unsigned commits to
|
||||
Savannah by using the pre-push Git hook located at
|
||||
@file{etc/git/pre-push}:
|
||||
|
||||
@example
|
||||
make authenticate
|
||||
cp etc/git/pre-push .git/hooks/pre-push
|
||||
@end example
|
||||
|
||||
To avoid accidentally pushing unsigned or signed with the wrong key
|
||||
commits to Savannah, make sure to configure Git according to
|
||||
@xref{Configuring Git}.
|
||||
|
||||
@subsection Commit Policy
|
||||
|
||||
If you get commit access, please make sure to follow the policy below
|
||||
(discussions of the policy can take place on
|
||||
If you get commit access, please make sure to follow
|
||||
the policy below (discussions of the policy can take place on
|
||||
@email{guix-devel@@gnu.org}).
|
||||
|
||||
Ensure you're aware of how the changes should be handled
|
||||
(@pxref{Managing Patches and Branches}) prior to being pushed to the
|
||||
repository, especially for the @code{master} branch.
|
||||
Non-trivial patches should always be posted to
|
||||
@email{guix-patches@@gnu.org} (trivial patches include fixing typos,
|
||||
etc.). This mailing list fills the patch-tracking database
|
||||
(@pxref{Tracking Bugs and Patches}).
|
||||
|
||||
If you're committing and pushing your own changes, try and wait at least
|
||||
one week (two weeks for more significant changes) after you send them
|
||||
for review. After this, if no one else is available to review them and
|
||||
if you're confident about the changes, it's OK to commit.
|
||||
For patches that just add a new package, and a simple one, it's OK to
|
||||
commit, if you're confident (which means you successfully built it in a
|
||||
chroot setup, and have done a reasonable copyright and license
|
||||
auditing). Likewise for package upgrades, except upgrades that trigger
|
||||
a lot of rebuilds (for example, upgrading GnuTLS or GLib). We have a
|
||||
mailing list for commit notifications (@email{guix-commits@@gnu.org}),
|
||||
so people can notice. Before pushing your changes, make sure to run
|
||||
@code{git pull --rebase}.
|
||||
|
||||
When pushing a commit on behalf of somebody else, please add a
|
||||
@code{Signed-off-by} line at the end of the commit log message---e.g.,
|
||||
@@ -1945,6 +1576,14 @@ right before pushing:
|
||||
make check-channel-news
|
||||
@end example
|
||||
|
||||
For anything else, please post to @email{guix-patches@@gnu.org} and
|
||||
leave time for a review, without committing anything (@pxref{Submitting
|
||||
Patches}). If you didn’t receive any reply after two weeks, and if
|
||||
you're confident, it's OK to commit.
|
||||
|
||||
That last part is subject to being adjusted, allowing individuals to commit
|
||||
directly on non-controversial changes on parts they’re familiar with.
|
||||
|
||||
@subsection Addressing Issues
|
||||
|
||||
Peer review (@pxref{Submitting Patches}) and tools such as
|
||||
@@ -2058,47 +1697,6 @@ This check can be disabled, @emph{at your own peril}, by setting the
|
||||
this variable is set, the updated package source is also added to the
|
||||
store. This is used as part of the release process of Guix.
|
||||
|
||||
@cindex documentation
|
||||
@node Writing Documentation
|
||||
@section Writing Documentation
|
||||
|
||||
Guix is documented using the Texinfo system. If you are not yet
|
||||
familiar with it, we accept contributions for documentation in most
|
||||
formats. That includes plain text, Markdown, Org, etc.
|
||||
|
||||
Documentation contributions can be sent to
|
||||
@email{guix-patches@@gnu.org}. Prepend @samp{[DOCUMENTATION]} to the
|
||||
subject.
|
||||
|
||||
When you need to make more than a simple addition to the documentation,
|
||||
we prefer that you send a proper patch as opposed to sending an email
|
||||
as described above. @xref{Submitting Patches} for more information on
|
||||
how to send your patches.
|
||||
|
||||
To modify the documentation, you need to edit @file{doc/guix.texi} and
|
||||
@file{doc/contributing.texi} (which contains this documentation
|
||||
section), or @file{doc/guix-cookbook.texi} for the cookbook. If
|
||||
you compiled the Guix repository before, you will have
|
||||
many more @file{.texi} files that are translations of these
|
||||
documents. Do not modify them, the translation is managed through
|
||||
@uref{https://translate.fedoraproject.org/projects/guix, Weblate}.
|
||||
@xref{Translating Guix} for more information.
|
||||
|
||||
To render documentation, you must first make sure that you ran
|
||||
@command{./configure} in your source tree (@pxref{Running Guix Before
|
||||
It Is Installed}). After that you can run one of the following
|
||||
commands:
|
||||
|
||||
@itemize
|
||||
@item @samp{make doc/guix.info} to compile the Info manual.
|
||||
You can check it with @command{info doc/guix.info}.
|
||||
@item @samp{make doc/guix.html} to compile the HTML version.
|
||||
You can point your browser to the relevant file in the
|
||||
@file{doc/guix.html} directory.
|
||||
@item @samp{make doc/guix-cookbook.info} for the cookbook Info manual.
|
||||
@item @samp{make doc/guix-cookbook.html} for the cookbook HTML version.
|
||||
@end itemize
|
||||
|
||||
@cindex translation
|
||||
@cindex l10n
|
||||
@cindex i18n
|
||||
@@ -2313,28 +1911,6 @@ Currently, some parts of Guix cannot be translated on Weblate, help wanted!
|
||||
translated.
|
||||
@end itemize
|
||||
|
||||
@subsubheading Conditions for Inclusion
|
||||
|
||||
There are no conditions for adding new translations of the @code{guix} and
|
||||
@code{guix-packages} components, other than they need at least one translated
|
||||
string. New languages will be added to Guix as soon as possible. The
|
||||
files may be removed if they fall out of sync and have no more translated
|
||||
strings.
|
||||
|
||||
Given that the web site is dedicated to new users, we want its translation
|
||||
to be as complete as possible before we include it in the language menu.
|
||||
For a new language to be included, it needs to reach at least 80% completion.
|
||||
When a language is included, it may be removed in the future if it stays
|
||||
out of sync and falls below 60% completion.
|
||||
|
||||
The manual and cookbook are automatically added in the default compilation
|
||||
target. Every time we synchronize translations, developers need to
|
||||
recompile all the translated manuals and cookbooks. This is useless for what
|
||||
is essentially the English manual or cookbook. Therefore, we will only
|
||||
include a new language when it reaches 10% completion in the component.
|
||||
When a language is included, it may be removed in the future if it stays
|
||||
out of sync and falls below 5% completion.
|
||||
|
||||
@subsubheading Translation Infrastructure
|
||||
|
||||
Weblate is backed by a git repository from which it discovers new strings to
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
(package
|
||||
(inherit gdb)
|
||||
(native-inputs (modify-inputs (package-native-inputs gdb)
|
||||
(prepend autoconf-2.69 automake texinfo))))
|
||||
(prepend autoconf-2.64 automake texinfo))))
|
||||
|
||||
+94
-1734
File diff suppressed because it is too large
Load Diff
+2322
-9034
File diff suppressed because it is too large
Load Diff
@@ -13,13 +13,12 @@
|
||||
(service home-bash-service-type
|
||||
(home-bash-configuration
|
||||
(guix-defaults? #t)
|
||||
(bash-profile (list (plain-file "bash-profile" "\
|
||||
export HISTFILE=$XDG_CACHE_HOME/.bash_history")))))
|
||||
(bash-profile '("\
|
||||
export HISTFILE=$XDG_CACHE_HOME/.bash_history"))))
|
||||
|
||||
(simple-service 'test-config
|
||||
home-xdg-configuration-files-service-type
|
||||
(list `("test.conf"
|
||||
home-files-service-type
|
||||
(list `("config/test.conf"
|
||||
,(plain-file "tmp-file.txt"
|
||||
"the content of
|
||||
~/.config/test.conf")))))))
|
||||
"the content of ~/.config/test.conf")))))))
|
||||
|
||||
|
||||
+8
-13
@@ -1,9 +1,9 @@
|
||||
# htmlxref.cnf - reference file for free Texinfo manuals on the web.
|
||||
# Modified by Ludovic Courtès <ludo@gnu.org> for the GNU Guix manual.
|
||||
|
||||
htmlxrefversion=2022-12-18.15; # UTC
|
||||
htmlxrefversion=2021-09-24.23; # UTC
|
||||
|
||||
# Copyright 2010-2020, 2022 Free Software Foundation, Inc.
|
||||
# Copyright 2010-2020 Free Software Foundation, Inc.
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
# are permitted in any medium without royalty provided the copyright
|
||||
@@ -291,6 +291,8 @@ gdbm chapter ${GDBM}/html_chapter/
|
||||
gdbm section ${GDBM}/html_section/
|
||||
gdbm node ${GDBM}/html_node/
|
||||
|
||||
# XXX: These are actually pages created by texi2html, so no quite following
|
||||
# the expected naming scheme.
|
||||
geiser chapter http://geiser.nongnu.org/
|
||||
|
||||
gettext mono ${GS}/gettext/manual/gettext.html
|
||||
@@ -409,21 +411,16 @@ GUILE_GNOME = ${GS}/guile-gnome/docs
|
||||
|
||||
guile-gtk node ${GS}/guile-gtk/docs/guile-gtk/
|
||||
|
||||
guile-netlink mono https://git.lepiller.eu/guile-netlink/manual/manual.html
|
||||
|
||||
guile-rpc mono ${GS}/guile-rpc/manual/guile-rpc.html
|
||||
guile-rpc node ${GS}/guile-rpc/manual/html_node/
|
||||
|
||||
GUIX_ROOT = https://guix.gnu.org
|
||||
GUIX = ${GUIX_ROOT}/manual
|
||||
GUIX = ${GS}/guix/manual
|
||||
guix.de mono ${GUIX}/de/guix.de.html
|
||||
guix.de node ${GUIX}/de/html_node/
|
||||
guix.es mono ${GUIX}/es/guix.es.html
|
||||
guix.es node ${GUIX}/es/html_node/
|
||||
guix.fr mono ${GUIX}/fr/guix.fr.html
|
||||
guix.fr node ${GUIX}/fr/html_node/
|
||||
guix.pt_BR mono ${GUIX}/pt-br/guix.pt_BR.html
|
||||
guix.pt_BR node ${GUIX}/pt-br/html_node/
|
||||
guix.ru mono ${GUIX}/ru/guix.ru.html
|
||||
guix.ru node ${GUIX}/ru/html_node/
|
||||
guix.zh_CN mono ${GUIX}/zh-cn/guix.zh_CN.html
|
||||
@@ -431,13 +428,11 @@ GUIX = ${GUIX_ROOT}/manual
|
||||
guix mono ${GUIX}/en/guix.html
|
||||
guix node ${GUIX}/en/html_node/
|
||||
|
||||
GUIX_COOKBOOK = ${GUIX_ROOT}/cookbook
|
||||
guix-cookbook.de mono ${GUIX_COOKBOOK}/de/guix-cookbook.de.html
|
||||
GUIX_COOKBOOK = ${GS}/guix/cookbook
|
||||
guix-cookbook.de mono ${GUIX_COOKBOOK}/de/guix-cookbook.html
|
||||
guix-cookbook.de node ${GUIX_COOKBOOK}/de/html_node/
|
||||
guix-cookbook.fr mono ${GUIX_COOKBOOK}/fr/guix-cookbook.fr.html
|
||||
guix-cookbook.fr mono ${GUIX_COOKBOOK}/fr/guix-cookbook.html
|
||||
guix-cookbook.fr node ${GUIX_COOKBOOK}/fr/html_node/
|
||||
guix-cookbook.sk mono ${GUIX_COOKBOOK}/sk/guix-cookbook.sk.html
|
||||
guix-cookbook.sk node ${GUIX_COOKBOOK}/sk/html_node/
|
||||
guix-cookbook mono ${GUIX_COOKBOOK}/en/guix-cookbook.html
|
||||
guix-cookbook node ${GUIX_COOKBOOK}/en/html_node/
|
||||
|
||||
|
||||
+17
-17
@@ -22,8 +22,8 @@
|
||||
# along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# If adding a language, update the following variables, and info_TEXINFOS.
|
||||
MANUAL_LANGUAGES = de es fr pt_BR ru zh_CN
|
||||
COOKBOOK_LANGUAGES = de fr ko sk
|
||||
MANUAL_LANGUAGES = de es fa fi fr it ko pt_BR ru sk zh_CN
|
||||
COOKBOOK_LANGUAGES = de es fa fi fr ko pt_BR ru sk uk zh_Hans
|
||||
|
||||
# Arg1: A list of languages codes.
|
||||
# Arg2: The file name stem.
|
||||
@@ -34,15 +34,27 @@ lang_to_texinfo = $(foreach lang,$(1),%D%/$(2).$(lang).texi)
|
||||
info_TEXINFOS = %D%/guix.texi \
|
||||
%D%/guix.de.texi \
|
||||
%D%/guix.es.texi \
|
||||
%D%/guix.fa.texi \
|
||||
%D%/guix.fi.texi \
|
||||
%D%/guix.fr.texi \
|
||||
%D%/guix.it.texi \
|
||||
%D%/guix.ko.texi \
|
||||
%D%/guix.pt_BR.texi \
|
||||
%D%/guix.ru.texi \
|
||||
%D%/guix.sk.texi \
|
||||
%D%/guix.zh_CN.texi \
|
||||
%D%/guix-cookbook.texi \
|
||||
%D%/guix-cookbook.de.texi \
|
||||
%D%/guix-cookbook.es.texi \
|
||||
%D%/guix-cookbook.fa.texi \
|
||||
%D%/guix-cookbook.fi.texi \
|
||||
%D%/guix-cookbook.fr.texi \
|
||||
%D%/guix-cookbook.ko.texi \
|
||||
%D%/guix-cookbook.sk.texi
|
||||
%D%/guix-cookbook.pt_BR.texi \
|
||||
%D%/guix-cookbook.ru.texi \
|
||||
%D%/guix-cookbook.sk.texi \
|
||||
%D%/guix-cookbook.uk.texi \
|
||||
%D%/guix-cookbook.zh_Hans.texi
|
||||
|
||||
%C%_guix_TEXINFOS = \
|
||||
%D%/contributing.texi \
|
||||
@@ -179,31 +191,19 @@ sub_commands_mans = \
|
||||
$(srcdir)/%D%/guix-archive.1 \
|
||||
$(srcdir)/%D%/guix-build.1 \
|
||||
$(srcdir)/%D%/guix-challenge.1 \
|
||||
$(srcdir)/%D%/guix-container.1 \
|
||||
$(srcdir)/%D%/guix-copy.1 \
|
||||
$(srcdir)/%D%/guix-deploy.1 \
|
||||
$(srcdir)/%D%/guix-describe.1 \
|
||||
$(srcdir)/%D%/guix-download.1 \
|
||||
$(srcdir)/%D%/guix-edit.1 \
|
||||
$(srcdir)/%D%/guix-environment.1 \
|
||||
$(srcdir)/%D%/guix-gc.1 \
|
||||
$(srcdir)/%D%/guix-git.1 \
|
||||
$(srcdir)/%D%/guix-graph.1 \
|
||||
$(srcdir)/%D%/guix-hash.1 \
|
||||
$(srcdir)/%D%/guix-home.1 \
|
||||
$(srcdir)/%D%/guix-import.1 \
|
||||
$(srcdir)/%D%/guix-lint.1 \
|
||||
$(srcdir)/%D%/guix-offload.1 \
|
||||
$(srcdir)/%D%/guix-pack.1 \
|
||||
$(srcdir)/%D%/guix-package.1 \
|
||||
$(srcdir)/%D%/guix-processes.1 \
|
||||
$(srcdir)/%D%/guix-publish.1 \
|
||||
$(srcdir)/%D%/guix-pull.1 \
|
||||
$(srcdir)/%D%/guix-refresh.1 \
|
||||
$(srcdir)/%D%/guix-repl.1 \
|
||||
$(srcdir)/%D%/guix-shell.1 \
|
||||
$(srcdir)/%D%/guix-size.1 \
|
||||
$(srcdir)/%D%/guix-style.1 \
|
||||
$(srcdir)/%D%/guix-system.1 \
|
||||
$(srcdir)/%D%/guix-time-machine.1 \
|
||||
$(srcdir)/%D%/guix-weather.1
|
||||
@@ -229,8 +229,8 @@ $(srcdir)/%D%/guix.1: scripts/guix.in $(sub_commands_mans)
|
||||
# The 'case' ensures the man pages are only generated if the corresponding
|
||||
# source script (the first prerequisite) has been changed. The $(GOBJECTS)
|
||||
# prerequisite is solely meant to force these docs to be made only after all
|
||||
# Guile modules have been compiled. We also need the guix script to exist.
|
||||
$(srcdir)/%D%/guix-%.1: guix/scripts/%.scm $(GOBJECTS) scripts/guix
|
||||
# Guile modules have been compiled.
|
||||
$(srcdir)/%D%/guix-%.1: guix/scripts/%.scm $(GOBJECTS)
|
||||
-@case '$?' in \
|
||||
*$<*) $(AM_V_P) && set -x || echo " HELP2MAN $@"; \
|
||||
$(gen_man) --output="$@" "guix $*";; \
|
||||
|
||||
+90
-109
@@ -6,7 +6,6 @@
|
||||
;;; Copyright © 2020, 2021 Ricardo Wurmus <rekado@elephly.net>
|
||||
;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
|
||||
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
|
||||
;;; Copyright © 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -29,19 +28,19 @@
|
||||
|
||||
;;; Code:
|
||||
|
||||
(use-modules ((sxml xpath) #:prefix xpath:)
|
||||
(srfi srfi-1)
|
||||
(srfi srfi-2)
|
||||
(srfi srfi-9)
|
||||
(srfi srfi-11)
|
||||
(srfi srfi-26)
|
||||
(ice-9 format)
|
||||
(ice-9 popen)
|
||||
(ice-9 match)
|
||||
(ice-9 rdelim)
|
||||
(ice-9 regex)
|
||||
(ice-9 textual-ports)
|
||||
(guix gexp))
|
||||
(import (sxml xpath)
|
||||
(srfi srfi-1)
|
||||
(srfi srfi-2)
|
||||
(srfi srfi-9)
|
||||
(srfi srfi-11)
|
||||
(srfi srfi-26)
|
||||
(ice-9 format)
|
||||
(ice-9 popen)
|
||||
(ice-9 match)
|
||||
(ice-9 rdelim)
|
||||
(ice-9 regex)
|
||||
(ice-9 textual-ports)
|
||||
(guix gexp))
|
||||
|
||||
(define* (break-string str #:optional (max-line-length 70))
|
||||
"Break the string STR into lines that are no longer than MAX-LINE-LENGTH.
|
||||
@@ -101,16 +100,12 @@ LINE-NO in PORT."
|
||||
(read-line port)
|
||||
(loop (1- i) last-top-level-sexp))))))
|
||||
|
||||
;;; Whether the hunk contains a newly added package (definition), a removed
|
||||
;;; package (removal) or something else (#false).
|
||||
(define hunk-types '(addition removal #false))
|
||||
|
||||
(define-record-type <hunk>
|
||||
(make-hunk file-name
|
||||
old-line-number
|
||||
new-line-number
|
||||
diff-lines
|
||||
type)
|
||||
definition?)
|
||||
hunk?
|
||||
(file-name hunk-file-name)
|
||||
;; Line number before the change
|
||||
@@ -119,8 +114,8 @@ LINE-NO in PORT."
|
||||
(new-line-number hunk-new-line-number)
|
||||
;; The full diff to be used with "git apply --cached"
|
||||
(diff-lines hunk-diff-lines)
|
||||
;; Does this hunk add or remove a package?
|
||||
(type hunk-type)) ;one of 'hunk-types'
|
||||
;; Does this hunk add a definition?
|
||||
(definition? hunk-definition?))
|
||||
|
||||
(define* (hunk->patch hunk #:optional (port (current-output-port)))
|
||||
(let ((file-name (hunk-file-name hunk)))
|
||||
@@ -138,30 +133,25 @@ LINE-NO in PORT."
|
||||
;; new definitions with changes to existing
|
||||
;; definitions.
|
||||
"--unified=1"
|
||||
"--" "gnu")))
|
||||
"gnu")))
|
||||
(define (extract-line-number line-tag)
|
||||
(abs (string->number
|
||||
(car (string-split line-tag #\,)))))
|
||||
(define (read-hunk)
|
||||
(let loop ((lines '())
|
||||
(type #false))
|
||||
(definition? #false))
|
||||
(let ((line (read-line port 'concat)))
|
||||
(cond
|
||||
((eof-object? line)
|
||||
(values (reverse lines) type))
|
||||
(values (reverse lines) definition?))
|
||||
((or (string-prefix? "@@ " line)
|
||||
(string-prefix? "diff --git" line))
|
||||
(unget-string port line)
|
||||
(values (reverse lines) type))
|
||||
(values (reverse lines) definition?))
|
||||
(else
|
||||
(loop (cons line lines)
|
||||
(or type
|
||||
(cond
|
||||
((string-prefix? "+(define" line)
|
||||
'addition)
|
||||
((string-prefix? "-(define" line)
|
||||
'removal)
|
||||
(else #false)))))))))
|
||||
(or definition?
|
||||
(string-prefix? "+(define" line))))))))
|
||||
(define info
|
||||
(let loop ((acc '())
|
||||
(file-name #f))
|
||||
@@ -176,13 +166,13 @@ LINE-NO in PORT."
|
||||
(match (string-split line #\space)
|
||||
((_ old-start new-start . _)
|
||||
(let-values
|
||||
(((diff-lines type) (read-hunk)))
|
||||
(((diff-lines definition?) (read-hunk)))
|
||||
(loop (cons (make-hunk file-name
|
||||
(extract-line-number old-start)
|
||||
(extract-line-number new-start)
|
||||
(cons (string-append line "\n")
|
||||
diff-lines)
|
||||
type) acc)
|
||||
definition?) acc)
|
||||
file-name)))))
|
||||
(else (loop acc file-name))))))
|
||||
(close-pipe port)
|
||||
@@ -224,10 +214,10 @@ corresponding to the top-level definition containing the staged changes."
|
||||
(define* (change-commit-message file-name old new #:optional (port (current-output-port)))
|
||||
"Print ChangeLog commit message for changes between OLD and NEW."
|
||||
(define (get-values expr field)
|
||||
(match ((xpath:sxpath `(// ,field quasiquote *)) expr)
|
||||
(match ((sxpath `(// ,field quasiquote *)) expr)
|
||||
(()
|
||||
;; New-style plain lists
|
||||
(match ((xpath:sxpath `(// ,field list *)) expr)
|
||||
(match ((sxpath `(// ,field list *)) expr)
|
||||
((inner) inner)
|
||||
(_ '())))
|
||||
;; Old-style labelled inputs
|
||||
@@ -244,7 +234,7 @@ corresponding to the top-level definition containing the staged changes."
|
||||
(define variable-name
|
||||
(second old))
|
||||
(define version
|
||||
(and=> ((xpath:sxpath '(// version *any*)) new)
|
||||
(and=> ((sxpath '(// version *any*)) new)
|
||||
first))
|
||||
(format port
|
||||
"gnu: ~a: Update to ~a.~%~%* ~a (~a): Update to ~a.~%"
|
||||
@@ -272,18 +262,10 @@ corresponding to the top-level definition containing the staged changes."
|
||||
(listify added))))))))))
|
||||
'(inputs propagated-inputs native-inputs)))
|
||||
|
||||
(define* (add-commit-message file-name variable-name
|
||||
#:optional (port (current-output-port)))
|
||||
"Print ChangeLog commit message for a change to FILE-NAME adding a
|
||||
definition."
|
||||
(format port "gnu: Add ~a.~%~%* ~a (~a): New variable.~%"
|
||||
variable-name file-name variable-name))
|
||||
|
||||
(define* (remove-commit-message file-name variable-name
|
||||
#:optional (port (current-output-port)))
|
||||
"Print ChangeLog commit message for a change to FILE-NAME removing a
|
||||
definition."
|
||||
(format port "gnu: Remove ~a.~%~%* ~a (~a): Delete variable.~%"
|
||||
(define* (add-commit-message file-name variable-name #:optional (port (current-output-port)))
|
||||
"Print ChangeLog commit message for a change to FILE-NAME adding a definition."
|
||||
(format port
|
||||
"gnu: Add ~a.~%~%* ~a (~a): New variable.~%"
|
||||
variable-name file-name variable-name))
|
||||
|
||||
(define* (custom-commit-message file-name variable-name message changelog
|
||||
@@ -362,67 +344,66 @@ modifying."
|
||||
(()
|
||||
(display "Nothing to be done.\n" (current-error-port)))
|
||||
(hunks
|
||||
(let-values (((definitions changes) (partition hunk-type hunks)))
|
||||
;; Additions/removals.
|
||||
(for-each
|
||||
(lambda (hunk)
|
||||
(and-let* ((define-line (find (cut string-match "(\\+|-)\\(define" <>)
|
||||
(hunk-diff-lines hunk)))
|
||||
(variable-name (and=> (string-tokenize define-line)
|
||||
second))
|
||||
(commit-message-proc (match (hunk-type hunk)
|
||||
('addition add-commit-message)
|
||||
('removal remove-commit-message))))
|
||||
(commit-message-proc (hunk-file-name hunk) variable-name)
|
||||
(let ((port (open-pipe* OPEN_WRITE
|
||||
"git" "apply"
|
||||
"--cached"
|
||||
"--unidiff-zero")))
|
||||
(hunk->patch hunk port)
|
||||
(unless (eqv? 0 (status:exit-val (close-pipe port)))
|
||||
(error "Cannot apply")))
|
||||
(let-values
|
||||
(((definitions changes)
|
||||
(partition hunk-definition? hunks)))
|
||||
|
||||
(let ((port (open-pipe* OPEN_WRITE "git" "commit" "-F" "-")))
|
||||
(commit-message-proc (hunk-file-name hunk) variable-name port)
|
||||
(usleep %delay)
|
||||
(unless (eqv? 0 (status:exit-val (close-pipe port)))
|
||||
(error "Cannot commit"))))
|
||||
(usleep %delay))
|
||||
definitions))
|
||||
|
||||
;; Changes.
|
||||
(for-each
|
||||
(match-lambda
|
||||
((new old . hunks)
|
||||
(for-each (lambda (hunk)
|
||||
(let ((port (open-pipe* OPEN_WRITE
|
||||
"git" "apply"
|
||||
"--cached"
|
||||
"--unidiff-zero")))
|
||||
(hunk->patch hunk port)
|
||||
(unless (eqv? 0 (status:exit-val (close-pipe port)))
|
||||
;; Additions.
|
||||
(for-each (lambda (hunk)
|
||||
(and-let*
|
||||
((define-line (find (cut string-prefix? "+(define" <>)
|
||||
(hunk-diff-lines hunk)))
|
||||
(variable-name (and=> (string-tokenize define-line) second)))
|
||||
(add-commit-message (hunk-file-name hunk) variable-name)
|
||||
(let ((port (open-pipe* OPEN_WRITE
|
||||
"git" "apply"
|
||||
"--cached"
|
||||
"--unidiff-zero")))
|
||||
(hunk->patch hunk port)
|
||||
(unless (eqv? 0 (status:exit-val (close-pipe port)))
|
||||
(error "Cannot apply")))
|
||||
(usleep %delay))
|
||||
hunks)
|
||||
(define copyright-line
|
||||
(any (lambda (line) (and=> (string-prefix? "+;;; Copyright ©" line)
|
||||
(const line)))
|
||||
(hunk-diff-lines (first hunks))))
|
||||
(cond
|
||||
(copyright-line
|
||||
(add-copyright-line copyright-line))
|
||||
(else
|
||||
(let ((port (open-pipe* OPEN_WRITE "git" "commit" "-F" "-")))
|
||||
(change-commit-message* (hunk-file-name (first hunks))
|
||||
old new)
|
||||
(change-commit-message* (hunk-file-name (first hunks))
|
||||
old new
|
||||
port)
|
||||
(usleep %delay)
|
||||
(unless (eqv? 0 (status:exit-val (close-pipe port)))
|
||||
(error "Cannot commit")))))))
|
||||
;; XXX: we recompute the hunks here because previous
|
||||
;; insertions lead to offsets.
|
||||
(new+old+hunks (diff-info))))))
|
||||
|
||||
(let ((port (open-pipe* OPEN_WRITE "git" "commit" "-F" "-")))
|
||||
(add-commit-message (hunk-file-name hunk)
|
||||
variable-name port)
|
||||
(usleep %delay)
|
||||
(unless (eqv? 0 (status:exit-val (close-pipe port)))
|
||||
(error "Cannot commit"))))
|
||||
(usleep %delay))
|
||||
definitions)
|
||||
|
||||
;; Changes.
|
||||
(for-each (match-lambda
|
||||
((new old . hunks)
|
||||
(for-each (lambda (hunk)
|
||||
(let ((port (open-pipe* OPEN_WRITE
|
||||
"git" "apply"
|
||||
"--cached"
|
||||
"--unidiff-zero")))
|
||||
(hunk->patch hunk port)
|
||||
(unless (eqv? 0 (status:exit-val (close-pipe port)))
|
||||
(error "Cannot apply")))
|
||||
(usleep %delay))
|
||||
hunks)
|
||||
(define copyright-line
|
||||
(any (lambda (line) (and=> (string-prefix? "+;;; Copyright ©" line)
|
||||
(const line)))
|
||||
(hunk-diff-lines (first hunks))))
|
||||
(cond
|
||||
(copyright-line
|
||||
(add-copyright-line copyright-line))
|
||||
(else
|
||||
(let ((port (open-pipe* OPEN_WRITE "git" "commit" "-F" "-")))
|
||||
(change-commit-message* (hunk-file-name (first hunks))
|
||||
old new)
|
||||
(change-commit-message* (hunk-file-name (first hunks))
|
||||
old new
|
||||
port)
|
||||
(usleep %delay)
|
||||
(unless (eqv? 0 (status:exit-val (close-pipe port)))
|
||||
(error "Cannot commit")))))))
|
||||
;; XXX: we recompute the hunks here because previous
|
||||
;; insertions lead to offsets.
|
||||
(new+old+hunks (diff-info)))))))
|
||||
|
||||
(apply main (cdr (command-line)))
|
||||
|
||||
+30
-31
@@ -117,59 +117,58 @@ _guix_is_removing ()
|
||||
$result
|
||||
}
|
||||
|
||||
_guix_is_short_option ()
|
||||
{
|
||||
case "${COMP_WORDS[$COMP_CWORD - 1]}" in
|
||||
--*) false;;
|
||||
-*$1) true ;;
|
||||
*) false ;;
|
||||
esac
|
||||
}
|
||||
|
||||
_guix_is_long_option ()
|
||||
{
|
||||
# Don't handle (non-GNU?) ‘--long-option VALUE’, as Guix doesn't either.
|
||||
case "${COMP_WORDS[$COMP_CWORD]}" in
|
||||
--$1=*) true ;;
|
||||
*) false ;;
|
||||
esac
|
||||
}
|
||||
|
||||
_guix_is_dash_f ()
|
||||
{
|
||||
_guix_is_short_option f ||
|
||||
_guix_is_long_option file ||
|
||||
_guix_is_long_option install-from-file
|
||||
[ "${COMP_WORDS[$COMP_CWORD - 1]}" = "-f" ] \
|
||||
|| { case "${COMP_WORDS[$COMP_CWORD]}" in
|
||||
--file=*|--install-from-file=*) true;;
|
||||
*) false;;
|
||||
esac }
|
||||
}
|
||||
|
||||
_guix_is_dash_l ()
|
||||
{
|
||||
_guix_is_short_option l ||
|
||||
_guix_is_long_option load
|
||||
[ "${COMP_WORDS[$COMP_CWORD - 1]}" = "-l" ] \
|
||||
|| { case "${COMP_WORDS[$COMP_CWORD]}" in
|
||||
--load=*) true;;
|
||||
*) false;;
|
||||
esac }
|
||||
}
|
||||
|
||||
_guix_is_dash_L ()
|
||||
{
|
||||
_guix_is_short_option L ||
|
||||
_guix_is_long_option load-path
|
||||
[ "${COMP_WORDS[$COMP_CWORD - 1]}" = "-L" ] \
|
||||
|| { case "${COMP_WORDS[$COMP_CWORD]}" in
|
||||
--load-path=*) true;;
|
||||
*) false;;
|
||||
esac }
|
||||
}
|
||||
|
||||
_guix_is_dash_m ()
|
||||
{
|
||||
_guix_is_short_option m ||
|
||||
_guix_is_long_option manifest
|
||||
[ "${COMP_WORDS[$COMP_CWORD - 1]}" = "-m" ] \
|
||||
|| { case "${COMP_WORDS[$COMP_CWORD]}" in
|
||||
--manifest=*) true;;
|
||||
*) false;;
|
||||
esac }
|
||||
}
|
||||
|
||||
_guix_is_dash_C ()
|
||||
{
|
||||
_guix_is_short_option C ||
|
||||
_guix_is_long_option channels
|
||||
[ "${COMP_WORDS[$COMP_CWORD - 1]}" = "-C" ] \
|
||||
|| { case "${COMP_WORDS[$COMP_CWORD]}" in
|
||||
--channels=*) true;;
|
||||
*) false;;
|
||||
esac }
|
||||
}
|
||||
|
||||
_guix_is_dash_p ()
|
||||
{
|
||||
_guix_is_short_option p ||
|
||||
_guix_is_long_option profile
|
||||
[ "${COMP_WORDS[$COMP_CWORD - 1]}" = "-p" ] \
|
||||
|| { case "${COMP_WORDS[$COMP_CWORD]}" in
|
||||
--profile=*) true;;
|
||||
*) false;;
|
||||
esac }
|
||||
}
|
||||
|
||||
_guix_complete_file ()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2021-2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -30,12 +30,11 @@
|
||||
(match (origin-actual-file-name origin)
|
||||
(#f #f)
|
||||
((? string? file)
|
||||
;; As of version 0.4.0, Disarchive can only deal with raw tarballs,
|
||||
;; gzip-compressed tarballs, and xz-compressed tarballs.
|
||||
;; As of version 0.2.1, Disarchive can only deal with raw tarballs and
|
||||
;; gzip-compressed tarballs.
|
||||
(and (origin-hash origin)
|
||||
(or (string-suffix? ".tar.gz" file)
|
||||
(string-suffix? ".tgz" file)
|
||||
(string-suffix? ".tar.xz" file)
|
||||
(string-suffix? ".tar" file))))))
|
||||
|
||||
(define (origin->disarchive origin)
|
||||
@@ -99,20 +98,6 @@ an empty directory if ORIGIN could not be disassembled."
|
||||
(directory-union "disarchive-collection"
|
||||
(filter-map (lambda (origin)
|
||||
(and (tarball-origin? origin)
|
||||
|
||||
;; Dismiss origins with (sha256 #f) such
|
||||
;; as that of IceCat.
|
||||
(and=> (origin-hash origin)
|
||||
content-hash-value)
|
||||
|
||||
;; FIXME: Exclude the Chromium tarball
|
||||
;; because it's huge and "disarchive
|
||||
;; disassemble" exceeds the max-silent
|
||||
;; timeout.
|
||||
(not (string-prefix?
|
||||
"chromium-"
|
||||
(origin-actual-file-name origin)))
|
||||
|
||||
(origin->disarchive origin)))
|
||||
origins)
|
||||
#:copy? #t))
|
||||
|
||||
@@ -3,16 +3,3 @@
|
||||
|
||||
[diff "texinfo"]
|
||||
xfuncname = "^@node[[:space:]]+([^,]+).*$"
|
||||
|
||||
[format]
|
||||
forceinbodyfrom = true # help preserve commit authorship
|
||||
thread = shallow
|
||||
useAutoBase = true
|
||||
|
||||
[pull]
|
||||
rebase = true
|
||||
|
||||
[sendemail]
|
||||
to = guix-patches@gnu.org
|
||||
headerCmd = etc/teams.scm cc-members-header-cmd
|
||||
thread = no
|
||||
|
||||
+3
-26
@@ -1,6 +1,6 @@
|
||||
; -*- lisp -*-
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2018, 2022 Ricardo Wurmus <rekado@elephly.net>
|
||||
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
|
||||
;;; Copyright © 2020 Daniel Brooks <db48x@db48x.net>
|
||||
;;; Copyright © 2020 Marius Bakke <marius@gnu.org>
|
||||
;;;
|
||||
@@ -37,13 +37,11 @@
|
||||
|
||||
(block guix_daemon
|
||||
;; Require existing types
|
||||
(typeattributeset cil_gen_require domain)
|
||||
(typeattributeset cil_gen_require init_t)
|
||||
(typeattributeset cil_gen_require init_var_run_t)
|
||||
(typeattributeset cil_gen_require nscd_var_run_t)
|
||||
(typeattributeset cil_gen_require system_dbusd_var_run_t)
|
||||
(typeattributeset cil_gen_require tmp_t)
|
||||
(typeattributeset cil_gen_require nscd_var_run_t)
|
||||
(typeattributeset cil_gen_require var_log_t)
|
||||
(typeattributeset cil_gen_require domain)
|
||||
|
||||
;; Declare own types
|
||||
(type guix_daemon_t)
|
||||
@@ -94,9 +92,6 @@
|
||||
(allow init_t
|
||||
guix_store_content_t
|
||||
(file (open read execute)))
|
||||
(allow init_t
|
||||
guix_profiles_t
|
||||
(dir (setattr)))
|
||||
|
||||
;; guix-daemon needs to know the names of users
|
||||
(allow guix_daemon_t
|
||||
@@ -176,11 +171,6 @@
|
||||
execute_no_trans read write open entrypoint map
|
||||
getattr link unlink)))
|
||||
|
||||
;; Remounting /gnu/store read-write.
|
||||
(allow guix_daemon_t
|
||||
fs_t
|
||||
(filesystem (remount)))
|
||||
|
||||
;; TODO: unknown
|
||||
(allow guix_daemon_t
|
||||
root_t
|
||||
@@ -228,9 +218,6 @@
|
||||
(allow guix_daemon_t
|
||||
tmpfs_t
|
||||
(file (create open read unlink write)))
|
||||
(allow guix_daemon_t ;same as above, but with tmp_t
|
||||
tmp_t
|
||||
(file (create open read unlink write)))
|
||||
(allow guix_daemon_t
|
||||
tmpfs_t
|
||||
(dir (getattr add_name remove_name write)))
|
||||
@@ -297,14 +284,6 @@
|
||||
guix_store_content_t
|
||||
(sock_file (create getattr setattr unlink write)))
|
||||
|
||||
;; Access to run state directories
|
||||
(allow guix_daemon_t
|
||||
system_dbusd_var_run_t
|
||||
(dir (search)))
|
||||
(allow guix_daemon_t
|
||||
init_var_run_t
|
||||
(dir (search)))
|
||||
|
||||
;; Access to configuration files and directories
|
||||
(allow guix_daemon_t
|
||||
guix_daemon_conf_t
|
||||
@@ -468,8 +447,6 @@
|
||||
any (unconfined_u object_r guix_store_content_t (low low)))
|
||||
(filecon "@prefix@/bin/guix-daemon"
|
||||
file (system_u object_r guix_daemon_exec_t (low low)))
|
||||
(filecon "@guix_localstatedir@/guix/profiles/per-user/[^/]+/current-guix/bin/guix-daemon"
|
||||
file (system_u object_r guix_daemon_exec_t (low low)))
|
||||
(filecon "@storedir@/.+-(guix-.+|profile)/bin/guix-daemon"
|
||||
file (system_u object_r guix_daemon_exec_t (low low)))
|
||||
(filecon "@storedir@/[a-z0-9]+-guix-daemon"
|
||||
|
||||
@@ -9,16 +9,10 @@ Description=Build daemon for GNU Guix
|
||||
ExecStart=@localstatedir@/guix/profiles/per-user/root/current-guix/bin/guix-daemon \
|
||||
--build-users-group=guixbuild --discover=no
|
||||
Environment='GUIX_LOCPATH=@localstatedir@/guix/profiles/per-user/root/guix-profile/lib/locale' LC_ALL=en_US.utf8
|
||||
RemainAfterExit=yes
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
|
||||
# Work around a nasty systemd ‘feature’ that kills the entire process tree
|
||||
# (including the daemon!) if any child, such as cc1plus, runs out of memory.
|
||||
OOMPolicy=continue
|
||||
|
||||
# Despite the name, this is rate-limited: a broken daemon will eventually fail.
|
||||
Restart=always
|
||||
|
||||
# See <https://lists.gnu.org/archive/html/guix-devel/2016-04/msg00608.html>.
|
||||
# Some package builds (for example, go@1.8.1) may require even more than
|
||||
# 1024 tasks.
|
||||
|
||||
+86
-176
@@ -3,15 +3,13 @@
|
||||
# Copyright © 2017 sharlatan <sharlatanus@gmail.com>
|
||||
# Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
|
||||
# Copyright © 2018 Efraim Flashner <efraim@flashner.co.il>
|
||||
# Copyright © 2019–2020, 2022 Tobias Geerinckx-Rice <me@tobias.gr>
|
||||
# Copyright © 2019, 2020 Tobias Geerinckx-Rice <me@tobias.gr>
|
||||
# Copyright © 2020 Morgan Smith <Morgan.J.Smith@outlook.com>
|
||||
# Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
|
||||
# Copyright © 2020 Daniel Brooks <db48x@db48x.net>
|
||||
# Copyright © 2021 Jakub Kądziołka <kuba@kadziolka.net>
|
||||
# Copyright © 2021 Chris Marusich <cmmarusich@gmail.com>
|
||||
# Copyright © 2021, 2022, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
# Copyright © 2022 Prafulla Giri <prafulla.giri@protonmail.com>
|
||||
# Copyright © 2023 Andrew Tropin <andrew@trop.in>
|
||||
# Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
#
|
||||
# This file is part of GNU Guix.
|
||||
#
|
||||
@@ -30,28 +28,12 @@
|
||||
|
||||
# We require Bash but for portability we'd rather not use /bin/bash or
|
||||
# /usr/bin/env in the shebang, hence this hack.
|
||||
|
||||
# Environment variables
|
||||
#
|
||||
# GUIX_BINARY_FILE_NAME
|
||||
#
|
||||
# Can be used to override the automatic download mechanism and point
|
||||
# to a local Guix binary archive filename like
|
||||
# "/tmp/guix-binary-1.4.0rc2.armhf-linux.tar.xz"
|
||||
#
|
||||
# GUIX_ALLOW_OVERWRITE
|
||||
#
|
||||
# Instead of aborting to avoid overwriting a previous installations,
|
||||
# allow copying over /var/guix or /gnu. This can be useful when the
|
||||
# installation required the user to extract Guix packs under /gnu to
|
||||
# satisfy its dependencies.
|
||||
|
||||
if [ "x$BASH_VERSION" = "x" ]
|
||||
then
|
||||
exec bash "$0" "$@"
|
||||
fi
|
||||
|
||||
set -eo pipefail
|
||||
set -e
|
||||
|
||||
[ "$UID" -eq 0 ] || { echo "This script must be run as root."; exit 1; }
|
||||
|
||||
@@ -70,7 +52,6 @@ REQUIRE=(
|
||||
"chmod"
|
||||
"uname"
|
||||
"groupadd"
|
||||
"useradd"
|
||||
"tail"
|
||||
"tr"
|
||||
"xz"
|
||||
@@ -111,20 +92,17 @@ _debug()
|
||||
fi
|
||||
}
|
||||
|
||||
die()
|
||||
{
|
||||
_err "${ERR}$*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Return true if user answered yes, false otherwise. The prompt is
|
||||
# yes-biased, that is, when the user simply enter newline, it is equivalent to
|
||||
# answering "yes".
|
||||
# Return true if user answered yes, false otherwise.
|
||||
# $1: The prompt question.
|
||||
prompt_yes_no() {
|
||||
local -l yn
|
||||
read -rp "$1 [Y/n]" yn
|
||||
[[ ! $yn || $yn = y || $yn = yes ]] || return 1
|
||||
while true; do
|
||||
read -rp "$1 " yn
|
||||
case $yn in
|
||||
[Yy]*) return 0;;
|
||||
[Nn]*) return 1;;
|
||||
*) _msg "Please answer yes or no."
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
chk_require()
|
||||
@@ -138,8 +116,10 @@ chk_require()
|
||||
command -v "$c" &>/dev/null || warn+=("$c")
|
||||
done
|
||||
|
||||
[ "${#warn}" -ne 0 ] && die "Missing commands: ${warn[*]}."
|
||||
|
||||
[ "${#warn}" -ne 0 ] &&
|
||||
{ _err "${ERR}Missing commands: ${warn[*]}.";
|
||||
return 1; }
|
||||
|
||||
_msg "${PAS}verification of required commands completed"
|
||||
}
|
||||
|
||||
@@ -154,27 +134,21 @@ chk_gpg_keyring()
|
||||
gpg_key_id=${GPG_SIGNING_KEYS[$user_id]}
|
||||
# Without --dry-run this command will create a ~/.gnupg owned by root on
|
||||
# systems where gpg has never been used, causing errors and confusion.
|
||||
if gpg --dry-run --list-keys "$gpg_key_id" >/dev/null 2>&1; then
|
||||
continue
|
||||
fi
|
||||
if prompt_yes_no "${INF}The following OpenPGP public key is \
|
||||
if ! gpg --dry-run --list-keys "$gpg_key_id" >/dev/null 2>&1; then
|
||||
if prompt_yes_no "${INF}The following OpenPGP public key is \
|
||||
required to verify the Guix binary signature: $gpg_key_id.
|
||||
Would you like me to fetch it for you?"; then
|
||||
# Use a reasonable time-out here so users don't report silent
|
||||
# ‘freezes’ when Savannah goes out to lunch, as has happened.
|
||||
if wget "https://sv.gnu.org/people/viewgpg.php?user_id=$user_id" \
|
||||
--timeout=30 --no-verbose -O- | gpg --import -; then
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
# If we reach this point, the key is (still) missing. Report further
|
||||
# missing keys, if any, but then abort the installation.
|
||||
_err "${ERR}Missing OpenPGP public key ($gpg_key_id).
|
||||
Would you like me to fetch it for you? (yes/no)"; then
|
||||
wget "https://sv.gnu.org/people/viewgpg.php?user_id=$user_id" \
|
||||
--no-verbose -O- | gpg --import -
|
||||
else
|
||||
_err "${ERR}Missing OpenPGP public key ($gpg_key_id).
|
||||
Fetch it with this command:
|
||||
|
||||
wget \"https://sv.gnu.org/people/viewgpg.php?user_id=$user_id\" -O - | \
|
||||
sudo -i gpg --import -"
|
||||
exit_flag=yes
|
||||
exit_flag=yes
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [ "$exit_flag" = yes ]; then
|
||||
exit 1
|
||||
@@ -246,7 +220,8 @@ chk_sys_arch()
|
||||
local arch=powerpc64le
|
||||
;;
|
||||
*)
|
||||
die "Unsupported CPU type: ${arch}"
|
||||
_err "${ERR}Unsupported CPU type: ${arch}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
case "$os" in
|
||||
@@ -254,7 +229,8 @@ chk_sys_arch()
|
||||
local os=linux
|
||||
;;
|
||||
*)
|
||||
die "Your operation system (${os}) is not supported."
|
||||
_err "${ERR}Your operation system (${os}) is not supported."
|
||||
exit 1
|
||||
esac
|
||||
|
||||
ARCH_OS="${arch}-${os}"
|
||||
@@ -278,7 +254,7 @@ chk_sys_nscd()
|
||||
configure_substitute_discovery() {
|
||||
if grep -q -- '--discover=no' "$1" && \
|
||||
prompt_yes_no "Would you like the Guix daemon to automatically \
|
||||
discover substitute servers on the local network?"; then
|
||||
discover substitute servers on the local network? (yes/no)"; then
|
||||
sed -i 's/--discover=no/--discover=yes/' "$1"
|
||||
fi
|
||||
}
|
||||
@@ -309,7 +285,8 @@ guix_get_bin_list()
|
||||
if [[ "${#bin_ver_ls}" -ne "0" ]]; then
|
||||
_msg "${PAS}Release for your system: ${default_ver}"
|
||||
else
|
||||
die "Could not obtain list of Guix releases."
|
||||
_err "${ERR}Could not obtain list of Guix releases."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Use default to download according to the list and local ARCH_OS.
|
||||
@@ -334,7 +311,8 @@ guix_get_bin()
|
||||
"${url}/${bin_ver}.tar.xz" "${url}/${bin_ver}.tar.xz.sig"; then
|
||||
_msg "${PAS}download completed."
|
||||
else
|
||||
die "could not download ${url}/${bin_ver}.tar.xz."
|
||||
_err "${ERR}could not download ${url}/${bin_ver}.tar.xz."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pushd "${dl_path}" >/dev/null
|
||||
@@ -342,7 +320,8 @@ guix_get_bin()
|
||||
_msg "${PAS}Signature is valid."
|
||||
popd >/dev/null
|
||||
else
|
||||
die "could not verify the signature."
|
||||
_err "${ERR}could not verify the signature."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -353,18 +332,17 @@ sys_create_store()
|
||||
|
||||
_debug "--- [ ${FUNCNAME[0]} ] ---"
|
||||
|
||||
if [[ -e /var/guix && -e /gnu ]]; then
|
||||
if [ -n "$GUIX_ALLOW_OVERWRITE" ]; then
|
||||
_msg "${WAR}Overwriting existing installation!"
|
||||
else
|
||||
die "A previous Guix installation was found. Refusing to overwrite."
|
||||
fi
|
||||
if [[ -e "/var/guix" || -e "/gnu" ]]; then
|
||||
_err "${ERR}A previous Guix installation was found. Refusing to overwrite."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$tmp_path"
|
||||
tar --extract --file "$pkg" && _msg "${PAS}unpacked archive"
|
||||
|
||||
_msg "${INF}Installing /var/guix and /gnu..."
|
||||
# Strip (skip) the leading ‘.’ component, which fails on read-only ‘/’.
|
||||
tar --extract --strip-components=1 --file "$pkg" -C /
|
||||
mv "${tmp_path}/var/guix" /var/
|
||||
mv "${tmp_path}/gnu" /
|
||||
|
||||
_msg "${INF}Linking the root user's profile"
|
||||
mkdir -p ~root/.config/guix
|
||||
@@ -434,27 +412,36 @@ sys_enable_guix_daemon()
|
||||
_msg "${PAS}enabled Guix daemon via upstart"
|
||||
;;
|
||||
systemd)
|
||||
{ install_unit()
|
||||
{
|
||||
local dest="/etc/systemd/system/$1"
|
||||
rm -f "$dest"
|
||||
cp ~root/.config/guix/current/lib/systemd/system/"$1" "$dest"
|
||||
chmod 664 "$dest"
|
||||
systemctl daemon-reload
|
||||
systemctl enable "$1"
|
||||
}
|
||||
{ # systemd .mount units must be named after the target directory.
|
||||
# Here we assume a hard-coded name of /gnu/store.
|
||||
# XXX Work around <https://issues.guix.gnu.org/41356> until next release.
|
||||
if [ -f ~root/.config/guix/current/lib/systemd/system/gnu-store.mount ]; then
|
||||
cp ~root/.config/guix/current/lib/systemd/system/gnu-store.mount \
|
||||
/etc/systemd/system/;
|
||||
chmod 664 /etc/systemd/system/gnu-store.mount;
|
||||
systemctl daemon-reload &&
|
||||
systemctl enable gnu-store.mount;
|
||||
fi
|
||||
|
||||
install_unit guix-daemon.service
|
||||
cp ~root/.config/guix/current/lib/systemd/system/guix-daemon.service \
|
||||
/etc/systemd/system/;
|
||||
chmod 664 /etc/systemd/system/guix-daemon.service;
|
||||
|
||||
# Work around <https://bugs.gnu.org/36074>, present in 1.0.1.
|
||||
sed -i /etc/systemd/system/guix-daemon.service \
|
||||
-e "s/GUIX_LOCPATH='/'GUIX_LOCPATH=/";
|
||||
|
||||
# Work around <https://bugs.gnu.org/35671>, present in 1.0.1.
|
||||
if ! grep en_US /etc/systemd/system/guix-daemon.service >/dev/null;
|
||||
then sed -i /etc/systemd/system/guix-daemon.service \
|
||||
-e 's/^Environment=\(.*\)$/Environment=\1 LC_ALL=en_US.UTF-8';
|
||||
fi;
|
||||
|
||||
configure_substitute_discovery \
|
||||
/etc/systemd/system/guix-daemon.service
|
||||
|
||||
# Install after guix-daemon.service to avoid a harmless warning.
|
||||
# systemd .mount units must be named after the target directory.
|
||||
# Here we assume a hard-coded name of /gnu/store.
|
||||
install_unit gnu-store.mount
|
||||
|
||||
systemctl daemon-reload &&
|
||||
systemctl enable guix-daemon &&
|
||||
systemctl start guix-daemon; } &&
|
||||
_msg "${PAS}enabled Guix daemon via systemd"
|
||||
;;
|
||||
@@ -501,22 +488,14 @@ sys_enable_guix_daemon()
|
||||
}
|
||||
|
||||
sys_authorize_build_farms()
|
||||
{ # authorize the public key(s) of the build farm(s)
|
||||
local hosts=(
|
||||
ci.guix.gnu.org
|
||||
bordeaux.guix.gnu.org
|
||||
)
|
||||
|
||||
{ # authorize the public key of the build farm
|
||||
if prompt_yes_no "Permit downloading pre-built package binaries from the \
|
||||
project's build farms?"; then
|
||||
for host in "${hosts[@]}"; do
|
||||
local key=~root/.config/guix/current/share/guix/$host.pub
|
||||
[ -f "$key" ] \
|
||||
&& guix archive --authorize < "$key" \
|
||||
&& _msg "${PAS}Authorized public key for $host"
|
||||
done
|
||||
else
|
||||
_msg "${INF}Skipped authorizing build farm public keys"
|
||||
project's build farm? (yes/no)"; then
|
||||
guix archive --authorize \
|
||||
< ~root/.config/guix/current/share/guix/ci.guix.gnu.org.pub \
|
||||
&& _msg "${PAS}Authorized public key for ci.guix.gnu.org"
|
||||
else
|
||||
_msg "${INF}Skipped authorizing build farm public keys"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -524,17 +503,7 @@ sys_create_init_profile()
|
||||
{ # Define for better desktop integration
|
||||
# This will not take effect until the next shell or desktop session!
|
||||
[ -d "/etc/profile.d" ] || mkdir /etc/profile.d # Just in case
|
||||
cat <<"EOF" > /etc/profile.d/zzz-guix.sh
|
||||
# Explicitly initialize XDG base directory variables to ease compatibility
|
||||
# with Guix System: see <https://issues.guix.gnu.org/56050#3>.
|
||||
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
||||
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
|
||||
export XDG_DATA_DIRS="${XDG_DATA_DIRS:-/usr/local/share/:/usr/share/}"
|
||||
export XDG_CONFIG_DIRS="${XDG_CONFIG_DIRS:-/etc/xdg}"
|
||||
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
|
||||
# no default for XDG_RUNTIME_DIR (depends on foreign distro for semantics)
|
||||
|
||||
cat <<"EOF" > /etc/profile.d/guix.sh
|
||||
# _GUIX_PROFILE: `guix pull` profile
|
||||
_GUIX_PROFILE="$HOME/.config/guix/current"
|
||||
export PATH="$_GUIX_PROFILE/bin${PATH:+:}$PATH"
|
||||
@@ -544,19 +513,16 @@ export PATH="$_GUIX_PROFILE/bin${PATH:+:}$PATH"
|
||||
# searches 'Info-default-directory-list'.
|
||||
export INFOPATH="$_GUIX_PROFILE/share/info:$INFOPATH"
|
||||
|
||||
# GUIX_PROFILE: User's default profile and home profile
|
||||
# GUIX_PROFILE: User's default profile
|
||||
GUIX_PROFILE="$HOME/.guix-profile"
|
||||
[ -f "$GUIX_PROFILE/etc/profile" ] && . "$GUIX_PROFILE/etc/profile"
|
||||
[ -L "$GUIX_PROFILE" ] || \
|
||||
GUIX_LOCPATH="$GUIX_PROFILE/lib/locale:${GUIX_LOCPATH:+:}$GUIX_LOCPATH"
|
||||
|
||||
GUIX_PROFILE="$HOME/.guix-home/profile"
|
||||
[ -f "$GUIX_PROFILE/etc/profile" ] && . "$GUIX_PROFILE/etc/profile"
|
||||
[ -L "$GUIX_PROFILE" ] || \
|
||||
GUIX_LOCPATH="$GUIX_PROFILE/lib/locale:${GUIX_LOCPATH:+:}$GUIX_LOCPATH"
|
||||
|
||||
[ -L $GUIX_PROFILE ] || return
|
||||
GUIX_LOCPATH="$GUIX_PROFILE/lib/locale"
|
||||
export GUIX_LOCPATH
|
||||
|
||||
[ -f "$GUIX_PROFILE/etc/profile" ] && . "$GUIX_PROFILE/etc/profile"
|
||||
|
||||
# set XDG_DATA_DIRS to include Guix installations
|
||||
export XDG_DATA_DIRS="$GUIX_PROFILE/share:${XDG_DATA_DIRS:-/usr/local/share/:/usr/share/}"
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -579,53 +545,9 @@ sys_create_shell_completion()
|
||||
_msg "${PAS}installed shell completion"
|
||||
}
|
||||
|
||||
sys_customize_bashrc()
|
||||
{
|
||||
prompt_yes_no "Customize users Bash shell prompt for Guix?" || return 0
|
||||
|
||||
for bashrc in /home/*/.bashrc /root/.bashrc; do
|
||||
test -f "$bashrc" || continue
|
||||
grep -Fq '$GUIX_ENVIRONMENT' "$bashrc" && continue
|
||||
cp "${bashrc}" "${bashrc}.bak"
|
||||
echo '
|
||||
# Automatically added by the Guix install script.
|
||||
if [ -n "$GUIX_ENVIRONMENT" ]; then
|
||||
if [[ $PS1 =~ (.*)"\\$" ]]; then
|
||||
PS1="${BASH_REMATCH[1]} [env]\\\$ "
|
||||
fi
|
||||
fi
|
||||
' >> "$bashrc"
|
||||
done
|
||||
_msg "${PAS}Bash shell prompt successfully customized for Guix"
|
||||
}
|
||||
|
||||
sys_maybe_setup_selinux()
|
||||
{
|
||||
if ! [ -f /sys/fs/selinux/policy ]
|
||||
then
|
||||
return
|
||||
fi
|
||||
|
||||
local c
|
||||
for c in semodule restorecon
|
||||
do
|
||||
if ! command -v "$c" &>/dev/null
|
||||
then
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
prompt_yes_no "Install SELinux policy that might be required to run guix-daemon?" \
|
||||
|| return 0
|
||||
|
||||
local var_guix=/var/guix/profiles/per-user/root/current-guix
|
||||
semodule -i "${var_guix}/share/selinux/guix-daemon.cil"
|
||||
restorecon -R /gnu /var/guix
|
||||
}
|
||||
|
||||
welcome()
|
||||
{
|
||||
local char
|
||||
cat<<"EOF"
|
||||
░░░ ░░░
|
||||
░░▒▒░░░░░░░░░ ░░░░░░░░░▒▒░░
|
||||
@@ -651,18 +573,8 @@ This script installs GNU Guix on your system
|
||||
|
||||
https://www.gnu.org/software/guix/
|
||||
EOF
|
||||
# Don't use ‘read -p’ here! It won't display when run non-interactively.
|
||||
echo -n "Press return to continue..."$'\r'
|
||||
if ! read -r char; then
|
||||
echo
|
||||
die "Can't read standard input. Hint: don't pipe scripts into a shell."
|
||||
fi
|
||||
if [ "$char" ]; then
|
||||
echo
|
||||
echo "...that ($char) was not a return!"
|
||||
_msg "${WAR}Use newlines to automate installation, e.g.: yes '' | ${0##*/}"
|
||||
_msg "${WAR}Any other method is unsupported and likely to break in future."
|
||||
fi
|
||||
echo -n "Press return to continue..."
|
||||
read -r
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -682,7 +594,7 @@ main()
|
||||
_msg "${INF}system is ${ARCH_OS}"
|
||||
|
||||
umask 0022
|
||||
tmp_path="$(mktemp -t -d guix.XXXXXX)"
|
||||
tmp_path="$(mktemp -t -d guix.XXX)"
|
||||
|
||||
if [ -z "${GUIX_BINARY_FILE_NAME}" ]; then
|
||||
guix_get_bin_list "${GNU_URL}"
|
||||
@@ -698,12 +610,10 @@ main()
|
||||
|
||||
sys_create_store "${GUIX_BINARY_FILE_NAME}" "${tmp_path}"
|
||||
sys_create_build_user
|
||||
sys_maybe_setup_selinux
|
||||
sys_enable_guix_daemon
|
||||
sys_authorize_build_farms
|
||||
sys_create_init_profile
|
||||
sys_create_shell_completion
|
||||
sys_customize_bashrc
|
||||
|
||||
_msg "${INF}cleaning up ${tmp_path}"
|
||||
rm -r "${tmp_path}"
|
||||
|
||||
@@ -11,12 +11,10 @@ After=guix-daemon.service
|
||||
[Service]
|
||||
ExecStart=@localstatedir@/guix/profiles/per-user/root/current-guix/bin/guix publish --user=nobody --port=8181
|
||||
Environment='GUIX_LOCPATH=@localstatedir@/guix/profiles/per-user/root/guix-profile/lib/locale' LC_ALL=en_US.utf8
|
||||
RemainAfterExit=yes
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
|
||||
# Despite the name, this is rate-limited: a broken daemon will eventually fail.
|
||||
Restart=always
|
||||
|
||||
# See <https://lists.gnu.org/archive/html/guix-devel/2016-04/msg00608.html>.
|
||||
TasksMax=1024
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2022 Leo Famulari <leo@famulari.name>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; This file returns a manifest of packages related to linux-libre.
|
||||
;;; Simplistically, it selects packages whose names begin with "linux-libre".
|
||||
;;; It is used to assist continuous integration of the kernel packages.
|
||||
|
||||
(use-modules (guix packages)
|
||||
(guix profiles)
|
||||
(gnu packages))
|
||||
|
||||
(manifest
|
||||
(map package->manifest-entry
|
||||
(fold-packages
|
||||
(lambda (package lst)
|
||||
(if (string-prefix? "linux-libre"
|
||||
(package-name package))
|
||||
(cons package lst)
|
||||
lst))
|
||||
'())))
|
||||
+10
-1070
File diff suppressed because it is too large
Load Diff
+18
-22
@@ -1,7 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2020-2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2020, 2021 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||
;;; Copyright © 2023 Andreas Enge <andreas@enge.fr>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -24,10 +23,9 @@
|
||||
(use-modules (gnu packages)
|
||||
(guix packages)
|
||||
(guix profiles)
|
||||
((guix platform) #:select (targets))
|
||||
((gnu ci) #:select (%cross-targets))
|
||||
((gnu services xorg) #:select (%default-xorg-modules))
|
||||
(guix utils)
|
||||
(guix gexp)
|
||||
(srfi srfi-1)
|
||||
(srfi srfi-26))
|
||||
|
||||
@@ -52,17 +50,18 @@ TARGET."
|
||||
"openssh" "emacs" "vim" "python" "guile" "guix")))
|
||||
|
||||
(define %base-packages/armhf
|
||||
;; The guix package doesn't build natively on armhf due to Guile memory
|
||||
;; issues compiling the package modules
|
||||
(remove (lambda (package)
|
||||
(string=? (package-name package) "guix"))
|
||||
%base-packages))
|
||||
;; XXX: Relax requirements for armhf-linux for lack of enough build power.
|
||||
(map (lambda (package)
|
||||
(if (string=? (package-name package) "emacs")
|
||||
(specification->package "emacs-no-x")
|
||||
package))
|
||||
%base-packages))
|
||||
|
||||
(define %base-packages/hurd
|
||||
;; XXX: For now we are less demanding of "i586-gnu".
|
||||
(map specification->package
|
||||
'("coreutils" "grep" "findutils" "gawk" "make"
|
||||
#;"gcc-toolchain" "tar" "xz")))
|
||||
"gcc-toolchain" "tar" "xz")))
|
||||
|
||||
(define %system-packages
|
||||
;; Key packages proposed by the Guix System installer.
|
||||
@@ -74,14 +73,16 @@ TARGET."
|
||||
"connman" "network-manager" "network-manager-applet"
|
||||
"openssh" "ntp" "tor"
|
||||
"linux-libre" "grub-hybrid"
|
||||
"icecat"))
|
||||
;; FIXME: Add IceCat when Rust is available on i686.
|
||||
;;"icecat"
|
||||
))
|
||||
%default-xorg-modules))
|
||||
|
||||
(define %packages-to-cross-build
|
||||
;; Packages that must be cross-buildable from x86_64-linux.
|
||||
;; FIXME: Add (@ (gnu packages gcc) gcc) when <https://bugs.gnu.org/40463>
|
||||
;; is fixed.
|
||||
(append (list (@ (gnu packages guile) guile-3.0/pinned))
|
||||
(append (list (@ (gnu packages guile) guile-3.0/fixed))
|
||||
(map specification->package
|
||||
'("coreutils" "grep" "sed" "findutils" "diffutils" "patch"
|
||||
"gawk" "gettext" "gzip" "xz"
|
||||
@@ -110,6 +111,8 @@ TARGET."
|
||||
(cond ((string=? system "i586-gnu")
|
||||
%base-packages/hurd)
|
||||
((string=? system "armhf-linux")
|
||||
;; FIXME: Drop special case when ci.guix.gnu.org
|
||||
;; has more ARMv7 build power.
|
||||
%base-packages/armhf)
|
||||
((string=? system "powerpc64le-linux")
|
||||
;; FIXME: Drop 'bootstrap-tarballs' until
|
||||
@@ -139,16 +142,9 @@ TARGET."
|
||||
(if (target-mingw? target)
|
||||
%packages-to-cross-build-for-mingw
|
||||
%packages-to-cross-build)))
|
||||
(fold delete (targets)
|
||||
'(;; Like in (gnu ci), dismiss cross-compilation to x86:
|
||||
;; it's pointless.
|
||||
"x86_64-linux-gnu"
|
||||
"i686-linux-gnu"
|
||||
|
||||
;; XXX: Important bits like libsigsegv and libffi don't
|
||||
;; support RISCV at the moment, so don't require RISCV
|
||||
;; support.
|
||||
"riscv64-linux-gnu")))))
|
||||
;; XXX: Important bits like libsigsegv and libffi don't support
|
||||
;; RISCV at the moment, so don't require RISCV support.
|
||||
(delete "riscv64-linux-gnu" %cross-targets))))
|
||||
|
||||
(define %cross-bootstrap-manifest
|
||||
(manifest
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
"ant-build-system"
|
||||
"asdf-build-system"
|
||||
"cargo-build-system"
|
||||
"chicken-build-system"
|
||||
"clojure-build-system"
|
||||
"cmake-build-system"
|
||||
"copy-build-system"
|
||||
@@ -28,7 +27,6 @@
|
||||
"linux-module-build-system"
|
||||
"maven-build-system"
|
||||
"meson-build-system"
|
||||
"minetest-build-system"
|
||||
"minify-build-system"
|
||||
"node-build-system"
|
||||
"ocaml-build-system"
|
||||
@@ -37,8 +35,6 @@
|
||||
"qt-build-system"
|
||||
"r-build-system"
|
||||
"rakudo-build-system"
|
||||
"rebar-build-system"
|
||||
"renpy-build-system"
|
||||
"ruby-build-system"
|
||||
"scons-build-system"
|
||||
"texlive-build-system"
|
||||
@@ -1,89 +0,0 @@
|
||||
-*- mode: lisp-data -*-
|
||||
|
||||
scheme-mode
|
||||
|
||||
(package...
|
||||
"(define-public " (s name)
|
||||
n> "(package"
|
||||
n > "(name \"" (s name) "\")"
|
||||
n > "(version \"" p "\")"
|
||||
n > "(source origin...)"
|
||||
n > "(build-system " (p "gnu") "-build-system)"
|
||||
n > "(home-page \"" p "\")"
|
||||
n > "(synopsis \"" p "\")"
|
||||
n > "(description \"" p "\")"
|
||||
n > "(license license:" (p "unknown") ")))" n)
|
||||
|
||||
(origin...
|
||||
"(origin"
|
||||
n> "(method " (p "url-fetch" method) ")"
|
||||
n> "(uri " (cl-case (and method (intern method))
|
||||
('git-fetch "git-reference...")
|
||||
('svn-fetch "svn-reference...")
|
||||
('hg-fetch "hg-reference...")
|
||||
('cvs-fetch "cvs-reference...")
|
||||
('bzr-fetch "bzr-reference...")
|
||||
(t "\"https://...\""))
|
||||
")"
|
||||
n>
|
||||
(cl-case (and method (intern method))
|
||||
('git-fetch
|
||||
(insert "(file-name (git-file-name name version))")
|
||||
(newline)
|
||||
(indent-according-to-mode))
|
||||
('hg-fetch
|
||||
(insert "(file-name (hg-file-name name version))")
|
||||
(newline)
|
||||
(indent-according-to-mode))
|
||||
('svn-fetch
|
||||
(insert "(file-name (string-append name \"-\" version \"-checkout\"))")
|
||||
(newline)
|
||||
(indent-according-to-mode))
|
||||
('cvs-fetch
|
||||
(insert "(file-name (string-append name \"-\" version \"-checkout\"))")
|
||||
(newline)
|
||||
(indent-according-to-mode))
|
||||
('bzr-fetch
|
||||
(insert "(file-name (string-append name \"-\" version \"-checkout\"))")
|
||||
(newline)
|
||||
(indent-according-to-mode))
|
||||
(t ""))
|
||||
> "(sha256"
|
||||
n > "(base32 \""
|
||||
;; hash of an empty directory
|
||||
(p "0sjjj9z1dhilhpc8pq4154czrb79z9cm044jvn75kxcjv6v5l2m5") "\")))")
|
||||
|
||||
(git-reference...
|
||||
"(git-reference"
|
||||
n> "(url \"" p "\")"
|
||||
n> "(commit " (p "commit") "))")
|
||||
|
||||
(svn-reference...
|
||||
"(svn-reference"
|
||||
n> "(url \"" p "\")"
|
||||
n> "(revision " (p "revision") "))")
|
||||
|
||||
(cvs-reference...
|
||||
"(cvs-reference"
|
||||
n> "(root-directory \"" p "\")"
|
||||
n> "(module \"" p "\")"
|
||||
n> "(revision \"" p "\"))")
|
||||
|
||||
(hg-reference...
|
||||
"(hg-reference"
|
||||
n> "(url \"" p "\")"
|
||||
n> "(changeset " (p "changeset") "))")
|
||||
|
||||
(bzr-reference...
|
||||
"(bzr-reference"
|
||||
n> "(url \"" p "\")"
|
||||
n> "(revision " (p "revision") "))")
|
||||
|
||||
(:phases\ "#:phases (modify-phases %standard-phases"
|
||||
n> p ")")
|
||||
|
||||
(add-before\ "(add-before '" p " '" p
|
||||
n > p ")")
|
||||
(add-after\ "(add-after '" p " '" p
|
||||
n > p ")")
|
||||
(replace\ "(replace '" p " " p")")
|
||||
@@ -1,158 +0,0 @@
|
||||
-*- mode: lisp-data -*-
|
||||
|
||||
text-mode :when (bound-and-true-p git-commit-mode)
|
||||
|
||||
(add\ "gnu: Add "
|
||||
(p (with-temp-buffer
|
||||
(magit-git-wash #'magit-diff-wash-diffs
|
||||
"diff" "--staged")
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "\\+(define-public \\(\\S-+\\)"
|
||||
nil 'noerror)
|
||||
(match-string-no-properties 1)))
|
||||
var)
|
||||
"." n n
|
||||
"* " (p (or (car (magit-staged-files)) ""))
|
||||
" (" (s var ) "): New variable.")
|
||||
|
||||
(remove\ "gnu: Remove "
|
||||
(p (with-temp-buffer
|
||||
(magit-git-wash #'magit-diff-wash-diffs
|
||||
"diff" "--staged")
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "\\-(define-public \\(\\S-+\\)"
|
||||
nil 'noerror)
|
||||
(match-string-no-properties 1)))
|
||||
var)
|
||||
"." n n
|
||||
"* " (p (or (car (magit-staged-files)) ""))
|
||||
" (" (s var) "): Delete variable.")
|
||||
|
||||
(rename\ "gnu: "
|
||||
(p (with-temp-buffer
|
||||
(magit-git-wash #'magit-diff-wash-diffs
|
||||
"diff" "--staged")
|
||||
(beginning-of-buffer)
|
||||
(when (search-forward "-(define-public " nil 'noerror)
|
||||
(thing-at-point 'sexp 'no-properties)))
|
||||
prev-var)
|
||||
": Rename package to "
|
||||
(p (with-temp-buffer
|
||||
(magit-git-wash #'magit-diff-wash-diffs
|
||||
"diff" "--staged")
|
||||
(beginning-of-buffer)
|
||||
(when (search-forward "+(define-public " nil 'noerror)
|
||||
(thing-at-point 'sexp 'no-properties)))
|
||||
new-var)
|
||||
"." n n
|
||||
"* " (p (or (car (magit-staged-files)) "")) " (" (s prev-var) "): "
|
||||
"Define in terms of" n
|
||||
"'deprecated-package'." n
|
||||
"(" (s new-var) "): New variable, formerly known as \""
|
||||
(s prev-var) "\".")
|
||||
|
||||
(update\ "gnu: "
|
||||
(p (with-temp-buffer
|
||||
(magit-git-wash #'magit-diff-wash-diffs
|
||||
"diff" "--staged")
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^[ ]*(define-public \\(\\S-+\\)"
|
||||
nil 'noerror)
|
||||
(match-string-no-properties 1)))
|
||||
var)
|
||||
": Update to "
|
||||
(p (with-temp-buffer
|
||||
(magit-git-wash #'magit-diff-wash-diffs
|
||||
"diff" "--staged")
|
||||
(goto-char (point-min))
|
||||
(search-forward "name" nil 'noerror)
|
||||
(search-forward "+" nil 'noerror) ; first change
|
||||
(when (and (search-forward "version " nil 'noerror)
|
||||
(looking-at-p "\""))
|
||||
(let ((end (save-excursion (search-forward "\")"
|
||||
nil 'noerror))))
|
||||
(when end
|
||||
(forward-char)
|
||||
(buffer-substring-no-properties (point) (- end 2))))))
|
||||
version)
|
||||
"." n n
|
||||
"* " (p (or (car (magit-staged-files)) "")) " (" (s var) "): "
|
||||
"Update to " (s version) "." n
|
||||
(mapconcat (lambda (file) (concat "* " file))
|
||||
(cdr (magit-staged-files))
|
||||
"\n"))
|
||||
|
||||
(addcl\ "gnu: Add cl-"
|
||||
(p (replace-regexp-in-string
|
||||
"^cl-" "" (with-temp-buffer
|
||||
(magit-git-wash #'magit-diff-wash-diffs
|
||||
"diff" "--staged")
|
||||
(beginning-of-buffer)
|
||||
(when (search-forward "+(define-public " nil 'noerror)
|
||||
(replace-regexp-in-string
|
||||
"^sbcl-" ""
|
||||
(thing-at-point 'sexp 'no-properties)))))
|
||||
var)
|
||||
"." n n
|
||||
"* " (p (or (car (magit-staged-files)) ""))
|
||||
" (cl-" (s var)
|
||||
", ecl-" (s var)
|
||||
", sbcl-" (s var) "): New variables.")
|
||||
|
||||
(https\ "gnu: "
|
||||
(p (with-temp-buffer
|
||||
(magit-git-wash #'magit-diff-wash-diffs
|
||||
"diff" "--staged")
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^[ ]*(define-public \\(\\S-+\\)"
|
||||
nil 'noerror)
|
||||
(match-string-no-properties 1)))
|
||||
var)
|
||||
": Use HTTPS home page." n n
|
||||
"* " (p (or (car (magit-staged-files)) ""))
|
||||
" (" (s var) ")[home-page]: Use HTTPS."
|
||||
n
|
||||
(mapconcat (lambda (file) (concat "* " file))
|
||||
(cdr (magit-staged-files))
|
||||
"\n"))
|
||||
|
||||
(move\ "gnu: "
|
||||
(p (with-temp-buffer
|
||||
(magit-git-wash #'magit-diff-wash-diffs
|
||||
"diff" "--staged")
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "\\-(define-public \\(\\S-+\\)"
|
||||
nil 'noerror)
|
||||
(match-string-no-properties 1)))
|
||||
var)
|
||||
": Move to ("
|
||||
(p (with-temp-buffer
|
||||
(magit-git-wash #'magit-diff-wash-diffs
|
||||
"diff" "--staged")
|
||||
(goto-char (point-min))
|
||||
(when (and
|
||||
(re-search-forward "\\+(define-public \\(\\S-+\\)"
|
||||
nil 'noerror)
|
||||
(re-search-backward "modified[ ]*\\(\\S-+\\)"
|
||||
nil 'noerror))
|
||||
(string-replace
|
||||
"\.scm" ""
|
||||
(string-replace "/" " "
|
||||
(match-string-no-properties 1)))))
|
||||
new-module)
|
||||
")." n
|
||||
n
|
||||
"* " (p (with-temp-buffer
|
||||
(magit-git-wash #'magit-diff-wash-diffs
|
||||
"diff" "--staged")
|
||||
(goto-char (point-min))
|
||||
(when (and
|
||||
(re-search-forward "\\-(define-public \\(\\S-+\\)"
|
||||
nil 'noerror)
|
||||
(re-search-backward "modified[ ]*\\(\\S-+\\)"
|
||||
nil 'noerror))
|
||||
(match-string-no-properties 1)))
|
||||
source)
|
||||
" (" (s var) "): Move from here…" n
|
||||
"* " (concat (string-replace " " "/" new-module) ".scm")
|
||||
" (" (s var) "): …to here.")
|
||||
@@ -1,9 +0,0 @@
|
||||
# -*- mode: snippet -*-
|
||||
# name: guix-vc-commit-message-add-package
|
||||
# key: add
|
||||
# --
|
||||
gnu: Add ${1:`(when (string-match "\\+(define-public \\(\\S-+\\)" vc-patch-string)
|
||||
(match-string-no-properties 1 vc-patch-string))`}.
|
||||
|
||||
* `(car (log-edit-files))` ($1): New variable.
|
||||
`(mapconcat (lambda (file) (concat "* " file)) (cdr (log-edit-files)) "\n")`
|
||||
@@ -1,9 +0,0 @@
|
||||
# -*- mode: snippet -*-
|
||||
# name: guix-vc-commit-message-remove-package
|
||||
# key: remove
|
||||
# --
|
||||
gnu: Remove ${1:`(when (string-match "\\-(define-public \\(\\S-+\\)" vc-patch-string)
|
||||
(match-string-no-properties 1 vc-patch-string))`}.
|
||||
|
||||
* `(car (log-edit-files))` ($1): Delete variable.
|
||||
`(mapconcat (lambda (file) (concat "* " file)) (cdr (log-edit-files)) "\n")`
|
||||
@@ -1,14 +0,0 @@
|
||||
# -*- mode: snippet -*-
|
||||
# name: guix-vc-commit-message-rename-package
|
||||
# key: rename
|
||||
# --
|
||||
gnu: ${1:`(when (string-match "\\-(define-public \\(\\S-+\\)" vc-patch-string)
|
||||
(match-string-no-properties 1 vc-patch-string))
|
||||
`}: Rename package to ${2:`
|
||||
(when (string-match "\\+(define-public \\(\\S-+\\)" vc-patch-string)
|
||||
(match-string-no-properties 1 vc-patch-string))`}.
|
||||
|
||||
* `(car (log-edit-files))` ($1): Define in terms of
|
||||
'deprecated-package'.
|
||||
($2): New variable, formerly known as "$1".
|
||||
`(mapconcat (lambda (file) (concat "* " file)) (cdr (log-edit-files)) "\n")`
|
||||
@@ -1,12 +0,0 @@
|
||||
# -*- mode: snippet -*-
|
||||
# name: guix-vc-commit-message-update-package
|
||||
# key: update
|
||||
# --
|
||||
|
||||
gnu: ${1:`(when (string-match "^[ ]*(define-public \\(\\S-+\\)" vc-patch-string)
|
||||
(match-string-no-properties 1 vc-patch-string))`}: Update to ${2:`
|
||||
(when (string-match "^\\+[ ]*(version \"\\(.*\\)\"" vc-patch-string)
|
||||
(match-string-no-properties 1 vc-patch-string))`}.
|
||||
|
||||
* `(car (log-edit-files))` ($1): Update to $2.$0
|
||||
`(mapconcat (lambda (file) (concat "* " file)) (cdr (log-edit-files)) "\n")`
|
||||
@@ -1,9 +0,0 @@
|
||||
# -*- mode: snippet -*-
|
||||
# name: guix-vc-commit-message-use-https-home-page
|
||||
# key: https
|
||||
# --
|
||||
gnu: ${1:`(when (string-match "^[ ]*(define-public \\(\\S-+\\)" vc-patch-string)
|
||||
(match-string-no-properties 1 vc-patch-string))`}: Use HTTPS home page URI.
|
||||
|
||||
* `(car (log-edit-files))` ($1)[home-page]: Use HTTPS URI.
|
||||
`(mapconcat (lambda (file) (concat "* " file)) (cdr (log-edit-files)) "\n")`
|
||||
@@ -1,9 +0,0 @@
|
||||
# -*- mode: snippet -*-
|
||||
# name: guix-news-entry
|
||||
# key: entry...
|
||||
# --
|
||||
(entry (commit "$1")
|
||||
(title
|
||||
(en "$2"))
|
||||
(body
|
||||
(en "$3")))
|
||||
@@ -1,13 +0,0 @@
|
||||
# -*- mode: snippet -*-
|
||||
# name: guix-commit-message-remove-package
|
||||
# key: remove
|
||||
# condition: git-commit-mode
|
||||
# --
|
||||
gnu: Remove ${1:`(with-temp-buffer
|
||||
(magit-git-wash #'magit-diff-wash-diffs
|
||||
"diff" "--staged")
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "\\-(define-public \\(\\S-+\\)" nil 'noerror)
|
||||
(match-string-no-properties 1)))`}.
|
||||
|
||||
* `(car (magit-staged-files))` ($1): Delete variable.
|
||||
+11
-16
@@ -1,5 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2016, 2018-2020, 2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2016, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -18,8 +18,7 @@
|
||||
|
||||
(use-modules (gnu tests)
|
||||
(gnu packages package-management)
|
||||
(guix monads)
|
||||
(guix store)
|
||||
((gnu ci) #:select (channel-source->package))
|
||||
((guix git-download) #:select (git-predicate))
|
||||
((guix utils) #:select (current-source-directory))
|
||||
(git)
|
||||
@@ -49,19 +48,15 @@ instance."
|
||||
;; of tests to run in the usual way:
|
||||
;;
|
||||
;; make check-system TESTS=installed-os
|
||||
(let ((guix (channel-source->package source #:commit commit)))
|
||||
(map (lambda (test)
|
||||
(system-test
|
||||
(inherit test)
|
||||
(value (mparameterize %store-monad ((current-guix-package guix))
|
||||
(system-test-value test)))))
|
||||
(match (getenv "TESTS")
|
||||
(#f
|
||||
(all-system-tests))
|
||||
((= string-tokenize (tests ...))
|
||||
(filter (lambda (test)
|
||||
(member (system-test-name test) tests))
|
||||
(all-system-tests)))))))
|
||||
(parameterize ((current-guix-package
|
||||
(channel-source->package source #:commit commit)))
|
||||
(match (getenv "TESTS")
|
||||
(#f
|
||||
(all-system-tests))
|
||||
((= string-tokenize (tests ...))
|
||||
(filter (lambda (test)
|
||||
(member (system-test-name test) tests))
|
||||
(all-system-tests))))))
|
||||
|
||||
(define (system-test->manifest-entry test)
|
||||
"Return a manifest entry for TEST, a system test."
|
||||
|
||||
@@ -1,840 +0,0 @@
|
||||
#!@GUILE@ \
|
||||
--no-auto-compile -s
|
||||
!#
|
||||
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2022, 2023 Ricardo Wurmus <rekado@elephly.net>
|
||||
;;; Copyright © 2022 Mathieu Othacehe <othacehe@gnu.org>
|
||||
;;; Copyright © 2022, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;; Copyright © 2022 Simon Tournier <zimon.toutoune@gmail.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This code defines development teams and team members, as well as their
|
||||
;; scope.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(use-modules (srfi srfi-1)
|
||||
(srfi srfi-9)
|
||||
(srfi srfi-26)
|
||||
(ice-9 format)
|
||||
(ice-9 regex)
|
||||
(ice-9 match)
|
||||
(ice-9 rdelim)
|
||||
(guix ui)
|
||||
(git))
|
||||
|
||||
(define-record-type <regexp*>
|
||||
(%make-regexp* pat flag rx)
|
||||
regexp*?
|
||||
(pat regexp*-pattern)
|
||||
(flag regexp*-flag)
|
||||
(rx regexp*-rx))
|
||||
|
||||
;;; Work around regexp implementation.
|
||||
;;; This record allows to track the regexp pattern and then display it.
|
||||
(define* (make-regexp* pat #:optional (flag regexp/extended))
|
||||
"Alternative to `make-regexp' producing annotated <regexp*> objects."
|
||||
(%make-regexp* pat flag (make-regexp pat flag)))
|
||||
|
||||
(define (regexp*-exec rx* str)
|
||||
"Execute the RX* regexp, a <regexp*> object."
|
||||
(regexp-exec (regexp*-rx rx*) str))
|
||||
|
||||
(define-record-type <team>
|
||||
(make-team id name description members scope)
|
||||
team?
|
||||
(id team-id)
|
||||
(name team-name)
|
||||
(description team-description)
|
||||
(members team-members set-team-members!)
|
||||
(scope team-scope))
|
||||
|
||||
(define-record-type <person>
|
||||
(make-person name email)
|
||||
person?
|
||||
(name person-name)
|
||||
(email person-email))
|
||||
|
||||
(define* (person name #:optional email)
|
||||
(make-person name email))
|
||||
|
||||
(define* (team id #:key name description (members '())
|
||||
(scope '()))
|
||||
(make-team id
|
||||
(or name (symbol->string id))
|
||||
description
|
||||
members
|
||||
scope))
|
||||
|
||||
(define %teams
|
||||
(make-hash-table))
|
||||
|
||||
(define-syntax define-team
|
||||
(lambda (x)
|
||||
(syntax-case x ()
|
||||
((_ id value)
|
||||
#`(begin
|
||||
(define-public id value)
|
||||
(hash-set! %teams 'id id))))))
|
||||
|
||||
(define-syntax-rule (define-member person teams ...)
|
||||
(let ((p person))
|
||||
(for-each (lambda (team-id)
|
||||
(let ((team
|
||||
(hash-ref %teams team-id
|
||||
(lambda ()
|
||||
(error (format #false
|
||||
"Unknown team ~a for ~a~%"
|
||||
team-id p))))))
|
||||
(set-team-members!
|
||||
team (cons p (team-members team)))))
|
||||
(quote (teams ...)))))
|
||||
|
||||
|
||||
(define-team python
|
||||
(team 'python
|
||||
#:name "Python team"
|
||||
#:description
|
||||
"Python, Python packages, the \"pypi\" importer, and the python-build-system."
|
||||
#:scope
|
||||
(list "gnu/packages/django.scm"
|
||||
"gnu/packages/jupyter.scm"
|
||||
;; Match haskell.scm and haskell-*.scm.
|
||||
(make-regexp* "^gnu/packages/python(-.+|)\\.scm$")
|
||||
"gnu/packages/sphinx.scm"
|
||||
"gnu/packages/tryton.scm"
|
||||
"guix/build/pyproject-build-system.scm"
|
||||
"guix/build-system/pyproject.scm"
|
||||
"guix/build/python-build-system.scm"
|
||||
"guix/build-system/python.scm"
|
||||
"guix/import/pypi.scm"
|
||||
"guix/scripts/import/pypi.scm"
|
||||
"tests/pypi.scm")))
|
||||
|
||||
(define-team haskell
|
||||
(team 'haskell
|
||||
#:name "Haskell team"
|
||||
#:description
|
||||
"GHC, Hugs, Haskell packages, the \"hackage\" and \"stackage\" importers, and
|
||||
the haskell-build-system."
|
||||
#:scope
|
||||
(list "gnu/packages/dhall.scm"
|
||||
;; Match haskell.scm and haskell-*.scm.
|
||||
(make-regexp* "^gnu/packages/haskell(-.+|)\\.scm$")
|
||||
"gnu/packages/purescript.scm"
|
||||
"guix/build/haskell-build-system.scm"
|
||||
"guix/build-system/haskell.scm"
|
||||
"guix/import/cabal.scm"
|
||||
"guix/import/hackage.scm"
|
||||
"guix/import/stackage.scm"
|
||||
"guix/scripts/import/hackage.scm")))
|
||||
|
||||
(define-team qt
|
||||
(team 'qt
|
||||
#:name "Qt team"
|
||||
#:description
|
||||
"The Qt toolkit/library and the qt-build-system,
|
||||
as well as some packages using Qt."
|
||||
#:scope (list "gnu/packages/qt.scm"
|
||||
"guix/build-system/qt.scm"
|
||||
"guix/build/qt-build-system.scm"
|
||||
"guix/build/qt-utils.scm")))
|
||||
|
||||
(define-team r
|
||||
(team 'r
|
||||
#:name "R team"
|
||||
#:description
|
||||
"The R language, CRAN and Bioconductor repositories, the \"cran\" importer,
|
||||
and the r-build-system."
|
||||
#:scope (list "gnu/packages/bioconductor.scm"
|
||||
"gnu/packages/cran.scm"
|
||||
"guix/build/r-build-system.scm"
|
||||
"guix/build-system/r.scm"
|
||||
"guix/import/cran.scm"
|
||||
"guix/scripts/import/cran.scm"
|
||||
"tests/cran.scm")))
|
||||
|
||||
(define-team telephony
|
||||
(team 'telephony
|
||||
#:name "Telephony team"
|
||||
#:description
|
||||
"Telephony packages and services such as Jami, Linphone, etc."
|
||||
#:scope (list "gnu/build/jami-service.scm"
|
||||
"gnu/packages/jami.scm"
|
||||
"gnu/packages/linphone.scm"
|
||||
"gnu/packages/telephony.scm"
|
||||
"gnu/services/telephony.scm"
|
||||
"gnu/tests/data/jami-dummy-account.dat"
|
||||
"gnu/tests/telephony.scm"
|
||||
"tests/services/telephony.scm")))
|
||||
|
||||
(define-team tex
|
||||
(team 'tex
|
||||
#:name "TeX team"
|
||||
#:description
|
||||
"TeX, LaTeX, XeLaTeX, LuaTeX, TeXLive, the texlive-build-system, and
|
||||
the \"texlive\" importer."
|
||||
#:scope (list "gnu/packages/tex.scm"
|
||||
"gnu/packages/texlive.scm"
|
||||
"guix/build/texlive-build-system.scm"
|
||||
"guix/build-system/texlive.scm"
|
||||
"guix/import/texlive.scm"
|
||||
"guix/scripts/import/texlive.scm"
|
||||
"tests/texlive.scm")))
|
||||
|
||||
(define-team julia
|
||||
(team 'julia
|
||||
#:name "Julia team"
|
||||
#:description
|
||||
"The Julia language, Julia packages, and the julia-build-system."
|
||||
#:scope (list (make-regexp* "^gnu/packages/julia(-.+|)\\.scm$")
|
||||
"guix/build/julia-build-system.scm"
|
||||
"guix/build-system/julia.scm")))
|
||||
|
||||
(define-team ocaml
|
||||
(team 'ocaml
|
||||
#:name "OCaml and Dune team"
|
||||
#:description
|
||||
"The OCaml language, the Dune build system, OCaml packages, the \"opam\"
|
||||
importer, and the ocaml-build-system."
|
||||
#:scope
|
||||
(list "gnu/packages/ocaml.scm"
|
||||
"gnu/packages/coq.scm"
|
||||
"guix/build/ocaml-build-system.scm"
|
||||
"guix/build/dune-build-system.scm"
|
||||
"guix/build-system/ocaml.scm"
|
||||
"guix/build-system/dune.scm"
|
||||
"guix/import/opam.scm"
|
||||
"guix/scripts/import/opam.scm"
|
||||
"tests/opam.scm")))
|
||||
|
||||
(define-team java
|
||||
(team 'java
|
||||
#:name "Java and Maven team"
|
||||
#:description
|
||||
"The JDK and JRE, the Maven build system, Java packages, the ant-build-system,
|
||||
and the maven-build-system."
|
||||
#:scope
|
||||
(list ;; Match java.scm and java-*.scm.
|
||||
(make-regexp* "^gnu/packages/java(-.+|)\\.scm$")
|
||||
;; Match maven.scm and maven-*.scm
|
||||
(make-regexp* "^gnu/packages/maven(-.+|)\\.scm$")
|
||||
"guix/build/ant-build-system.scm"
|
||||
"guix/build/java-utils.scm"
|
||||
"guix/build/maven-build-system.scm"
|
||||
;; The maven directory
|
||||
(make-regexp* "^guix/build/maven/")
|
||||
"guix/build-system/ant.scm"
|
||||
"guix/build-system/maven.scm")))
|
||||
|
||||
(define-team science
|
||||
(team 'science
|
||||
#:name "Science team"
|
||||
#:description "The main science disciplines and fields related
|
||||
packages (e.g. Astronomy, Chemistry, Math, Physics etc.)"
|
||||
#:scope (list "gnu/packages/algebra.scm"
|
||||
"gnu/packages/astronomy.scm"
|
||||
"gnu/packages/geo.scm"
|
||||
"gnu/packages/chemistry.scm"
|
||||
"gnu/packages/maths.scm")))
|
||||
|
||||
(define-team emacs
|
||||
(team 'emacs
|
||||
#:name "Emacs team"
|
||||
#:description "The extensible, customizable text editor and its
|
||||
ecosystem."
|
||||
#:scope (list "gnu/packages/aux-files/emacs/guix-emacs.el"
|
||||
(make-regexp* "^gnu/packages/emacs(-.+|)\\.scm$")
|
||||
"gnu/packages/tree-sitter.scm"
|
||||
"guix/build/emacs-build-system.scm"
|
||||
"guix/build/emacs-utils.scm"
|
||||
"guix/build-system/emacs.scm"
|
||||
"guix/import/elpa.scm"
|
||||
"guix/scripts/import/elpa.scm"
|
||||
"tests/elpa.scm")))
|
||||
|
||||
(define-team lisp
|
||||
(team 'lisp
|
||||
#:name "Lisp team"
|
||||
#:description
|
||||
"Common Lisp and similar languages, Common Lisp packages and the
|
||||
asdf-build-system."
|
||||
#:scope (list (make-regexp* "^gnu/packages/lisp(-.+|)\\.scm$")
|
||||
"guix/build/asdf-build-system.scm"
|
||||
"guix/build/lisp-utils.scm"
|
||||
"guix/build-system/asdf.scm")))
|
||||
|
||||
(define-team ruby
|
||||
(team 'ruby
|
||||
#:name "Ruby team"
|
||||
#:scope (list "gnu/packages/ruby.scm"
|
||||
"guix/build/ruby-build-system.scm"
|
||||
"guix/build-system/ruby.scm"
|
||||
"guix/import/gem.scm"
|
||||
"guix/scripts/import/gem.scm"
|
||||
"tests/gem.scm")))
|
||||
|
||||
(define-team go
|
||||
(team 'go
|
||||
#:name "Go team"
|
||||
#:scope (list "gnu/packages/golang.scm"
|
||||
"guix/build/go-build-system.scm"
|
||||
"guix/build-system/go.scm"
|
||||
"guix/import/go.scm"
|
||||
"guix/scripts/import/go.scm"
|
||||
"tests/go.scm")))
|
||||
|
||||
(define-team bootstrap
|
||||
(team 'bootstrap
|
||||
#:name "Bootstrap"
|
||||
#:scope (list "gnu/packages/mes.scm")))
|
||||
|
||||
(define-team embedded
|
||||
(team 'embedded
|
||||
#:name "Embedded"
|
||||
#:scope (list "gnu/packages/bootloaders.scm"
|
||||
"gnu/packages/firmware.scm")))
|
||||
|
||||
(define-team rust
|
||||
(team 'rust
|
||||
#:name "Rust"
|
||||
#:scope (list (make-regexp* "^gnu/packages/(crates|rust)(-.+|)\\.scm$")
|
||||
"gnu/packages/sequoia.scm"
|
||||
"guix/build/cargo-build-system.scm"
|
||||
"guix/build/cargo-utils.scm"
|
||||
"guix/build-system/cargo.scm"
|
||||
"guix/import/crate.scm"
|
||||
"guix/scripts/import/crate.scm"
|
||||
"tests/crate.scm")))
|
||||
|
||||
(define-team kernel
|
||||
(team 'kernel
|
||||
#:name "Linux-libre kernel team"
|
||||
#:scope (list "gnu/build/linux-modules.scm"
|
||||
"gnu/packages/linux.scm"
|
||||
"gnu/tests/linux-modules.scm"
|
||||
"guix/build/linux-module-build-system.scm"
|
||||
"guix/build-system/linux-module.scm")))
|
||||
|
||||
(define-team core
|
||||
(team 'core
|
||||
#:name "Core / Tools / Internals"
|
||||
#:scope
|
||||
(list "guix/avahi.scm"
|
||||
"guix/base16.scm"
|
||||
"guix/base32.scm"
|
||||
"guix/base64.scm"
|
||||
"guix/bzr-download.scm"
|
||||
"guix/cache.scm"
|
||||
"guix/channels.scm"
|
||||
"guix/ci.scm"
|
||||
"guix/colors.scm"
|
||||
"guix/combinators.scm"
|
||||
"guix/config.scm"
|
||||
"guix/cpio.scm"
|
||||
"guix/cpu.scm"
|
||||
"guix/cve.scm"
|
||||
"guix/cvs-download.scm"
|
||||
"guix/deprecation.scm"
|
||||
"guix/derivations.scm"
|
||||
"guix/describe.scm"
|
||||
"guix/diagnostics.scm"
|
||||
"guix/discovery.scm"
|
||||
"guix/docker.scm"
|
||||
"guix/download.scm"
|
||||
"guix/elf.scm"
|
||||
"guix/ftp-client.scm"
|
||||
"guix/gexp.scm"
|
||||
"guix/git-authenticate.scm"
|
||||
"guix/git-download.scm"
|
||||
"guix/git.scm"
|
||||
"guix/glob.scm"
|
||||
"guix/gnu-maintenance.scm"
|
||||
"guix/gnupg.scm"
|
||||
"guix/grafts.scm"
|
||||
"guix/graph.scm"
|
||||
"guix/hash.scm"
|
||||
"guix/hg-download.scm"
|
||||
"guix/http-client.scm"
|
||||
"guix/i18n.scm"
|
||||
"guix/inferior.scm"
|
||||
"guix/ipfs.scm"
|
||||
"guix/least-authority.scm"
|
||||
"guix/licenses.scm"
|
||||
"guix/lint.scm"
|
||||
"guix/man-db.scm"
|
||||
"guix/memoization.scm"
|
||||
"guix/modules.scm"
|
||||
"guix/monad-repl.scm"
|
||||
"guix/monads.scm"
|
||||
"guix/narinfo.scm"
|
||||
"guix/nar.scm"
|
||||
"guix/openpgp.scm"
|
||||
"guix/packages.scm"
|
||||
"guix/pki.scm"
|
||||
"guix/platform.scm"
|
||||
"guix/profiles.scm"
|
||||
"guix/profiling.scm"
|
||||
"guix/progress.scm"
|
||||
"guix/quirks.scm"
|
||||
"guix/read-print.scm"
|
||||
"guix/records.scm"
|
||||
"guix/remote.scm"
|
||||
"guix/repl.scm"
|
||||
"guix/search-paths.scm"
|
||||
"guix/self.scm"
|
||||
"guix/serialization.scm"
|
||||
"guix/sets.scm"
|
||||
"guix/ssh.scm"
|
||||
"guix/status.scm"
|
||||
"guix/store.scm"
|
||||
"guix/substitutes.scm"
|
||||
"guix/svn-download.scm"
|
||||
"guix/swh.scm"
|
||||
"guix/tests.scm"
|
||||
"guix/transformations.scm"
|
||||
"guix/ui.scm"
|
||||
"guix/upstream.scm"
|
||||
"guix/utils.scm"
|
||||
"guix/workers.scm"
|
||||
(make-regexp* "^guix/platforms/")
|
||||
(make-regexp* "^guix/scripts/")
|
||||
(make-regexp* "^guix/store/"))))
|
||||
|
||||
(define-team games
|
||||
(team 'games
|
||||
#:name "Games and Toys"
|
||||
#:description "Packaging programs for amusement."
|
||||
#:scope (list "gnu/packages/games.scm"
|
||||
"gnu/packages/game-development.scm"
|
||||
"gnu/packages/minetest.scm"
|
||||
"gnu/packages/esolangs.scm" ; granted, rather niche
|
||||
"gnu/packages/motti.scm"
|
||||
"guix/build/minetest-build-system.scm")))
|
||||
|
||||
(define-team localization
|
||||
(team 'localization
|
||||
#:name "Localization (l10n) team"
|
||||
#:description
|
||||
"Localization of your system to specific languages."
|
||||
#:scope (list "gnu/packages/anthy.scm"
|
||||
"gnu/packages/fcitx5.scm"
|
||||
"gnu/packages/fcitx.scm"
|
||||
"gnu/packages/fonts.scm"
|
||||
"gnu/packages/ibus.scm")))
|
||||
|
||||
(define-team translations
|
||||
(team 'translations
|
||||
#:name "Translations"
|
||||
#:scope (list "etc/news.scm"
|
||||
(make-regexp* "^po/"))))
|
||||
|
||||
(define-team installer
|
||||
(team 'installer
|
||||
#:name "Installer script and system installer"
|
||||
#:scope (list (make-regexp* "^gnu/installer(\\.scm$|/)"))))
|
||||
|
||||
(define-team home
|
||||
(team 'home
|
||||
#:name "Team for \"Guix Home\""
|
||||
#:scope (list (make-regexp* "^(gnu|guix/scripts)/home(\\.scm$|/)")
|
||||
"tests/guix-home.sh"
|
||||
"tests/home-import.scm"
|
||||
"tests/home-services.scm")))
|
||||
|
||||
(define-team mentors
|
||||
(team 'mentors
|
||||
#:name "Mentors"
|
||||
#:description
|
||||
"A group of mentors who chaperone contributions by newcomers."))
|
||||
|
||||
(define-team mozilla
|
||||
(team 'mozilla
|
||||
#:name "Mozilla"
|
||||
#:description
|
||||
"Taking care about Icecat and Icedove, built from Mozilla Firefox
|
||||
and Thunderbird."
|
||||
#:scope (list "gnu/packages/gnuzilla.scm")))
|
||||
|
||||
(define-team racket
|
||||
(team 'racket
|
||||
#:name "Racket team"
|
||||
#:description
|
||||
"The Racket language and Racket-based languages, Racket packages,
|
||||
Racket's variant of Chez Scheme, and development of a Racket build system and
|
||||
importer."
|
||||
#:scope (list "gnu/packages/chez.scm"
|
||||
"gnu/packages/racket.scm")))
|
||||
|
||||
(define-team reproduciblebuilds
|
||||
(team 'reproduciblebuilds
|
||||
#:name "Reproducible Builds team"
|
||||
#:description
|
||||
"Reproducible Builds tooling and issues that affect any guix packages."
|
||||
#:scope (list "gnu/packages/diffoscope.scm")))
|
||||
|
||||
(define-team gnome
|
||||
(team 'gnome
|
||||
#:name "Gnome team"
|
||||
#:description
|
||||
"The Gnome desktop environment, along with core technologies such as
|
||||
GLib/GIO, GTK, GStreamer and Webkit."
|
||||
#:scope (list "gnu/packages/glib.scm"
|
||||
"gnu/packages/gstreamer.scm"
|
||||
"gnu/packages/gtk.scm"
|
||||
"gnu/packages/gnome.scm"
|
||||
"gnu/packages/gnome-xyz.scm"
|
||||
"gnu/packages/webkit.scm"
|
||||
"guix/build/glib-or-gtk-build-system.scm"
|
||||
"guix/build/meson-build-system.scm")))
|
||||
|
||||
(define-team xfce
|
||||
(team 'xfce
|
||||
#:name "Xfce team"
|
||||
#:description "Xfce desktop environment."
|
||||
#:scope (list "gnu/packages/xfce.scm")))
|
||||
|
||||
(define-team lxqt
|
||||
(team 'lxqt
|
||||
#:name "LXQt team"
|
||||
#:description "LXQt desktop environment."
|
||||
#:scope (list "gnu/packages/lxqt.scm"
|
||||
"gnu/packages/qt.scm")))
|
||||
|
||||
|
||||
(define-member (person "Eric Bavier"
|
||||
"bavier@posteo.net")
|
||||
science)
|
||||
|
||||
(define-member (person "Lars-Dominik Braun"
|
||||
"lars@6xq.net")
|
||||
python haskell)
|
||||
|
||||
(define-member (person "Jonathan Brielmaier"
|
||||
"jonathan.brielmaier@web.de")
|
||||
mozilla)
|
||||
|
||||
(define-member (person "Ludovic Courtès"
|
||||
"ludo@gnu.org")
|
||||
core home bootstrap installer mentors)
|
||||
|
||||
(define-member (person "Andreas Enge"
|
||||
"andreas@enge.fr")
|
||||
lxqt science tex)
|
||||
|
||||
(define-member (person "Tobias Geerinckx-Rice"
|
||||
"me@tobias.gr")
|
||||
core kernel mentors)
|
||||
|
||||
(define-member (person "Björn Höfling"
|
||||
"bjoern.hoefling@bjoernhoefling.de")
|
||||
java)
|
||||
|
||||
(define-member (person "Leo Famulari"
|
||||
"leo@famulari.name")
|
||||
kernel)
|
||||
|
||||
(define-member (person "Efraim Flashner"
|
||||
"efraim@flashner.co.il")
|
||||
embedded bootstrap julia rust science)
|
||||
|
||||
(define-member (person "jgart"
|
||||
"jgart@dismail.de")
|
||||
python lisp mentors)
|
||||
|
||||
(define-member (person "Guillaume Le Vaillant"
|
||||
"glv@posteo.net")
|
||||
lisp)
|
||||
|
||||
(define-member (person "Julien Lepiller"
|
||||
"julien@lepiller.eu")
|
||||
java ocaml translations)
|
||||
|
||||
(define-member (person "Philip McGrath"
|
||||
"philip@philipmcgrath.com")
|
||||
racket)
|
||||
|
||||
(define-member (person "Mathieu Othacehe"
|
||||
"othacehe@gnu.org")
|
||||
core installer mentors)
|
||||
|
||||
(define-member (person "Florian Pelz"
|
||||
"pelzflorian@pelzflorian.de")
|
||||
translations)
|
||||
|
||||
(define-member (person "Liliana Marie Prikler"
|
||||
"liliana.prikler@gmail.com")
|
||||
emacs games gnome)
|
||||
|
||||
(define-member (person "Ricardo Wurmus"
|
||||
"rekado@elephly.net")
|
||||
r core mentors tex)
|
||||
|
||||
(define-member (person "Christopher Baines"
|
||||
"guix@cbaines.net")
|
||||
core mentors ruby)
|
||||
|
||||
(define-member (person "Andrew Tropin"
|
||||
"andrew@trop.in")
|
||||
home emacs)
|
||||
|
||||
(define-member (person "pukkamustard"
|
||||
"pukkamustard@posteo.net")
|
||||
ocaml)
|
||||
|
||||
(define-member (person "Josselin Poiret"
|
||||
"dev@jpoiret.xyz")
|
||||
core installer)
|
||||
|
||||
(define-member (person "("
|
||||
"paren@disroot.org")
|
||||
home mentors)
|
||||
|
||||
(define-member (person "Simon Tournier"
|
||||
"zimon.toutoune@gmail.com")
|
||||
julia core mentors)
|
||||
|
||||
(define-member (person "Raghav Gururajan"
|
||||
"rg@raghavgururajan.name")
|
||||
gnome mentors)
|
||||
|
||||
(define-member (person "宋文武"
|
||||
"iyzsong@envs.net")
|
||||
games localization lxqt xfce)
|
||||
|
||||
(define-member (person "Vagrant Cascadian"
|
||||
"vagrant@debian.org")
|
||||
embedded)
|
||||
|
||||
(define-member (person "Vagrant Cascadian"
|
||||
"vagrant@reproducible-builds.org")
|
||||
reproduciblebuilds)
|
||||
|
||||
(define-member (person "Zhu Zihao"
|
||||
"all_but_last@163.com")
|
||||
localization xfce)
|
||||
|
||||
(define-member (person "Maxim Cournoyer"
|
||||
"maxim.cournoyer@gmail.com")
|
||||
gnome qt telephony)
|
||||
|
||||
(define-member (person "Katherine Cox-Buday"
|
||||
"cox.katherine.e+guix@gmail.com")
|
||||
emacs go lisp)
|
||||
|
||||
|
||||
(define (find-team name)
|
||||
(or (hash-ref %teams (string->symbol name))
|
||||
(error (format #false
|
||||
"no such team: ~a~%" name))))
|
||||
|
||||
(define (find-team-by-scope files)
|
||||
"Return the team(s) which scope matches at least one of the FILES, as list
|
||||
of file names as string."
|
||||
(hash-fold
|
||||
(lambda (key team acc)
|
||||
(if (any (lambda (file)
|
||||
(any (match-lambda
|
||||
((? string? scope)
|
||||
(string=? scope file))
|
||||
((? regexp*? scope)
|
||||
(regexp*-exec scope file)))
|
||||
(team-scope team)))
|
||||
files)
|
||||
(cons team acc)
|
||||
acc))
|
||||
'()
|
||||
%teams))
|
||||
|
||||
(define (cc . teams)
|
||||
"Return arguments for `git send-email' to notify the members of the given
|
||||
TEAMS when a patch is received by Debbugs."
|
||||
(let ((members (append-map team-members teams)))
|
||||
(unless (null? members)
|
||||
(format #true "--add-header=\"X-Debbugs-Cc: ~{~a~^, ~}\""
|
||||
(map person-email (sort-members members))))))
|
||||
|
||||
(define (sort-members members)
|
||||
"Deduplicate and sort MEMBERS alphabetically by their name."
|
||||
(sort (delete-duplicates members equal?)
|
||||
(lambda (m1 m2)
|
||||
(string<? (person-name m1) (person-name m2)))))
|
||||
|
||||
(define (member->string member)
|
||||
"Return the 'email <name>' string representation of MEMBER."
|
||||
(let* ((name (person-name member))
|
||||
(quoted-name/maybe (if (string-contains name ",")
|
||||
(string-append "\"" name "\"")
|
||||
name)))
|
||||
(format #false "~a <~a>" quoted-name/maybe (person-email member))))
|
||||
|
||||
(define* (list-members team #:key (prefix ""))
|
||||
"Print the members of the given TEAM."
|
||||
(for-each (lambda (member)
|
||||
(format #t "~a~a~%" prefix (member->string member)))
|
||||
(sort-members (team-members team))))
|
||||
|
||||
(define (print-team team)
|
||||
"Print TEAM, a <team> record object."
|
||||
(format #t
|
||||
"\
|
||||
id: ~a
|
||||
name: ~a
|
||||
description: ~a
|
||||
~amembers:
|
||||
"
|
||||
(team-id team)
|
||||
(team-name team)
|
||||
(or (and=> (team-description team)
|
||||
(lambda (text)
|
||||
(string->recutils
|
||||
(fill-paragraph text (%text-width)
|
||||
(string-length "description: ")))))
|
||||
"<none>")
|
||||
(match (team-scope team)
|
||||
(() "")
|
||||
(scope (format #f "scope:~%~{+ ~a~^~%~}~%"
|
||||
(sort (map (match-lambda
|
||||
((? regexp*? rx)
|
||||
(regexp*-pattern rx))
|
||||
(item item))
|
||||
scope)
|
||||
string<?)))))
|
||||
(list-members team #:prefix "+ ")
|
||||
(newline))
|
||||
|
||||
(define (sort-teams teams)
|
||||
"Sort TEAMS, a list of <team> record objects."
|
||||
(sort teams
|
||||
(lambda (team1 team2)
|
||||
(string<? (symbol->string (team-id team1))
|
||||
(symbol->string (team-id team2))))))
|
||||
|
||||
(define* (list-teams #:optional team-names)
|
||||
"Print all teams, their scope and their members."
|
||||
(for-each print-team
|
||||
(sort-teams
|
||||
(if team-names
|
||||
(map find-team team-names)
|
||||
(hash-map->list (lambda (_ value) value) %teams)))))
|
||||
|
||||
|
||||
(define (diff-revisions rev-start rev-end)
|
||||
"Return the list of added, modified or removed files between REV-START
|
||||
and REV-END, two git revision strings."
|
||||
(let* ((repository (repository-open (getcwd)))
|
||||
(commit1 (commit-lookup repository
|
||||
(object-id
|
||||
(revparse-single repository rev-start))))
|
||||
(commit2 (commit-lookup repository
|
||||
(object-id
|
||||
(revparse-single repository rev-end))))
|
||||
(diff (diff-tree-to-tree repository
|
||||
(commit-tree commit1)
|
||||
(commit-tree commit2)))
|
||||
(files '()))
|
||||
(diff-foreach
|
||||
diff
|
||||
(lambda (delta progress)
|
||||
(set! files
|
||||
(cons (diff-file-path (diff-delta-old-file delta)) files))
|
||||
0)
|
||||
(const 0)
|
||||
(const 0)
|
||||
(const 0))
|
||||
files))
|
||||
|
||||
(define (git-patch->commit-id file)
|
||||
"Parse the commit ID from the first line of FILE, a patch produced with git."
|
||||
(call-with-input-file file
|
||||
(lambda (port)
|
||||
(let ((m (string-match "^From ([0-9a-f]{40})" (read-line port))))
|
||||
(unless m
|
||||
(error "invalid patch file:" file))
|
||||
(match:substring m 1)))))
|
||||
|
||||
(define (git-patch->revisions file)
|
||||
"Return the start and end revisions of FILE, a patch file produced with git."
|
||||
(let* ((rev-end (git-patch->commit-id file))
|
||||
(rev-start (string-append rev-end "^")))
|
||||
(list rev-start rev-end)))
|
||||
|
||||
(define (patch->teams patch-file)
|
||||
"Return the name of the teams in scope for the changes in PATCH-FILE."
|
||||
(map (compose symbol->string team-id)
|
||||
(find-team-by-scope (apply diff-revisions
|
||||
(git-patch->revisions patch-file)))))
|
||||
|
||||
|
||||
(define (main . args)
|
||||
(match args
|
||||
(("cc" . team-names)
|
||||
(apply cc (map find-team team-names)))
|
||||
(("cc-members" patch-file)
|
||||
(unless (file-exists? patch-file)
|
||||
(error "patch file does not exist:" patch-file))
|
||||
(apply main "cc-members" (git-patch->revisions patch-file)))
|
||||
(("cc-members" rev-start rev-end)
|
||||
(apply cc (find-team-by-scope
|
||||
(diff-revisions rev-start rev-end))))
|
||||
(("cc-members-header-cmd" patch-file)
|
||||
(let* ((teams (map find-team (patch->teams patch-file)))
|
||||
(members (sort-members (append-map team-members teams))))
|
||||
(unless (null? members)
|
||||
(format #true "X-Debbugs-Cc: ~{~a~^, ~}"
|
||||
(map member->string members)))))
|
||||
(("cc-mentors-header-cmd" patch-file)
|
||||
(format #true "X-Debbugs-Cc: ~{~a~^, ~}"
|
||||
(map member->string
|
||||
(sort-members (team-members (find-team "mentors"))))))
|
||||
(("get-maintainer" patch-file)
|
||||
(apply main "list-members" (patch->teams patch-file)))
|
||||
(("list-teams" . args)
|
||||
(list-teams))
|
||||
(("list-members" . team-names)
|
||||
(for-each
|
||||
(lambda (team-name)
|
||||
(list-members (find-team team-name)))
|
||||
team-names))
|
||||
(("show" . team-names)
|
||||
(list-teams team-names))
|
||||
(anything
|
||||
(format (current-error-port)
|
||||
"Usage: etc/teams.scm <command> [<args>]
|
||||
|
||||
Commands:
|
||||
cc <team-name>
|
||||
get git send-email flags for cc-ing <team-name>
|
||||
cc-members <start> <end> | <patch>
|
||||
cc teams related to files changed between revisions or in a patch file
|
||||
cc-members-header-cmd <patch>
|
||||
cc-members variant for use with 'git send-email --header-cmd'
|
||||
cc-mentors-header-cmd <patch>
|
||||
command to use with 'git send-email --header-cmd' to notify mentors
|
||||
list-teams
|
||||
list teams and their members
|
||||
list-members <team-name>
|
||||
list members belonging to <team-name>
|
||||
get-maintainer <patch>
|
||||
compatibility mode with Linux get_maintainer.pl
|
||||
show <team-name>
|
||||
display <team-name> properties~%"))))
|
||||
|
||||
(apply main (cdr (command-line)))
|
||||
@@ -1,50 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; This file returns a manifest of packages related to linux-libre.
|
||||
;;; Simplistically, it selects packages whose names begin with "linux-libre".
|
||||
;;; It is used to assist continuous integration of the kernel packages.
|
||||
|
||||
(use-modules (guix packages)
|
||||
(guix profiles)
|
||||
(guix utils)
|
||||
(gnu packages))
|
||||
|
||||
(define* (qt-packages-manifest #:key major-version negate-version-test?)
|
||||
"Return a manifest of Qt packages for MAJOR-VERSION, or any version if left
|
||||
unspecified. If NEGATE-VERSION-TEST? is true, select all the Qt packages
|
||||
*not* matching MAJOR-VERSION."
|
||||
(manifest
|
||||
(map package->manifest-entry
|
||||
(fold-packages
|
||||
(lambda (package lst)
|
||||
(let ((uri (and=> (package-source package)
|
||||
(lambda (x)
|
||||
(and (origin? x)
|
||||
(origin-uri x))))))
|
||||
(if (and uri
|
||||
(string? uri)
|
||||
(string-prefix? "mirror://qt/" uri)
|
||||
(if major-version
|
||||
((if negate-version-test? not identity)
|
||||
(string=? major-version (version-major
|
||||
(package-version package))))
|
||||
#t))
|
||||
(cons package lst)
|
||||
lst)))
|
||||
'()))))
|
||||
@@ -1,34 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; This file returns a manifest of packages related to linux-libre.
|
||||
;;; Simplistically, it selects packages whose names begin with "linux-libre".
|
||||
;;; It is used to assist continuous integration of the kernel packages.
|
||||
|
||||
(load "common.scm")
|
||||
|
||||
;;; Commentary:
|
||||
;;;
|
||||
;;; This manifest can be used to update the latest Qt packages collection, via
|
||||
;;; e.g.:
|
||||
;;;
|
||||
;;; ./pre-inst-env guix refresh -u -m etc/teams/qt/qt-manifest.scm
|
||||
;;;
|
||||
;;; Code:
|
||||
|
||||
(qt-packages-manifest #:major-version "5" #:negate-version-test? #t)
|
||||
@@ -1,34 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; This file returns a manifest of packages related to linux-libre.
|
||||
;;; Simplistically, it selects packages whose names begin with "linux-libre".
|
||||
;;; It is used to assist continuous integration of the kernel packages.
|
||||
|
||||
(load "common.scm")
|
||||
|
||||
;;; Commentary:
|
||||
;;;
|
||||
;;; This manifest can be used to update the Qt 5 packages collection, via
|
||||
;;; e.g.:
|
||||
;;;
|
||||
;;; ./pre-inst-env guix refresh -u -m etc/teams/qt/qt5-manifest.scm --target-version=5.15.10
|
||||
;;;
|
||||
;;; Code:
|
||||
|
||||
(qt-packages-manifest #:major-version "5")
|
||||
@@ -1,84 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; This file returns a manifest containing entries to build past Guix
|
||||
;;; releases from the current Guix, as per 'guix time-machine'.
|
||||
|
||||
(use-modules (srfi srfi-9) (ice-9 match)
|
||||
(guix channels) (guix gexp)
|
||||
((guix store) #:select (%store-monad))
|
||||
((guix monads) #:select (mparameterize return))
|
||||
((guix git) #:select (%repository-cache-directory))
|
||||
((guix build utils) #:select (mkdir-p)))
|
||||
|
||||
;; Representation of the latest channels. This type exists just so we can
|
||||
;; refer to such records in a gexp.
|
||||
(define-record-type <guix-instance>
|
||||
(guix-instance channels)
|
||||
guix-instance?
|
||||
(channels guix-instance-channels))
|
||||
|
||||
(define-gexp-compiler (guix-instance-compiler (instance <guix-instance>)
|
||||
system target)
|
||||
(match instance
|
||||
(($ <guix-instance> channels)
|
||||
;; When this manifest is evaluated by Cuirass, make sure it does not
|
||||
;; fiddle with the cached checkout that Cuirass is also using since
|
||||
;; concurrent accesses are unsafe.
|
||||
(mparameterize %store-monad ((%repository-cache-directory
|
||||
(string-append (%repository-cache-directory)
|
||||
"/time-travel/" system)))
|
||||
(return (mkdir-p (%repository-cache-directory)))
|
||||
(latest-channel-derivation channels)))))
|
||||
|
||||
(define (guix-instance->manifest-entry instance)
|
||||
"Return a manifest entry for INSTANCE."
|
||||
(define (shorten commit)
|
||||
(string-take commit 7))
|
||||
|
||||
(manifest-entry
|
||||
(name "guix")
|
||||
(version (string-join (map (compose shorten channel-commit)
|
||||
(guix-instance-channels instance))
|
||||
"-"))
|
||||
(item instance)))
|
||||
|
||||
(define (commit->guix-instance commit)
|
||||
"Return a Guix instance for COMMIT."
|
||||
(guix-instance (list (channel
|
||||
(inherit %default-guix-channel)
|
||||
(commit commit)))))
|
||||
|
||||
(define %release-commits
|
||||
;; Release commits: the list of version/commit pairs.
|
||||
'(("1.3.0" . "a0178d34f582b50e9bdbb0403943129ae5b560ff")
|
||||
("1.2.0" . "a099685659b4bfa6b3218f84953cbb7ff9e88063")
|
||||
("1.1.0" . "d62c9b2671be55ae0305bebfda17b595f33797f2")
|
||||
("1.0.1" . "d68de958b60426798ed62797ff7c96c327a672ac")
|
||||
("1.0.0" . "6298c3ffd9654d3231a6f25390b056483e8f407c")
|
||||
("0.16.0" . "4a0b87f0ec5b6c2dcf82b372dd20ca7ea6acdd9c")))
|
||||
|
||||
(manifest
|
||||
(map (match-lambda
|
||||
((version . commit)
|
||||
(let ((entry (guix-instance->manifest-entry
|
||||
(commit->guix-instance commit))))
|
||||
(manifest-entry
|
||||
(inherit entry)
|
||||
(version version)))))
|
||||
%release-commits))
|
||||
+2
-2
@@ -29,7 +29,7 @@
|
||||
;;; Code:
|
||||
|
||||
(define %artwork-repository
|
||||
(let ((commit "4c7f2ce6428a63e202cd2a9474a06f68a946934d"))
|
||||
(let ((commit "2f2fe74c1078be605a6a93c2193fd6c715cebbb0"))
|
||||
(origin
|
||||
(method git-fetch)
|
||||
(uri (git-reference
|
||||
@@ -39,6 +39,6 @@
|
||||
"-checkout"))
|
||||
(sha256
|
||||
(base32
|
||||
"1rl569759q9wm1dxn7nkq3873d2k92giic7aa6jwzwr3n16prc7y")))))
|
||||
"0c8r0phvm3wgf914n2kw1461cwdjl2zbzqvzq9x7d9pwkgv7xmq7")))))
|
||||
|
||||
;;; artwork.scm ends here
|
||||
|
||||
+87
-151
@@ -1,11 +1,9 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2017 David Craven <david@craven.ch>
|
||||
;;; Copyright © 2017, 2020, 2022 Mathieu Othacehe <othacehe@gnu.org>
|
||||
;;; Copyright © 2017, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
|
||||
;;; Copyright © 2017 Leo Famulari <leo@famulari.name>
|
||||
;;; Copyright © 2019, 2021 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||
;;; Copyright © 2022 Josselin Poiret <dev@jpoiret.xyz>
|
||||
;;; Copyright © 2022 Reza Alizadeh Majd <r.majd@pantherx.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -23,8 +21,6 @@
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu bootloader)
|
||||
#:use-module (gnu system file-systems)
|
||||
#:use-module (gnu system uuid)
|
||||
#:use-module (guix discovery)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix profiles)
|
||||
@@ -34,8 +30,6 @@
|
||||
#:use-module (guix diagnostics)
|
||||
#:use-module (guix i18n)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-34)
|
||||
#:use-module (srfi srfi-35)
|
||||
#:use-module (ice-9 match)
|
||||
#:export (menu-entry
|
||||
menu-entry?
|
||||
@@ -48,7 +42,6 @@
|
||||
menu-entry-multiboot-kernel
|
||||
menu-entry-multiboot-arguments
|
||||
menu-entry-multiboot-modules
|
||||
menu-entry-chain-loader
|
||||
|
||||
menu-entry->sexp
|
||||
sexp->menu-entry
|
||||
@@ -76,7 +69,7 @@
|
||||
bootloader-configuration-terminal-inputs
|
||||
bootloader-configuration-serial-unit
|
||||
bootloader-configuration-serial-speed
|
||||
bootloader-configuration-device-tree-support?
|
||||
bootloader-configuration-additional-configuration
|
||||
|
||||
%bootloaders
|
||||
lookup-bootloader-by-name
|
||||
@@ -107,77 +100,34 @@
|
||||
(multiboot-arguments menu-entry-multiboot-arguments
|
||||
(default '())) ; list of string-valued gexps
|
||||
(multiboot-modules menu-entry-multiboot-modules
|
||||
(default '())) ; list of multiboot commands, where
|
||||
(default '()))) ; list of multiboot commands, where
|
||||
; a command is a list of <string>
|
||||
(chain-loader menu-entry-chain-loader
|
||||
(default #f))) ; string, path of efi file
|
||||
|
||||
(define (report-menu-entry-error menu-entry)
|
||||
(raise
|
||||
(condition
|
||||
(&message
|
||||
(message
|
||||
(format #f (G_ "invalid menu-entry: ~a") menu-entry)))
|
||||
(&fix-hint
|
||||
(hint
|
||||
(G_ "Please chose only one of:
|
||||
@enumerate
|
||||
@item direct boot by specifying fields @code{linux},
|
||||
@code{linux-arguments} and @code{linux-modules},
|
||||
@item multiboot by specifying fields @code{multiboot-kernel},
|
||||
@code{multiboot-arguments} and @code{multiboot-modules},
|
||||
@item chain-loader by specifying field @code{chain-loader}.
|
||||
@end enumerate"))))))
|
||||
|
||||
(define (menu-entry->sexp entry)
|
||||
"Return ENTRY serialized as an sexp."
|
||||
(define (device->sexp device)
|
||||
(match device
|
||||
((? uuid? uuid)
|
||||
`(uuid ,(uuid-type uuid) ,(uuid->string uuid)))
|
||||
((? file-system-label? label)
|
||||
`(label ,(file-system-label->string label)))
|
||||
(_ device)))
|
||||
(match entry
|
||||
(($ <menu-entry> label device mount-point
|
||||
(? identity linux) linux-arguments (? identity initrd)
|
||||
#f () () #f)
|
||||
(($ <menu-entry> label device mount-point linux linux-arguments initrd #f
|
||||
())
|
||||
`(menu-entry (version 0)
|
||||
(label ,label)
|
||||
(device ,(device->sexp device))
|
||||
(device ,device)
|
||||
(device-mount-point ,mount-point)
|
||||
(linux ,linux)
|
||||
(linux-arguments ,linux-arguments)
|
||||
(initrd ,initrd)))
|
||||
(($ <menu-entry> label device mount-point #f () #f
|
||||
(? identity multiboot-kernel) multiboot-arguments
|
||||
multiboot-modules #f)
|
||||
multiboot-kernel multiboot-arguments multiboot-modules)
|
||||
`(menu-entry (version 0)
|
||||
(label ,label)
|
||||
(device ,(device->sexp device))
|
||||
(device ,device)
|
||||
(device-mount-point ,mount-point)
|
||||
(multiboot-kernel ,multiboot-kernel)
|
||||
(multiboot-arguments ,multiboot-arguments)
|
||||
(multiboot-modules ,multiboot-modules)))
|
||||
(($ <menu-entry> label device mount-point #f () #f #f () ()
|
||||
(? identity chain-loader))
|
||||
`(menu-entry (version 0)
|
||||
(label ,label)
|
||||
(device ,(device->sexp device))
|
||||
(device-mount-point ,mount-point)
|
||||
(chain-loader ,chain-loader)))
|
||||
(_ (report-menu-entry-error entry))))
|
||||
(multiboot-modules ,multiboot-modules)))))
|
||||
|
||||
(define (sexp->menu-entry sexp)
|
||||
"Turn SEXP, an sexp as returned by 'menu-entry->sexp', into a <menu-entry>
|
||||
record."
|
||||
(define (sexp->device device-sexp)
|
||||
(match device-sexp
|
||||
(('uuid type uuid-string)
|
||||
(uuid uuid-string type))
|
||||
(('label label)
|
||||
(file-system-label label))
|
||||
(_ device-sexp)))
|
||||
(match sexp
|
||||
(('menu-entry ('version 0)
|
||||
('label label) ('device device)
|
||||
@@ -186,7 +136,7 @@ record."
|
||||
('initrd initrd) _ ...)
|
||||
(menu-entry
|
||||
(label label)
|
||||
(device (sexp->device device))
|
||||
(device device)
|
||||
(device-mount-point mount-point)
|
||||
(linux linux)
|
||||
(linux-arguments linux-arguments)
|
||||
@@ -199,20 +149,11 @@ record."
|
||||
('multiboot-modules multiboot-modules) _ ...)
|
||||
(menu-entry
|
||||
(label label)
|
||||
(device (sexp->device device))
|
||||
(device device)
|
||||
(device-mount-point mount-point)
|
||||
(multiboot-kernel multiboot-kernel)
|
||||
(multiboot-arguments multiboot-arguments)
|
||||
(multiboot-modules multiboot-modules)))
|
||||
(('menu-entry ('version 0)
|
||||
('label label) ('device device)
|
||||
('device-mount-point mount-point)
|
||||
('chain-loader chain-loader) _ ...)
|
||||
(menu-entry
|
||||
(label label)
|
||||
(device (sexp->device device))
|
||||
(device-mount-point mount-point)
|
||||
(chain-loader chain-loader)))))
|
||||
(multiboot-modules multiboot-modules)))))
|
||||
|
||||
|
||||
;;;
|
||||
@@ -253,33 +194,29 @@ instead~%")))
|
||||
(define-record-type* <bootloader-configuration>
|
||||
bootloader-configuration make-bootloader-configuration
|
||||
bootloader-configuration?
|
||||
(bootloader
|
||||
bootloader-configuration-bootloader) ;<bootloader>
|
||||
(targets %bootloader-configuration-targets
|
||||
(default #f)) ;list of strings
|
||||
(target %bootloader-configuration-target ;deprecated
|
||||
(default #f)
|
||||
(sanitize warn-target-field-deprecation))
|
||||
(menu-entries bootloader-configuration-menu-entries
|
||||
(default '())) ;list of <menu-entry>
|
||||
(default-entry bootloader-configuration-default-entry
|
||||
(default 0)) ;integer
|
||||
(timeout bootloader-configuration-timeout
|
||||
(default 5)) ;seconds as integer
|
||||
(keyboard-layout bootloader-configuration-keyboard-layout
|
||||
(default #f)) ;<keyboard-layout> | #f
|
||||
(theme bootloader-configuration-theme
|
||||
(default #f)) ;bootloader-specific theme
|
||||
(terminal-outputs bootloader-configuration-terminal-outputs
|
||||
(default '(gfxterm))) ;list of symbols
|
||||
(terminal-inputs bootloader-configuration-terminal-inputs
|
||||
(default '())) ;list of symbols
|
||||
(serial-unit bootloader-configuration-serial-unit
|
||||
(default #f)) ;integer | #f
|
||||
(serial-speed bootloader-configuration-serial-speed
|
||||
(default #f)) ;integer | #f
|
||||
(device-tree-support? bootloader-configuration-device-tree-support?
|
||||
(default #t))) ;boolean
|
||||
(bootloader bootloader-configuration-bootloader) ;<bootloader>
|
||||
(targets %bootloader-configuration-targets ;list of strings
|
||||
(default #f))
|
||||
(target %bootloader-configuration-target ;deprecated
|
||||
(default #f) (sanitize warn-target-field-deprecation))
|
||||
(menu-entries bootloader-configuration-menu-entries ;list of <menu-entry>
|
||||
(default '()))
|
||||
(default-entry bootloader-configuration-default-entry ;integer
|
||||
(default 0))
|
||||
(timeout bootloader-configuration-timeout ;seconds as integer
|
||||
(default 5))
|
||||
(keyboard-layout bootloader-configuration-keyboard-layout ;<keyboard-layout> | #f
|
||||
(default #f))
|
||||
(theme bootloader-configuration-theme ;bootloader-specific theme
|
||||
(default #f))
|
||||
(terminal-outputs bootloader-configuration-terminal-outputs ;list of symbols
|
||||
(default '(gfxterm)))
|
||||
(terminal-inputs bootloader-configuration-terminal-inputs ;list of symbols
|
||||
(default '()))
|
||||
(serial-unit bootloader-configuration-serial-unit ;integer | #f
|
||||
(default #f))
|
||||
(serial-speed bootloader-configuration-serial-speed ;integer | #f
|
||||
(default #f)))
|
||||
|
||||
(define-deprecated (bootloader-configuration-target config)
|
||||
bootloader-configuration-targets
|
||||
@@ -322,22 +259,26 @@ instead~%")))
|
||||
(force %bootloaders))
|
||||
(leave (G_ "~a: no such bootloader~%") name)))
|
||||
|
||||
(define (efi-bootloader-profile packages files hooks)
|
||||
"Creates a profile from the lists of PACKAGES and FILES from the store.
|
||||
This profile is meant to be used by the bootloader-installer.
|
||||
(define (efi-bootloader-profile files bootloader-package hooks)
|
||||
"Creates a profile with BOOTLOADER-PACKAGE and a directory collection/ with
|
||||
links to additional FILES from the store. This collection is meant to be used
|
||||
by the bootloader installer.
|
||||
|
||||
FILES is a list of file or directory names from the store, which will be
|
||||
symlinked into the profile. If a directory name ends with '/', then the
|
||||
directory content instead of the directory itself will be symlinked into the
|
||||
profile.
|
||||
symlinked into the collection/ directory. If a directory name ends with '/',
|
||||
then the directory content instead of the directory itself will be symlinked
|
||||
into the collection/ directory.
|
||||
|
||||
FILES may contain file like objects produced by procedures like plain-file,
|
||||
FILES may contain file like objects produced by functions like plain-file,
|
||||
local-file, etc., or package contents produced with file-append.
|
||||
|
||||
HOOKS lists additional hook functions to modify the profile."
|
||||
(define (efi-bootloader-profile-hook manifest)
|
||||
(define (bootloader-collection manifest)
|
||||
(define build
|
||||
(with-imported-modules '((guix build utils))
|
||||
(with-imported-modules '((guix build utils)
|
||||
(ice-9 ftw)
|
||||
(srfi srfi-1)
|
||||
(srfi srfi-26))
|
||||
#~(begin
|
||||
(use-modules ((guix build utils)
|
||||
#:select (mkdir-p strip-store-file-name))
|
||||
@@ -361,7 +302,8 @@ HOOKS lists additional hook functions to modify the profile."
|
||||
(define (name-is-store-entry? name)
|
||||
"Return #t if NAME is a direct store entry and nothing inside."
|
||||
(not (string-index (strip-store-file-name name) #\/)))
|
||||
(let* ((files '#$files)
|
||||
(let* ((collection (string-append #$output "/collection"))
|
||||
(files '#$files)
|
||||
(directories (filter name-ends-with-/? files))
|
||||
(names-from-directories
|
||||
(append-map (lambda (directory)
|
||||
@@ -369,11 +311,11 @@ HOOKS lists additional hook functions to modify the profile."
|
||||
directories))
|
||||
(names (append names-from-directories
|
||||
(remove name-ends-with-/? files))))
|
||||
(mkdir-p #$output)
|
||||
(mkdir-p collection)
|
||||
(if (every file-exists? names)
|
||||
(begin
|
||||
(for-each (lambda (name)
|
||||
(symlink-to name #$output
|
||||
(symlink-to name collection
|
||||
(if (name-is-store-entry? name)
|
||||
strip-store-file-name
|
||||
basename)))
|
||||
@@ -381,63 +323,57 @@ HOOKS lists additional hook functions to modify the profile."
|
||||
#t)
|
||||
#f)))))
|
||||
|
||||
(gexp->derivation "efi-bootloader-profile"
|
||||
(gexp->derivation "bootloader-collection"
|
||||
build
|
||||
#:local-build? #t
|
||||
#:substitutable? #f
|
||||
#:properties
|
||||
`((type . profile-hook)
|
||||
(hook . efi-bootloader-profile-hook))))
|
||||
(hook . bootloader-collection))))
|
||||
|
||||
(profile (content (packages->manifest packages))
|
||||
(name "efi-bootloader-profile")
|
||||
(hooks (cons efi-bootloader-profile-hook hooks))
|
||||
(profile (content (packages->manifest (list bootloader-package)))
|
||||
(name "bootloader-profile")
|
||||
(hooks (append (list bootloader-collection) hooks))
|
||||
(locales? #f)
|
||||
(allow-collisions? #f)
|
||||
(relative-symlinks? #f)))
|
||||
|
||||
(define* (efi-bootloader-chain final-bootloader
|
||||
(define* (efi-bootloader-chain files
|
||||
final-bootloader
|
||||
#:key
|
||||
(packages '())
|
||||
(files '())
|
||||
(hooks '())
|
||||
installer
|
||||
disk-image-installer)
|
||||
"Define a chain of bootloaders with the FINAL-BOOTLOADER, optional PACKAGES,
|
||||
and optional directories and files from the store given in the list of FILES.
|
||||
installer)
|
||||
"Define a bootloader chain with FINAL-BOOTLOADER as the final bootloader and
|
||||
certain directories and files from the store given in the list of FILES.
|
||||
|
||||
The package of the FINAL-BOOTLOADER and all PACKAGES and FILES will be placed
|
||||
in an efi-bootloader-profile, which will be passed to the INSTALLER.
|
||||
|
||||
FILES may contain file-like objects produced by procedures like plain-file,
|
||||
local-file, etc., or package contents produced with file-append.
|
||||
FILES may contain file like objects produced by functions like plain-file,
|
||||
local-file, etc., or package contents produced with file-append. They will be
|
||||
collected inside a directory collection/ inside a generated bootloader profile,
|
||||
which will be passed to the INSTALLER.
|
||||
|
||||
If a directory name in FILES ends with '/', then the directory content instead
|
||||
of the directory itself will be symlinked into the efi-bootloader-profile.
|
||||
of the directory itself will be symlinked into the collection/ directory.
|
||||
|
||||
The procedures in the HOOKS list can be used to further modify the bootloader
|
||||
profile. It is possible to pass a single function instead of a list.
|
||||
|
||||
If the INSTALLER argument is used, then this gexp procedure will be called to
|
||||
install the efi-bootloader-profile. Otherwise the installer of the
|
||||
FINAL-BOOTLOADER will be called.
|
||||
|
||||
If the DISK-IMAGE-INSTALLER is used, then this gexp procedure will be called
|
||||
to install the efi-bootloader-profile into a disk image. Otherwise the
|
||||
disk-image-installer of the FINAL-BOOTLOADER will be called."
|
||||
(bootloader
|
||||
(inherit final-bootloader)
|
||||
(name "efi-bootloader-chain")
|
||||
(package
|
||||
(efi-bootloader-profile (cons (bootloader-package final-bootloader)
|
||||
packages)
|
||||
files
|
||||
(if (list? hooks)
|
||||
hooks
|
||||
(list hooks))))
|
||||
(installer
|
||||
(or installer
|
||||
(bootloader-installer final-bootloader)))
|
||||
(disk-image-installer
|
||||
(or disk-image-installer
|
||||
(bootloader-disk-image-installer final-bootloader)))))
|
||||
If the INSTALLER argument is used, then this function will be called to install
|
||||
the bootloader. Otherwise the installer of the FINAL-BOOTLOADER will be called."
|
||||
(let* ((final-installer (or installer
|
||||
(bootloader-installer final-bootloader)))
|
||||
(profile (efi-bootloader-profile files
|
||||
(bootloader-package final-bootloader)
|
||||
(if (list? hooks)
|
||||
hooks
|
||||
(list hooks)))))
|
||||
(bootloader
|
||||
(inherit final-bootloader)
|
||||
(package profile)
|
||||
(installer
|
||||
#~(lambda (bootloader target mount-point)
|
||||
(#$final-installer bootloader target mount-point)
|
||||
(copy-recursively
|
||||
(string-append bootloader "/collection")
|
||||
(string-append mount-point target)
|
||||
#:follow-symlinks? #t
|
||||
#:log (%make-void-port "w")))))))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2017 David Craven <david@craven.ch>
|
||||
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
|
||||
;;; Copyright © 2022 Reza Alizadeh Majd <r.majd@pantherx.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -39,9 +38,6 @@ corresponding to old generations of the system."
|
||||
(define all-entries
|
||||
(append entries (bootloader-configuration-menu-entries config)))
|
||||
|
||||
(define with-fdtdir?
|
||||
(bootloader-configuration-device-tree-support? config))
|
||||
|
||||
(define (menu-entry->gexp entry)
|
||||
(let ((label (menu-entry-label entry))
|
||||
(kernel (menu-entry-linux entry))
|
||||
@@ -50,16 +46,12 @@ corresponding to old generations of the system."
|
||||
#~(format port "LABEL ~a
|
||||
MENU LABEL ~a
|
||||
KERNEL ~a
|
||||
~a
|
||||
FDTDIR ~a/lib/dtbs
|
||||
INITRD ~a
|
||||
APPEND ~a
|
||||
~%"
|
||||
#$label #$label
|
||||
#$kernel
|
||||
(if #$with-fdtdir?
|
||||
(string-append "FDTDIR " (dirname #$kernel) "/lib/dtbs")
|
||||
"")
|
||||
#$initrd
|
||||
#$kernel (dirname #$kernel) #$initrd
|
||||
(string-join (list #$@kernel-arguments)))))
|
||||
|
||||
(define builder
|
||||
|
||||
+112
-253
@@ -3,12 +3,10 @@
|
||||
;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
|
||||
;;; Copyright © 2017 Leo Famulari <leo@famulari.name>
|
||||
;;; Copyright © 2017, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
|
||||
;;; Copyright © 2019, 2020, 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
|
||||
;;; Copyright © 2019, 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||
;;; Copyright © 2019, 2020 Miguel Ángel Arruga Vivas <rosen644835@gmail.com>
|
||||
;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;; Copyright © 2020 Stefan <stefan-guix@vodafonemail.de>
|
||||
;;; Copyright © 2022 Karl Hallsby <karl@hallsby.com>
|
||||
;;; Copyright © 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -52,15 +50,11 @@
|
||||
grub-theme-color-highlight
|
||||
grub-theme-gfxmode
|
||||
|
||||
install-grub-efi-removable
|
||||
make-grub-efi-netboot-installer
|
||||
install-grub-efi-netboot
|
||||
|
||||
grub-bootloader
|
||||
grub-efi-bootloader
|
||||
grub-efi-removable-bootloader
|
||||
grub-efi32-bootloader
|
||||
grub-efi-netboot-bootloader
|
||||
grub-efi-netboot-removable-bootloader
|
||||
grub-mkrescue-bootloader
|
||||
grub-minimal-bootloader
|
||||
|
||||
@@ -354,7 +348,7 @@ code."
|
||||
((or #f (? string?))
|
||||
#~(format #f "search --file --set ~a" #$file)))))
|
||||
|
||||
(define* (make-grub-configuration grub config entries
|
||||
(define* (grub-configuration-file config entries
|
||||
#:key
|
||||
(locale #f)
|
||||
(system (%current-system))
|
||||
@@ -375,63 +369,44 @@ when booting a root file system on a Btrfs subvolume."
|
||||
(let ((label (menu-entry-label entry))
|
||||
(linux (menu-entry-linux entry))
|
||||
(device (menu-entry-device entry))
|
||||
(device-mount-point (menu-entry-device-mount-point entry))
|
||||
(multiboot-kernel (menu-entry-multiboot-kernel entry))
|
||||
(chain-loader (menu-entry-chain-loader entry)))
|
||||
(cond
|
||||
(linux
|
||||
(let ((arguments (menu-entry-linux-arguments entry))
|
||||
(linux (normalize-file linux
|
||||
device-mount-point
|
||||
store-directory-prefix))
|
||||
(initrd (normalize-file (menu-entry-initrd entry)
|
||||
device-mount-point
|
||||
store-directory-prefix)))
|
||||
;; Here DEVICE is the store and DEVICE-MOUNT-POINT is its mount point.
|
||||
;; Use the right file names for LINUX and INITRD in case
|
||||
;; DEVICE-MOUNT-POINT is not "/", meaning that the store is on a
|
||||
;; separate partition.
|
||||
(device-mount-point (menu-entry-device-mount-point entry)))
|
||||
(if linux
|
||||
(let ((arguments (menu-entry-linux-arguments entry))
|
||||
(linux (normalize-file linux
|
||||
device-mount-point
|
||||
store-directory-prefix))
|
||||
(initrd (normalize-file (menu-entry-initrd entry)
|
||||
device-mount-point
|
||||
store-directory-prefix)))
|
||||
;; Here DEVICE is the store and DEVICE-MOUNT-POINT is its mount point.
|
||||
;; Use the right file names for LINUX and INITRD in case
|
||||
;; DEVICE-MOUNT-POINT is not "/", meaning that the store is on a
|
||||
;; separate partition.
|
||||
|
||||
;; When STORE-DIRECTORY-PREFIX is defined, prepend it the linux and
|
||||
;; initrd paths, to allow booting from a Btrfs subvolume.
|
||||
#~(format port "menuentry ~s {
|
||||
;; When BTRFS-SUBVOLUME-FILE-NAME is defined, prepend it the linux and
|
||||
;; initrd paths, to allow booting from a Btrfs subvolume.
|
||||
#~(format port "menuentry ~s {
|
||||
~a
|
||||
linux ~a ~a
|
||||
initrd ~a
|
||||
}~%"
|
||||
#$label
|
||||
#$(grub-root-search device linux)
|
||||
#$linux (string-join (list #$@arguments))
|
||||
#$initrd)))
|
||||
(multiboot-kernel
|
||||
(let* ((kernel (menu-entry-multiboot-kernel entry))
|
||||
(arguments (menu-entry-multiboot-arguments entry))
|
||||
;; Choose between device names as understood by Mach's built-in
|
||||
;; IDE driver ("hdX") and those understood by rumpdisk ("wdX"
|
||||
;; in the "noide" case).
|
||||
(disk (if (member "noide" arguments) "w" "h"))
|
||||
(modules (menu-entry-multiboot-modules entry))
|
||||
(root-index 1)) ; XXX EFI will need root-index 2
|
||||
#~(format port "
|
||||
menuentry ~s {
|
||||
multiboot ~a root=part:~a:device:~ad0~a~a
|
||||
}~%"
|
||||
#$label
|
||||
#$kernel
|
||||
#$root-index
|
||||
#$disk
|
||||
(string-join (list #$@arguments) " " 'prefix)
|
||||
(string-join (map string-join '#$modules)
|
||||
"\n module " 'prefix))))
|
||||
(chain-loader
|
||||
#$label
|
||||
#$(grub-root-search device linux)
|
||||
#$linux (string-join (list #$@arguments))
|
||||
#$initrd))
|
||||
(let ((kernel (menu-entry-multiboot-kernel entry))
|
||||
(arguments (menu-entry-multiboot-arguments entry))
|
||||
(modules (menu-entry-multiboot-modules entry))
|
||||
(root-index 1)) ; XXX EFI will need root-index 2
|
||||
#~(format port "
|
||||
menuentry ~s {
|
||||
~a
|
||||
chainloader ~a
|
||||
multiboot ~a root=device:hd0s~a~a~a
|
||||
}~%"
|
||||
#$label
|
||||
#$(grub-root-search device chain-loader)
|
||||
#$chain-loader)))))
|
||||
#$kernel
|
||||
#$root-index (string-join (list #$@arguments) " " 'prefix)
|
||||
(string-join (map string-join '#$modules)
|
||||
"\n module " 'prefix))))))
|
||||
|
||||
(define (crypto-devices)
|
||||
(define (crypto-device->cryptomount dev)
|
||||
@@ -460,7 +435,9 @@ menuentry ~s {
|
||||
(define locale-config
|
||||
(let* ((entry (first all-entries))
|
||||
(device (menu-entry-device entry))
|
||||
(mount-point (menu-entry-device-mount-point entry)))
|
||||
(mount-point (menu-entry-device-mount-point entry))
|
||||
(bootloader (bootloader-configuration-bootloader config))
|
||||
(grub (bootloader-package bootloader)))
|
||||
#~(let ((locale #$(and locale
|
||||
(locale-definition-source
|
||||
(locale-name->definition locale))))
|
||||
@@ -486,6 +463,8 @@ set lang=~a~%"
|
||||
|
||||
(define keyboard-layout-config
|
||||
(let* ((layout (bootloader-configuration-keyboard-layout config))
|
||||
(grub (bootloader-package
|
||||
(bootloader-configuration-bootloader config)))
|
||||
(keymap* (and layout
|
||||
(keyboard-layout-file layout #:grub grub)))
|
||||
(entry (first all-entries))
|
||||
@@ -536,16 +515,6 @@ fi~%"))))
|
||||
#:options '(#:local-build? #t
|
||||
#:substitutable? #f)))
|
||||
|
||||
(define (grub-configuration-file config . args)
|
||||
(let* ((bootloader (bootloader-configuration-bootloader config))
|
||||
(grub (bootloader-package bootloader)))
|
||||
(apply make-grub-configuration grub config args)))
|
||||
|
||||
(define (grub-efi-configuration-file . args)
|
||||
(apply make-grub-configuration grub-efi args))
|
||||
|
||||
(define grub-cfg "/boot/grub/grub.cfg")
|
||||
|
||||
|
||||
|
||||
;;;
|
||||
@@ -639,79 +608,42 @@ fi~%"))))
|
||||
"--bootloader-id=Guix"
|
||||
"--efi-directory" target-esp)))))
|
||||
|
||||
(define install-grub-efi-removable
|
||||
#~(lambda (bootloader efi-dir mount-point)
|
||||
;; NOTE: mount-point is /mnt in guix system init /etc/config.scm /mnt/point
|
||||
;; NOTE: efi-dir comes from target list of booloader configuration
|
||||
;; There is nothing useful to do when called in the context of a disk
|
||||
;; image generation.
|
||||
(when efi-dir
|
||||
;; Install GRUB onto the EFI partition mounted at EFI-DIR, for the
|
||||
;; system whose root is mounted at MOUNT-POINT.
|
||||
(let ((grub-install (string-append bootloader "/sbin/grub-install"))
|
||||
(install-dir (string-append mount-point "/boot"))
|
||||
;; When installing Guix, it's common to mount EFI-DIR below
|
||||
;; MOUNT-POINT rather than /boot/efi on the live image.
|
||||
(target-esp (if (file-exists? (string-append mount-point efi-dir))
|
||||
(string-append mount-point efi-dir)
|
||||
efi-dir)))
|
||||
;; Tell 'grub-install' that there might be a LUKS-encrypted /boot or
|
||||
;; root partition.
|
||||
(setenv "GRUB_ENABLE_CRYPTODISK" "y")
|
||||
(invoke/quiet grub-install "--boot-directory" install-dir
|
||||
"--removable"
|
||||
;; "--no-nvram"
|
||||
"--bootloader-id=Guix"
|
||||
"--efi-directory" target-esp)))))
|
||||
|
||||
(define install-grub-efi32
|
||||
#~(lambda (bootloader efi-dir mount-point)
|
||||
;; There is nothing useful to do when called in the context of a disk
|
||||
;; image generation.
|
||||
(when efi-dir
|
||||
;; Install GRUB onto the EFI partition mounted at EFI-DIR, for the
|
||||
;; system whose root is mounted at MOUNT-POINT.
|
||||
(let ((grub-install (string-append bootloader "/sbin/grub-install"))
|
||||
(install-dir (string-append mount-point "/boot"))
|
||||
;; When installing Guix, it's common to mount EFI-DIR below
|
||||
;; MOUNT-POINT rather than /boot/efi on the live image.
|
||||
(target-esp (if (file-exists? (string-append mount-point efi-dir))
|
||||
(string-append mount-point efi-dir)
|
||||
efi-dir)))
|
||||
;; Tell 'grub-install' that there might be a LUKS-encrypted /boot or
|
||||
;; root partition.
|
||||
(setenv "GRUB_ENABLE_CRYPTODISK" "y")
|
||||
(invoke/quiet grub-install "--boot-directory" install-dir
|
||||
"--bootloader-id=Guix"
|
||||
(cond ((target-x86?) "--target=i386-efi")
|
||||
((target-arm?) "--target=arm-efi"))
|
||||
"--efi-directory" target-esp)))))
|
||||
|
||||
(define* (make-grub-efi-netboot-installer grub-efi grub-cfg subdir)
|
||||
"Make a bootloader-installer for a grub-efi-netboot bootloader, which expects
|
||||
its files in SUBDIR and its configuration file in GRUB-CFG.
|
||||
|
||||
As a grub-efi-netboot package is already pre-installed by 'grub-mknetdir', the
|
||||
installer basically copies all files from the bootloader-package (or profile)
|
||||
into the bootloader-target directory.
|
||||
|
||||
Additionally for network booting over TFTP, two relative symlinks to the store
|
||||
and to the GRUB-CFG file are necessary. Due to this a TFTP root directory must
|
||||
not be located on a FAT file-system.
|
||||
|
||||
If the bootloader-target does not support symlinks, then it is assumed to be a
|
||||
kind of EFI System Partition (ESP). In this case an intermediate configuration
|
||||
file is created with the help of GRUB-EFI to load the GRUB-CFG.
|
||||
|
||||
The installer is usable for any efi-bootloader-chain, which prepares the
|
||||
bootloader-profile in a way ready for copying.
|
||||
|
||||
The installer does not manipulate the system's 'UEFI Boot Manager'.
|
||||
|
||||
The returned installer accepts the BOOTLOADER, TARGET and MOUNT-POINT
|
||||
arguments. Its job is to copy the BOOTLOADER, which must be a pre-installed
|
||||
grub-efi-netboot package with a SUBDIR like efi/boot or efi/Guix, below the
|
||||
directory TARGET for the system whose root is mounted at MOUNT-POINT.
|
||||
(define (install-grub-efi-netboot subdir)
|
||||
"Define a grub-efi-netboot bootloader installer for installation in SUBDIR,
|
||||
which is usually efi/Guix or efi/boot."
|
||||
(let* ((system (string-split (nix-system->gnu-triplet
|
||||
(or (%current-target-system)
|
||||
(%current-system)))
|
||||
#\-))
|
||||
(arch (first system))
|
||||
(boot-efi-link (match system
|
||||
;; These are the supportend systems and the names
|
||||
;; defined by the UEFI standard for removable media.
|
||||
(("i686" _ ...) "/bootia32.efi")
|
||||
(("x86_64" _ ...) "/bootx64.efi")
|
||||
(("arm" _ ...) "/bootarm.efi")
|
||||
(("aarch64" _ ...) "/bootaa64.efi")
|
||||
(("riscv" _ ...) "/bootriscv32.efi")
|
||||
(("riscv64" _ ...) "/bootriscv64.efi")
|
||||
;; Other systems are not supported, although defined.
|
||||
;; (("riscv128" _ ...) "/bootriscv128.efi")
|
||||
;; (("ia64" _ ...) "/bootia64.efi")
|
||||
((_ ...) #f)))
|
||||
(core-efi (string-append
|
||||
;; This is the arch dependent file name of GRUB, e.g.
|
||||
;; i368-efi/core.efi or arm64-efi/core.efi.
|
||||
(match arch
|
||||
("i686" "i386")
|
||||
("aarch64" "arm64")
|
||||
("riscv" "riscv32")
|
||||
(_ arch))
|
||||
"-efi/core.efi")))
|
||||
(with-imported-modules
|
||||
'((guix build union))
|
||||
#~(lambda (bootloader target mount-point)
|
||||
"Install the BOOTLOADER, which must be the package grub, as e.g.
|
||||
bootx64.efi or bootaa64.efi into SUBDIR, which is usually efi/Guix or efi/boot,
|
||||
below the directory TARGET for the system whose root is mounted at MOUNT-POINT.
|
||||
|
||||
MOUNT-POINT is the last argument in 'guix system init /etc/config.scm mnt/point'
|
||||
or '/' for other 'guix system' commands.
|
||||
@@ -721,19 +653,17 @@ bootloader-configuration in:
|
||||
|
||||
(operating-system
|
||||
(bootloader (bootloader-configuration
|
||||
(targets '(\"/boot/efi\"))
|
||||
(targets '(\"/boot\"))
|
||||
…))
|
||||
…)
|
||||
|
||||
TARGET is required to be an absolute directory name, usually mounted via NFS,
|
||||
and finally needs to be provided by a TFTP server as
|
||||
the TFTP root directory.
|
||||
and finally needs to be provided by a TFTP server as the TFTP root directory.
|
||||
|
||||
Usually the installer will be used to prepare network booting over TFTP. Then
|
||||
GRUB will load tftp://server/SUBDIR/grub.cfg and this file will instruct it to
|
||||
load more files from the store like tftp://server/gnu/store/…-linux…/Image.
|
||||
|
||||
To make this possible two symlinks are created. The first symlink points
|
||||
To make this possible two symlinks will be created. The first symlink points
|
||||
relatively form MOUNT-POINT/TARGET/SUBDIR/grub.cfg to
|
||||
MOUNT-POINT/boot/grub/grub.cfg, and the second symlink points relatively from
|
||||
MOUNT-POINT/TARGET/%store-prefix to MOUNT-POINT/%store-prefix.
|
||||
@@ -743,80 +673,34 @@ paths on the TFTP server side are unknown.
|
||||
|
||||
It is also important to note that both symlinks will point outside the TFTP root
|
||||
directory and that the TARGET/%store-prefix symlink makes the whole store
|
||||
accessible via TFTP. Possibly the TFTP server must be configured to allow
|
||||
accesses outside its TFTP root directory. This all may need to be considered
|
||||
for security aspects. It is advised to disable any TFTP write access!
|
||||
|
||||
The installer can also be used to prepare booting from local storage, if the
|
||||
underlying file-system, like FAT on an EFI System Partition (ESP), does not
|
||||
support symlinks. In this case the MOUNT-POINT/TARGET/SUBDIR/grub.cfg will be
|
||||
created with the help of GRUB-EFI to load the /boot/grub/grub.cfg file. A
|
||||
symlink to the store is not needed in this case."
|
||||
(with-imported-modules '((guix build union))
|
||||
#~(lambda (bootloader target mount-point)
|
||||
;; In context of a disk image creation TARGET will be #f and an
|
||||
;; installer is expected to do necessary installations on MOUNT-POINT,
|
||||
;; which will become the root file system. If TARGET is #f, this
|
||||
;; installer has nothing to do, as it only cares about the EFI System
|
||||
;; Partition (ESP).
|
||||
(when target
|
||||
(use-modules ((guix build union) #:select (symlink-relative))
|
||||
(ice-9 popen)
|
||||
(ice-9 rdelim))
|
||||
(let* ((mount-point/target (string-append mount-point target "/"))
|
||||
;; When installing Guix, it is common to mount TARGET below
|
||||
;; MOUNT-POINT rather than the root directory.
|
||||
(bootloader-target (if (file-exists? mount-point/target)
|
||||
mount-point/target
|
||||
target))
|
||||
(store (string-append mount-point (%store-prefix)))
|
||||
(store-link (string-append bootloader-target (%store-prefix)))
|
||||
(grub-cfg (string-append mount-point #$grub-cfg))
|
||||
(grub-cfg-link (string-append bootloader-target
|
||||
#$subdir "/"
|
||||
(basename grub-cfg))))
|
||||
;; Copy the bootloader into the bootloader-target directory.
|
||||
;; Should we beforehand recursively delete any existing file?
|
||||
(copy-recursively bootloader bootloader-target
|
||||
#:follow-symlinks? #t
|
||||
#:log (%make-void-port "w"))
|
||||
;; For TFTP we need to install additional relative symlinks.
|
||||
;; If we install on an EFI System Partition (ESP) or some other FAT
|
||||
;; file-system, then symlinks cannot be created and are not needed.
|
||||
;; Therefore we ignore exceptions when trying.
|
||||
;; Prepare the symlink to the grub.cfg.
|
||||
(mkdir-p (dirname grub-cfg-link))
|
||||
(false-if-exception (delete-file grub-cfg-link))
|
||||
(if (unspecified?
|
||||
(false-if-exception (symlink-relative grub-cfg grub-cfg-link)))
|
||||
;; Symlinks are supported.
|
||||
(begin
|
||||
;; Prepare the symlink to the store.
|
||||
(mkdir-p (dirname store-link))
|
||||
(false-if-exception (delete-file store-link))
|
||||
(symlink-relative store store-link))
|
||||
;; Creating symlinks does not seem to be supported. Probably
|
||||
;; an ESP is used. Add a script to search and load the actual
|
||||
;; grub.cfg.
|
||||
(let* ((probe #$(file-append grub-efi "/sbin/grub-probe"))
|
||||
(port (open-pipe* OPEN_READ probe "--target=fs_uuid"
|
||||
grub-cfg))
|
||||
(search-root
|
||||
(match (read-line port)
|
||||
((? eof-object?)
|
||||
;; There is no UUID available. As a fallback search
|
||||
;; everywhere for the grub.cfg.
|
||||
(string-append "search --file --set " #$grub-cfg))
|
||||
(fs-uuid
|
||||
;; The UUID to load the grub.cfg from is known.
|
||||
(string-append "search --fs-uuid --set " fs-uuid))))
|
||||
(load-grub-cfg (string-append "configfile " #$grub-cfg)))
|
||||
(close-pipe port)
|
||||
(with-output-to-file grub-cfg-link
|
||||
(lambda ()
|
||||
(display (string-join (list search-root
|
||||
load-grub-cfg)
|
||||
"\n")))))))))))
|
||||
accessible via TFTP. Possibly the TFTP server must be configured
|
||||
to allow accesses outside its TFTP root directory. This may need to be
|
||||
considered for security aspects."
|
||||
(use-modules ((guix build union) #:select (symlink-relative)))
|
||||
(let* ((net-dir (string-append mount-point target "/"))
|
||||
(sub-dir (string-append net-dir #$subdir "/"))
|
||||
(store (string-append mount-point (%store-prefix)))
|
||||
(store-link (string-append net-dir (%store-prefix)))
|
||||
(grub-cfg (string-append mount-point "/boot/grub/grub.cfg"))
|
||||
(grub-cfg-link (string-append sub-dir (basename grub-cfg)))
|
||||
(boot-efi-link (string-append sub-dir #$boot-efi-link)))
|
||||
;; Prepare the symlink to the store.
|
||||
(mkdir-p (dirname store-link))
|
||||
(false-if-exception (delete-file store-link))
|
||||
(symlink-relative store store-link)
|
||||
;; Prepare the symlink to the grub.cfg, which points into the store.
|
||||
(mkdir-p (dirname grub-cfg-link))
|
||||
(false-if-exception (delete-file grub-cfg-link))
|
||||
(symlink-relative grub-cfg grub-cfg-link)
|
||||
;; Install GRUB, which refers to the grub.cfg, with support for
|
||||
;; encrypted partitions,
|
||||
(setenv "GRUB_ENABLE_CRYPTODISK" "y")
|
||||
(invoke/quiet (string-append bootloader "/bin/grub-mknetdir")
|
||||
(string-append "--net-directory=" net-dir)
|
||||
(string-append "--subdir=" #$subdir))
|
||||
;; Prepare the bootloader symlink, which points to core.efi of GRUB.
|
||||
(false-if-exception (delete-file boot-efi-link))
|
||||
(symlink #$core-efi boot-efi-link))))))
|
||||
|
||||
|
||||
|
||||
@@ -834,7 +718,7 @@ symlink to the store is not needed in this case."
|
||||
(package grub)
|
||||
(installer install-grub)
|
||||
(disk-image-installer install-grub-disk-image)
|
||||
(configuration-file grub-cfg)
|
||||
(configuration-file "/boot/grub/grub.cfg")
|
||||
(configuration-file-generator grub-configuration-file)))
|
||||
|
||||
(define grub-minimal-bootloader
|
||||
@@ -844,42 +728,17 @@ symlink to the store is not needed in this case."
|
||||
|
||||
(define grub-efi-bootloader
|
||||
(bootloader
|
||||
(name 'grub-efi)
|
||||
(package grub-efi)
|
||||
(inherit grub-bootloader)
|
||||
(installer install-grub-efi)
|
||||
(disk-image-installer #f)
|
||||
(configuration-file grub-cfg)
|
||||
(configuration-file-generator grub-configuration-file)))
|
||||
|
||||
(define grub-efi-removable-bootloader
|
||||
(bootloader
|
||||
(inherit grub-efi-bootloader)
|
||||
(name 'grub-efi-removable-bootloader)
|
||||
(installer install-grub-efi-removable)))
|
||||
|
||||
(define grub-efi32-bootloader
|
||||
(bootloader
|
||||
(inherit grub-efi-bootloader)
|
||||
(installer install-grub-efi32)
|
||||
(name 'grub-efi32)
|
||||
(package grub-efi32)))
|
||||
|
||||
(define (make-grub-efi-netboot-bootloader name subdir)
|
||||
(bootloader
|
||||
(name name)
|
||||
(package (make-grub-efi-netboot (symbol->string name) subdir))
|
||||
(installer (make-grub-efi-netboot-installer grub-efi grub-cfg subdir))
|
||||
(disk-image-installer #f)
|
||||
(configuration-file grub-cfg)
|
||||
(configuration-file-generator grub-efi-configuration-file)))
|
||||
(name 'grub-efi)
|
||||
(package grub-efi)))
|
||||
|
||||
(define grub-efi-netboot-bootloader
|
||||
(make-grub-efi-netboot-bootloader 'grub-efi-netboot-bootloader
|
||||
"efi/Guix"))
|
||||
|
||||
(define grub-efi-netboot-removable-bootloader
|
||||
(make-grub-efi-netboot-bootloader 'grub-efi-netboot-removable-bootloader
|
||||
"efi/boot"))
|
||||
(bootloader
|
||||
(inherit grub-efi-bootloader)
|
||||
(name 'grub-efi-netboot-bootloader)
|
||||
(installer (install-grub-efi-netboot "efi/Guix"))))
|
||||
|
||||
(define grub-mkrescue-bootloader
|
||||
(bootloader
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
;;; Copyright © 2017, 2019 Mathieu Othacehe <m.othacehe@gmail.com>
|
||||
;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
|
||||
;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||
;;; Copyright © 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -44,8 +42,6 @@
|
||||
u-boot-puma-rk3399-bootloader
|
||||
u-boot-rock64-rk3328-bootloader
|
||||
u-boot-rockpro64-rk3399-bootloader
|
||||
u-boot-sifive-unmatched-bootloader
|
||||
u-boot-ts7970-q-2g-1000mhz-c-bootloader
|
||||
u-boot-wandboard-bootloader))
|
||||
|
||||
(define install-u-boot
|
||||
@@ -131,21 +127,6 @@
|
||||
|
||||
(define install-pinebook-pro-rk3399-u-boot install-rockpro64-rk3399-u-boot)
|
||||
|
||||
(define install-u-boot-ts7970-q-2g-1000mhz-c-u-boot
|
||||
#~(lambda (bootloader device mount-point)
|
||||
(let ((u-boot.imx (string-append bootloader "/libexec/u-boot.imx"))
|
||||
(install-dir (string-append mount-point "/boot")))
|
||||
(install-file u-boot.imx install-dir))))
|
||||
|
||||
(define install-sifive-unmatched-u-boot
|
||||
#~(lambda (bootloader root-index image)
|
||||
(let ((spl (string-append bootloader "/libexec/spl/u-boot-spl.bin"))
|
||||
(u-boot (string-append bootloader "/libexec/u-boot.itb")))
|
||||
(write-file-on-device spl (stat:size (stat spl))
|
||||
image (* 34 512))
|
||||
(write-file-on-device u-boot (stat:size (stat u-boot))
|
||||
image (* 2082 512)))))
|
||||
|
||||
|
||||
|
||||
;;;
|
||||
@@ -274,19 +255,3 @@
|
||||
(inherit u-boot-bootloader)
|
||||
(package u-boot-pinebook-pro-rk3399)
|
||||
(disk-image-installer install-pinebook-pro-rk3399-u-boot)))
|
||||
|
||||
(define u-boot-ts7970-q-2g-1000mhz-c-bootloader
|
||||
;; This bootloader doesn't really need to be installed, as it is read from
|
||||
;; an SPI memory chip, not the SD card. It is copied to /boot/u-boot.imx
|
||||
;; for convenience and should be manually flashed at the U-Boot prompt.
|
||||
(bootloader
|
||||
(inherit u-boot-bootloader)
|
||||
(package u-boot-ts7970-q-2g-1000mhz-c)
|
||||
(installer install-u-boot-ts7970-q-2g-1000mhz-c-u-boot)
|
||||
(disk-image-installer #f)))
|
||||
|
||||
(define u-boot-sifive-unmatched-bootloader
|
||||
(bootloader
|
||||
(inherit u-boot-bootloader)
|
||||
(package u-boot-sifive-unmatched)
|
||||
(disk-image-installer install-sifive-unmatched-u-boot)))
|
||||
|
||||
@@ -363,14 +363,9 @@ second element is the name it should appear at, such as:
|
||||
"Tell the kernel to look for device firmware under DIRECTORY. This
|
||||
mechanism bypasses udev: it allows Linux to handle firmware loading directly
|
||||
by itself, without having to resort to a \"user helper\"."
|
||||
|
||||
;; If the kernel was built without firmware loading support, this file
|
||||
;; does not exist. Do nothing in that case.
|
||||
(let ((firmware-path "/sys/module/firmware_class/parameters/path"))
|
||||
(when (file-exists? firmware-path)
|
||||
(call-with-output-file firmware-path
|
||||
(lambda (port)
|
||||
(display directory port))))))
|
||||
(call-with-output-file "/sys/module/firmware_class/parameters/path"
|
||||
(lambda (port)
|
||||
(display directory port))))
|
||||
|
||||
(define (activate-ptrace-attach)
|
||||
"Allow users to PTRACE_ATTACH their own processes.
|
||||
|
||||
+13
-24
@@ -1,8 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
|
||||
;;; Copyright © 2019 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
|
||||
;;; Copyright © 2022 Timothy Sample <samplet@ngyro.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -56,12 +54,8 @@
|
||||
;;; EFI bootloader.
|
||||
;;;
|
||||
|
||||
(define* (install-efi grub grub-config esp #:key targets)
|
||||
"Write a self-contained GRUB EFI loader to the mounted ESP using
|
||||
GRUB-CONFIG.
|
||||
|
||||
If TARGETS is set, use its car as the GRUB image format and its cdr as
|
||||
the output filename. Otherwise, use defaults for the host platform."
|
||||
(define (install-efi grub grub-config esp)
|
||||
"Write a self-contained GRUB EFI loader to the mounted ESP using GRUB-CONFIG."
|
||||
(let* ((system %host-type)
|
||||
;; Hard code the output location to a well-known path recognized by
|
||||
;; compliant firmware. See "3.5.1.1 Removable Media Boot Behaviour":
|
||||
@@ -69,15 +63,14 @@ the output filename. Otherwise, use defaults for the host platform."
|
||||
(grub-mkstandalone (string-append grub "/bin/grub-mkstandalone"))
|
||||
(efi-directory (string-append esp "/EFI/BOOT"))
|
||||
;; Map grub target names to boot file names.
|
||||
(efi-targets (or targets
|
||||
(cond ((string-prefix? "x86_64" system)
|
||||
'("x86_64-efi" . "BOOTX64.EFI"))
|
||||
((string-prefix? "i686" system)
|
||||
'("i386-efi" . "BOOTIA32.EFI"))
|
||||
((string-prefix? "armhf" system)
|
||||
'("arm-efi" . "BOOTARM.EFI"))
|
||||
((string-prefix? "aarch64" system)
|
||||
'("arm64-efi" . "BOOTAA64.EFI"))))))
|
||||
(efi-targets (cond ((string-prefix? "x86_64" system)
|
||||
'("x86_64-efi" . "BOOTX64.EFI"))
|
||||
((string-prefix? "i686" system)
|
||||
'("i386-efi" . "BOOTIA32.EFI"))
|
||||
((string-prefix? "armhf" system)
|
||||
'("arm-efi" . "BOOTARM.EFI"))
|
||||
((string-prefix? "aarch64" system)
|
||||
'("arm64-efi" . "BOOTAA64.EFI")))))
|
||||
;; grub-mkstandalone requires a TMPDIR to prepare the firmware image.
|
||||
(setenv "TMPDIR" esp)
|
||||
|
||||
@@ -88,12 +81,9 @@ the output filename. Otherwise, use defaults for the host platform."
|
||||
;; Graft the configuration file onto the image.
|
||||
(string-append "boot/grub/grub.cfg=" grub-config))))
|
||||
|
||||
(define* (install-efi-loader grub-efi esp #:key targets)
|
||||
(define (install-efi-loader grub-efi esp)
|
||||
"Install in ESP directory the given GRUB-EFI bootloader. Configure it to
|
||||
load the Grub bootloader located in the 'Guix_image' root partition.
|
||||
|
||||
If TARGETS is set, use its car as the GRUB image format and its cdr as
|
||||
the output filename. Otherwise, use defaults for the host platform."
|
||||
load the Grub bootloader located in the 'Guix_image' root partition."
|
||||
(let ((grub-config "grub.cfg"))
|
||||
(call-with-output-file grub-config
|
||||
(lambda (port)
|
||||
@@ -107,6 +97,5 @@ the output filename. Otherwise, use defaults for the host platform."
|
||||
insmod part_gpt~@
|
||||
search --set=root --label Guix_image~@
|
||||
configfile /boot/grub/grub.cfg~%")))
|
||||
(install-efi grub-efi grub-config esp #:targets targets)
|
||||
(install-efi grub-efi grub-config esp)
|
||||
(delete-file grub-config)))
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2020, 2021 Marius Bakke <marius@gnu.org>
|
||||
;;; Copyright © 2022 Nicolas Graves <ngraves@ngraves.fr>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -20,9 +19,10 @@
|
||||
(define-module (gnu build chromium-extension)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix packages)
|
||||
#:use-module (gnu packages chromium)
|
||||
#:use-module (gnu packages gnupg)
|
||||
#:use-module (gnu packages tls)
|
||||
#:use-module (gnu packages node-xyz)
|
||||
#:use-module (gnu packages xorg)
|
||||
#:use-module (guix build-system trivial)
|
||||
#:export (make-chromium-extension))
|
||||
|
||||
@@ -69,14 +69,24 @@ in PACKAGE-OUTPUT of PACKAGE. The extension will be signed with SIGNING-KEY."
|
||||
(string-append name "-" version ".crx")
|
||||
(with-imported-modules '((guix build utils))
|
||||
#~(begin
|
||||
;; This is not great. We pull Xorg and Chromium just to Zip and
|
||||
;; sign an extension. This should be implemented with something
|
||||
;; lighter. (TODO: where is the CRXv3 documentation..?)
|
||||
(use-modules (guix build utils))
|
||||
(let ((crx3 #+(file-append node-crx3 "/bin/crx3"))
|
||||
(let ((chromium #$(file-append ungoogled-chromium "/bin/chromium"))
|
||||
(xvfb #$(file-append xorg-server "/bin/Xvfb"))
|
||||
(packdir (string-append (getcwd) "/extension")))
|
||||
(mkdir packdir)
|
||||
(copy-recursively (ungexp package package-output) packdir
|
||||
;; Ensure consistent file modification times.
|
||||
#:keep-mtime? #t)
|
||||
(invoke crx3 "--keyPath" #$signing-key packdir)
|
||||
(system (string-append xvfb " :1 &"))
|
||||
(setenv "DISPLAY" ":1")
|
||||
(sleep 2) ;give Xorg some time to initialize...
|
||||
(invoke chromium
|
||||
"--user-data-dir=chromium-profile"
|
||||
(string-append "--pack-extension=" packdir)
|
||||
(string-append "--pack-extension-key=" #$signing-key))
|
||||
(copy-file (string-append packdir ".crx") #$output))))
|
||||
#:local-build? #t))
|
||||
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2021, 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;;
|
||||
;;; This module contains procedures to interact with D-Bus via the 'dbus-send'
|
||||
;;; command line utility. Before using any public procedure
|
||||
;;;
|
||||
;;; Code:
|
||||
|
||||
(define-module (gnu build dbus-service)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-19)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:autoload (d-bus protocol connections) (d-bus-conn?
|
||||
d-bus-conn-flush
|
||||
d-bus-connect
|
||||
d-bus-disconnect
|
||||
d-bus-session-bus-address
|
||||
d-bus-system-bus-address)
|
||||
#:autoload (d-bus protocol messages) (MESSAGE_TYPE_METHOD_CALL
|
||||
d-bus-headers-ref
|
||||
d-bus-message-body
|
||||
d-bus-message-headers
|
||||
d-bus-read-message
|
||||
d-bus-write-message
|
||||
header-PATH
|
||||
header-DESTINATION
|
||||
header-INTERFACE
|
||||
header-MEMBER
|
||||
header-SIGNATURE
|
||||
make-d-bus-message)
|
||||
#:export (%dbus-query-timeout
|
||||
|
||||
initialize-dbus-connection!
|
||||
%current-dbus-connection
|
||||
send-dbus
|
||||
call-dbus-method
|
||||
|
||||
dbus-available-services
|
||||
dbus-service-available?
|
||||
|
||||
with-retries))
|
||||
|
||||
(define %dbus-query-timeout 2) ;in seconds
|
||||
|
||||
;;; Use Fibers' sleep to enable cooperative scheduling in Shepherd >= 0.9.0,
|
||||
;;; which is required at least for the Jami service.
|
||||
(define sleep*
|
||||
(lambda () ;delay execution
|
||||
(if (resolve-module '(fibers) #f #:ensure #f)
|
||||
(module-ref (resolve-interface '(fibers)) 'sleep)
|
||||
(begin
|
||||
(format #t "Fibers not available -- blocking 'sleep' in use~%")
|
||||
sleep))))
|
||||
|
||||
;;;
|
||||
;;; Utilities.
|
||||
;;;
|
||||
|
||||
(define-syntax-rule (with-retries n delay body ...)
|
||||
"Retry the code in BODY up to N times until it doesn't raise an exception nor
|
||||
return #f, else raise an error. A delay of DELAY seconds is inserted before
|
||||
each retry."
|
||||
(let loop ((attempts 0))
|
||||
(catch #t
|
||||
(lambda ()
|
||||
(let ((result (begin body ...)))
|
||||
(if (not result)
|
||||
(error "failed attempt" attempts)
|
||||
result)))
|
||||
(lambda args
|
||||
(if (< attempts n)
|
||||
(begin
|
||||
((sleep*) delay) ;else wait and retry
|
||||
(loop (+ 1 attempts)))
|
||||
(error "maximum number of retry attempts reached"
|
||||
body ... args))))))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Low level wrappers above AC/D-Bus.
|
||||
;;;
|
||||
|
||||
;; The active D-Bus connection (a parameter) used by the other procedures.
|
||||
(define %current-dbus-connection (make-parameter #f))
|
||||
|
||||
(define* (initialize-dbus-connection!
|
||||
#:key (address (or (d-bus-session-bus-address)
|
||||
(d-bus-system-bus-address))))
|
||||
"Initialize the D-Bus connection. ADDRESS should be the address of the D-Bus
|
||||
session, e.g. \"unix:path=/var/run/dbus/system_bus_socket\", the default value
|
||||
if ADDRESS is not provided and DBUS_SESSION_BUS_ADDRESS is not set. Return
|
||||
the initialized D-Bus connection."
|
||||
;; Clear current correction if already active.
|
||||
(when (d-bus-conn? (%current-dbus-connection))
|
||||
(d-bus-disconnect (%current-dbus-connection)))
|
||||
|
||||
(let ((connection (d-bus-connect address)))
|
||||
(%current-dbus-connection connection) ;update connection parameter
|
||||
(call-dbus-method "Hello")) ;initial handshake
|
||||
|
||||
(%current-dbus-connection))
|
||||
|
||||
(define* (send-dbus message #:key
|
||||
(connection (%current-dbus-connection))
|
||||
timeout)
|
||||
"Send a D-Bus MESSAGE to CONNECTION and return the body of its reply. Up to
|
||||
READ-RETRIES replies are read until a matching reply is found, else an error
|
||||
is raised. MESSAGE is to be constructed with `make-d-bus-message'. When the
|
||||
body contains a single element, it is returned directly, else the body
|
||||
elements are returned as a list. TIMEOUT is a timeout value in seconds."
|
||||
(let ((serial (d-bus-write-message connection message))
|
||||
(start-time (current-time time-monotonic))
|
||||
(timeout* (or timeout %dbus-query-timeout)))
|
||||
(d-bus-conn-flush connection)
|
||||
(let retry ()
|
||||
(when (> (time-second (time-difference (current-time time-monotonic)
|
||||
start-time))
|
||||
timeout*)
|
||||
(error 'dbus "fail to get reply in timeout" timeout*))
|
||||
(let* ((reply (d-bus-read-message connection))
|
||||
(reply-headers (d-bus-message-headers reply))
|
||||
(reply-serial (d-bus-headers-ref reply-headers 'REPLY_SERIAL))
|
||||
(error-name (d-bus-headers-ref reply-headers 'ERROR_NAME))
|
||||
(body (d-bus-message-body reply)))
|
||||
;; Validate the reply matches the message.
|
||||
(when error-name
|
||||
(error 'dbus "method failed with error" error-name body))
|
||||
;; Some replies do not include a serial header, such as the for the
|
||||
;; org.freedesktop.DBus NameAcquired one.
|
||||
(if (and reply-serial (= serial reply-serial))
|
||||
(match body
|
||||
((x x* ..1) ;contains 2 ore more elements
|
||||
body)
|
||||
((x)
|
||||
x) ;single element; return it directly
|
||||
(#f #f))
|
||||
(retry))))))
|
||||
|
||||
(define (argument->signature-type argument)
|
||||
"Infer the D-Bus signature type from ARGUMENT."
|
||||
;; XXX: avoid ..1 when using vectors due to a bug (?) in (ice-9 match).
|
||||
(match argument
|
||||
((? boolean?) "b")
|
||||
((? string?) "s")
|
||||
(#((? string?) (? string?) ...) "as")
|
||||
(#(((? string?) . (? string?))
|
||||
((? string?) . (? string?)) ...) "a{ss}")
|
||||
(_ (error 'dbus "no rule to infer type from argument" argument))))
|
||||
|
||||
(define* (call-dbus-method method
|
||||
#:key
|
||||
(path "/org/freedesktop/DBus")
|
||||
(destination "org.freedesktop.DBus")
|
||||
(interface "org.freedesktop.DBus")
|
||||
(connection (%current-dbus-connection))
|
||||
arguments
|
||||
timeout)
|
||||
"Call the D-Bus method specified by METHOD, PATH, DESTINATION and INTERFACE.
|
||||
The currently active D-Bus CONNECTION is used unless explicitly provided.
|
||||
Method arguments may be provided via ARGUMENTS sent as the message body.
|
||||
TIMEOUT limit the maximum time to allow for the reply. Return the body of the
|
||||
reply."
|
||||
(let ((message (make-d-bus-message
|
||||
MESSAGE_TYPE_METHOD_CALL 0 #f '()
|
||||
`#(,(header-PATH path)
|
||||
,(header-DESTINATION destination)
|
||||
,(header-INTERFACE interface)
|
||||
,(header-MEMBER method)
|
||||
,@(if arguments
|
||||
(list (header-SIGNATURE
|
||||
(string-join
|
||||
(map argument->signature-type arguments)
|
||||
"")))
|
||||
'()))
|
||||
arguments)))
|
||||
(send-dbus message #:connection connection #:timeout timeout)))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Higher-level, D-Bus procedures.
|
||||
;;;
|
||||
|
||||
(define (dbus-available-services)
|
||||
"Return the list of available (acquired) D-Bus services."
|
||||
(let ((names (vector->list (call-dbus-method "ListNames"))))
|
||||
;; Remove entries such as ":1.7".
|
||||
(remove (cut string-prefix? ":" <>) names)))
|
||||
|
||||
(define (dbus-service-available? service)
|
||||
"Predicate to check for the D-Bus SERVICE availability."
|
||||
(member service (dbus-available-services)))
|
||||
|
||||
;; Local Variables:
|
||||
;; eval: (put 'with-retries 'scheme-indent-function 2)
|
||||
;; End:
|
||||
+47
-125
@@ -1,12 +1,11 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2014-2018, 2020-2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2016, 2017 David Craven <david@craven.ch>
|
||||
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
|
||||
;;; Copyright © 2019 Guillaume Le Vaillant <glv@posteo.net>
|
||||
;;; Copyright © 2019–2021 Tobias Geerinckx-Rice <me@tobias.gr>
|
||||
;;; Copyright © 2019 David C. Trudgian <dave@trudgian.net>
|
||||
;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;; Copyright © 2022 Oleg Pykhalov <go.wigust@gmail.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -53,11 +52,8 @@
|
||||
read-partition-uuid
|
||||
read-luks-partition-uuid
|
||||
|
||||
cleanly-unmounted-ext2?
|
||||
|
||||
bind-mount
|
||||
|
||||
system*/tty
|
||||
mount-flags->bit-mask
|
||||
check-file-system
|
||||
mount-file-system
|
||||
@@ -71,45 +67,6 @@
|
||||
;;;
|
||||
;;; Code:
|
||||
|
||||
(define (system*/console program . args)
|
||||
"Run PROGRAM with ARGS in a tty on top of /dev/console. The return value is
|
||||
as for 'system*'."
|
||||
(match (primitive-fork)
|
||||
(0
|
||||
(dynamic-wind
|
||||
(const #t)
|
||||
(lambda ()
|
||||
(login-tty (open-fdes "/dev/console" O_RDWR))
|
||||
(apply execlp program program args))
|
||||
(lambda ()
|
||||
(primitive-_exit 127))))
|
||||
(pid
|
||||
(cdr (waitpid pid)))))
|
||||
|
||||
(define (system*/tty program . args)
|
||||
"Run PROGRAM with ARGS, creating a tty if its standard input isn't one.
|
||||
The return value is as for 'system*'.
|
||||
|
||||
This is necessary for commands such as 'cryptsetup open' or 'fsck' that may
|
||||
need to interact with the user but might be invoked from shepherd, where
|
||||
standard input is /dev/null."
|
||||
(apply (if (isatty? (current-input-port))
|
||||
system*
|
||||
system*/console)
|
||||
program args))
|
||||
|
||||
(define (call-with-input-file file proc)
|
||||
"Like 'call-with-input-file', but pass O_CLOEXEC."
|
||||
(let ((port #f))
|
||||
(dynamic-wind
|
||||
(lambda ()
|
||||
(set! port (open file (logior O_RDONLY O_CLOEXEC))))
|
||||
(lambda ()
|
||||
(proc port))
|
||||
(lambda ()
|
||||
(close-port port)
|
||||
(set! port #f)))))
|
||||
|
||||
(define (bind-mount source target)
|
||||
"Bind-mount SOURCE at TARGET."
|
||||
(mount source target "" MS_BIND))
|
||||
@@ -208,23 +165,6 @@ NUL terminator, return the size of the bytevector."
|
||||
if DEVICE does not contain an ext2 file system."
|
||||
(read-superblock device 1024 264 ext2-superblock?))
|
||||
|
||||
(define (ext2-superblock-cleanly-unmounted? sblock)
|
||||
"Return true if SBLOCK denotes a file system that was cleanly unmounted,
|
||||
false otherwise."
|
||||
(define EXT2_VALID_FS 1) ;cleanly unmounted
|
||||
(define EXT2_ERROR_FS 2) ;errors detected
|
||||
|
||||
(define EXT3_FEATURE_INCOMPAT_RECOVER #x0004) ;journal needs recovery
|
||||
|
||||
(let ((state (bytevector-u16-ref sblock 58 %ext2-endianness)))
|
||||
(cond ((= state EXT2_VALID_FS)
|
||||
(let ((incompatible-features
|
||||
(bytevector-u32-ref sblock 96 %ext2-endianness)))
|
||||
(zero? (logand incompatible-features
|
||||
EXT3_FEATURE_INCOMPAT_RECOVER))))
|
||||
((= state EXT2_ERROR_FS) #f)
|
||||
(else (error "invalid ext2 superblock state" state)))))
|
||||
|
||||
(define (ext2-superblock-uuid sblock)
|
||||
"Return the UUID of ext2 superblock SBLOCK as a 16-byte bytevector."
|
||||
(sub-bytevector sblock 104 16))
|
||||
@@ -240,23 +180,18 @@ true, check the file system even if it's marked as clean. If REPAIR is false,
|
||||
do not write to the file system to fix errors. If it's #t, fix all
|
||||
errors. Otherwise, fix only those considered safe to repair automatically."
|
||||
(match (status:exit-val
|
||||
(apply system*/tty "e2fsck" "-v" "-C" "0"
|
||||
`(,@(if force? '("-f") '())
|
||||
,@(match repair
|
||||
(#f '("-n"))
|
||||
(#t '("-y"))
|
||||
(_ '("-p")))
|
||||
,device)))
|
||||
(apply system* `("e2fsck" "-v" "-C" "0"
|
||||
,@(if force? '("-f") '())
|
||||
,@(match repair
|
||||
(#f '("-n"))
|
||||
(#t '("-y"))
|
||||
(_ '("-p")))
|
||||
,device)))
|
||||
(0 'pass)
|
||||
(1 'errors-corrected)
|
||||
(2 'reboot-required)
|
||||
(_ 'fatal-error)))
|
||||
|
||||
(define (cleanly-unmounted-ext2? device) ;convenience procedure
|
||||
"Return true if DEVICE is an ext2 file system and if it was cleanly
|
||||
unmounted."
|
||||
(ext2-superblock-cleanly-unmounted? (read-ext2-superblock device)))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Linux swap.
|
||||
@@ -377,14 +312,14 @@ errors. Otherwise, fix only those considered safe to repair automatically."
|
||||
(status
|
||||
;; A number, or #f on abnormal termination (e.g., assertion failure).
|
||||
(status:exit-val
|
||||
(apply system*/tty "bcachefs" "fsck" "-v"
|
||||
`(,@(if force? '("-f") '())
|
||||
,@(match repair
|
||||
(#f '("-n"))
|
||||
(#t '("-y"))
|
||||
(_ '("-p")))
|
||||
;; Make each multi-device member a separate argument.
|
||||
,@(string-split device #\:))))))
|
||||
(apply system* `("bcachefs" "fsck" "-v"
|
||||
,@(if force? '("-f") '())
|
||||
,@(match repair
|
||||
(#f '("-n"))
|
||||
(#t '("-y"))
|
||||
(_ '("-p")))
|
||||
;; Make each multi-device member a separate argument.
|
||||
,@(string-split device #\:))))))
|
||||
(match (and=> status (cut logand <> (lognot ignored-bits)))
|
||||
(0 'pass)
|
||||
(1 'errors-corrected)
|
||||
@@ -429,17 +364,17 @@ false, do not write to DEVICE. If it's #t, fix any errors found. Otherwise,
|
||||
fix only those considered safe to repair automatically."
|
||||
(if force?
|
||||
(match (status:exit-val
|
||||
(apply system*/tty "btrfs" "check" "--progress"
|
||||
;; Btrfs's ‘--force’ is not relevant to us here.
|
||||
`(,@(match repair
|
||||
;; Upstream considers ALL repairs dangerous
|
||||
;; and will warn the user at run time.
|
||||
(#t '("--repair"))
|
||||
(_ '("--readonly" ; a no-op for clarity
|
||||
;; A 466G file system with 180G used is
|
||||
;; enough to kill btrfs with 6G of RAM.
|
||||
"--mode" "lowmem")))
|
||||
,device)))
|
||||
(apply system* `("btrfs" "check" "--progress"
|
||||
;; Btrfs's ‘--force’ is not relevant to us here.
|
||||
,@(match repair
|
||||
;; Upstream considers ALL repairs dangerous
|
||||
;; and will warn the user at run time.
|
||||
(#t '("--repair"))
|
||||
(_ '("--readonly" ; a no-op for clarity
|
||||
;; A 466G file system with 180G used is
|
||||
;; enough to kill btrfs with 6G of RAM.
|
||||
"--mode" "lowmem")))
|
||||
,device)))
|
||||
(0 'pass)
|
||||
(_ 'fatal-error))
|
||||
'pass))
|
||||
@@ -477,11 +412,11 @@ ignored: a full file system scan is always performed. If REPAIR is false, do
|
||||
not write to the file system to fix errors. Otherwise, automatically fix them
|
||||
using the least destructive approach."
|
||||
(match (status:exit-val
|
||||
(system*/tty "fsck.vfat" "-v"
|
||||
(match repair
|
||||
(#f "-n")
|
||||
(_ "-a")) ;no 'safe/#t distinction
|
||||
device))
|
||||
(apply system* `("fsck.vfat" "-v"
|
||||
,@(match repair
|
||||
(#f '("-n"))
|
||||
(_ '("-a"))) ; no 'safe/#t distinction
|
||||
,device)))
|
||||
(0 'pass)
|
||||
(1 'errors-corrected)
|
||||
(_ 'fatal-error)))
|
||||
@@ -610,7 +545,7 @@ do not write to the file system to fix errors, and replay the transaction log
|
||||
only if FORCE? is true. Otherwise, replay the transaction log before checking
|
||||
and automatically fix found errors."
|
||||
(match (status:exit-val
|
||||
(apply system*/tty
|
||||
(apply system*
|
||||
`("jfs_fsck" "-v"
|
||||
;; The ‘LEVEL’ logic is convoluted. To quote fsck/xchkdsk.c
|
||||
;; (‘-p’, ‘-a’, and ‘-r’ are aliases in every way):
|
||||
@@ -686,10 +621,10 @@ REPAIR are true, automatically fix found errors."
|
||||
"warning: forced check of F2FS ~a implies repairing any errors~%"
|
||||
device))
|
||||
(match (status:exit-val
|
||||
(apply system*/tty "fsck.f2fs"
|
||||
`(,@(if force? '("-f") '())
|
||||
,@(if repair '("-p") '("--dry-run"))
|
||||
,device)))
|
||||
(apply system* `("fsck.f2fs"
|
||||
,@(if force? '("-f") '())
|
||||
,@(if repair '("-p") '("--dry-run"))
|
||||
,device)))
|
||||
;; 0 and -1 are the only two possibilities according to the man page.
|
||||
(0 'pass)
|
||||
(_ 'fatal-error)))
|
||||
@@ -774,9 +709,9 @@ ignored: a full check is always performed. Repair is not possible: if REPAIR is
|
||||
true and the volume has been repaired by an external tool, clear the volume
|
||||
dirty flag to indicate that it's now safe to mount."
|
||||
(match (status:exit-val
|
||||
(system*/tty "ntfsfix"
|
||||
(if repair "--clear-dirty" "--no-action")
|
||||
device))
|
||||
(apply system* `("ntfsfix"
|
||||
,@(if repair '("--clear-dirty") '("--no-action"))
|
||||
,device)))
|
||||
(0 'pass)
|
||||
(_ 'fatal-error)))
|
||||
|
||||
@@ -819,11 +754,11 @@ write to DEVICE. If it's #t, replay the log, check, and fix any errors found.
|
||||
Otherwise, only replay the log, and check without attempting further repairs."
|
||||
(define (xfs_repair)
|
||||
(status:exit-val
|
||||
(system*/tty "xfs_repair" "-Pv"
|
||||
(match repair
|
||||
(#t "-e")
|
||||
(_ "-n")) ;will miss some errors
|
||||
device)))
|
||||
(apply system* `("xfs_repair" "-Pv"
|
||||
,@(match repair
|
||||
(#t '("-e"))
|
||||
(_ '("-n"))) ; will miss some errors
|
||||
,device))))
|
||||
(if force?
|
||||
;; xfs_repair fails with exit status 2 if the log is dirty, which is
|
||||
;; likely in situations where you're running xfs_repair. Only the kernel
|
||||
@@ -899,10 +834,6 @@ caught and lead to a warning and #f as the result."
|
||||
(format (current-error-port)
|
||||
"warning: failed to read from device '~a'~%" device)
|
||||
#f)
|
||||
((= EMEDIUMTYPE errno) ;inaccessible, like DRBD secondaries
|
||||
(format (current-error-port)
|
||||
"warning: failed to open device '~a'~%" device)
|
||||
#f)
|
||||
(else
|
||||
(apply throw args))))))))
|
||||
|
||||
@@ -1123,12 +1054,11 @@ an exception in such cases but perform the nearest sane action."
|
||||
"Return the number suitable for the 'flags' argument of 'mount' that
|
||||
corresponds to the symbols listed in FLAGS."
|
||||
(let loop ((flags flags))
|
||||
;; Note: Keep in sync with ‘invalid-file-system-flags’.
|
||||
(match flags
|
||||
(('read-only rest ...)
|
||||
(logior MS_RDONLY (loop rest)))
|
||||
(('bind-mount rest ...)
|
||||
(logior MS_REC (logior MS_BIND (loop rest))))
|
||||
(logior MS_BIND (loop rest)))
|
||||
(('no-suid rest ...)
|
||||
(logior MS_NOSUID (loop rest)))
|
||||
(('no-dev rest ...)
|
||||
@@ -1137,14 +1067,10 @@ corresponds to the symbols listed in FLAGS."
|
||||
(logior MS_NOEXEC (loop rest)))
|
||||
(('no-atime rest ...)
|
||||
(logior MS_NOATIME (loop rest)))
|
||||
(('no-diratime rest ...)
|
||||
(logior MS_NODIRATIME (loop rest)))
|
||||
(('strict-atime rest ...)
|
||||
(logior MS_STRICTATIME (loop rest)))
|
||||
(('lazy-time rest ...)
|
||||
(logior MS_LAZYTIME (loop rest)))
|
||||
(('shared rest ...)
|
||||
(loop rest))
|
||||
(()
|
||||
0))))
|
||||
|
||||
@@ -1202,16 +1128,12 @@ corresponds to the symbols listed in FLAGS."
|
||||
(not (file-is-directory? source)))
|
||||
(unless (file-exists? target)
|
||||
(mkdir-p (dirname target))
|
||||
(close-fdes
|
||||
(open-fdes target (logior O_WRONLY O_CREAT O_CLOEXEC))))
|
||||
(call-with-output-file target (const #t)))
|
||||
(mkdir-p target))
|
||||
|
||||
(cond
|
||||
((string-prefix? "nfs" type)
|
||||
(mount-nfs source target type flags options))
|
||||
((memq 'shared (file-system-flags fs))
|
||||
(mount source target type flags options)
|
||||
(mount "none" target #f MS_SHARED))
|
||||
(else
|
||||
(mount source target type flags options)))
|
||||
|
||||
|
||||
+28
-63
@@ -1,6 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2020-2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2020, 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
|
||||
;;; Copyright © 2020, 2021 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -105,7 +105,7 @@ Return the value associated with OPTION, or #f on failure."
|
||||
|
||||
;; TODO: Set the 'gnu.translator' extended attribute for passive translator
|
||||
;; settings?
|
||||
(mkdir-p (scope "servers/bus/pci")))
|
||||
)
|
||||
|
||||
(define (passive-translator-xattr? file-name)
|
||||
"Return true if FILE-NAME has an extended @code{gnu.translator} attribute
|
||||
@@ -127,9 +127,6 @@ set."
|
||||
|
||||
(define (translated? file-name)
|
||||
"Return true if a translator is installed on FILE-NAME."
|
||||
;; On GNU/Hurd, 'getxattr' in glibc opens the file without O_NOTRANS, and
|
||||
;; then, for "gnu.translator", it calls 'file_get_translator', resulting in
|
||||
;; EOPNOTSUPP (conversely, 'showtrans' opens the file with O_NOTRANS).
|
||||
(if (string-contains %host-type "linux-gnu")
|
||||
(passive-translator-xattr? file-name)
|
||||
(passive-translator-installed? file-name)))
|
||||
@@ -183,8 +180,7 @@ set."
|
||||
(mkdir-p dir))))
|
||||
|
||||
(define servers
|
||||
'(("servers/bus/pci" ("/hurd/pci-arbiter"))
|
||||
("servers/crash-dump-core" ("/hurd/crash" "--dump-core"))
|
||||
'(("servers/crash-dump-core" ("/hurd/crash" "--dump-core"))
|
||||
("servers/crash-kill" ("/hurd/crash" "--kill"))
|
||||
("servers/crash-suspend" ("/hurd/crash" "--suspend"))
|
||||
("servers/password" ("/hurd/password"))
|
||||
@@ -195,7 +191,7 @@ set."
|
||||
("proc" ("/hurd/procfs" "--stat-mode=444"))))
|
||||
|
||||
(define devices
|
||||
`(("dev/full" ("/hurd/null" "--full") #o666)
|
||||
'(("dev/full" ("/hurd/null" "--full") #o666)
|
||||
("dev/null" ("/hurd/null") #o666)
|
||||
("dev/random" ("/hurd/random" "--seed-file" "/var/lib/random-seed")
|
||||
#o644)
|
||||
@@ -214,58 +210,31 @@ set."
|
||||
;; 'fd_to_filename' in libc expects it.
|
||||
("dev/fd" ("/hurd/magic" "--directory" "fd") #o555)
|
||||
|
||||
("dev/rumpdisk" ("/hurd/rumpdisk") #o660)
|
||||
("dev/netdde" ("/hurd/netdde") #o660)
|
||||
("dev/eth0" ("/hurd/devnode" "--master-device=/dev/net"
|
||||
"eth0")
|
||||
#o660)
|
||||
("dev/eth1" ("/hurd/devnode" "--master-device=/dev/net"
|
||||
"eth1")
|
||||
#o660)
|
||||
("dev/tty1" ("/hurd/term" "/dev/tty1" "hurdio" "/dev/vcs/1/console")
|
||||
#o666)
|
||||
("dev/tty2" ("/hurd/term" "/dev/tty2" "hurdio" "/dev/vcs/2/console")
|
||||
#o666)
|
||||
("dev/tty3" ("/hurd/term" "/dev/tty3" "hurdio" "/dev/vcs/3/console")
|
||||
#o666)
|
||||
|
||||
;; Create a number of ttys; syslogd writes to tty12 by default.
|
||||
;; FIXME: Creating /dev/tty12 leads the console client to switch to
|
||||
;; tty12 when syslogd starts, which is confusing for users. Thus, do
|
||||
;; not create tty12.
|
||||
,@(map (lambda (n)
|
||||
(let ((n (number->string n)))
|
||||
`(,(string-append "dev/tty" n)
|
||||
("/hurd/term" ,(string-append "/dev/tty" n)
|
||||
"hurdio" ,(string-append "/dev/vcs/" n "/console"))
|
||||
#o666)))
|
||||
(iota 11 1))
|
||||
("dev/ptyp0" ("/hurd/term" "/dev/ptyp0" "pty-master" "/dev/ttyp0")
|
||||
#o666)
|
||||
("dev/ptyp1" ("/hurd/term" "/dev/ptyp1" "pty-master" "/dev/ttyp1")
|
||||
#o666)
|
||||
("dev/ptyp2" ("/hurd/term" "/dev/ptyp2" "pty-master" "/dev/ttyp2")
|
||||
#o666)
|
||||
|
||||
,@(append-map (lambda (n)
|
||||
(let ((n (number->string n)))
|
||||
`((,(string-append "dev/ptyp" n)
|
||||
("/hurd/term" ,(string-append "/dev/ptyp" n)
|
||||
"pty-master" ,(string-append "/dev/ttyp" n))
|
||||
#o666)
|
||||
|
||||
(,(string-append "dev/ttyp" n)
|
||||
("/hurd/term" ,(string-append "/dev/ttyp" n)
|
||||
"pty-slave" ,(string-append "/dev/ptyp" n))
|
||||
#o666))))
|
||||
(iota 10 0))
|
||||
,@(append-map (lambda (n)
|
||||
(let* ((n (number->string n))
|
||||
(drive (string-append "dev/wd" n))
|
||||
(disk (string-append "@/dev/disk:wd" n)))
|
||||
`((,drive ("/hurd/storeio" ,disk) #o600)
|
||||
,@(map (lambda (p)
|
||||
(let ((p (number->string p)))
|
||||
`(,(string-append drive "s" p)
|
||||
("/hurd/storeio"
|
||||
"--store-type=typed"
|
||||
,(string-append
|
||||
"part:" p ":device:" disk))
|
||||
#o660)))
|
||||
(iota 4 1)))))
|
||||
(iota 4 0))))
|
||||
("dev/ttyp0" ("/hurd/term" "/dev/ttyp0" "pty-slave" "/dev/ptyp0")
|
||||
#o666)
|
||||
("dev/ttyp1" ("/hurd/term" "/dev/ttyp1" "pty-slave" "/dev/ptyp1")
|
||||
#o666)
|
||||
("dev/ttyp2" ("/hurd/term" "/dev/ttyp2" "pty-slave" "/dev/ptyp2")
|
||||
#o666)))
|
||||
|
||||
(for-each scope-set-translator servers)
|
||||
(mkdir* "dev/vcs/1")
|
||||
(mkdir* "dev/vcs/2")
|
||||
(mkdir* "dev/vcs/2")
|
||||
(rename-file (scope "dev/console") (scope "dev/console-"))
|
||||
(for-each scope-set-translator devices)
|
||||
|
||||
@@ -274,10 +243,6 @@ set."
|
||||
(false-if-EEXIST (symlink "/dev/fd/1" (scope "dev/stdout")))
|
||||
(false-if-EEXIST (symlink "/dev/fd/2" (scope "dev/stderr")))
|
||||
(false-if-EEXIST (symlink "crash-dump-core" (scope "servers/crash")))
|
||||
(false-if-EEXIST (symlink "/dev/rumpdisk" (scope "dev/disk")))
|
||||
(false-if-EEXIST (symlink "/dev/netdde" (scope "dev/net")))
|
||||
(false-if-EEXIST (symlink "/servers/socket/2" (scope "servers/socket/inet")))
|
||||
(false-if-EEXIST (symlink "/servers/socket/26" (scope "servers/socket/inet6")))
|
||||
|
||||
;; Make sure /etc/mtab is a symlink to /proc/mounts.
|
||||
(false-if-exception (delete-file (scope "etc/mtab")))
|
||||
@@ -309,14 +274,14 @@ XXX TODO: use Linux xattr/setxattr to remove (settrans in) /libexec/RUNSYSTEM
|
||||
(system (find-long-option "gnu.system" args))
|
||||
(to-load (find-long-option "gnu.load" args)))
|
||||
|
||||
(false-if-exception (delete-file "/hurd"))
|
||||
(let ((hurd/hurd (readlink* (string-append system "/profile/hurd"))))
|
||||
(symlink hurd/hurd "/hurd"))
|
||||
|
||||
(format #t "Setting-up essential translators...\n")
|
||||
(setenv "PATH" (string-append system "/profile/bin"))
|
||||
(set-hurd-device-translators)
|
||||
|
||||
(false-if-exception (delete-file "/hurd"))
|
||||
(let ((hurd/hurd (readlink* (string-append system "/profile/hurd"))))
|
||||
(symlink hurd/hurd "/hurd"))
|
||||
|
||||
(format #t "Starting pager...\n")
|
||||
(unless (zero? (system* "/hurd/mach-defpager"))
|
||||
(format #t "FAILED...Good luck!\n"))
|
||||
|
||||
+13
-50
@@ -5,9 +5,6 @@
|
||||
;;; Copyright © 2017 Marius Bakke <mbakke@fastmail.com>
|
||||
;;; Copyright © 2020, 2022 Tobias Geerinckx-Rice <me@tobias.gr>
|
||||
;;; Copyright © 2020 Mathieu Othacehe <m.othacehe@gmail.com>
|
||||
;;; Copyright © 2022 Pavel Shlyak <p.shlyak@pantherx.org>
|
||||
;;; Copyright © 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
|
||||
;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -29,7 +26,6 @@
|
||||
#:use-module (guix build syscalls)
|
||||
#:use-module (guix build utils)
|
||||
#:use-module (guix store database)
|
||||
#:use-module (guix utils)
|
||||
#:use-module (gnu build bootloader)
|
||||
#:use-module (gnu build install)
|
||||
#:use-module (gnu build linux-boot)
|
||||
@@ -44,7 +40,6 @@
|
||||
convert-disk-image
|
||||
genimage
|
||||
initialize-efi-partition
|
||||
initialize-efi32-partition
|
||||
initialize-root-partition
|
||||
|
||||
make-iso9660-image))
|
||||
@@ -53,13 +48,12 @@
|
||||
"Take SEXP, a tuple as returned by 'partition->gexp', and turn it into a
|
||||
<partition> record."
|
||||
(match sexp
|
||||
((size file-system file-system-options label uuid flags)
|
||||
((size file-system file-system-options label uuid)
|
||||
(partition (size size)
|
||||
(file-system file-system)
|
||||
(file-system-options file-system-options)
|
||||
(label label)
|
||||
(uuid uuid)
|
||||
(flags flags)))))
|
||||
(uuid uuid)))))
|
||||
|
||||
(define (size-in-kib size)
|
||||
"Convert SIZE expressed in bytes, to kilobytes and return it as a string."
|
||||
@@ -87,10 +81,7 @@ turn doesn't take any constant overhead into account, force a 1-MiB minimum."
|
||||
(journal-options "lazy_itable_init=1,lazy_journal_init=1"))
|
||||
(apply invoke
|
||||
`("fakeroot" "mke2fs" "-t" ,fs "-d" ,root
|
||||
"-L" ,label
|
||||
,@(if uuid
|
||||
`("-U" ,(uuid->string uuid))
|
||||
'())
|
||||
"-L" ,label "-U" ,(uuid->string uuid)
|
||||
"-E" ,(format #f "root_owner=~a:~a,~a"
|
||||
owner-uid owner-gid journal-options)
|
||||
,@fs-options
|
||||
@@ -101,21 +92,16 @@ turn doesn't take any constant overhead into account, force a 1-MiB minimum."
|
||||
(estimate-partition-size root)
|
||||
size)))))))
|
||||
|
||||
(define* (make-vfat-image partition target root fs-bits)
|
||||
(define* (make-vfat-image partition target root)
|
||||
"Handle the creation of VFAT partition images. See 'make-partition-image'."
|
||||
(let ((size (partition-size partition))
|
||||
(label (partition-label partition))
|
||||
(flags (partition-flags partition)))
|
||||
(apply invoke "fakeroot" "mkdosfs" "-n" label "-C" target
|
||||
"-F" (number->string fs-bits)
|
||||
(size-in-kib
|
||||
(if (eq? size 'guess)
|
||||
(estimate-partition-size root)
|
||||
size))
|
||||
;; u-boot in particular needs the formatted block
|
||||
;; size and the physical block size to be equal.
|
||||
;; TODO: What about 4k blocks?
|
||||
(if (member 'esp flags) (list "-S" "512") '()))
|
||||
(label (partition-label partition)))
|
||||
(invoke "fakeroot" "mkdosfs" "-n" label "-C" target
|
||||
"-F" "16" "-S" "1024"
|
||||
(size-in-kib
|
||||
(if (eq? size 'guess)
|
||||
(estimate-partition-size root)
|
||||
size)))
|
||||
(for-each (lambda (file)
|
||||
(unless (member file '("." ".."))
|
||||
(invoke "mcopy" "-bsp" "-i" target
|
||||
@@ -123,14 +109,6 @@ turn doesn't take any constant overhead into account, force a 1-MiB minimum."
|
||||
(string-append "::" file))))
|
||||
(scandir root))))
|
||||
|
||||
(define* (make-unformatted-image partition target)
|
||||
"Make an unformatted partition of a certain size."
|
||||
(let ((size (partition-size partition)))
|
||||
;; Create the file and then truncate it to the desired size.
|
||||
(with-output-to-file target
|
||||
(lambda _ (display "")))
|
||||
(truncate-file target size)))
|
||||
|
||||
(define* (make-partition-image partition-sexp target root)
|
||||
"Create and return the image of PARTITION-SEXP as TARGET. Use the given
|
||||
ROOT directory to populate the image."
|
||||
@@ -139,12 +117,8 @@ ROOT directory to populate the image."
|
||||
(cond
|
||||
((string-prefix? "ext" type)
|
||||
(make-ext-image partition target root))
|
||||
((or (string=? type "vfat") (string=? type "fat16"))
|
||||
(make-vfat-image partition target root 16))
|
||||
((string=? type "fat32")
|
||||
(make-vfat-image partition target root 32))
|
||||
((string=? type "unformatted")
|
||||
(make-unformatted-image partition target))
|
||||
((string=? type "vfat")
|
||||
(make-vfat-image partition target root))
|
||||
(else
|
||||
(raise (condition
|
||||
(&message
|
||||
@@ -188,17 +162,6 @@ produced by #:references-graphs. Pass WAL-MODE? to call-with-database."
|
||||
"Install in ROOT directory, an EFI loader using GRUB-EFI."
|
||||
(install-efi-loader grub-efi root))
|
||||
|
||||
(define* (initialize-efi32-partition root
|
||||
#:key
|
||||
grub-efi32
|
||||
#:allow-other-keys)
|
||||
"Install in ROOT directory, an EFI 32bit loader using GRUB-EFI32."
|
||||
(install-efi-loader grub-efi32 root
|
||||
#:targets (cond ((target-x86?)
|
||||
'("i386-efi" . "BOOTIA32.EFI"))
|
||||
((target-arm?)
|
||||
'("arm-efi" . "BOOTARM.EFI")))))
|
||||
|
||||
(define* (initialize-root-partition root
|
||||
#:key
|
||||
bootcfg
|
||||
|
||||
+22
-61
@@ -1,7 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2013-2020, 2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
|
||||
;;; Copyright © 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -57,24 +56,19 @@ that the fonts, background images, etc. referred to by BOOTCFG are not GC'd."
|
||||
(define* (evaluate-populate-directive directive target
|
||||
#:key
|
||||
(default-gid 0)
|
||||
(default-uid 0)
|
||||
(error-on-dangling-symlink? #t))
|
||||
(default-uid 0))
|
||||
"Evaluate DIRECTIVE, an sexp describing a file or directory to create under
|
||||
directory TARGET. DEFAULT-UID and DEFAULT-GID are the default UID and GID in
|
||||
the context of the caller. If the directive matches those defaults then,
|
||||
'chown' won't be run. When ERROR-ON-DANGLING-SYMLINK? is true, abort with an
|
||||
error when a dangling symlink would be created."
|
||||
(define target* (if (string-suffix? "/" target)
|
||||
target
|
||||
(string-append target "/")))
|
||||
'chown' won't be run."
|
||||
(let loop ((directive directive))
|
||||
(catch 'system-error
|
||||
(lambda ()
|
||||
(match directive
|
||||
(('directory name)
|
||||
(mkdir-p (string-append target* name)))
|
||||
(mkdir-p (string-append target name)))
|
||||
(('directory name uid gid)
|
||||
(let ((dir (string-append target* name)))
|
||||
(let ((dir (string-append target name)))
|
||||
(mkdir-p dir)
|
||||
;; If called from a context without "root" permissions, "chown"
|
||||
;; to root will fail. In that case, do not try to run "chown"
|
||||
@@ -84,38 +78,27 @@ error when a dangling symlink would be created."
|
||||
(chown dir uid gid))))
|
||||
(('directory name uid gid mode)
|
||||
(loop `(directory ,name ,uid ,gid))
|
||||
(chmod (string-append target* name) mode))
|
||||
(chmod (string-append target name) mode))
|
||||
(('file name)
|
||||
(call-with-output-file (string-append target* name)
|
||||
(call-with-output-file (string-append target name)
|
||||
(const #t)))
|
||||
(('file name (? string? content))
|
||||
(call-with-output-file (string-append target* name)
|
||||
(call-with-output-file (string-append target name)
|
||||
(lambda (port)
|
||||
(display content port))))
|
||||
((new '-> old)
|
||||
(let ((new* (string-append target* new)))
|
||||
(let try ()
|
||||
(catch 'system-error
|
||||
(lambda ()
|
||||
(when error-on-dangling-symlink?
|
||||
;; When the symbolic link points to a relative path,
|
||||
;; checking if its target exists must be done relatively
|
||||
;; to the link location.
|
||||
(unless (if (string-prefix? "/" old)
|
||||
(file-exists? old)
|
||||
(with-directory-excursion (dirname new*)
|
||||
(file-exists? old)))
|
||||
(error (format #f "symlink `~a' points to nonexistent \
|
||||
file `~a'" new* old))))
|
||||
(symlink old new*))
|
||||
(lambda args
|
||||
;; When doing 'guix system init' on the current '/', some
|
||||
;; symlinks may already exists. Override them.
|
||||
(if (= EEXIST (system-error-errno args))
|
||||
(begin
|
||||
(delete-file new*)
|
||||
(try))
|
||||
(apply throw args)))))))))
|
||||
(let try ()
|
||||
(catch 'system-error
|
||||
(lambda ()
|
||||
(symlink old (string-append target new)))
|
||||
(lambda args
|
||||
;; When doing 'guix system init' on the current '/', some
|
||||
;; symlinks may already exists. Override them.
|
||||
(if (= EEXIST (system-error-errno args))
|
||||
(begin
|
||||
(delete-file (string-append target new))
|
||||
(try))
|
||||
(apply throw args))))))))
|
||||
(lambda args
|
||||
;; Usually we can only get here when installing to an existing root,
|
||||
;; as with 'guix system init foo.scm /'.
|
||||
@@ -159,10 +142,7 @@ STORE."
|
||||
includes /etc, /var, /run, /bin/sh, etc., and all the symlinks to SYSTEM.
|
||||
EXTRAS is a list of directives appended to the built-in directives to populate
|
||||
TARGET."
|
||||
;; It's expected that some symbolic link targets do not exist yet, so do not
|
||||
;; error on dangling links.
|
||||
(for-each (cut evaluate-populate-directive <> target
|
||||
#:error-on-dangling-symlink? #f)
|
||||
(for-each (cut evaluate-populate-directive <> target)
|
||||
(append (directives (%store-directory)) extras))
|
||||
|
||||
;; Add system generation 1.
|
||||
@@ -282,31 +262,12 @@ disk."
|
||||
(mount "/.rw-store" (%store-directory) "" MS_MOVE)
|
||||
(rmdir "/.rw-store")))
|
||||
|
||||
(define (umount* directory)
|
||||
"Unmount DIRECTORY, but retry a few times upon EBUSY."
|
||||
(let loop ((attempts 5))
|
||||
(catch 'system-error
|
||||
(lambda ()
|
||||
(umount directory))
|
||||
(lambda args
|
||||
(if (and (= EBUSY (system-error-errno args))
|
||||
(> attempts 0))
|
||||
(begin
|
||||
(sleep 1)
|
||||
(loop (- attempts 1)))
|
||||
(apply throw args))))))
|
||||
|
||||
(define (unmount-cow-store target backing-directory)
|
||||
"Unmount copy-on-write store."
|
||||
(let ((tmp-dir "/remove"))
|
||||
(mkdir-p tmp-dir)
|
||||
(mount (%store-directory) tmp-dir "" MS_MOVE)
|
||||
|
||||
;; We might get EBUSY at this point, possibly because of lingering
|
||||
;; processes with open file descriptors. Use 'umount*' to retry upon
|
||||
;; EBUSY, leaving a bit of time. See <https://issues.guix.gnu.org/59884>.
|
||||
(umount* tmp-dir)
|
||||
|
||||
(umount tmp-dir)
|
||||
(rmdir tmp-dir)
|
||||
(delete-file-recursively
|
||||
(string-append target backing-directory))))
|
||||
|
||||
+328
-69
@@ -1,5 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2021, 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -24,16 +24,16 @@
|
||||
;;; Code:
|
||||
|
||||
(define-module (gnu build jami-service)
|
||||
#:use-module (gnu build dbus-service)
|
||||
#:use-module (ice-9 format)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (ice-9 peg)
|
||||
#:use-module (ice-9 rdelim)
|
||||
#:use-module (ice-9 regex)
|
||||
#:use-module (rnrs io ports)
|
||||
#:autoload (shepherd service) (fork+exec-command)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:export (jami-service-available?
|
||||
|
||||
account-fingerprint?
|
||||
#:export (account-fingerprint?
|
||||
account-details->recutil
|
||||
get-accounts
|
||||
get-usernames
|
||||
@@ -51,12 +51,43 @@
|
||||
set-all-moderators
|
||||
set-moderator
|
||||
username->all-moderators?
|
||||
username->moderators))
|
||||
username->moderators
|
||||
|
||||
dbus-available-services
|
||||
dbus-service-available?
|
||||
|
||||
%send-dbus-binary
|
||||
%send-dbus-bus
|
||||
%send-dbus-user
|
||||
%send-dbus-group
|
||||
%send-dbus-debug
|
||||
send-dbus
|
||||
|
||||
with-retries))
|
||||
|
||||
;;;
|
||||
;;; Utilities.
|
||||
;;;
|
||||
|
||||
(define-syntax-rule (with-retries n delay body ...)
|
||||
"Retry the code in BODY up to N times until it doesn't raise an exception
|
||||
nor return #f, else raise an error. A delay of DELAY seconds is inserted
|
||||
before each retry."
|
||||
(let loop ((attempts 0))
|
||||
(catch #t
|
||||
(lambda ()
|
||||
(let ((result (begin body ...)))
|
||||
(if (not result)
|
||||
(error "failed attempt" attempts)
|
||||
result)))
|
||||
(lambda args
|
||||
(if (< attempts n)
|
||||
(begin
|
||||
(sleep delay) ;else wait and retry
|
||||
(loop (+ 1 attempts)))
|
||||
(error "maximum number of retry attempts reached"
|
||||
body ... args))))))
|
||||
|
||||
(define (alist->list alist)
|
||||
"Flatten ALIST into a list."
|
||||
(append-map (match-lambda
|
||||
@@ -73,34 +104,212 @@ hexadecimal characters."
|
||||
(and (string? val)
|
||||
(regexp-exec account-fingerprint-rx val)))
|
||||
|
||||
|
||||
;;;
|
||||
;;; D-Bus reply parser.
|
||||
;;;
|
||||
|
||||
(define (parse-dbus-reply reply)
|
||||
"Return the parse tree of REPLY, a string returned by the 'dbus-send'
|
||||
command."
|
||||
;; Refer to 'man 1 dbus-send' for the grammar reference. Note that the
|
||||
;; format of the replies doesn't match the format of the input, which is the
|
||||
;; one documented, but it gives an idea. For an even better reference, see
|
||||
;; the `print_iter' procedure of the 'dbus-print-message.c' file from the
|
||||
;; 'dbus' package sources.
|
||||
(define-peg-string-patterns
|
||||
"contents <- header (item / container (item / container*)?)
|
||||
item <-- WS type WS value NL
|
||||
container <- array / dict / variant
|
||||
array <-- array-start (item / container)* array-end
|
||||
dict <-- array-start dict-entry* array-end
|
||||
dict-entry <-- dict-entry-start item item dict-entry-end
|
||||
variant <-- variant-start item
|
||||
type <-- 'string' / 'int16' / 'uint16' / 'int32' / 'uint32' / 'int64' /
|
||||
'uint64' / 'double' / 'byte' / 'boolean' / 'objpath'
|
||||
value <-- (!NL .)* NL
|
||||
header < (!NL .)* NL
|
||||
variant-start < WS 'variant'
|
||||
array-start < WS 'array [' NL
|
||||
array-end < WS ']' NL
|
||||
dict-entry-start < WS 'dict entry(' NL
|
||||
dict-entry-end < WS ')' NL
|
||||
DQ < '\"'
|
||||
WS < ' '*
|
||||
NL < '\n'*")
|
||||
|
||||
(peg:tree (match-pattern contents reply)))
|
||||
|
||||
(define (strip-quotes text)
|
||||
"Strip the leading and trailing double quotes (\") characters from TEXT."
|
||||
(let* ((text* (if (string-prefix? "\"" text)
|
||||
(string-drop text 1)
|
||||
text))
|
||||
(text** (if (string-suffix? "\"" text*)
|
||||
(string-drop-right text* 1)
|
||||
text*)))
|
||||
text**))
|
||||
|
||||
(define (deserialize-item item)
|
||||
"Return the value described by the ITEM parse tree as a Guile object."
|
||||
;; Strings are printed wrapped in double quotes (see the print_iter
|
||||
;; procedure in dbus-print-message.c).
|
||||
(match item
|
||||
(('item ('type "string") ('value value))
|
||||
(strip-quotes value))
|
||||
(('item ('type "boolean") ('value value))
|
||||
(if (string=? "true" value)
|
||||
#t
|
||||
#f))
|
||||
(('item _ ('value value))
|
||||
value)))
|
||||
|
||||
(define (serialize-boolean bool)
|
||||
"Return the serialized format expected by dbus-send for BOOL."
|
||||
(format #f "boolean:~:[false~;true~]" bool))
|
||||
|
||||
(define (dict->alist dict-parse-tree)
|
||||
"Translate a dict parse tree to an alist."
|
||||
(define (tuples->alist tuples)
|
||||
(map (lambda (x) (apply cons x)) tuples))
|
||||
|
||||
(match dict-parse-tree
|
||||
('dict
|
||||
'())
|
||||
(('dict ('dict-entry keys values) ...)
|
||||
(let ((keys* (map deserialize-item keys))
|
||||
(values* (map deserialize-item values)))
|
||||
(tuples->alist (zip keys* values*))))))
|
||||
|
||||
(define (array->list array-parse-tree)
|
||||
"Translate an array parse tree to a list."
|
||||
(match array-parse-tree
|
||||
('array
|
||||
'())
|
||||
(('array items ...)
|
||||
(map deserialize-item items))))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Low-level, D-Bus-related procedures.
|
||||
;;;
|
||||
|
||||
;;; The following parameters are used in the jami-service-type service
|
||||
;;; definition to conveniently customize the behavior of the send-dbus helper,
|
||||
;;; even when called indirectly.
|
||||
(define %send-dbus-binary (make-parameter "dbus-send"))
|
||||
(define %send-dbus-bus (make-parameter #f))
|
||||
(define %send-dbus-user (make-parameter #f))
|
||||
(define %send-dbus-group (make-parameter #f))
|
||||
(define %send-dbus-debug (make-parameter #f))
|
||||
|
||||
(define* (send-dbus #:key service path interface method
|
||||
bus
|
||||
dbus-send
|
||||
user group
|
||||
timeout
|
||||
arguments)
|
||||
"Return the response of DBUS-SEND, else raise an error. Unless explicitly
|
||||
provided, DBUS-SEND takes the value of the %SEND-DBUS-BINARY parameter. BUS
|
||||
can be used to specify the bus address, such as 'unix:path=/var/run/jami/bus'.
|
||||
Alternatively, the %SEND-DBUS-BUS parameter can be used. ARGUMENTS can be
|
||||
used to pass input values to a D-Bus method call. TIMEOUT is the amount of
|
||||
time to wait for a reply in milliseconds before giving up with an error. USER
|
||||
and GROUP allow choosing under which user/group the DBUS-SEND command is
|
||||
executed. Alternatively, the %SEND-DBUS-USER and %SEND-DBUS-GROUP parameters
|
||||
can be used instead."
|
||||
(let* ((command `(,(if dbus-send
|
||||
dbus-send
|
||||
(%send-dbus-binary))
|
||||
,@(if (or bus (%send-dbus-bus))
|
||||
(list (string-append "--bus="
|
||||
(or bus (%send-dbus-bus))))
|
||||
'())
|
||||
"--print-reply"
|
||||
,@(if timeout
|
||||
(list (format #f "--reply-timeout=~d" timeout))
|
||||
'())
|
||||
,(string-append "--dest=" service) ;e.g., cx.ring.Ring
|
||||
,path ;e.g., /cx/ring/Ring/ConfigurationManager
|
||||
,(string-append interface "." method)
|
||||
,@(or arguments '())))
|
||||
(temp-port (mkstemp! (string-copy "/tmp/dbus-send-output-XXXXXXX")))
|
||||
(temp-file (port-filename temp-port)))
|
||||
(dynamic-wind
|
||||
(lambda ()
|
||||
(let* ((uid (or (and=> (or user (%send-dbus-user))
|
||||
(compose passwd:uid getpwnam)) -1))
|
||||
(gid (or (and=> (or group (%send-dbus-group))
|
||||
(compose group:gid getgrnam)) -1)))
|
||||
(chown temp-port uid gid)))
|
||||
(lambda ()
|
||||
(let ((pid (fork+exec-command command
|
||||
#:user (or user (%send-dbus-user))
|
||||
#:group (or group (%send-dbus-group))
|
||||
#:log-file temp-file)))
|
||||
(match (waitpid pid)
|
||||
((_ . status)
|
||||
(let ((exit-status (status:exit-val status))
|
||||
(output (call-with-port temp-port get-string-all)))
|
||||
(if (= 0 exit-status)
|
||||
output
|
||||
(error "the send-dbus command exited with: "
|
||||
command exit-status output)))))))
|
||||
(lambda ()
|
||||
(false-if-exception (delete-file temp-file))))))
|
||||
|
||||
(define (parse-account-ids reply)
|
||||
"Return the Jami account IDs from REPLY, which is assumed to be the output
|
||||
of the Jami D-Bus `getAccountList' method."
|
||||
(array->list (parse-dbus-reply reply)))
|
||||
|
||||
(define (parse-account-details reply)
|
||||
"Parse REPLY, which is assumed to be the output of the Jami D-Bus
|
||||
`getAccountDetails' method, and return its content as an alist."
|
||||
(dict->alist (parse-dbus-reply reply)))
|
||||
|
||||
(define (parse-contacts reply)
|
||||
"Parse REPLY, which is assumed to be the output of the Jamid D-Bus
|
||||
`getContacts' method, and return its content as an alist."
|
||||
(match (parse-dbus-reply reply)
|
||||
('array
|
||||
'())
|
||||
(('array dicts ...)
|
||||
(map dict->alist dicts))))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Higher-level, D-Bus-related procedures.
|
||||
;;;
|
||||
|
||||
(define (validate-fingerprint fingerprint)
|
||||
"Validate that fingerprint is 40 characters long."
|
||||
(unless (account-fingerprint? fingerprint)
|
||||
(error "Account fingerprint is not valid:" fingerprint)))
|
||||
|
||||
(define (jami-service-available?)
|
||||
"Whether the Jami D-Bus service was acquired by the D-Bus daemon."
|
||||
(unless (%current-dbus-connection)
|
||||
(initialize-dbus-connection!))
|
||||
(dbus-service-available? "cx.ring.Ring"))
|
||||
(define (dbus-available-services)
|
||||
"Return the list of available (acquired) D-Bus services."
|
||||
(let ((reply (parse-dbus-reply
|
||||
(send-dbus #:service "org.freedesktop.DBus"
|
||||
#:path "/org/freedesktop/DBus"
|
||||
#:interface "org.freedesktop.DBus"
|
||||
#:method "ListNames"))))
|
||||
;; Remove entries such as ":1.7".
|
||||
(remove (cut string-prefix? ":" <>)
|
||||
(array->list reply))))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Bindings for the Jami D-Bus API.
|
||||
;;;
|
||||
(define (dbus-service-available? service)
|
||||
"Predicate to check for the D-Bus SERVICE availability."
|
||||
(member service (dbus-available-services)))
|
||||
|
||||
(define* (call-configuration-manager-method method #:optional arguments
|
||||
#:key timeout)
|
||||
"Query the Jami D-Bus ConfigurationManager interface with METHOD applied to
|
||||
ARGUMENTS. TIMEOUT can optionally be provided as a value in seconds."
|
||||
(unless (%current-dbus-connection)
|
||||
(initialize-dbus-connection!))
|
||||
(call-dbus-method method
|
||||
#:path "/cx/ring/Ring/ConfigurationManager"
|
||||
#:destination "cx.ring.Ring"
|
||||
#:interface "cx.ring.Ring.ConfigurationManager"
|
||||
#:arguments arguments
|
||||
#:timeout timeout))
|
||||
(define* (send-dbus/configuration-manager #:key method arguments timeout)
|
||||
"Query the Jami D-Bus ConfigurationManager service."
|
||||
(send-dbus #:service "cx.ring.Ring"
|
||||
#:path "/cx/ring/Ring/ConfigurationManager"
|
||||
#:interface "cx.ring.Ring.ConfigurationManager"
|
||||
#:method method
|
||||
#:arguments arguments
|
||||
#:timeout timeout))
|
||||
|
||||
;;; The following methods are for internal use; they make use of the account
|
||||
;;; ID, an implementation detail of Jami the user should not need to be
|
||||
@@ -108,17 +317,22 @@ ARGUMENTS. TIMEOUT can optionally be provided as a value in seconds."
|
||||
(define (get-account-ids)
|
||||
"Return the available Jami account identifiers (IDs). Account IDs are an
|
||||
implementation detail used to identify the accounts in Jami."
|
||||
(vector->list (call-configuration-manager-method "getAccountList")))
|
||||
(parse-account-ids
|
||||
(send-dbus/configuration-manager #:method "getAccountList")))
|
||||
|
||||
(define (id->account-details id)
|
||||
"Retrieve the account data associated with the given account ID."
|
||||
(vector->list (call-configuration-manager-method "getAccountDetails"
|
||||
(list id))))
|
||||
(parse-account-details
|
||||
(send-dbus/configuration-manager
|
||||
#:method "getAccountDetails"
|
||||
#:arguments (list (string-append "string:" id)))))
|
||||
|
||||
(define (id->volatile-account-details id)
|
||||
"Retrieve the account data associated with the given account ID."
|
||||
(vector->list (call-configuration-manager-method "getVolatileAccountDetails"
|
||||
(list id))))
|
||||
(parse-account-details
|
||||
(send-dbus/configuration-manager
|
||||
#:method "getVolatileAccountDetails"
|
||||
#:arguments (list (string-append "string:" id)))))
|
||||
|
||||
(define (id->account id)
|
||||
"Retrieve the complete account data associated with the given account ID."
|
||||
@@ -148,16 +362,19 @@ implementation detail used to identify the accounts in Jami."
|
||||
'()))))
|
||||
(get-account-ids))))
|
||||
(or (assoc-ref %username-to-id-cache username)
|
||||
(let ((message (format #f "no account ID for ~:[username~;fingerprint~]"
|
||||
(account-fingerprint? username))))
|
||||
(let ((message (format #f "Could not retrieve a local account ID\
|
||||
for ~:[username~;fingerprint~]" (account-fingerprint? username))))
|
||||
(error message username))))
|
||||
|
||||
(define (account->username account)
|
||||
"Return the public key fingerprint of ACCOUNT."
|
||||
(assoc-ref account "Account.username"))
|
||||
"Return USERNAME, the registered username associated with ACCOUNT, else its
|
||||
public key fingerprint."
|
||||
(or (assoc-ref account "Account.registeredName")
|
||||
(assoc-ref account "Account.username")))
|
||||
|
||||
(define (id->username id)
|
||||
"Return the public key fingerprint corresponding to account with ID, else #f."
|
||||
"Return USERNAME, the registered username associated with ID, else its
|
||||
public key fingerprint, else #f."
|
||||
(account->username (id->account id)))
|
||||
|
||||
(define (get-accounts)
|
||||
@@ -183,21 +400,27 @@ registered username."
|
||||
should *not* be encrypted with a password. Return the username associated
|
||||
with the account."
|
||||
(invalidate-username-to-id-cache!)
|
||||
(let ((id (call-configuration-manager-method
|
||||
"addAccount" (list `#(("Account.archivePath" . ,archive)
|
||||
("Account.type" . "RING"))))))
|
||||
(let ((reply (send-dbus/configuration-manager
|
||||
#:method "addAccount"
|
||||
#:arguments (list (string-append
|
||||
"dict:string:string:Account.archivePath,"
|
||||
archive
|
||||
",Account.type,RING")))))
|
||||
;; The account information takes some time to be populated.
|
||||
(with-retries 20 1
|
||||
(let ((username (id->username id)))
|
||||
(if (and=> username (negate string-null?))
|
||||
username
|
||||
#f)))))
|
||||
(let ((id (deserialize-item (parse-dbus-reply reply))))
|
||||
(with-retries 20 1
|
||||
(let ((username (id->username id)))
|
||||
(if (string-null? username)
|
||||
#f
|
||||
username))))))
|
||||
|
||||
(define (remove-account username)
|
||||
"Delete the Jami account associated with USERNAME, the account 40 characters
|
||||
fingerprint or a registered username."
|
||||
(let ((id (username->id username)))
|
||||
(call-configuration-manager-method "removeAccount" (list id)))
|
||||
(send-dbus/configuration-manager
|
||||
#:method "removeAccount"
|
||||
#:arguments (list (string-append "string:" id))))
|
||||
(invalidate-username-to-id-cache!))
|
||||
|
||||
(define* (username->contacts username)
|
||||
@@ -207,16 +430,15 @@ contacts. USERNAME can be either the account 40 characters public key
|
||||
fingerprint or a registered username. The contacts returned are represented
|
||||
using their 40 characters fingerprint."
|
||||
(let* ((id (username->id username))
|
||||
;; The contacts are returned as "aa{ss}", that is, an array of arrays
|
||||
;; containing (string . string) pairs.
|
||||
(contacts (map vector->list
|
||||
(vector->list (call-configuration-manager-method
|
||||
"getContacts" (list id)))))
|
||||
(reply (send-dbus/configuration-manager
|
||||
#:method "getContacts"
|
||||
#:arguments (list (string-append "string:" id))))
|
||||
(all-contacts (parse-contacts reply))
|
||||
(banned? (lambda (contact)
|
||||
(and=> (assoc-ref contact "banned")
|
||||
(cut string=? "true" <>))))
|
||||
(banned (filter banned? contacts))
|
||||
(not-banned (filter (negate banned?) contacts))
|
||||
(banned (filter banned? all-contacts))
|
||||
(not-banned (filter (negate banned?) all-contacts))
|
||||
(fingerprint (cut assoc-ref <> "id")))
|
||||
(values (map fingerprint not-banned)
|
||||
(map fingerprint banned))))
|
||||
@@ -227,20 +449,27 @@ the account associated with USERNAME (either a fingerprint or a registered
|
||||
username). When BAN? is true, also mark the contact as banned."
|
||||
(validate-fingerprint contact)
|
||||
(let ((id (username->id username)))
|
||||
(call-configuration-manager-method "removeContact" (list id contact ban?))))
|
||||
(send-dbus/configuration-manager
|
||||
#:method "removeContact"
|
||||
#:arguments (list (string-append "string:" id)
|
||||
(string-append "string:" contact)
|
||||
(serialize-boolean ban?)))))
|
||||
|
||||
(define (add-contact contact username)
|
||||
"Add CONTACT, the 40 characters public key fingerprint of a contact, to the
|
||||
account of USERNAME (either a fingerprint or a registered username)."
|
||||
(validate-fingerprint contact)
|
||||
(let ((id (username->id username)))
|
||||
(call-configuration-manager-method "addContact" (list id contact))))
|
||||
(send-dbus/configuration-manager
|
||||
#:method "addContact"
|
||||
#:arguments (list (string-append "string:" id)
|
||||
(string-append "string:" contact)))))
|
||||
|
||||
(define* (set-account-details details username #:key timeout)
|
||||
"Set DETAILS, an alist containing the key value pairs to set for the account
|
||||
of USERNAME, a registered username or account fingerprint. The value of the
|
||||
parameters not provided are unchanged. TIMEOUT is a value in milliseconds to
|
||||
pass to the `call-configuration-manager-method' procedure."
|
||||
pass to the `send-dbus/configuration-manager' procedure."
|
||||
(let* ((id (username->id username))
|
||||
(current-details (id->account-details id))
|
||||
(updated-details (map (match-lambda
|
||||
@@ -248,29 +477,52 @@ pass to the `call-configuration-manager-method' procedure."
|
||||
(or (and=> (assoc-ref details key)
|
||||
(cut cons key <>))
|
||||
(cons key value))))
|
||||
current-details)))
|
||||
(call-configuration-manager-method
|
||||
"setAccountDetails" (list id (list->vector updated-details))
|
||||
#:timeout timeout)))
|
||||
current-details))
|
||||
;; dbus-send does not permit sending null strings (it throws a
|
||||
;; "malformed dictionary" error). Luckily they seem to have the
|
||||
;; semantic of "default account value" in Jami; so simply drop them.
|
||||
(updated-details* (remove (match-lambda
|
||||
((_ . value)
|
||||
(string-null? value)))
|
||||
updated-details)))
|
||||
(send-dbus/configuration-manager
|
||||
#:timeout timeout
|
||||
#:method "setAccountDetails"
|
||||
#:arguments
|
||||
(list (string-append "string:" id)
|
||||
(string-append "dict:string:string:"
|
||||
(string-join (alist->list updated-details*)
|
||||
","))))))
|
||||
|
||||
(define (set-all-moderators enabled? username)
|
||||
"Set the 'AllModerators' property to enabled? for the account of USERNAME, a
|
||||
registered username or account fingerprint."
|
||||
(let ((id (username->id username)))
|
||||
(call-configuration-manager-method "setAllModerators" (list id enabled?))))
|
||||
(send-dbus/configuration-manager
|
||||
#:method "setAllModerators"
|
||||
#:arguments
|
||||
(list (string-append "string:" id)
|
||||
(serialize-boolean enabled?)))))
|
||||
|
||||
(define (username->all-moderators? username)
|
||||
"Return the 'AllModerators' property for the account of USERNAME, a
|
||||
registered username or account fingerprint."
|
||||
(let ((id (username->id username)))
|
||||
(call-configuration-manager-method "isAllModerators" (list id))))
|
||||
(let* ((id (username->id username))
|
||||
(reply (send-dbus/configuration-manager
|
||||
#:method "isAllModerators"
|
||||
#:arguments
|
||||
(list (string-append "string:" id)))))
|
||||
(deserialize-item (parse-dbus-reply reply))))
|
||||
|
||||
(define (username->moderators username)
|
||||
"Return the moderators for the account of USERNAME, a registered username or
|
||||
account fingerprint."
|
||||
(let* ((id (username->id username)))
|
||||
(vector->list (call-configuration-manager-method "getDefaultModerators"
|
||||
(list id)))))
|
||||
(let* ((id (username->id username))
|
||||
(reply (send-dbus/configuration-manager
|
||||
#:method "getDefaultModerators"
|
||||
#:arguments
|
||||
(list (string-append "string:" id)))))
|
||||
(array->list (parse-dbus-reply reply))))
|
||||
|
||||
(define (set-moderator contact enabled? username)
|
||||
"Set the moderator flag to ENABLED? for CONTACT, the 40 characters public
|
||||
@@ -278,8 +530,11 @@ key fingerprint of a contact for the account of USERNAME, a registered
|
||||
username or account fingerprint."
|
||||
(validate-fingerprint contact)
|
||||
(let* ((id (username->id username)))
|
||||
(call-configuration-manager-method "setDefaultModerator"
|
||||
(list id contact enabled?))))
|
||||
(send-dbus/configuration-manager #:method "setDefaultModerator"
|
||||
#:arguments
|
||||
(list (string-append "string:" id)
|
||||
(string-append "string:" contact)
|
||||
(serialize-boolean enabled?)))))
|
||||
|
||||
(define (disable-account username)
|
||||
"Disable the account known by USERNAME, a registered username or account
|
||||
@@ -288,7 +543,7 @@ fingerprint."
|
||||
;; Waiting for the reply on this command takes a very
|
||||
;; long time that trips the default D-Bus timeout value
|
||||
;; (25 s), for some reason.
|
||||
#:timeout 60))
|
||||
#:timeout 60000))
|
||||
|
||||
(define (enable-account username)
|
||||
"Enable the account known by USERNAME, a registered username or account
|
||||
@@ -326,3 +581,7 @@ requirements."
|
||||
(fold alist-delete account-details first-items))))
|
||||
|
||||
(string-join (map pair->recutil-property sorted-account-details) "\n"))
|
||||
|
||||
;; Local Variables:
|
||||
;; eval: (put 'with-retries 'scheme-indent-function 2)
|
||||
;; End:
|
||||
|
||||
@@ -589,6 +589,15 @@ upon error."
|
||||
(load-linux-modules-from-directory linux-modules
|
||||
linux-module-directory)
|
||||
|
||||
(unless (or (member "hibernate=noresume" args)
|
||||
;; Also handle the equivalent old-style argument.
|
||||
;; See Documentation/admin-guide/kernel-parameters.txt.
|
||||
(member "noresume" args))
|
||||
;; Try to resume immediately after loading (storage) modules
|
||||
;; but before any on-disk file systems have been mounted.
|
||||
(false-if-exception ; failure is not fatal
|
||||
(resume-if-hibernated (find-long-option "resume" args))))
|
||||
|
||||
(when keymap-file
|
||||
(let ((status (system* "loadkeys" keymap-file)))
|
||||
(unless (zero? status)
|
||||
@@ -622,15 +631,6 @@ the root file system...\n" root-delay)
|
||||
(unless (pre-mount)
|
||||
(error "pre-mount actions failed")))
|
||||
|
||||
(unless (or (member "hibernate=noresume" args)
|
||||
;; Also handle the equivalent old-style argument.
|
||||
;; See Documentation/admin-guide/kernel-parameters.txt.
|
||||
(member "noresume" args))
|
||||
;; Try to resume immediately after loading (storage) modules
|
||||
;; but before any on-disk file systems have been mounted.
|
||||
(false-if-exception ; failure is not fatal
|
||||
(resume-if-hibernated (find-long-option "resume" args))))
|
||||
|
||||
(setenv "EXT2FS_NO_MTAB_OK" "1")
|
||||
|
||||
;; Mount the root file system.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2015 David Thompson <davet@gnu.org>
|
||||
;;; Copyright © 2017-2019, 2022, 2023 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -233,7 +233,7 @@ that host UIDs (respectively GIDs) map to in the namespace."
|
||||
;; The parent process must initialize the user namespace for the child
|
||||
;; before it can boot. To negotiate this, a pipe is used such that the
|
||||
;; child process blocks until the parent writes to it.
|
||||
(match (socketpair PF_UNIX (logior SOCK_CLOEXEC SOCK_STREAM) 0)
|
||||
(match (socketpair PF_UNIX SOCK_STREAM 0)
|
||||
((child . parent)
|
||||
(let ((flags (namespaces->bit-mask namespaces)))
|
||||
(match (clone flags)
|
||||
@@ -301,28 +301,8 @@ delete it when leaving the dynamic extent of this call."
|
||||
(lambda ()
|
||||
(false-if-exception (delete-file-recursively tmp-dir))))))
|
||||
|
||||
(define (wait-child-process)
|
||||
"Wait for one child process and return a pair, like 'waitpid', or return #f
|
||||
if there are no child processes left."
|
||||
(catch 'system-error
|
||||
(lambda ()
|
||||
(waitpid WAIT_ANY))
|
||||
(lambda args
|
||||
(if (= ECHILD (system-error-errno args))
|
||||
#f
|
||||
(apply throw args)))))
|
||||
|
||||
(define (status->exit-status status)
|
||||
"Reify STATUS as an exit status."
|
||||
(or (status:exit-val status)
|
||||
;; See <http://www.tldp.org/LDP/abs/html/exitcodes.html#EXITCODESREF>.
|
||||
(+ 128 (or (status:term-sig status)
|
||||
(status:stop-sig status)))))
|
||||
|
||||
(define* (call-with-container mounts thunk #:key (namespaces %namespaces)
|
||||
(host-uids 1) (guest-uid 0) (guest-gid 0)
|
||||
(relayed-signals (list SIGINT SIGTERM))
|
||||
(child-is-pid1? #t)
|
||||
(process-spawned-hook (const #t)))
|
||||
"Run THUNK in a new container process and return its exit status; call
|
||||
PROCESS-SPAWNED-HOOK with the PID of the new process that has been spawned.
|
||||
@@ -340,71 +320,27 @@ can map more than a single uid/gid.
|
||||
GUEST-UID and GUEST-GID specify the first UID (respectively GID) that host
|
||||
UIDs (respectively GIDs) map to in the namespace.
|
||||
|
||||
RELAYED-SIGNALS is the list of signals that are \"relayed\" to the container
|
||||
process when caught by its parent.
|
||||
|
||||
When CHILD-IS-PID1? is true, and if NAMESPACES contains 'pid', then the child
|
||||
process runs directly as PID 1. As such, it is responsible for (1) installing
|
||||
signal handlers and (2) reaping terminated processes by calling 'waitpid'.
|
||||
When CHILD-IS-PID1? is false, a new intermediate process is created instead
|
||||
that takes this responsibility.
|
||||
|
||||
Note that if THUNK needs to load any additional Guile modules, the relevant
|
||||
module files must be present in one of the mappings in MOUNTS and the Guile
|
||||
load path must be adjusted as needed."
|
||||
(define thunk*
|
||||
(if (and (memq 'pid namespaces)
|
||||
(not child-is-pid1?))
|
||||
(lambda ()
|
||||
;; Behave like an init process: create a sub-process that calls
|
||||
;; THUNK, and wait for child processes. Furthermore, forward
|
||||
;; RELAYED-SIGNALS to the child process.
|
||||
(match (primitive-fork)
|
||||
(0
|
||||
(call-with-clean-exit thunk))
|
||||
(pid
|
||||
(install-signal-handlers pid)
|
||||
(let loop ()
|
||||
(match (wait-child-process)
|
||||
((child . status)
|
||||
(if (= child pid)
|
||||
(primitive-exit (status->exit-status status))
|
||||
(loop)))
|
||||
(#f
|
||||
(primitive-exit 128))))))) ;cannot happen
|
||||
thunk))
|
||||
|
||||
(define (periodically-schedule-asyncs)
|
||||
;; XXX: In Guile there's a time window where a signal-handling async could
|
||||
;; be queued without being processed by the time we enter a blocking
|
||||
;; syscall like waitpid(2) (info "(guile) Signals"). This terrible hack
|
||||
;; ensures pending asyncs get a chance to run periodically.
|
||||
(sigaction SIGALRM (lambda _ (alarm 1)))
|
||||
(alarm 1))
|
||||
|
||||
(define (install-signal-handlers pid)
|
||||
;; Install handlers that forward signals to PID.
|
||||
(define (relay-signal signal)
|
||||
(false-if-exception (kill pid signal)))
|
||||
|
||||
(periodically-schedule-asyncs)
|
||||
(for-each (lambda (signal)
|
||||
(sigaction signal relay-signal))
|
||||
relayed-signals))
|
||||
|
||||
(call-with-temporary-directory
|
||||
(lambda (root)
|
||||
(let ((pid (run-container root mounts namespaces host-uids thunk*
|
||||
(let ((pid (run-container root mounts namespaces host-uids thunk
|
||||
#:guest-uid guest-uid
|
||||
#:guest-gid guest-gid)))
|
||||
(install-signal-handlers pid)
|
||||
;; Catch SIGINT and kill the container process.
|
||||
(sigaction SIGINT
|
||||
(lambda (signum)
|
||||
(false-if-exception
|
||||
(kill pid SIGKILL))))
|
||||
|
||||
(process-spawned-hook pid)
|
||||
(match (waitpid pid)
|
||||
((_ . status) status))))))
|
||||
|
||||
(define (container-excursion pid thunk)
|
||||
"Run THUNK as a child process within the namespaces of process PID and
|
||||
return the exit status, an integer as returned by 'waitpid'."
|
||||
return the exit status."
|
||||
(define (namespace-file pid namespace)
|
||||
(string-append "/proc/" (number->string pid) "/ns/" namespace))
|
||||
|
||||
@@ -432,29 +368,16 @@ return the exit status, an integer as returned by 'waitpid'."
|
||||
'("user" "ipc" "uts" "net" "pid" "mnt"))
|
||||
(purify-environment)
|
||||
(chdir "/")
|
||||
|
||||
;; Per setns(2), changing the PID namespace only applies to child
|
||||
;; processes, not to the process itself. Thus fork so that THUNK runs
|
||||
;; in the right PID namespace, which also gives it access to /proc.
|
||||
(match (primitive-fork)
|
||||
(0 (call-with-clean-exit thunk))
|
||||
(pid (primitive-exit
|
||||
(match (waitpid pid)
|
||||
((_ . status)
|
||||
(or (status:exit-val status) 127)))))))))
|
||||
(thunk))))
|
||||
(pid
|
||||
(match (waitpid pid)
|
||||
((_ . status)
|
||||
status)))))
|
||||
(status:exit-val status))))))
|
||||
|
||||
(define (container-excursion* pid thunk)
|
||||
"Like 'container-excursion', but return the return value of THUNK."
|
||||
(match (pipe)
|
||||
((in . out)
|
||||
;; Make sure IN and OUT are not inherited if THUNK forks + execs.
|
||||
(fcntl in F_SETFD FD_CLOEXEC)
|
||||
(fcntl out F_SETFD FD_CLOEXEC)
|
||||
|
||||
(match (container-excursion pid
|
||||
(lambda ()
|
||||
(close-port in)
|
||||
|
||||
+1
-134
@@ -1,5 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2014, 2016, 2018, 2019, 2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2014, 2016, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
|
||||
;;; Copyright © 2018 Danny Milosavljevic <dannym@scratchpost.org>
|
||||
;;;
|
||||
@@ -28,7 +28,6 @@
|
||||
#:use-module (rnrs io ports)
|
||||
#:use-module (rnrs bytevectors)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-9 gnu)
|
||||
#:use-module (srfi srfi-11)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:use-module (ice-9 ftw)
|
||||
@@ -51,17 +50,6 @@
|
||||
load-linux-module*
|
||||
load-linux-modules-from-directory
|
||||
|
||||
pci-devices
|
||||
pci-device?
|
||||
pci-device-vendor
|
||||
pci-device-id
|
||||
pci-device-class
|
||||
pci-device-module-alias
|
||||
storage-pci-device?
|
||||
network-pci-device?
|
||||
display-pci-device?
|
||||
load-pci-device-database
|
||||
|
||||
current-module-debugging-port
|
||||
|
||||
device-module-aliases
|
||||
@@ -441,127 +429,6 @@ key such as 'MAJOR or 'DEVTYPE and each cdr is the corresponding value."
|
||||
(line
|
||||
(loop (cons (key=value->pair line) result))))))
|
||||
|
||||
;; PCI device known to the Linux kernel.
|
||||
(define-immutable-record-type <pci-device>
|
||||
(pci-device vendor device class module-alias)
|
||||
pci-device?
|
||||
(vendor pci-device-vendor) ;integer
|
||||
(device pci-device-id) ;integer
|
||||
(class pci-device-class) ;integer
|
||||
(module-alias pci-device-module-alias)) ;string | #f
|
||||
|
||||
(define (pci-device-class-predicate mask bits)
|
||||
(lambda (device)
|
||||
"Return true if DEVICE has the chosen class."
|
||||
(= (logand mask (pci-device-class device)) bits)))
|
||||
|
||||
(define storage-pci-device? ;"Mass storage controller" class
|
||||
(pci-device-class-predicate #xff0000 #x010000))
|
||||
(define network-pci-device? ;"Network controller" class
|
||||
(pci-device-class-predicate #xff0000 #x020000))
|
||||
(define display-pci-device? ;"Display controller" class
|
||||
(pci-device-class-predicate #xff0000 #x030000))
|
||||
|
||||
(define (pci-devices)
|
||||
"Return the list of PCI devices of the system (<pci-device> records)."
|
||||
(define (read-hex port)
|
||||
(let ((line (read-line port)))
|
||||
(and (string? line)
|
||||
(string-prefix? "0x" line)
|
||||
(string->number (string-drop line 2) 16))))
|
||||
|
||||
(filter-map (lambda (directory)
|
||||
(define properties
|
||||
(call-with-input-file (string-append directory "/uevent")
|
||||
read-uevent))
|
||||
(define vendor
|
||||
(call-with-input-file (string-append directory "/vendor")
|
||||
read-hex))
|
||||
(define device
|
||||
(call-with-input-file (string-append directory "/device")
|
||||
read-hex))
|
||||
(define class
|
||||
(call-with-input-file (string-append directory "/class")
|
||||
read-hex))
|
||||
|
||||
(pci-device vendor device class
|
||||
(assq-ref properties 'MODALIAS)))
|
||||
(find-files "/sys/bus/pci/devices"
|
||||
#:stat lstat)))
|
||||
|
||||
(define (read-pci-device-database port)
|
||||
"Parse the 'pci.ids' database that ships with the pciutils package and is
|
||||
maintained at <https://pci-ids.ucw.cz/>."
|
||||
(define (comment? str)
|
||||
(string-prefix? "#" (string-trim str)))
|
||||
(define (blank? str)
|
||||
(string-null? (string-trim-both str)))
|
||||
(define (device? str)
|
||||
(eqv? #\tab (string-ref str 0)))
|
||||
(define (subvendor? str)
|
||||
(string-prefix? "\t\t" str))
|
||||
(define (class? str)
|
||||
(string-prefix? "C " str))
|
||||
(define (parse-id-line str)
|
||||
(let* ((str (string-trim-both str))
|
||||
(space (string-index str char-set:whitespace)))
|
||||
(values (string->number (string-take str space) 16)
|
||||
(string-trim (string-drop str (+ 1 space))))))
|
||||
(define (finish vendor vendor-id devices table)
|
||||
(fold (lambda (device table)
|
||||
(match device
|
||||
((device-id . name)
|
||||
(vhash-consv (logior (ash vendor-id 16) device-id)
|
||||
(cons vendor name)
|
||||
table))))
|
||||
table
|
||||
devices))
|
||||
|
||||
(let loop ((table vlist-null)
|
||||
(vendor-id #f)
|
||||
(vendor #f)
|
||||
(devices '()))
|
||||
(match (read-line port)
|
||||
((? eof-object?)
|
||||
(let ((table (if (and vendor vendor-id)
|
||||
(finish vendor vendor-id devices table)
|
||||
table)))
|
||||
(lambda (vendor device)
|
||||
(match (vhash-assv (logior (ash vendor 16) device) table)
|
||||
(#f
|
||||
(values #f #f))
|
||||
((_ . (vendor . name))
|
||||
(values vendor name))))))
|
||||
((? comment?)
|
||||
(loop table vendor-id vendor devices))
|
||||
((? blank?)
|
||||
(loop table vendor-id vendor devices))
|
||||
((? subvendor?) ;currently ignored
|
||||
(loop table vendor-id vendor devices))
|
||||
((? class?) ;currently ignored
|
||||
(loop table vendor-id vendor devices))
|
||||
((? device? line)
|
||||
(let-values (((id name) (parse-id-line line)))
|
||||
(loop table vendor-id vendor
|
||||
(if (and vendor-id vendor) ;class or device?
|
||||
(alist-cons id name devices)
|
||||
devices))))
|
||||
(line
|
||||
(let ((table (if (and vendor vendor-id)
|
||||
(finish vendor vendor-id devices table)
|
||||
table)))
|
||||
(let-values (((vendor-id vendor) (parse-id-line line)))
|
||||
(loop table vendor-id vendor '())))))))
|
||||
|
||||
(define (load-pci-device-database file)
|
||||
"Read the 'pci.ids' database at FILE (get it from the pciutils package or
|
||||
from <https://pci-ids.ucw.cz/>) and return a lookup procedure that takes a PCI
|
||||
vendor ID and a device ID (two integers) and returns the vendor name and
|
||||
device name as two values."
|
||||
(let ((port (open-file file "r0")))
|
||||
(call-with-gzip-input-port port
|
||||
read-pci-device-database)))
|
||||
|
||||
(define (device-module-aliases device)
|
||||
"Return the list of module aliases required by DEVICE, a /dev file name, as
|
||||
in this example:
|
||||
|
||||
+58
-144
@@ -1,8 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2016-2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2018 Chris Marusich <cmmarusich@gmail.com>
|
||||
;;; Copyright © 2022, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -23,21 +21,19 @@
|
||||
#:use-module (srfi srfi-9)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:use-module (srfi srfi-64)
|
||||
#:use-module (srfi srfi-71)
|
||||
#:use-module (rnrs io ports)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (ice-9 popen)
|
||||
#:use-module (ice-9 regex)
|
||||
#:export (marionette?
|
||||
marionette-pid
|
||||
make-marionette
|
||||
marionette-eval
|
||||
wait-for-file
|
||||
wait-for-tcp-port
|
||||
wait-for-unix-socket
|
||||
marionette-control
|
||||
marionette-screen-text
|
||||
wait-for-screen-text
|
||||
%default-ocrad-arguments
|
||||
%qwerty-us-keystrokes
|
||||
marionette-type
|
||||
|
||||
@@ -109,14 +105,11 @@ QEMU monitor and to the guest's backdoor REPL."
|
||||
"-monitor" (string-append "unix:" socket-directory "/monitor")
|
||||
"-chardev" (string-append "socket,id=repl,path=" socket-directory
|
||||
"/repl")
|
||||
"-chardev" (string-append "socket,id=qga,server=on,wait=off,path="
|
||||
socket-directory "/qemu-ga")
|
||||
|
||||
;; See
|
||||
;; <http://www.linux-kvm.org/page/VMchannel_Requirements#Invocation>.
|
||||
"-device" "virtio-serial"
|
||||
"-device" "virtserialport,chardev=repl,name=org.gnu.guix.port.0"
|
||||
"-device" "virtserialport,chardev=qga,name=org.qemu.guest_agent.0"))
|
||||
"-device" "virtserialport,chardev=repl,name=org.gnu.guix.port.0"))
|
||||
|
||||
(define (accept* port)
|
||||
(match (select (list port) '() (list port) timeout)
|
||||
@@ -181,18 +174,7 @@ QEMU monitor and to the guest's backdoor REPL."
|
||||
(($ <marionette> command pid monitor (= force repl))
|
||||
(write exp repl)
|
||||
(newline repl)
|
||||
(with-exception-handler
|
||||
(lambda (exn)
|
||||
(simple-format
|
||||
(current-error-port)
|
||||
"error reading marionette response: ~A
|
||||
remaining response: ~A\n"
|
||||
exn
|
||||
(get-line repl))
|
||||
(raise-exception exn))
|
||||
(lambda ()
|
||||
(read repl))
|
||||
#:unwind? #t))))
|
||||
(read repl))))
|
||||
|
||||
(define* (wait-for-file file marionette
|
||||
#:key (timeout 10) (read 'read))
|
||||
@@ -201,14 +183,7 @@ FILE has not shown up after TIMEOUT seconds, raise an error."
|
||||
(match (marionette-eval
|
||||
`(let loop ((i ,timeout))
|
||||
(cond ((file-exists? ,file)
|
||||
(cons 'success
|
||||
(let ((content
|
||||
(call-with-input-file ,file ,read)))
|
||||
(if (eof-object? content)
|
||||
;; #<eof> can't be read, so convert to the
|
||||
;; empty string
|
||||
""
|
||||
content))))
|
||||
(cons 'success (call-with-input-file ,file ,read)))
|
||||
((> i 0)
|
||||
(sleep 1)
|
||||
(loop (- i 1)))
|
||||
@@ -221,38 +196,31 @@ FILE has not shown up after TIMEOUT seconds, raise an error."
|
||||
(error "file didn't show up" file))))
|
||||
|
||||
(define* (wait-for-tcp-port port marionette
|
||||
#:key
|
||||
(timeout 20)
|
||||
(address `(make-socket-address AF_INET
|
||||
INADDR_LOOPBACK
|
||||
,port)))
|
||||
#:key (timeout 20))
|
||||
"Wait for up to TIMEOUT seconds for PORT to accept connections in
|
||||
MARIONETTE. ADDRESS must be an expression that returns a socket address,
|
||||
typically a call to 'make-socket-address'. Raise an error on failure."
|
||||
MARIONETTE. Raise an error on failure."
|
||||
;; Note: The 'connect' loop has to run within the guest because, when we
|
||||
;; forward ports to the host, connecting to the host never raises
|
||||
;; ECONNREFUSED.
|
||||
(match (marionette-eval
|
||||
`(let* ((address ,address)
|
||||
(sock (socket (sockaddr:fam address) SOCK_STREAM 0)))
|
||||
(let loop ((i 0))
|
||||
(catch 'system-error
|
||||
(lambda ()
|
||||
(connect sock address)
|
||||
(close-port sock)
|
||||
'success)
|
||||
(lambda args
|
||||
(if (< i ,timeout)
|
||||
(begin
|
||||
(sleep 1)
|
||||
(loop (+ 1 i)))
|
||||
(list 'failure address))))))
|
||||
`(begin
|
||||
(let ((sock (socket PF_INET SOCK_STREAM 0)))
|
||||
(let loop ((i 0))
|
||||
(catch 'system-error
|
||||
(lambda ()
|
||||
(connect sock AF_INET INADDR_LOOPBACK ,port)
|
||||
(close-port sock)
|
||||
'success)
|
||||
(lambda args
|
||||
(if (< i ,timeout)
|
||||
(begin
|
||||
(sleep 1)
|
||||
(loop (+ 1 i)))
|
||||
'failure))))))
|
||||
marionette)
|
||||
('success #t)
|
||||
(('failure address)
|
||||
(error "nobody's listening on port"
|
||||
(list (inet-ntop (sockaddr:fam address) (sockaddr:addr address))
|
||||
(sockaddr:port address))))))
|
||||
('failure
|
||||
(error "nobody's listening on port" port))))
|
||||
|
||||
(define* (wait-for-unix-socket file-name marionette
|
||||
#:key (timeout 20))
|
||||
@@ -280,8 +248,8 @@ accept connections in MARIONETTE. Raise an error on failure."
|
||||
|
||||
(define (marionette-control command marionette)
|
||||
"Run COMMAND in the QEMU monitor of MARIONETTE. COMMAND is a string such as
|
||||
\"sendkey ctrl-alt-f1\" or \"screendump foo.ppm\" (info \"(QEMU) QEMU
|
||||
Monitor\")."
|
||||
\"sendkey ctrl-alt-f1\" or \"screendump foo.ppm\" (info \"(qemu-doc)
|
||||
pcsys_monitor\")."
|
||||
(match marionette
|
||||
(($ <marionette> _ _ monitor)
|
||||
(display command monitor)
|
||||
@@ -289,106 +257,54 @@ Monitor\")."
|
||||
;; The "quit" command terminates QEMU immediately, with no output.
|
||||
(unless (string=? command "quit") (wait-for-monitor-prompt monitor)))))
|
||||
|
||||
(define %default-ocrad-arguments
|
||||
'("--invert" "--scale=10"))
|
||||
(define* (marionette-screen-text marionette
|
||||
#:key
|
||||
(ocrad "ocrad"))
|
||||
"Take a screenshot of MARIONETTE, perform optical character
|
||||
recognition (OCR), and return the text read from the screen as a string. Do
|
||||
this by invoking OCRAD (file name for GNU Ocrad's command)"
|
||||
(define (random-file-name)
|
||||
(string-append "/tmp/marionette-screenshot-"
|
||||
(number->string (random (expt 2 32)) 16)
|
||||
".ppm"))
|
||||
|
||||
(define* (invoke-ocrad-ocr image #:key (ocrad "ocrad")
|
||||
(ocr-arguments %default-ocrad-arguments))
|
||||
"Invoke the OCRAD command on image, and return the recognized text."
|
||||
(let* ((command (string-join `(,ocrad ,@ocr-arguments ,image)))
|
||||
(pipe (open-input-pipe command))
|
||||
(text (get-string-all pipe)))
|
||||
(unless (zero? (close-pipe pipe))
|
||||
(error "'ocrad' failed" ocrad))
|
||||
text))
|
||||
|
||||
(define* (invoke-tesseract-ocr image #:key (tesseract "tesseract")
|
||||
(ocr-arguments '()))
|
||||
"Invoke the TESSERACT command on IMAGE, and return the recognized text."
|
||||
(let* ((output-basename (tmpnam))
|
||||
(output-basename* (string-append output-basename ".txt"))
|
||||
(arguments (cons* image output-basename ocr-arguments)))
|
||||
(let ((image (random-file-name)))
|
||||
(dynamic-wind
|
||||
(const #t)
|
||||
(lambda ()
|
||||
(let ((exit-val (status:exit-val
|
||||
(apply system* tesseract arguments))))
|
||||
(unless (zero? exit-val)
|
||||
(error "'tesseract' failed" tesseract))
|
||||
(call-with-input-file output-basename* get-string-all)))
|
||||
(lambda ()
|
||||
(false-if-exception (delete-file output-basename))
|
||||
(false-if-exception (delete-file output-basename*))))))
|
||||
(marionette-control (string-append "screendump " image)
|
||||
marionette)
|
||||
|
||||
(define* (marionette-screen-text marionette #:key (ocr "ocrad")
|
||||
ocr-arguments)
|
||||
"Take a screenshot of MARIONETTE, perform optical character
|
||||
recognition (OCR), and return the text read from the screen as a string, along
|
||||
the screen dump image used. Do this by invoking OCR, which should be the file
|
||||
name of GNU Ocrad's@command{ocrad} or Tesseract OCR's @command{tesseract}
|
||||
command. The screen dump image returned as the second value should be deleted
|
||||
if it is not needed."
|
||||
(define image (string-append (tmpnam) ".ppm"))
|
||||
;; Use the QEMU Monitor to save an image of the screen to the host.
|
||||
(marionette-control (string-append "screendump " image) marionette)
|
||||
;; Process it via the OCR.
|
||||
(cond
|
||||
((string-contains ocr "ocrad")
|
||||
(values (invoke-ocrad-ocr image
|
||||
#:ocrad ocr
|
||||
#:ocr-arguments
|
||||
(or ocr-arguments %default-ocrad-arguments))
|
||||
image))
|
||||
((string-contains ocr "tesseract")
|
||||
(values (invoke-tesseract-ocr image
|
||||
#:tesseract ocr
|
||||
#:ocr-arguments (or ocr-arguments '()))
|
||||
image))
|
||||
(else (error "unsupported ocr command"))))
|
||||
;; Tell Ocrad to invert the image colors (make it black on white) and
|
||||
;; to scale the image up, which significantly improves the quality of
|
||||
;; the result. In spite of this, be aware that OCR confuses "y" and
|
||||
;; "V" and sometimes erroneously introduces white space.
|
||||
(let* ((pipe (open-pipe* OPEN_READ ocrad
|
||||
"-i" "-s" "10" image))
|
||||
(text (get-string-all pipe)))
|
||||
(unless (zero? (close-pipe pipe))
|
||||
(error "'ocrad' failed" ocrad))
|
||||
text))
|
||||
(lambda ()
|
||||
(false-if-exception (delete-file image))))))
|
||||
|
||||
(define* (wait-for-screen-text marionette predicate
|
||||
#:key
|
||||
(ocr "ocrad")
|
||||
ocr-arguments
|
||||
(timeout 30)
|
||||
pre-action
|
||||
post-action)
|
||||
#:key (timeout 30) (ocrad "ocrad"))
|
||||
"Wait for TIMEOUT seconds or until the screen text on MARIONETTE matches
|
||||
PREDICATE, whichever comes first. Raise an error when TIMEOUT is exceeded.
|
||||
The error contains the recognized text along the preserved file name of the
|
||||
screen dump, which is relative to the current working directory. If
|
||||
PRE-ACTION is provided, it should be a thunk to call before each OCR attempt.
|
||||
Likewise for POST-ACTION, except it runs at the end of a successful OCR."
|
||||
PREDICATE, whichever comes first. Raise an error when TIMEOUT is exceeded."
|
||||
(define start
|
||||
(car (gettimeofday)))
|
||||
|
||||
(define end
|
||||
(+ start timeout))
|
||||
|
||||
(let loop ((last-text #f)
|
||||
(last-screendump #f))
|
||||
(let loop ()
|
||||
(if (> (car (gettimeofday)) end)
|
||||
(let ((screendump-backup (string-drop last-screendump 5)))
|
||||
;; Move the file from /tmp/fileXXXXXX.pmm to the current working
|
||||
;; directory, so that it is preserved in the test derivation output.
|
||||
(copy-file last-screendump screendump-backup)
|
||||
(delete-file last-screendump)
|
||||
(error "'wait-for-screen-text' timeout"
|
||||
'ocr-text: last-text
|
||||
'screendump: screendump-backup))
|
||||
(let* ((_ (and (procedure? pre-action) (pre-action)))
|
||||
(text screendump
|
||||
(marionette-screen-text marionette
|
||||
#:ocr ocr
|
||||
#:ocr-arguments ocr-arguments))
|
||||
(_ (and (procedure? post-action) (post-action)))
|
||||
(result (predicate text)))
|
||||
(cond (result
|
||||
(delete-file screendump)
|
||||
result)
|
||||
(else
|
||||
(sleep 1)
|
||||
(loop text screendump)))))))
|
||||
(error "'wait-for-screen-text' timeout" predicate)
|
||||
(or (predicate (marionette-screen-text marionette #:ocrad ocrad))
|
||||
(begin
|
||||
(sleep 1)
|
||||
(loop))))))
|
||||
|
||||
(define %qwerty-us-keystrokes
|
||||
;; Maps "special" characters to their keystrokes.
|
||||
@@ -410,10 +326,8 @@ Likewise for POST-ACTION, except it runs at the end of a successful OCR."
|
||||
(#\> . "shift-dot")
|
||||
(#\. . "dot")
|
||||
(#\, . "comma")
|
||||
(#\: . "shift-semicolon")
|
||||
(#\; . "semicolon")
|
||||
(#\' . "apostrophe")
|
||||
(#\! . "shift-1")
|
||||
(#\" . "shift-apostrophe")
|
||||
(#\` . "grave_accent")
|
||||
(#\bs . "backspace")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2020-2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2020, 2021 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
@@ -47,52 +47,6 @@
|
||||
;; to syslog.
|
||||
#'(format (current-output-port) fmt args ...))))))
|
||||
|
||||
(define-syntax with-modules
|
||||
(syntax-rules ()
|
||||
"Dynamically load the given MODULEs at run time, making the chosen
|
||||
bindings available within the lexical scope of BODY."
|
||||
((_ ((module #:select (bindings ...)) rest ...) body ...)
|
||||
(let* ((iface (resolve-interface 'module))
|
||||
(bindings (module-ref iface 'bindings))
|
||||
...)
|
||||
(with-modules (rest ...) body ...)))
|
||||
((_ () body ...)
|
||||
(begin body ...))))
|
||||
|
||||
(define (wait-for-readable-fd port timeout)
|
||||
"Wait until PORT has data available for reading or TIMEOUT has expired.
|
||||
Return #t in the former case and #f in the latter case."
|
||||
(match (resolve-module '(fibers) #f #:ensure #f) ;using Fibers?
|
||||
(#f
|
||||
(log "blocking on socket...~%")
|
||||
(match (select (list port) '() '() timeout)
|
||||
(((_) () ()) #t)
|
||||
((() () ()) #f)))
|
||||
(fibers
|
||||
;; We're running on the Shepherd 0.9+ with Fibers. Arrange to make a
|
||||
;; non-blocking wait so that other fibers can be scheduled in while we
|
||||
;; wait for PORT.
|
||||
(with-modules (((fibers) #:select (spawn-fiber sleep))
|
||||
((fibers channels)
|
||||
#:select (make-channel put-message get-message)))
|
||||
;; Make PORT non-blocking.
|
||||
(let ((flags (fcntl port F_GETFL)))
|
||||
(fcntl port F_SETFL (logior O_NONBLOCK flags)))
|
||||
|
||||
(let ((channel (make-channel)))
|
||||
(spawn-fiber
|
||||
(lambda ()
|
||||
(sleep timeout) ;suspends the fiber
|
||||
(put-message channel 'timeout)))
|
||||
(spawn-fiber
|
||||
(lambda ()
|
||||
(lookahead-u8 port) ;suspends the fiber
|
||||
(put-message channel 'readable)))
|
||||
(log "suspending fiber on socket...~%")
|
||||
(match (get-message channel)
|
||||
('readable #t)
|
||||
('timeout #f)))))))
|
||||
|
||||
(define* (secret-service-send-secrets port secret-root
|
||||
#:key (retry 60)
|
||||
(handshake-timeout 120))
|
||||
@@ -119,11 +73,8 @@ wait for at most HANDSHAKE-TIMEOUT seconds for handshake to complete. Return
|
||||
files)))
|
||||
|
||||
(log "sending secrets to ~a~%" port)
|
||||
(let ((sock (socket AF_INET (logior SOCK_CLOEXEC SOCK_STREAM) 0))
|
||||
(addr (make-socket-address AF_INET INADDR_LOOPBACK port))
|
||||
(sleep (if (resolve-module '(fibers) #f)
|
||||
(module-ref (resolve-interface '(fibers)) 'sleep)
|
||||
sleep)))
|
||||
(let ((sock (socket AF_INET SOCK_STREAM 0))
|
||||
(addr (make-socket-address AF_INET INADDR_LOOPBACK port)))
|
||||
;; Connect to QEMU on the forwarded port. The 'connect' call succeeds as
|
||||
;; soon as QEMU is ready, even if there's no server listening on the
|
||||
;; forward port inside the guest.
|
||||
@@ -142,22 +93,23 @@ wait for at most HANDSHAKE-TIMEOUT seconds for handshake to complete. Return
|
||||
|
||||
;; Wait for "hello" message from the server. This is the only way to know
|
||||
;; that we're really connected to the server inside the guest.
|
||||
(if (wait-for-readable-fd sock handshake-timeout)
|
||||
(match (read sock)
|
||||
(('secret-service-server ('version version ...))
|
||||
(log "sending files from ~s...~%" secret-root)
|
||||
(send-files sock)
|
||||
(log "done sending files to port ~a~%" port)
|
||||
(close-port sock)
|
||||
secret-root)
|
||||
(x
|
||||
(log "invalid handshake ~s~%" x)
|
||||
(close-port sock)
|
||||
#f))
|
||||
(begin ;timeout
|
||||
(log "timeout while sending files to ~a~%" port)
|
||||
(close-port sock)
|
||||
#f))))
|
||||
(match (select (list sock) '() '() handshake-timeout)
|
||||
(((_) () ())
|
||||
(match (read sock)
|
||||
(('secret-service-server ('version version ...))
|
||||
(log "sending files from ~s...~%" secret-root)
|
||||
(send-files sock)
|
||||
(log "done sending files to port ~a~%" port)
|
||||
(close-port sock)
|
||||
secret-root)
|
||||
(x
|
||||
(log "invalid handshake ~s~%" x)
|
||||
(close-port sock)
|
||||
#f)))
|
||||
((() () ()) ;timeout
|
||||
(log "timeout while sending files to ~a~%" port)
|
||||
(close-port sock)
|
||||
#f))))
|
||||
|
||||
(define (delete-file* file)
|
||||
"Ensure FILE does not exist."
|
||||
@@ -177,7 +129,7 @@ and #f otherwise."
|
||||
;; Wait for a TCP connection on PORT. Note: We cannot use the
|
||||
;; virtio-serial ports, which would be safer, because they are
|
||||
;; (presumably) unsupported on GNU/Hurd.
|
||||
(let ((sock (socket AF_INET (logior SOCK_CLOEXEC SOCK_STREAM) 0)))
|
||||
(let ((sock (socket AF_INET SOCK_STREAM 0)))
|
||||
(bind sock AF_INET INADDR_ANY port)
|
||||
(listen sock 1)
|
||||
(log "waiting for secrets on port ~a...~%" port)
|
||||
@@ -250,8 +202,4 @@ and #f otherwise."
|
||||
(close-port port))
|
||||
result))
|
||||
|
||||
;;; Local Variables:
|
||||
;;; eval: (put 'with-modules 'scheme-indent-function 1)
|
||||
;;; End:
|
||||
|
||||
;;; secret-service.scm ends here
|
||||
|
||||
+31
-64
@@ -1,8 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2017, 2018, 2019, 2020, 2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2020 Mathieu Othacehe <othacehe@gnu.org>
|
||||
;;; Copyright © 2022 Leo Nikkilä <hello@lnikki.la>
|
||||
;;; Copyright © 2022 Arun Isaac <arunisaac@systemreboot.net>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -32,8 +30,7 @@
|
||||
exec-command
|
||||
%precious-signals)
|
||||
#:autoload (shepherd system) (unblock-signals)
|
||||
#:export (default-mounts
|
||||
make-forkexec-constructor/container
|
||||
#:export (make-forkexec-constructor/container
|
||||
fork+exec-command/container))
|
||||
|
||||
;;; Commentary:
|
||||
@@ -106,13 +103,8 @@
|
||||
separate mount and PID name space. Return the \"outer\" PID. "
|
||||
(match (container-excursion* pid
|
||||
(lambda ()
|
||||
;; XXX: Trick for Shepherd 0.9: prevent 'read-pid-file' from
|
||||
;; using (@ (fibers) sleep), which would try to suspend the
|
||||
;; current task, which doesn't work in this extra process.
|
||||
(with-continuation-barrier
|
||||
(lambda ()
|
||||
(read-pid-file pid-file
|
||||
#:max-delay max-delay)))))
|
||||
(read-pid-file pid-file
|
||||
#:max-delay max-delay)))
|
||||
(#f
|
||||
;; Send SIGTERM to the whole process group.
|
||||
(catch-system-error (kill (- pid) SIGTERM))
|
||||
@@ -122,28 +114,6 @@ separate mount and PID name space. Return the \"outer\" PID. "
|
||||
;; PID is always 1, but that's not what Shepherd needs to know.
|
||||
pid)))
|
||||
|
||||
(define* (exec-command* command #:key user group log-file pid-file
|
||||
(supplementary-groups '())
|
||||
(directory "/") (environment-variables (environ)))
|
||||
"Like 'exec-command', but first restore signal handles modified by
|
||||
shepherd (PID 1)."
|
||||
;; First restore the default handlers.
|
||||
(for-each (cut sigaction <> SIG_DFL) %precious-signals)
|
||||
|
||||
;; Unblock any signals that have been blocked by the parent process.
|
||||
(unblock-signals %precious-signals)
|
||||
|
||||
(mkdir-p "/var/run")
|
||||
(clean-up pid-file)
|
||||
|
||||
(exec-command command
|
||||
#:user user
|
||||
#:group group
|
||||
#:supplementary-groups supplementary-groups
|
||||
#:log-file log-file
|
||||
#:directory directory
|
||||
#:environment-variables environment-variables))
|
||||
|
||||
(define* (make-forkexec-constructor/container command
|
||||
#:key
|
||||
(namespaces
|
||||
@@ -151,7 +121,6 @@ shepherd (PID 1)."
|
||||
(mappings '())
|
||||
(user #f)
|
||||
(group #f)
|
||||
(supplementary-groups '())
|
||||
(log-file #f)
|
||||
pid-file
|
||||
(pid-file-timeout 5)
|
||||
@@ -187,7 +156,7 @@ namespace, in addition to essential bind-mounts such /proc."
|
||||
(when log-file
|
||||
;; Create LOG-FILE so we can map it in the container.
|
||||
(unless (file-exists? log-file)
|
||||
(close (open log-file (logior O_CREAT O_APPEND O_CLOEXEC) #o640))
|
||||
(call-with-output-file log-file (const #t))
|
||||
(when user
|
||||
(let ((pw (getpwnam user)))
|
||||
(chown log-file (passwd:uid pw) (passwd:gid pw))))))
|
||||
@@ -195,16 +164,24 @@ namespace, in addition to essential bind-mounts such /proc."
|
||||
(let ((pid (run-container container-directory
|
||||
mounts namespaces 1
|
||||
(lambda ()
|
||||
(exec-command* command
|
||||
#:user user
|
||||
#:group group
|
||||
#:supplementary-groups
|
||||
supplementary-groups
|
||||
#:pid-file pid-file
|
||||
#:log-file log-file
|
||||
#:directory directory
|
||||
#:environment-variables
|
||||
environment-variables)))))
|
||||
;; First restore the default handlers.
|
||||
(for-each (cut sigaction <> SIG_DFL)
|
||||
%precious-signals)
|
||||
|
||||
;; Unblock any signals that have been blocked
|
||||
;; by the parent process.
|
||||
(unblock-signals %precious-signals)
|
||||
|
||||
(mkdir-p "/var/run")
|
||||
(clean-up pid-file)
|
||||
|
||||
(exec-command command
|
||||
#:user user
|
||||
#:group group
|
||||
#:log-file log-file
|
||||
#:directory directory
|
||||
#:environment-variables
|
||||
environment-variables)))))
|
||||
(if pid-file
|
||||
(if (or (memq 'mnt namespaces) (memq 'pid namespaces))
|
||||
(read-pid-file/container pid pid-file
|
||||
@@ -232,24 +209,14 @@ on Hurd systems for instance, fallback to direct forking."
|
||||
((head . rest)
|
||||
(loop rest (cons head result))))))
|
||||
|
||||
(let ((container-support? (file-exists? "/proc/self/ns")))
|
||||
(if (and container-support?
|
||||
(not (and pid (= pid (getpid)))))
|
||||
(container-excursion* pid
|
||||
(lambda ()
|
||||
;; Note: In the Shepherd 0.9, 'fork+exec-command' expects to be
|
||||
;; called from the shepherd process (because it creates a pipe to
|
||||
;; capture stdout/stderr and spawns a logging fiber) so we cannot
|
||||
;; use it here.
|
||||
(match (primitive-fork)
|
||||
(0 (dynamic-wind
|
||||
(const #t)
|
||||
(lambda ()
|
||||
(apply exec-command* command (strip-pid args)))
|
||||
(lambda ()
|
||||
(primitive-_exit 127))))
|
||||
(pid pid)))) ;XXX: assuming the same PID namespace
|
||||
(apply fork+exec-command command (strip-pid args)))))
|
||||
(let ((container-support?
|
||||
(file-exists? "/proc/self/ns"))
|
||||
(fork-proc (lambda ()
|
||||
(apply fork+exec-command command
|
||||
(strip-pid args)))))
|
||||
(if container-support?
|
||||
(container-excursion* pid fork-proc)
|
||||
(fork-proc))))
|
||||
|
||||
;; Local Variables:
|
||||
;; eval: (put 'container-excursion* 'scheme-indent-function 1)
|
||||
|
||||
+117
-81
@@ -1,5 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2012-2023 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2012-2021 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2017, 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||
;;; Copyright © 2018, 2019 Clément Lassieur <clement@lassieur.org>
|
||||
;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
|
||||
@@ -21,17 +21,18 @@
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu ci)
|
||||
#:use-module (guix build-system channel)
|
||||
#:use-module (guix channels)
|
||||
#:use-module (guix config)
|
||||
#:autoload (guix describe) (package-channels)
|
||||
#:use-module (guix memoization)
|
||||
#:use-module (guix describe)
|
||||
#:use-module (guix store)
|
||||
#:use-module (guix grafts)
|
||||
#:use-module (guix profiles)
|
||||
#:use-module (guix packages)
|
||||
#:autoload (guix transformations) (tunable-package? tuned-package)
|
||||
#:use-module (guix channels)
|
||||
#:use-module (guix config)
|
||||
#:use-module (guix derivations)
|
||||
#:use-module (guix build-system)
|
||||
#:use-module (guix monads)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix ui)
|
||||
@@ -40,14 +41,12 @@
|
||||
#:use-module ((guix utils) #:select (%current-system))
|
||||
#:use-module ((guix scripts system) #:select (read-operating-system))
|
||||
#:use-module ((guix scripts pack)
|
||||
#:select (self-contained-tarball))
|
||||
#:select (lookup-compressor self-contained-tarball))
|
||||
#:use-module (gnu bootloader)
|
||||
#:use-module (gnu bootloader u-boot)
|
||||
#:use-module (gnu compression)
|
||||
#:use-module (gnu image)
|
||||
#:use-module (gnu packages)
|
||||
#:use-module (gnu packages gcc)
|
||||
#:use-module (gnu packages gdb)
|
||||
#:use-module (gnu packages base)
|
||||
#:use-module (gnu packages gawk)
|
||||
#:use-module (gnu packages guile)
|
||||
@@ -56,7 +55,6 @@
|
||||
#:use-module (gnu packages multiprecision)
|
||||
#:use-module (gnu packages make-bootstrap)
|
||||
#:use-module (gnu packages package-management)
|
||||
#:use-module (guix platform)
|
||||
#:use-module (gnu system)
|
||||
#:use-module (gnu system image)
|
||||
#:use-module (gnu system vm)
|
||||
@@ -73,6 +71,8 @@
|
||||
image->job
|
||||
|
||||
%core-packages
|
||||
%cross-targets
|
||||
channel-source->package
|
||||
|
||||
arguments->systems
|
||||
cuirass-jobs))
|
||||
@@ -139,7 +139,7 @@ SYSTEM."
|
||||
;; Note: Don't put the '-final' package variants because (1) that's
|
||||
;; implicit, and (2) they cannot be cross-built (due to the explicit input
|
||||
;; chain.)
|
||||
(list gcc-10 gcc-11 gcc-12 glibc binutils gdb-minimal
|
||||
(list gcc-8 gcc-9 gcc-10 gcc-11 glibc binutils
|
||||
gmp mpfr mpc coreutils findutils diffutils patch sed grep
|
||||
gawk gnu-gettext hello guile-2.2 guile-3.0 zlib gzip xz guix
|
||||
%bootstrap-binaries-tarball
|
||||
@@ -169,6 +169,17 @@ SYSTEM."
|
||||
(drop-right %core-packages 6)
|
||||
%core-packages))
|
||||
|
||||
(define %cross-targets
|
||||
'("mips64el-linux-gnu"
|
||||
"arm-linux-gnueabihf"
|
||||
"aarch64-linux-gnu"
|
||||
"powerpc-linux-gnu"
|
||||
"powerpc64le-linux-gnu"
|
||||
"riscv64-linux-gnu"
|
||||
"i586-pc-gnu" ;aka. GNU/Hurd
|
||||
"i686-w64-mingw32"
|
||||
"x86_64-w64-mingw32"))
|
||||
|
||||
(define (cross-jobs store system)
|
||||
"Return a list of cross-compilation jobs for SYSTEM."
|
||||
(define (from-32-to-64? target)
|
||||
@@ -210,7 +221,7 @@ SYSTEM."
|
||||
package target system))
|
||||
(packages-to-cross-build target)))
|
||||
(remove (either from-32-to-64? same? pointless?)
|
||||
(targets))))
|
||||
%cross-targets)))
|
||||
|
||||
(define* (guix-jobs store systems #:key source commit)
|
||||
"Return a list of jobs for Guix itself."
|
||||
@@ -253,44 +264,77 @@ otherwise use the IMAGE name."
|
||||
(drv (run-with-store store
|
||||
(mbegin %store-monad
|
||||
(set-guile-for-build (default-guile))
|
||||
(lower-object (system-image image) system)))))
|
||||
(lower-object (system-image image))))))
|
||||
(parameterize ((%graft? #f))
|
||||
(derivation->job name drv))))
|
||||
|
||||
(define* (image-jobs store system
|
||||
#:key source commit)
|
||||
(define (image-jobs store system)
|
||||
"Return a list of jobs that build images for SYSTEM."
|
||||
(define MiB
|
||||
(expt 2 20))
|
||||
|
||||
(parameterize ((current-guix-package
|
||||
(channel-source->package source #:commit commit)))
|
||||
(if (member system %guix-system-supported-systems)
|
||||
`(,(image->job store
|
||||
(image
|
||||
(inherit efi-disk-image)
|
||||
(operating-system installation-os))
|
||||
#:name "usb-image"
|
||||
#:system system)
|
||||
,(image->job
|
||||
store
|
||||
(image
|
||||
(inherit (image-with-label
|
||||
iso9660-image
|
||||
(string-append "GUIX_" system "_"
|
||||
(if (> (string-length %guix-version) 7)
|
||||
(substring %guix-version 0 7)
|
||||
%guix-version))))
|
||||
(operating-system installation-os))
|
||||
#:name "iso9660-image"
|
||||
#:system system)
|
||||
;; Only cross-compile Guix System images from x86_64-linux for now.
|
||||
,@(if (string=? system "x86_64-linux")
|
||||
(map (cut image->job store <>
|
||||
#:system system)
|
||||
%guix-system-images)
|
||||
'()))
|
||||
'())))
|
||||
(if (member system %guix-system-supported-systems)
|
||||
`(,(image->job store
|
||||
(image
|
||||
(inherit efi-disk-image)
|
||||
(operating-system installation-os))
|
||||
#:name "usb-image"
|
||||
#:system system)
|
||||
,(image->job
|
||||
store
|
||||
(image
|
||||
(inherit (image-with-label
|
||||
iso9660-image
|
||||
(string-append "GUIX_" system "_"
|
||||
(if (> (string-length %guix-version) 7)
|
||||
(substring %guix-version 0 7)
|
||||
%guix-version))))
|
||||
(operating-system installation-os))
|
||||
#:name "iso9660-image"
|
||||
#:system system)
|
||||
;; Only cross-compile Guix System images from x86_64-linux for now.
|
||||
,@(if (string=? system "x86_64-linux")
|
||||
(map (cut image->job store <>
|
||||
#:system system)
|
||||
%guix-system-images)
|
||||
'()))
|
||||
'()))
|
||||
|
||||
(define channel-build-system
|
||||
;; Build system used to "convert" a channel instance to a package.
|
||||
(let* ((build (lambda* (name inputs
|
||||
#:key source commit system
|
||||
#:allow-other-keys)
|
||||
(mlet* %store-monad ((source (if (string? source)
|
||||
(return source)
|
||||
(lower-object source)))
|
||||
(instance
|
||||
-> (checkout->channel-instance
|
||||
source #:commit commit)))
|
||||
(channel-instances->derivation (list instance)))))
|
||||
(lower (lambda* (name #:key system source commit
|
||||
#:allow-other-keys)
|
||||
(bag
|
||||
(name name)
|
||||
(system system)
|
||||
(build build)
|
||||
(arguments `(#:source ,source
|
||||
#:commit ,commit))))))
|
||||
(build-system (name 'channel)
|
||||
(description "Turn a channel instance into a package.")
|
||||
(lower lower))))
|
||||
|
||||
(define* (channel-source->package source #:key commit)
|
||||
"Return a package for the given channel SOURCE, a lowerable object."
|
||||
(package
|
||||
(inherit guix)
|
||||
(version (string-append (package-version guix) "+"))
|
||||
(build-system channel-build-system)
|
||||
(arguments `(#:source ,source
|
||||
#:commit ,commit))
|
||||
(inputs '())
|
||||
(native-inputs '())
|
||||
(propagated-inputs '())))
|
||||
|
||||
(define* (system-test-jobs store system
|
||||
#:key source commit)
|
||||
@@ -343,32 +387,29 @@ otherwise use the IMAGE name."
|
||||
;; Return the name of a package's job.
|
||||
package-name)
|
||||
|
||||
(define base-packages
|
||||
(mlambda (system)
|
||||
"Return the set of packages considered to be part of the base for SYSTEM."
|
||||
(delete-duplicates
|
||||
(append-map (match-lambda
|
||||
((_ package _ ...)
|
||||
(match (package-transitive-inputs package)
|
||||
(((_ inputs _ ...) ...)
|
||||
inputs))))
|
||||
(%final-inputs system)))))
|
||||
|
||||
(define package->job
|
||||
(lambda* (store package system #:key (suffix ""))
|
||||
"Return a job for PACKAGE on SYSTEM, or #f if this combination is not
|
||||
(let ((base-packages
|
||||
(delete-duplicates
|
||||
(append-map (match-lambda
|
||||
((_ package _ ...)
|
||||
(match (package-transitive-inputs package)
|
||||
(((_ inputs _ ...) ...)
|
||||
inputs))))
|
||||
(%final-inputs)))))
|
||||
(lambda* (store package system #:key (suffix ""))
|
||||
"Return a job for PACKAGE on SYSTEM, or #f if this combination is not
|
||||
valid. Append SUFFIX to the job name."
|
||||
(cond ((member package (base-packages system))
|
||||
(package-job store (string-append "base." (job-name package))
|
||||
package system #:suffix suffix))
|
||||
((supported-package? package system)
|
||||
(let ((drv (package-derivation store package system
|
||||
#:graft? #f)))
|
||||
(and (substitutable-derivation? drv)
|
||||
(package-job store (job-name package)
|
||||
package system #:suffix suffix))))
|
||||
(else
|
||||
#f))))
|
||||
(cond ((member package base-packages)
|
||||
(package-job store (string-append "base." (job-name package))
|
||||
package system #:suffix suffix))
|
||||
((supported-package? package system)
|
||||
(let ((drv (package-derivation store package system
|
||||
#:graft? #f)))
|
||||
(and (substitutable-derivation? drv)
|
||||
(package-job store (job-name package)
|
||||
package system #:suffix suffix))))
|
||||
(else
|
||||
#f)))))
|
||||
|
||||
(define %x86-64-micro-architectures
|
||||
;; Micro-architectures for which we build tuned variants.
|
||||
@@ -421,9 +462,9 @@ valid. Append SUFFIX to the job name."
|
||||
(map channel-url channels)))
|
||||
arguments))
|
||||
|
||||
(define (manifests->jobs store manifests systems)
|
||||
(define (manifests->jobs store manifests)
|
||||
"Return the list of jobs for the entries in MANIFESTS, a list of file
|
||||
names, for each one of SYSTEMS."
|
||||
names."
|
||||
(define (load-manifest manifest)
|
||||
(save-module-excursion
|
||||
(lambda ()
|
||||
@@ -434,12 +475,11 @@ names, for each one of SYSTEMS."
|
||||
(string-append (manifest-entry-name entry) "-"
|
||||
(manifest-entry-version entry)))
|
||||
|
||||
(define (manifest-entry->job entry system)
|
||||
(define (manifest-entry->job entry)
|
||||
(let* ((obj (manifest-entry-item entry))
|
||||
(drv (parameterize ((%graft? #f))
|
||||
(run-with-store store
|
||||
(lower-object obj system)
|
||||
#:system system)))
|
||||
(lower-object obj))))
|
||||
(max-silent-time (or (and (package? obj)
|
||||
(assoc-ref (package-properties obj)
|
||||
'max-silent-time))
|
||||
@@ -451,13 +491,11 @@ names, for each one of SYSTEMS."
|
||||
#:max-silent-time max-silent-time
|
||||
#:timeout timeout)))
|
||||
|
||||
(let ((entries (delete-duplicates
|
||||
(append-map (compose manifest-entries load-manifest)
|
||||
manifests)
|
||||
manifest-entry=?)))
|
||||
(append-map (lambda (system)
|
||||
(map (cut manifest-entry->job <> system) entries))
|
||||
systems)))
|
||||
(map manifest-entry->job
|
||||
(delete-duplicates
|
||||
(append-map (compose manifest-entries load-manifest)
|
||||
manifests)
|
||||
manifest-entry=?)))
|
||||
|
||||
(define (arguments->systems arguments)
|
||||
"Return the systems list from ARGUMENTS."
|
||||
@@ -539,9 +577,7 @@ names, for each one of SYSTEMS."
|
||||
hello system))))
|
||||
('images
|
||||
;; Build Guix System images only.
|
||||
(image-jobs store system
|
||||
#:source source
|
||||
#:commit commit))
|
||||
(image-jobs store system))
|
||||
('system-tests
|
||||
;; Build Guix System tests only.
|
||||
(system-test-jobs store system
|
||||
@@ -579,7 +615,7 @@ names, for each one of SYSTEMS."
|
||||
(('manifests . rest)
|
||||
;; Build packages in the list of manifests.
|
||||
(let ((manifests (arguments->manifests rest channels)))
|
||||
(manifests->jobs store manifests systems)))
|
||||
(manifests->jobs store manifests)))
|
||||
(else
|
||||
(error "unknown subset" subset))))
|
||||
systems)))
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2022 Mathieu Othacehe <othacehe@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu compression)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix ui)
|
||||
#:use-module ((gnu packages compression) #:hide (zip))
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-9)
|
||||
#:use-module (ice-9 match)
|
||||
#:export (compressor
|
||||
compressor?
|
||||
compressor-name
|
||||
compressor-extension
|
||||
compressor-command
|
||||
%compressors
|
||||
lookup-compressor))
|
||||
|
||||
;; Type of a compression tool.
|
||||
(define-record-type <compressor>
|
||||
(compressor name extension command)
|
||||
compressor?
|
||||
(name compressor-name) ;string (e.g., "gzip")
|
||||
(extension compressor-extension) ;string (e.g., ".lz")
|
||||
(command compressor-command)) ;gexp (e.g., #~(list "/gnu/store/…/gzip"
|
||||
; "-9n" ))
|
||||
|
||||
(define %compressors
|
||||
;; Available compression tools.
|
||||
(list (compressor "gzip" ".gz"
|
||||
#~(list #+(file-append gzip "/bin/gzip") "-9n"))
|
||||
(compressor "lzip" ".lz"
|
||||
#~(list #+(file-append lzip "/bin/lzip") "-9"))
|
||||
(compressor "xz" ".xz"
|
||||
#~(append (list #+(file-append xz "/bin/xz")
|
||||
"-e")
|
||||
(%xz-parallel-args)))
|
||||
(compressor "bzip2" ".bz2"
|
||||
#~(list #+(file-append bzip2 "/bin/bzip2") "-9"))
|
||||
(compressor "zstd" ".zst"
|
||||
;; The default level 3 compresses better than gzip in a
|
||||
;; fraction of the time, while the highest level 19
|
||||
;; (de)compresses more slowly and worse than xz.
|
||||
#~(list #+(file-append zstd "/bin/zstd") "-3"))
|
||||
(compressor "none" "" #f)))
|
||||
|
||||
(define (lookup-compressor name)
|
||||
"Return the compressor object called NAME. Error out if it could not be
|
||||
found."
|
||||
(or (find (match-lambda
|
||||
(($ <compressor> name*)
|
||||
(string=? name* name)))
|
||||
%compressors)
|
||||
(leave (G_ "~a: compressor not found~%") name)))
|
||||
+4
-41
@@ -1,6 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
|
||||
;;; Copyright © 2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -28,22 +27,18 @@
|
||||
#:use-module (guix diagnostics)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix store)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (ice-9 regex)
|
||||
|
||||
#:export (home-environment
|
||||
home-environment?
|
||||
this-home-environment
|
||||
|
||||
home-environment-derivation
|
||||
home-environment-packages
|
||||
home-environment-user-services
|
||||
home-environment-essential-services
|
||||
home-environment-services
|
||||
home-environment-location
|
||||
|
||||
home-environment-with-provenance
|
||||
|
||||
home-generation-base))
|
||||
home-environment-with-provenance))
|
||||
|
||||
;;; Comment:
|
||||
;;;
|
||||
@@ -97,27 +92,13 @@
|
||||
(home-environment-essential-services he))))
|
||||
|
||||
(define* (home-environment-derivation he)
|
||||
"Return a derivation that builds home environment."
|
||||
"Return a derivation that builds OS."
|
||||
(let* ((services (home-environment-services he))
|
||||
(home (fold-services services
|
||||
#:target-type home-service-type)))
|
||||
(service-value home)))
|
||||
|
||||
|
||||
(define (home-environment-configuration-file he)
|
||||
"Return the configuration file of HE, based on its 'location' field, or #f
|
||||
if it could not be determined."
|
||||
(let ((file (and=> (home-environment-location he)
|
||||
location-file)))
|
||||
(and file
|
||||
(or (and (string-prefix? "/" file) file)
|
||||
(search-path %load-path file)))))
|
||||
|
||||
(define* (home-environment-with-provenance he
|
||||
#:optional
|
||||
(config-file
|
||||
(home-environment-configuration-file
|
||||
he)))
|
||||
(define* (home-environment-with-provenance he config-file)
|
||||
"Return a variant of HE that stores its own provenance information,
|
||||
including CONFIG-FILE, if available. This is achieved by adding an instance
|
||||
of HOME-PROVENANCE-SERVICE-TYPE to its services."
|
||||
@@ -133,21 +114,3 @@ of HOME-PROVENANCE-SERVICE-TYPE to its services."
|
||||
(run-with-store store (home-environment-derivation he)
|
||||
#:system system
|
||||
#:target target)))))
|
||||
|
||||
(define %profile-generation-rx
|
||||
;; Regexp that matches profile generation.
|
||||
(make-regexp "(.*)-([0-9]+)-link$"))
|
||||
|
||||
(define (home-generation-base file)
|
||||
"If FILE is a Home generation GC root such as \"guix-home-42-link\",
|
||||
return its corresponding base---e.g., \"guix-home\". Otherwise return #f.
|
||||
|
||||
This is similar to the 'generation-profile' procedure but applied to Home
|
||||
generations."
|
||||
(match (regexp-exec %profile-generation-rx file)
|
||||
(#f #f)
|
||||
(m (let ((profile (match:substring m 1)))
|
||||
;; Distinguish from a "real" profile and from a system generation.
|
||||
(and (file-exists? (string-append profile "/on-first-login"))
|
||||
(file-exists? (string-append profile "/profile/manifest"))
|
||||
profile)))))
|
||||
|
||||
+29
-196
@@ -1,7 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2021-2023 Andrew Tropin <andrew@trop.in>
|
||||
;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
|
||||
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
|
||||
;;; Copyright © 2022-2023 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -21,7 +20,6 @@
|
||||
(define-module (gnu home services)
|
||||
#:use-module (gnu services)
|
||||
#:use-module ((gnu packages package-management) #:select (guix))
|
||||
#:use-module ((gnu packages base) #:select (coreutils))
|
||||
#:use-module (guix channels)
|
||||
#:use-module (guix monads)
|
||||
#:use-module (guix store)
|
||||
@@ -33,47 +31,30 @@
|
||||
#:use-module (guix diagnostics)
|
||||
#:use-module (guix i18n)
|
||||
#:use-module (guix modules)
|
||||
#:use-module (guix memoization)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-9)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (ice-9 vlist)
|
||||
|
||||
#:export (home-service-type
|
||||
home-profile-service-type
|
||||
home-environment-variables-service-type
|
||||
home-files-service-type
|
||||
home-xdg-configuration-files-service-type
|
||||
home-xdg-data-files-service-type
|
||||
home-run-on-first-login-service-type
|
||||
home-activation-service-type
|
||||
home-run-on-change-service-type
|
||||
home-provenance-service-type
|
||||
|
||||
literal-string
|
||||
literal-string?
|
||||
literal-string-value
|
||||
|
||||
with-shell-quotation-bindings
|
||||
environment-variable-shell-definitions
|
||||
home-files-directory
|
||||
xdg-configuration-files-directory
|
||||
xdg-data-files-directory
|
||||
|
||||
fold-home-service-types
|
||||
lookup-home-service-types
|
||||
home-provenance
|
||||
|
||||
define-service-type-mapping
|
||||
system->home-service-type
|
||||
|
||||
%initialize-gettext)
|
||||
|
||||
#:re-export (service
|
||||
service-type
|
||||
service-extension
|
||||
for-home
|
||||
for-home?))
|
||||
service-extension))
|
||||
|
||||
;;; Comment:
|
||||
;;;
|
||||
@@ -184,60 +165,6 @@ packages, configuration files, activation script, and so on.")))
|
||||
configuration files that the user has declared in their
|
||||
@code{home-environment} record.")))
|
||||
|
||||
;; Representation of a literal string.
|
||||
(define-record-type <literal-string>
|
||||
(literal-string str)
|
||||
literal-string?
|
||||
(str literal-string-value))
|
||||
|
||||
(define (with-shell-quotation-bindings exp)
|
||||
"Insert EXP, a gexp, in a lexical environment providing the
|
||||
'shell-single-quote' and 'shell-double-quote' bindings."
|
||||
#~(let* ((quote-string
|
||||
(lambda (value quoted-chars)
|
||||
(list->string (string-fold-right
|
||||
(lambda (chr lst)
|
||||
(if (memq chr quoted-chars)
|
||||
(append (list #\\ chr) lst)
|
||||
(cons chr lst)))
|
||||
'()
|
||||
value))))
|
||||
(shell-double-quote
|
||||
(lambda (value)
|
||||
;; Double-quote VALUE, leaving dollar sign as is.
|
||||
(string-append "\"" (quote-string value '(#\" #\\))
|
||||
"\"")))
|
||||
(shell-single-quote
|
||||
(lambda (value)
|
||||
;; Single-quote VALUE to enter a literal string.
|
||||
(string-append "'" (quote-string value '(#\'))
|
||||
"'"))))
|
||||
#$exp))
|
||||
|
||||
(define (environment-variable-shell-definitions variables)
|
||||
"Return a gexp that evaluates to a list of POSIX shell statements defining
|
||||
VARIABLES, a list of environment variable name/value pairs. The returned code
|
||||
ensures variable values are properly quoted."
|
||||
(with-shell-quotation-bindings
|
||||
#~(string-append
|
||||
#$@(map (match-lambda
|
||||
((key . #f)
|
||||
"")
|
||||
((key . #t)
|
||||
#~(string-append "export " #$key "\n"))
|
||||
((key . (or (? string? value)
|
||||
(? file-like? value)
|
||||
(? gexp? value)))
|
||||
#~(string-append "export " #$key "="
|
||||
(shell-double-quote #$value)
|
||||
"\n"))
|
||||
((key . (? literal-string? value))
|
||||
#~(string-append "export " #$key "="
|
||||
(shell-single-quote
|
||||
#$(literal-string-value value))
|
||||
"\n")))
|
||||
variables))))
|
||||
|
||||
(define (environment-variables->setup-environment-script vars)
|
||||
"Return a file that can be sourced by a POSIX compliant shell which
|
||||
initializes the environment. The file will source the home
|
||||
@@ -250,7 +177,7 @@ If value is @code{#f} variable will be omitted.
|
||||
If value is @code{#t} variable will be just exported.
|
||||
For any other, value variable will be set to the @code{value} and
|
||||
exported."
|
||||
(define (warn-about-duplicate-definitions)
|
||||
(define (warn-about-duplicate-defenitions)
|
||||
(fold
|
||||
(lambda (x acc)
|
||||
(when (equal? (car x) (car acc))
|
||||
@@ -261,18 +188,15 @@ exported."
|
||||
(sort vars (lambda (a b)
|
||||
(string<? (car a) (car b))))))
|
||||
|
||||
(warn-about-duplicate-definitions)
|
||||
(warn-about-duplicate-defenitions)
|
||||
(with-monad
|
||||
%store-monad
|
||||
(return
|
||||
`(("setup-environment"
|
||||
;; TODO: It's necessary to source ~/.guix-profile too
|
||||
;; on foreign distros
|
||||
,(computed-file "setup-environment"
|
||||
#~(call-with-output-file #$output
|
||||
(lambda (port)
|
||||
(set-port-encoding! port "UTF-8")
|
||||
(display "\
|
||||
,(apply mixed-text-file "setup-environment"
|
||||
"\
|
||||
HOME_ENVIRONMENT=$HOME/.guix-home
|
||||
GUIX_PROFILE=\"$HOME_ENVIRONMENT/profile\"
|
||||
PROFILE_FILE=\"$HOME_ENVIRONMENT/profile/etc/profile\"
|
||||
@@ -299,10 +223,17 @@ case $XCURSOR_PATH in
|
||||
*) export XCURSOR_PATH=$HOME_ENVIRONMENT/profile/share/icons:$XCURSOR_PATH ;;
|
||||
esac
|
||||
|
||||
" port)
|
||||
(display
|
||||
#$(environment-variable-shell-definitions vars)
|
||||
port)))))))))
|
||||
"
|
||||
|
||||
(append-map
|
||||
(match-lambda
|
||||
((key . #f)
|
||||
'())
|
||||
((key . #t)
|
||||
(list "export " key "\n"))
|
||||
((key . value)
|
||||
(list "export " key "=" value "\n")))
|
||||
vars)))))))
|
||||
|
||||
(define home-environment-variables-service-type
|
||||
(service-type (name 'home-environment-variables)
|
||||
@@ -352,12 +283,12 @@ directory containing FILES."
|
||||
(extend append)
|
||||
(default-value '())
|
||||
(description "Files that will be put in
|
||||
@file{~/.guix-home/files}, and further processed during activation.")))
|
||||
@file{~~/.guix-home/files}, and further processed during activation.")))
|
||||
|
||||
(define xdg-configuration-files-directory ".config")
|
||||
(define xdg-configuration-files-directory "config")
|
||||
|
||||
(define (xdg-configuration-files files)
|
||||
"Add .config/ prefix to each file-path in FILES."
|
||||
"Add config/ prefix to each file-path in FILES."
|
||||
(map (match-lambda
|
||||
((file-path . rest)
|
||||
(cons (string-append xdg-configuration-files-directory "/" file-path)
|
||||
@@ -365,7 +296,7 @@ directory containing FILES."
|
||||
files))
|
||||
|
||||
(define home-xdg-configuration-files-service-type
|
||||
(service-type (name 'home-xdg-configuration)
|
||||
(service-type (name 'home-files)
|
||||
(extensions
|
||||
(list (service-extension home-files-service-type
|
||||
xdg-configuration-files)))
|
||||
@@ -373,30 +304,7 @@ directory containing FILES."
|
||||
(extend append)
|
||||
(default-value '())
|
||||
(description "Files that will be put in
|
||||
@file{~/.guix-home/files/.config}, and further processed during activation.")))
|
||||
|
||||
(define xdg-data-files-directory ".local/share")
|
||||
|
||||
(define (xdg-data-files files)
|
||||
"Add .local/share prefix to each file-path in FILES."
|
||||
(map (match-lambda
|
||||
((file-path . rest)
|
||||
(cons (string-append xdg-data-files-directory "/" file-path)
|
||||
rest)))
|
||||
files))
|
||||
|
||||
(define home-xdg-data-files-service-type
|
||||
(service-type (name 'home-xdg-data)
|
||||
(extensions
|
||||
(list (service-extension home-files-service-type
|
||||
xdg-data-files)))
|
||||
(compose concatenate)
|
||||
(extend append)
|
||||
(default-value '())
|
||||
(description "Files that will be put in
|
||||
@file{~/.guix-home/files/.local/share}, and further processed during
|
||||
activation.")))
|
||||
|
||||
@file{~~/.guix-home/files/config}, and further processed during activation.")))
|
||||
|
||||
(define %initialize-gettext
|
||||
#~(begin
|
||||
@@ -407,11 +315,9 @@ activation.")))
|
||||
(define (compute-on-first-login-script _ gexps)
|
||||
(program-file
|
||||
"on-first-login"
|
||||
(with-imported-modules (source-module-closure '((guix i18n)
|
||||
(guix diagnostics)))
|
||||
(with-imported-modules (source-module-closure '((guix i18n)))
|
||||
#~(begin
|
||||
(use-modules (guix i18n)
|
||||
(guix diagnostics))
|
||||
(use-modules (guix i18n))
|
||||
#$%initialize-gettext
|
||||
|
||||
(let* ((xdg-runtime-dir (or (getenv "XDG_RUNTIME_DIR")
|
||||
@@ -428,7 +334,7 @@ activation.")))
|
||||
(begin #$@gexps (touch flag-file-path)))
|
||||
;; TRANSLATORS: 'on-first-login' is the name of a service and
|
||||
;; shouldn't be translated
|
||||
(warning (G_ "XDG_RUNTIME_DIR doesn't exists, on-first-login script
|
||||
(display (G_ "XDG_RUNTIME_DIR doesn't exists, on-first-login script
|
||||
won't execute anything. You can check if xdg runtime directory exists,
|
||||
XDG_RUNTIME_DIR variable is set to appropriate value and manually execute the
|
||||
script by running '$HOME/.guix-home/on-first-login'"))))))))
|
||||
@@ -459,9 +365,8 @@ extended with one gexp.")))
|
||||
(he-path (string-append (getenv "HOME") "/.guix-home"))
|
||||
(new-home-env (getenv "GUIX_NEW_HOME"))
|
||||
(new-home (or new-home-env
|
||||
;; Absolute path of the directory of the activation
|
||||
;; file if called interactively.
|
||||
(canonicalize-path (dirname (car (command-line))))))
|
||||
;; Path of the activation file if called interactively
|
||||
(dirname (car (command-line)))))
|
||||
(old-home-env (getenv "GUIX_OLD_HOME"))
|
||||
(old-home (or old-home-env
|
||||
(if (file-exists? (he-init-file he-path))
|
||||
@@ -469,9 +374,8 @@ extended with one gexp.")))
|
||||
#f))))
|
||||
(if (file-exists? (he-init-file new-home))
|
||||
(let* ((port ((@ (ice-9 popen) open-input-pipe)
|
||||
(format #f "source ~a && ~a -0"
|
||||
(he-init-file new-home)
|
||||
#$(file-append coreutils "/bin/env"))))
|
||||
(format #f "source ~a && env -0"
|
||||
(he-init-file new-home))))
|
||||
(result ((@ (ice-9 rdelim) read-delimited) "" port))
|
||||
(vars (map (lambda (x)
|
||||
(let ((si (string-index x #\=)))
|
||||
@@ -519,67 +423,6 @@ directory. @command{activate} script automatically called during
|
||||
reconfiguration or generation switching. This service can be extended
|
||||
with one gexp, but many times, and all gexps must be idempotent.")))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Service type graph rewriting.
|
||||
;;;
|
||||
|
||||
(define (service-type-mapping proc)
|
||||
"Return a procedure that applies PROC to map a service type graph to another
|
||||
one."
|
||||
(define (rewrite extension)
|
||||
(match (proc (service-extension-target extension))
|
||||
(#f #f)
|
||||
(target
|
||||
(service-extension target
|
||||
(service-extension-compute extension)))))
|
||||
|
||||
(define replace
|
||||
(mlambdaq (type)
|
||||
(service-type
|
||||
(inherit type)
|
||||
(name (symbol-append 'home- (service-type-name type)))
|
||||
(location (service-type-location type))
|
||||
(extensions (filter-map rewrite (service-type-extensions type))))))
|
||||
|
||||
replace)
|
||||
|
||||
(define %system/home-service-type-mapping
|
||||
;; Mapping of System to Home services.
|
||||
(make-hash-table))
|
||||
|
||||
(define system->home-service-type
|
||||
;; Map the given System service type to the corresponding Home service type.
|
||||
(let ()
|
||||
(define (replace type)
|
||||
(define replacement
|
||||
(hashq-ref %system/home-service-type-mapping type
|
||||
*unspecified*))
|
||||
|
||||
(if (eq? replacement *unspecified*)
|
||||
type
|
||||
replacement))
|
||||
|
||||
(service-type-mapping replace)))
|
||||
|
||||
(define-syntax define-service-type-mapping
|
||||
(syntax-rules (=>)
|
||||
((_ system-type => home-type)
|
||||
(hashq-set! %system/home-service-type-mapping
|
||||
system-type home-type))))
|
||||
|
||||
(define-syntax define-service-type-mappings
|
||||
(syntax-rules (=>)
|
||||
((_ (system-type => home-type) ...)
|
||||
(begin
|
||||
(define-service-type-mapping system-type => home-type)
|
||||
...))))
|
||||
|
||||
(define-service-type-mappings
|
||||
(system-service-type => home-service-type)
|
||||
(activation-service-type => home-activation-service-type)
|
||||
(profile-service-type => home-profile-service-type))
|
||||
|
||||
|
||||
;;;
|
||||
;;; On-change.
|
||||
@@ -737,13 +580,3 @@ environment, and its configuration file, when available.")))
|
||||
|
||||
(define* (fold-home-service-types proc seed)
|
||||
(fold-service-types proc seed (all-home-service-modules)))
|
||||
|
||||
(define lookup-home-service-types
|
||||
(let ((table
|
||||
(delay (fold-home-service-types (lambda (type result)
|
||||
(vhash-consq (service-type-name type)
|
||||
type result))
|
||||
vlist-null))))
|
||||
(lambda (name)
|
||||
"Return the list of services with the given NAME (a symbol)."
|
||||
(vhash-foldq* cons '() name (force table)))))
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2022 ( <paren@disroot.org>
|
||||
;;; Copyright © 2023 conses <contact@conses.eu>
|
||||
;;; Copyright © 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -23,25 +20,15 @@
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu home services shepherd)
|
||||
#:use-module (gnu services configuration)
|
||||
#:autoload (gnu packages glib) (dbus)
|
||||
#:autoload (gnu packages xdisorg) (redshift unclutter)
|
||||
#:autoload (gnu packages xorg) (setxkbmap xmodmap)
|
||||
#:autoload (gnu packages xdisorg) (redshift)
|
||||
#:use-module (guix records)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (ice-9 match)
|
||||
#:export (home-redshift-configuration
|
||||
home-redshift-configuration?
|
||||
home-redshift-service-type
|
||||
|
||||
home-dbus-configuration
|
||||
home-dbus-service-type
|
||||
|
||||
home-unclutter-configuration
|
||||
home-unclutter-service-type
|
||||
|
||||
home-xmodmap-configuration
|
||||
home-xmodmap-service-type))
|
||||
home-redshift-service-type))
|
||||
|
||||
|
||||
;;;
|
||||
@@ -104,26 +91,26 @@ queried for location information.")
|
||||
"Nighttime color temperature (kelvins).")
|
||||
|
||||
(daytime-brightness
|
||||
maybe-inexact-number
|
||||
(maybe-inexact-number 'disabled)
|
||||
"Daytime screen brightness, between 0.1 and 1.0.")
|
||||
(nighttime-brightness
|
||||
maybe-inexact-number
|
||||
(maybe-inexact-number 'disabled)
|
||||
"Nighttime screen brightness, between 0.1 and 1.0.")
|
||||
|
||||
(latitude
|
||||
maybe-inexact-number
|
||||
(maybe-inexact-number 'disabled)
|
||||
"Latitude, when @code{location-provider} is @code{'manual}.")
|
||||
(longitude
|
||||
maybe-inexact-number
|
||||
(maybe-inexact-number 'disabled)
|
||||
"Longitude, when @code{location-provider} is @code{'manual}.")
|
||||
|
||||
(dawn-time
|
||||
maybe-string
|
||||
(maybe-string 'disabled)
|
||||
"Custom time for the transition from night to day in the
|
||||
morning---@code{\"HH:MM\"} format. When specified, solar elevation is not
|
||||
used to determine the daytime/nighttime period.")
|
||||
(dusk-time
|
||||
maybe-string
|
||||
(maybe-string 'disabled)
|
||||
"Likewise, custom time for the transition from day to night in the
|
||||
evening.")
|
||||
|
||||
@@ -174,8 +161,7 @@ format."))
|
||||
(start #~(make-forkexec-constructor
|
||||
(list #$(file-append redshift "/bin/redshift")
|
||||
"-c" #$config-file)))
|
||||
(stop #~(make-kill-destructor))
|
||||
(actions (list (shepherd-configuration-action config-file))))))
|
||||
(stop #~(make-kill-destructor)))))
|
||||
|
||||
(define home-redshift-service-type
|
||||
(service-type
|
||||
@@ -186,153 +172,3 @@ format."))
|
||||
(description
|
||||
"Run Redshift, a program that adjusts the color temperature of display
|
||||
according to time of day.")))
|
||||
|
||||
|
||||
;;;
|
||||
;;; D-Bus.
|
||||
;;;
|
||||
|
||||
(define-record-type* <home-dbus-configuration>
|
||||
home-dbus-configuration make-home-dbus-configuration
|
||||
home-dbus-configuration?
|
||||
(dbus home-dbus-dbus ;file-like
|
||||
(default dbus)))
|
||||
|
||||
(define (home-dbus-shepherd-services config)
|
||||
(list (shepherd-service
|
||||
(documentation "Run the D-Bus daemon in session-specific mode.")
|
||||
(provision '(dbus))
|
||||
(start #~(make-forkexec-constructor
|
||||
(list #$(file-append (home-dbus-dbus config)
|
||||
"/bin/dbus-daemon")
|
||||
"--nofork" "--session"
|
||||
(format #f "--address=unix:path=~a/bus"
|
||||
(or (getenv "XDG_RUNTIME_DIR")
|
||||
(format #f "/run/user/~a"
|
||||
(getuid)))))
|
||||
#:environment-variables
|
||||
(cons "DBUS_VERBOSE=1"
|
||||
(default-environment-variables))
|
||||
#:log-file
|
||||
(format #f "~a/log/dbus.log"
|
||||
(or (getenv "XDG_STATE_HOME")
|
||||
(format #f "~a/.local/state"
|
||||
(getenv "HOME"))))))
|
||||
(stop #~(make-kill-destructor)))))
|
||||
|
||||
(define (home-dbus-environment-variables config)
|
||||
'(("DBUS_SESSION_BUS_ADDRESS"
|
||||
. "unix:path=${XDG_RUNTIME_DIR:-/run/user/$UID}/bus")))
|
||||
|
||||
(define home-dbus-service-type
|
||||
(service-type
|
||||
(name 'home-dbus)
|
||||
(extensions
|
||||
(list (service-extension home-shepherd-service-type
|
||||
home-dbus-shepherd-services)
|
||||
(service-extension home-environment-variables-service-type
|
||||
home-dbus-environment-variables)))
|
||||
(default-value (home-dbus-configuration))
|
||||
(description
|
||||
"Run the session-specific D-Bus inter-process message bus.")))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Unclutter.
|
||||
;;;
|
||||
|
||||
(define-configuration/no-serialization home-unclutter-configuration
|
||||
(unclutter
|
||||
(file-like unclutter)
|
||||
"The @code{unclutter} package to use.")
|
||||
(idle-timeout
|
||||
(integer 5)
|
||||
"Timeout in seconds after which to hide the cursor."))
|
||||
|
||||
(define (home-unclutter-shepherd-service config)
|
||||
(list
|
||||
(shepherd-service
|
||||
(provision '(unclutter))
|
||||
(requirement '())
|
||||
(one-shot? #t)
|
||||
(start #~(make-forkexec-constructor
|
||||
(list
|
||||
#$(file-append
|
||||
(home-unclutter-configuration-unclutter config)
|
||||
"/bin/unclutter")
|
||||
"-idle"
|
||||
(number->string
|
||||
#$(home-unclutter-configuration-idle-timeout config)))
|
||||
#:log-file (string-append
|
||||
(or (getenv "XDG_STATE_HOME")
|
||||
(format #f "~a/.local/state"
|
||||
(getenv "HOME")))
|
||||
"/log/unclutter.log"))))))
|
||||
|
||||
(define home-unclutter-service-type
|
||||
(service-type
|
||||
(name 'home-unclutter)
|
||||
(extensions
|
||||
(list
|
||||
(service-extension home-shepherd-service-type
|
||||
home-unclutter-shepherd-service)))
|
||||
(default-value (home-unclutter-configuration))
|
||||
(description "Run the @code{unclutter} daemon, which, on systems using the
|
||||
Xorg graphical display server, automatically hides the cursor after a
|
||||
user-defined timeout has expired.")))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Xmodmap.
|
||||
;;;
|
||||
|
||||
(define-configuration/no-serialization home-xmodmap-configuration
|
||||
(xmodmap
|
||||
(file-like xmodmap)
|
||||
"The @code{xmodmap} package to use.")
|
||||
(key-map
|
||||
(list '())
|
||||
"List of expressions to be read by @code{xmodmap} on service startup."))
|
||||
|
||||
(define (serialize-xmodmap-configuration field-name val)
|
||||
(define serialize-field
|
||||
(match-lambda
|
||||
((key . value)
|
||||
(format #f "~a = ~a" key value))
|
||||
(e e)))
|
||||
|
||||
#~(string-append
|
||||
#$@(interpose (map serialize-field val) "\n" 'suffix)))
|
||||
|
||||
(define (xmodmap-shepherd-service config)
|
||||
(define config-file
|
||||
(mixed-text-file
|
||||
"config"
|
||||
(serialize-xmodmap-configuration
|
||||
#f (home-xmodmap-configuration-key-map config))))
|
||||
|
||||
(list
|
||||
(shepherd-service
|
||||
(provision '(xmodmap))
|
||||
(start #~(make-system-constructor
|
||||
(string-join
|
||||
(list #$(file-append
|
||||
(home-xmodmap-configuration-xmodmap config)
|
||||
"/bin/xmodmap")
|
||||
#$config-file))))
|
||||
(stop #~(make-system-constructor
|
||||
#$(file-append setxkbmap "/bin/setxkbmap")))
|
||||
(documentation "On startup, run @code{xmodmap} and read the expressions in
|
||||
the configuration file. On stop, reset all the mappings back to the
|
||||
defaults."))))
|
||||
|
||||
(define home-xmodmap-service-type
|
||||
(service-type
|
||||
(name 'home-xmodmap)
|
||||
(extensions
|
||||
(list
|
||||
(service-extension home-shepherd-service-type
|
||||
xmodmap-shepherd-service)))
|
||||
(default-value (home-xmodmap-configuration))
|
||||
(description "Run the @code{xmodmap} utility to modify keymaps and pointer
|
||||
buttons under the Xorg display server via user-defined expressions.")))
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2023 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu home services dict)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services dict)
|
||||
#:use-module ((gnu system shadow) #:select (account-service-type))
|
||||
;; For the 'home-shepherd-service-type' mapping.
|
||||
#:use-module (gnu home services shepherd)
|
||||
#:export (home-dicod-service-type)
|
||||
#:re-export (dicod-configuration))
|
||||
|
||||
(define home-dicod-service-type
|
||||
(service-type
|
||||
(inherit (system->home-service-type
|
||||
(remove-service-extensions dicod-service-type
|
||||
(list account-service-type))))
|
||||
(default-value (for-home (dicod-configuration)))))
|
||||
@@ -1,8 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
|
||||
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
|
||||
;;; Copyright © 2023 Giacomo Leidi <goodoldpaul@autistici.org>
|
||||
;;; Copyright © 2023 Andrew Patterson <andrewpatt7@gmail.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -23,9 +21,6 @@
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu packages fontutils)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (sxml simple)
|
||||
|
||||
#:export (home-fontconfig-service-type))
|
||||
|
||||
@@ -38,36 +33,15 @@
|
||||
;;;
|
||||
;;; Code:
|
||||
|
||||
(define (write-fontconfig-doctype)
|
||||
"Prints fontconfig's DOCTYPE to current-output-port."
|
||||
;; This is necessary because SXML doesn't seem to have a way to represent a doctype,
|
||||
;; but sxml->xml /does/ currently call any thunks in the SXML with the XML output port
|
||||
;; as current-output-port, allowing the output to include arbitrary text instead of
|
||||
;; just properly quoted XML.
|
||||
(format #t "<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>"))
|
||||
|
||||
(define (config->sxml config)
|
||||
"Converts a <home-fontconfig-configuration> record into the SXML representation
|
||||
of fontconfig's fonts.conf file."
|
||||
(define (snippets->sxml snippet)
|
||||
(match snippet
|
||||
((or (? string? dir)
|
||||
(? gexp? dir))
|
||||
`(dir ,dir))
|
||||
((? list?)
|
||||
snippet)))
|
||||
`(*TOP* (*PI* xml "version='1.0'")
|
||||
,write-fontconfig-doctype
|
||||
(fontconfig
|
||||
,@(map snippets->sxml config))))
|
||||
|
||||
(define (add-fontconfig-config-file config)
|
||||
(define (add-fontconfig-config-file he-symlink-path)
|
||||
`(("fontconfig/fonts.conf"
|
||||
,(mixed-text-file
|
||||
"fonts.conf"
|
||||
(call-with-output-string
|
||||
(lambda (port)
|
||||
(sxml->xml (config->sxml config) port)))))))
|
||||
"<?xml version='1.0'?>
|
||||
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
|
||||
<fontconfig>
|
||||
<dir>~/.guix-home/profile/share/fonts</dir>
|
||||
</fontconfig>"))))
|
||||
|
||||
(define (regenerate-font-cache-gexp _)
|
||||
`(("profile/share/fonts"
|
||||
@@ -85,9 +59,7 @@ of fontconfig's fonts.conf file."
|
||||
(service-extension
|
||||
home-profile-service-type
|
||||
(const (list fontconfig)))))
|
||||
(compose concatenate)
|
||||
(extend append)
|
||||
(default-value '("~/.guix-home/profile/share/fonts"))
|
||||
(default-value #f)
|
||||
(description
|
||||
"Provides configuration file for fontconfig and make
|
||||
fc-* utilities aware of font packages installed in Guix Home's profile.")))
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2023 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu home services gnupg)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module ((guix records) #:select (match-record))
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services configuration)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu home services shepherd)
|
||||
#:autoload (gnu packages gnupg) (gnupg pinentry parcimonie)
|
||||
#:export (home-gpg-agent-configuration
|
||||
home-gpg-agent-configuration?
|
||||
home-gpg-agent-configuration-gnupg
|
||||
home-gpg-agent-configuration-pinentry-program
|
||||
home-gpg-agent-configuration-ssh-support?
|
||||
home-gpg-agent-configuration-default-cache-ttl
|
||||
home-gpg-agent-configuration-max-cache-ttl
|
||||
home-gpg-agent-configuration-max-cache-ttl-ssh
|
||||
home-gpg-agent-configuration-extra-content
|
||||
|
||||
home-gpg-agent-service-type
|
||||
|
||||
home-parcimonie-configuration
|
||||
home-parcimonie-configuration?
|
||||
home-parcimonie-configuration-parcimonie
|
||||
home-parcimonie-configuration-gnupg-already-torified?
|
||||
home-parcimonie-configuration-refresh-guix-keyrings?
|
||||
home-parcimonie-configuration-extra-content
|
||||
|
||||
home-parcimonie-service-type))
|
||||
|
||||
(define raw-configuration-string? string?)
|
||||
|
||||
;; Configuration of 'gpg-agent'.
|
||||
(define-configuration/no-serialization home-gpg-agent-configuration
|
||||
(gnupg
|
||||
(file-like gnupg)
|
||||
"The GnuPG package to use.")
|
||||
(pinentry-program
|
||||
(file-like (file-append pinentry "/bin/pinentry-curses"))
|
||||
"Pinentry program to use. Pinentry is a small user interface that
|
||||
@command{gpg-agent} delegates to anytime it needs user input for a passphrase
|
||||
or @acronym{PIN, personal identification number} (@pxref{Top,,, pinentry,
|
||||
Using the PIN-Entry}).")
|
||||
(ssh-support?
|
||||
(boolean #f)
|
||||
"Whether to enable @acronym{SSH, secure shell} support. When true,
|
||||
@command{gpg-agent} acts as a drop-in replacement for OpenSSH's
|
||||
@command{ssh-agent} program, taking care of OpenSSH secret keys and directing
|
||||
passphrase requests to the chosen Pinentry program.")
|
||||
(default-cache-ttl
|
||||
(integer 600)
|
||||
"Time a cache entry is valid, in seconds.")
|
||||
(max-cache-ttl
|
||||
(integer 7200)
|
||||
"Maximum time a cache entry is valid, in seconds. After this time a cache
|
||||
entry will be expired even if it has been accessed recently.")
|
||||
(default-cache-ttl-ssh
|
||||
(integer 1800)
|
||||
"Time a cache entry for SSH keys is valid, in seconds.")
|
||||
(max-cache-ttl-ssh
|
||||
(integer 7200)
|
||||
"Maximum time a cache entry for SSH keys is valid, in seconds.")
|
||||
(extra-content
|
||||
(raw-configuration-string "")
|
||||
"Raw content to add to the end of @file{~/.gnupg/gpg-agent.conf}."))
|
||||
|
||||
(define (home-gpg-agent-configuration-file config)
|
||||
"Return the @file{gpg-agent.conf} file for @var{config}."
|
||||
(match-record config <home-gpg-agent-configuration>
|
||||
(pinentry-program default-cache-ttl max-cache-ttl
|
||||
default-cache-ttl-ssh max-cache-ttl-ssh
|
||||
extra-content)
|
||||
(mixed-text-file "gpg-agent.conf"
|
||||
"pinentry-program " pinentry-program "\n"
|
||||
"default-cache-ttl "
|
||||
(number->string default-cache-ttl) "\n"
|
||||
"max-cache-ttl "
|
||||
(number->string max-cache-ttl) "\n"
|
||||
"default-cache-ttl-ssh "
|
||||
(number->string default-cache-ttl-ssh) "\n"
|
||||
"max-cache-ttl-ssh "
|
||||
(number->string max-cache-ttl-ssh) "\n"
|
||||
extra-content)))
|
||||
|
||||
(define (home-gpg-agent-shepherd-services config)
|
||||
"Return the possibly-empty list of Shepherd services for @var{config}."
|
||||
(match-record config <home-gpg-agent-configuration>
|
||||
(gnupg ssh-support?)
|
||||
;; 'gpg-agent' is started on demand by GnuPG's programs, but it has to be
|
||||
;; started explicitly when OpenSSH support is enabled (info "(gnupg) Agent
|
||||
;; Options").
|
||||
(if ssh-support?
|
||||
(let ((endpoint (lambda (name socket)
|
||||
#~(endpoint
|
||||
(make-socket-address
|
||||
AF_UNIX
|
||||
(string-append %user-runtime-dir
|
||||
"/gnupg/" #$socket))
|
||||
#:name #$name
|
||||
#:socket-directory-permissions #o700))))
|
||||
(list (shepherd-service
|
||||
(provision '(gpg-agent ssh-agent))
|
||||
(modules '((shepherd support))) ;for '%user-runtime-dir'
|
||||
(start #~(make-systemd-constructor
|
||||
(list #$(file-append gnupg "/bin/gpg-agent")
|
||||
"--supervised" "--enable-ssh-support")
|
||||
(list #$(endpoint "ssh" "S.gpg-agent.ssh")
|
||||
#$(endpoint "browser" "S.gpg-agent.browser")
|
||||
#$(endpoint "extra" "S.gpg-agent.extra")
|
||||
;; #$(endpoint "scdaemon" "S.scdaemon")
|
||||
#$(endpoint "std" "S.gpg-agent"))))
|
||||
(stop #~(make-systemd-destructor))
|
||||
(documentation "Start 'gpg-agent', the GnuPG passphrase
|
||||
agent, with support for handling OpenSSH material."))))
|
||||
'())))
|
||||
|
||||
(define (home-gpg-agent-files config)
|
||||
`((".gnupg/gpg-agent.conf" ,(home-gpg-agent-configuration-file config))))
|
||||
|
||||
(define (home-gpg-agent-environment-variables config)
|
||||
"Return GnuPG environment variables needed for @var{config}."
|
||||
(if (home-gpg-agent-configuration-ssh-support? config)
|
||||
`(("SSH_AUTH_SOCK"
|
||||
. "$XDG_RUNTIME_DIR/gnupg/S.gpg-agent.ssh"))
|
||||
'()))
|
||||
|
||||
(define home-gpg-agent-service-type
|
||||
(service-type
|
||||
(name 'home-gpg-agent)
|
||||
(extensions
|
||||
(list (service-extension home-files-service-type
|
||||
home-gpg-agent-files)
|
||||
(service-extension home-shepherd-service-type
|
||||
home-gpg-agent-shepherd-services)
|
||||
(service-extension home-environment-variables-service-type
|
||||
home-gpg-agent-environment-variables)))
|
||||
(default-value (home-gpg-agent-configuration))
|
||||
(description
|
||||
"Configure GnuPG's agent, @command{gpg-agent}, which is responsible for
|
||||
managing OpenPGP and optionally SSH private keys. When SSH support is
|
||||
enabled, @command{gpg-agent} acts as a drop-in replacement for OpenSSH's
|
||||
@command{ssh-agent}.")))
|
||||
|
||||
(define-configuration/no-serialization home-parcimonie-configuration
|
||||
(parcimonie
|
||||
(file-like parcimonie)
|
||||
"The parcimonie package to use.")
|
||||
(verbose?
|
||||
(boolean #f)
|
||||
"Provide extra output to the log file.")
|
||||
(gnupg-aleady-torified?
|
||||
(boolean #f)
|
||||
"GnuPG is already configured to use tor and parcimonie won't attempt to use
|
||||
tor directly.")
|
||||
(refresh-guix-keyrings?
|
||||
(boolean #f)
|
||||
"Also refresh any Guix keyrings found in the XDG_CONFIG_DIR.")
|
||||
(extra-content
|
||||
(raw-configuration-string "")
|
||||
"Raw content to add to the parcimonie service."))
|
||||
|
||||
(define (home-parcimonie-shepherd-service config)
|
||||
"Return a user service to run parcimonie."
|
||||
(match-record config <home-parcimonie-configuration>
|
||||
(parcimonie verbose? gnupg-aleady-torified?
|
||||
refresh-guix-keyrings? extra-content)
|
||||
(let ((log-file #~(string-append %user-log-dir "/parcimonie.log")))
|
||||
(list (shepherd-service
|
||||
(provision '(parcimonie))
|
||||
(modules '((shepherd support) ;for '%user-log-dir'
|
||||
(guix build utils)
|
||||
(srfi srfi-1)))
|
||||
(start #~(make-forkexec-constructor
|
||||
(cons*
|
||||
#$(file-append parcimonie "/bin/parcimonie")
|
||||
#$@(if verbose?
|
||||
'("--verbose")
|
||||
'())
|
||||
#$@(if gnupg-aleady-torified?
|
||||
'("--gnupg_already_torified")
|
||||
'())
|
||||
#$@(if (not (string=? extra-content ""))
|
||||
(list extra-content)
|
||||
'())
|
||||
#$@(if refresh-guix-keyrings?
|
||||
'((append-map
|
||||
(lambda (item)
|
||||
(list (string-append "--gnupg_extra_args="
|
||||
"--keyring=" item)))
|
||||
(find-files
|
||||
(string-append (getenv "XDG_CONFIG_HOME") "/guix")
|
||||
"^trustedkeys\\.kbx$")))
|
||||
'((list))))
|
||||
#:log-file #$log-file))
|
||||
(stop #~(make-kill-destructor))
|
||||
(respawn? #t)
|
||||
(documentation "Incrementally refresh gnupg keyring over Tor"))))))
|
||||
|
||||
(define home-parcimonie-service-type
|
||||
(service-type
|
||||
(name 'home-parcimonie)
|
||||
(extensions
|
||||
(list (service-extension home-shepherd-service-type
|
||||
home-parcimonie-shepherd-service)))
|
||||
(default-value (home-parcimonie-configuration))
|
||||
(description
|
||||
"Incrementally refresh GnuPG keyrings over Tor.")))
|
||||
@@ -1,44 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2022 Reily Siegel <mail@reilysiegel.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu home services guix)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (guix channels)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (ice-9 pretty-print)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:export (home-channels-service-type))
|
||||
|
||||
(define (channels-xdg-files channels)
|
||||
`(("guix/channels.scm"
|
||||
,(plain-file
|
||||
"channels.scm"
|
||||
(call-with-output-string
|
||||
(lambda (port)
|
||||
(pretty-print (cons 'list (map channel->code channels)) port)))))))
|
||||
|
||||
(define home-channels-service-type
|
||||
(service-type
|
||||
(name 'home-channels)
|
||||
(default-value %default-channels)
|
||||
(compose concatenate)
|
||||
(extend append)
|
||||
(extensions
|
||||
(list (service-extension home-xdg-configuration-files-service-type
|
||||
channels-xdg-files)))
|
||||
(description "Manages the per-user Guix channels specification.")))
|
||||
@@ -1,222 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2023 Tanguy Le Carrour <tanguy@bioneland.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu home services mail)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services configuration)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu home services shepherd)
|
||||
#:use-module (gnu packages mail)
|
||||
#:use-module (ice-9 string-fun)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:export (home-msmtp-configuration
|
||||
home-msmtp-configuration?
|
||||
home-msmtp-configuration-defaults
|
||||
home-msmtp-configuration-accounts
|
||||
home-msmtp-configuration-default-account
|
||||
home-msmtp-configuration-extra-content
|
||||
home-msmtp-service-type
|
||||
msmtp-configuration
|
||||
msmtp-configuration-auth?
|
||||
msmtp-configuration-tls?
|
||||
msmtp-configuration-tls-starttls?
|
||||
msmtp-configuration-tls-trust-file
|
||||
msmtp-configuration-log-file
|
||||
msmtp-configuration-host
|
||||
msmtp-configuration-port
|
||||
msmtp-configuration-user
|
||||
msmtp-configuration-from
|
||||
msmtp-configuration-password-eval
|
||||
msmtp-configuration-extra-content
|
||||
msmtp-account
|
||||
msmtp-account-name
|
||||
msmtp-account-configuration))
|
||||
|
||||
(define-maybe string (prefix msmtp-configuration-))
|
||||
(define-maybe boolean (prefix msmtp-configuration-))
|
||||
(define-maybe integer (prefix msmtp-configuration-))
|
||||
|
||||
;; Serialization of 'msmtp'.
|
||||
(define (uglify-symbol field-name)
|
||||
(let* ((name (symbol->string field-name))
|
||||
(ugly-name (string-replace-substring name "-" "_")))
|
||||
(if (string-suffix? "?" ugly-name)
|
||||
(string-drop-right ugly-name 1)
|
||||
ugly-name)))
|
||||
|
||||
(define (msmtp-configuration-serialize-boolean field-name value)
|
||||
#~(string-append #$(uglify-symbol field-name) " "
|
||||
(if #$value "on" "off") "\n"))
|
||||
|
||||
(define (msmtp-configuration-serialize-string field-name value)
|
||||
#~(string-append #$(uglify-symbol field-name) " " #$value "\n"))
|
||||
|
||||
(define (msmtp-configuration-serialize-maybe-string-no-underscore field-name value)
|
||||
#~(if #$(maybe-value-set? value)
|
||||
(string-append
|
||||
#$(string-replace-substring (uglify-symbol field-name) "_" "") " " #$value "\n")
|
||||
""))
|
||||
|
||||
(define (msmtp-configuration-serialize-integer field-name value)
|
||||
#~(string-append #$(uglify-symbol field-name) " "
|
||||
(number->string #$value) "\n"))
|
||||
|
||||
(define (msmtp-configuration-serialize-extra-content field-name value)
|
||||
#~(if (string=? #$value "") "" (string-append #$value "\n")))
|
||||
|
||||
(define (msmtp-account-serialize-name field-name value)
|
||||
#~(string-append "\naccount " #$value "\n"))
|
||||
|
||||
(define (msmtp-account-serialize-msmtp-configuration field-name value)
|
||||
#~(string-append #$(serialize-configuration value msmtp-configuration-fields)))
|
||||
|
||||
(define (home-msmtp-configuration-serialize-list-of-msmtp-accounts field-name value)
|
||||
#~(string-append #$@(map (cut serialize-configuration <> msmtp-account-fields)
|
||||
value)))
|
||||
|
||||
(define (home-msmtp-configuration-serialize-msmtp-configuration field-name value)
|
||||
#~(string-append "defaults\n"
|
||||
#$(serialize-configuration value msmtp-configuration-fields)))
|
||||
|
||||
(define (home-msmtp-configuration-serialize-default-account field-name value)
|
||||
#~(if #$(maybe-value-set? value)
|
||||
(string-append "\naccount default : " #$value "\n")
|
||||
""))
|
||||
|
||||
(define (home-msmtp-configuration-serialize-extra-content field-name value)
|
||||
#~(if (string=? #$value "") "" (string-append #$value "\n")))
|
||||
|
||||
;; Configuration of 'msmtp'.
|
||||
;; Source <https://marlam.de/msmtp/msmtp.html#Configuration-files>.
|
||||
(define-configuration msmtp-configuration
|
||||
(auth?
|
||||
maybe-boolean
|
||||
"Enable or disable authentication.")
|
||||
|
||||
(tls?
|
||||
maybe-boolean
|
||||
"Enable or disable TLS (also known as SSL) for secured connections.")
|
||||
|
||||
(tls-starttls?
|
||||
maybe-boolean
|
||||
"Choose the TLS variant: start TLS from within the session (‘on’, default),
|
||||
or tunnel the session through TLS (‘off’).")
|
||||
|
||||
(tls-trust-file
|
||||
maybe-string
|
||||
"Activate server certificate verification using a list of
|
||||
trusted Certification Authorities (CAs).")
|
||||
|
||||
(log-file
|
||||
maybe-string
|
||||
"Enable logging to the specified file. An empty argument disables logging.
|
||||
The file name ‘-’ directs the log information to standard output."
|
||||
(serializer msmtp-configuration-serialize-maybe-string-no-underscore))
|
||||
|
||||
(host
|
||||
maybe-string
|
||||
"The SMTP server to send the mail to.")
|
||||
|
||||
(port
|
||||
maybe-integer
|
||||
"The port that the SMTP server listens on. The default is 25 (\"smtp\"),
|
||||
unless TLS without STARTTLS is used, in which case it is 465 (\"smtps\").")
|
||||
|
||||
(user
|
||||
maybe-string
|
||||
"Set the user name for authentication.")
|
||||
|
||||
(from
|
||||
maybe-string
|
||||
"Set the envelope-from address.")
|
||||
|
||||
(password-eval
|
||||
maybe-string
|
||||
"Set the password for authentication to the output (stdout) of the command cmd."
|
||||
(serializer msmtp-configuration-serialize-maybe-string-no-underscore))
|
||||
|
||||
(extra-content
|
||||
(string "")
|
||||
"Extra content appended as-is to the configuration block. Run
|
||||
@command{man msmtp} for more information about the configuration file
|
||||
format."
|
||||
(serializer msmtp-configuration-serialize-extra-content))
|
||||
|
||||
(prefix msmtp-configuration-))
|
||||
|
||||
(define-configuration msmtp-account
|
||||
(name
|
||||
(string)
|
||||
"The unique name of the account."
|
||||
(serializer msmtp-account-serialize-name))
|
||||
|
||||
(configuration
|
||||
(msmtp-configuration)
|
||||
"The configuration for this given account.")
|
||||
|
||||
(prefix msmtp-account-))
|
||||
|
||||
(define (list-of-msmtp-accounts? lst)
|
||||
(every msmtp-account? lst))
|
||||
|
||||
(define-configuration home-msmtp-configuration
|
||||
(defaults
|
||||
(msmtp-configuration (msmtp-configuration))
|
||||
"The configuration that will be set as default for all accounts.")
|
||||
|
||||
(accounts
|
||||
(list-of-msmtp-accounts '())
|
||||
"A list of @code{msmtp-account} records which contain
|
||||
information about all your accounts.")
|
||||
|
||||
(default-account
|
||||
maybe-string
|
||||
"Set the default account."
|
||||
(serializer home-msmtp-configuration-serialize-default-account))
|
||||
|
||||
(extra-content
|
||||
(string "")
|
||||
"Extra content appended as-is to the configuration file. Run
|
||||
@command{man msmtp} for more information about the configuration file
|
||||
format."
|
||||
(serializer home-msmtp-configuration-serialize-extra-content))
|
||||
|
||||
(prefix home-msmtp-configuration-))
|
||||
|
||||
(define (home-msmtp-files config)
|
||||
(list
|
||||
`(".config/msmtp/config"
|
||||
,(mixed-text-file "msmtp-config"
|
||||
(serialize-configuration config home-msmtp-configuration-fields)))))
|
||||
|
||||
(define (home-msmtp-profile-entries config)
|
||||
(list msmtp))
|
||||
|
||||
(define home-msmtp-service-type
|
||||
(service-type (name 'home-msmtp)
|
||||
(extensions
|
||||
(list (service-extension home-profile-service-type
|
||||
home-msmtp-profile-entries)
|
||||
(service-extension home-files-service-type
|
||||
home-msmtp-files)))
|
||||
(default-value (home-msmtp-configuration))
|
||||
(description "Configure msmtp, a simple
|
||||
@acronym{SMTP, Simple Mail Transfer Protocol} client that can relay email
|
||||
to SMTP servers.")))
|
||||
+66
-15
@@ -1,8 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2021, 2023 Andrew Tropin <andrew@trop.in>
|
||||
;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
|
||||
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
|
||||
;;; Copyright © 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||
;;; Copyright © 2023 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -20,9 +18,15 @@
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu home services mcron)
|
||||
#:use-module (gnu packages guile-xyz)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu services shepherd)
|
||||
#:use-module (gnu home services shepherd)
|
||||
#:use-module (gnu services mcron) ;for the service mapping
|
||||
#:use-module (guix records)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (ice-9 match)
|
||||
|
||||
#:export (home-mcron-configuration
|
||||
home-mcron-service-type))
|
||||
|
||||
@@ -49,16 +53,63 @@
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
(define-syntax-rule (home-mcron-configuration fields ...)
|
||||
;; Macro provided for backward compatibility.
|
||||
(for-home (mcron-configuration fields ...)))
|
||||
(define-record-type* <home-mcron-configuration> home-mcron-configuration
|
||||
make-home-mcron-configuration
|
||||
home-mcron-configuration?
|
||||
(package home-mcron-configuration-package ; package
|
||||
(default mcron))
|
||||
(jobs home-mcron-configuration-jobs ; list of jobs
|
||||
(default '())))
|
||||
|
||||
(define job-files (@@ (gnu services mcron) job-files))
|
||||
(define shepherd-schedule-action
|
||||
(@@ (gnu services mcron) shepherd-schedule-action))
|
||||
|
||||
(define home-mcron-shepherd-services
|
||||
(match-lambda
|
||||
(($ <home-mcron-configuration> mcron '()) ; no jobs to run
|
||||
'())
|
||||
(($ <home-mcron-configuration> mcron jobs)
|
||||
(let ((files (job-files mcron jobs)))
|
||||
(list (shepherd-service
|
||||
(documentation "User cron jobs.")
|
||||
(provision '(mcron))
|
||||
(modules `((srfi srfi-1)
|
||||
(srfi srfi-26)
|
||||
(ice-9 popen) ; for the 'schedule' action
|
||||
(ice-9 rdelim)
|
||||
(ice-9 match)
|
||||
,@%default-modules))
|
||||
(start #~(make-forkexec-constructor
|
||||
(list #$(file-append mcron "/bin/mcron") #$@files)
|
||||
#:log-file (string-append
|
||||
(or (getenv "XDG_LOG_HOME")
|
||||
(format #f "~a/.local/var/log"
|
||||
(getenv "HOME")))
|
||||
"/mcron.log")))
|
||||
(stop #~(make-kill-destructor))
|
||||
(actions
|
||||
(list (shepherd-schedule-action mcron files)))))))))
|
||||
|
||||
(define home-mcron-profile (compose list home-mcron-configuration-package))
|
||||
|
||||
(define (home-mcron-extend config jobs)
|
||||
(home-mcron-configuration
|
||||
(inherit config)
|
||||
(jobs (append (home-mcron-configuration-jobs config)
|
||||
jobs))))
|
||||
|
||||
(define home-mcron-service-type
|
||||
(service-type
|
||||
(inherit (system->home-service-type mcron-service-type))
|
||||
(default-value (for-home (mcron-configuration)))))
|
||||
|
||||
(define-service-type-mapping
|
||||
mcron-service-type => home-mcron-service-type)
|
||||
|
||||
;;; mcron.scm ends here
|
||||
(service-type (name 'home-mcron)
|
||||
(extensions
|
||||
(list (service-extension
|
||||
home-shepherd-service-type
|
||||
home-mcron-shepherd-services)
|
||||
(service-extension
|
||||
home-profile-service-type
|
||||
home-mcron-profile)))
|
||||
(compose concatenate)
|
||||
(extend home-mcron-extend)
|
||||
(default-value (home-mcron-configuration))
|
||||
(description
|
||||
"Install and configure the GNU mcron cron job manager.")))
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu home services media)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu home services shepherd)
|
||||
#:use-module (gnu packages kodi)
|
||||
#:use-module (gnu services configuration)
|
||||
#:use-module (gnu services shepherd)
|
||||
#:use-module (guix records)
|
||||
#:use-module (guix gexp)
|
||||
#:export (home-kodi-configuration
|
||||
home-kodi-service-type))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Kodi.
|
||||
;;;
|
||||
|
||||
(define-record-type* <home-kodi-configuration>
|
||||
home-kodi-configuration make-home-kodi-configuration
|
||||
home-kodi-configuration?
|
||||
(kodi home-kodi-kodi ;file-like
|
||||
(default kodi))
|
||||
(extra-options home-kodi-extra-options ;list of string
|
||||
(default '())))
|
||||
|
||||
(define (home-kodi-services config)
|
||||
"Return a <shepherd-service> for kodi with CONFIG."
|
||||
(match-record config <home-kodi-configuration>
|
||||
(kodi extra-options)
|
||||
(let* ((kodi (file-append kodi "/bin/kodi"))
|
||||
(command #~'(#$kodi "-fs" #$@extra-options))
|
||||
(log-file #~(string-append %user-log-dir "/kodi.log")))
|
||||
(list (shepherd-service
|
||||
(documentation "Run the kodi media center.")
|
||||
(provision '(kodi))
|
||||
(modules '((shepherd support))) ;for '%user-log-dir'
|
||||
(start #~(make-forkexec-constructor #$command
|
||||
#:log-file #$log-file))
|
||||
(stop #~(make-kill-destructor)))))))
|
||||
|
||||
(define home-kodi-service-type
|
||||
(service-type
|
||||
(name 'home-kodi)
|
||||
(default-value (home-kodi-configuration))
|
||||
(extensions
|
||||
(list (service-extension home-shepherd-service-type
|
||||
home-kodi-services)))
|
||||
(description
|
||||
"Install and configure the Kodi media center so that it runs as a Shepherd
|
||||
service.")))
|
||||
@@ -1,66 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu home services messaging)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu home services shepherd)
|
||||
#:use-module (gnu packages messaging)
|
||||
#:use-module (gnu services configuration)
|
||||
#:use-module (gnu services shepherd)
|
||||
#:use-module (guix records)
|
||||
#:use-module (guix gexp)
|
||||
#:export (home-znc-configuration
|
||||
home-znc-service-type))
|
||||
|
||||
;;;
|
||||
;;; Znc.
|
||||
;;;
|
||||
(define-record-type* <home-znc-configuration>
|
||||
home-znc-configuration make-home-znc-configuration
|
||||
home-znc-configuration?
|
||||
(znc home-znc-znc ;string
|
||||
(default znc))
|
||||
(extra-options home-znc-extra-options ;list of string
|
||||
(default '())))
|
||||
|
||||
(define (home-znc-services config)
|
||||
"Return a <shepherd-service> for znc with CONFIG."
|
||||
(match-record config <home-znc-configuration>
|
||||
(znc extra-options)
|
||||
(let* ((znc (file-append znc "/bin/znc"))
|
||||
(command #~'(#$znc "--foreground" #$@extra-options))
|
||||
(log-file #~(string-append %user-log-dir "/znc.log")))
|
||||
(list (shepherd-service
|
||||
(documentation "Run the znc IRC bouncer.")
|
||||
(provision '(znc))
|
||||
(modules '((shepherd support))) ;for '%user-log-dir'
|
||||
(start #~(make-forkexec-constructor #$command
|
||||
#:log-file #$log-file))
|
||||
(stop #~(make-kill-destructor)))))))
|
||||
|
||||
(define home-znc-service-type
|
||||
(service-type
|
||||
(name 'home-znc)
|
||||
(default-value (home-znc-configuration))
|
||||
(extensions
|
||||
(list (service-extension home-shepherd-service-type
|
||||
home-znc-services)))
|
||||
(description
|
||||
"Install and configure @command{znc}, an @acronym{IRC, Internet Relay
|
||||
Chat} bouncer, as a Shepherd service.")))
|
||||
@@ -1,145 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2022 ( <paren@disroot.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify
|
||||
;;; it under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation, either version 3 of the License, or
|
||||
;;; (at your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful,
|
||||
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu home services pm)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix packages)
|
||||
#:use-module (guix records)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu home services shepherd)
|
||||
#:use-module (gnu packages monitoring)
|
||||
#:use-module (gnu services shepherd)
|
||||
|
||||
#:export (home-batsignal-configuration
|
||||
home-batsignal-service-type))
|
||||
|
||||
;;;
|
||||
;;; batsignal
|
||||
;;;
|
||||
;;; Daemon for running commands and displaying notifications on
|
||||
;;; battery events.
|
||||
;;;
|
||||
|
||||
(define-record-type* <home-batsignal-configuration>
|
||||
home-batsignal-configuration make-home-batsignal-configuration
|
||||
home-batsignal-configuration?
|
||||
(warning-level batsignal-warning-level ;integer
|
||||
(default 15))
|
||||
(warning-message batsignal-warning-message ;string | #f
|
||||
(default #f))
|
||||
(critical-level batsignal-critical-level ;integer
|
||||
(default 5))
|
||||
(critical-message batsignal-critical-message ;string | #f
|
||||
(default #f))
|
||||
(danger-level batsignal-danger-level ;integer
|
||||
(default 2))
|
||||
(danger-command batsignal-danger-command ;file-like | string | #f
|
||||
(default #f))
|
||||
(full-level batsignal-full-level ;integer | #f
|
||||
(default #f))
|
||||
(full-message batsignal-full-message ;string | #f
|
||||
(default #f))
|
||||
(batteries batsignal-batteries ;list of string
|
||||
(default '()))
|
||||
(poll-delay batsignal-poll-delay ;integer
|
||||
(default 60))
|
||||
(icon batsignal-icon ;file-like | #f
|
||||
(default #f))
|
||||
(notifications? batsignal-notifications? ;boolean
|
||||
(default #t))
|
||||
(notifications-expire? batsignal-notifications-expire? ;boolean
|
||||
(default #f))
|
||||
(notification-command batsignal-notification-command ;string | #f
|
||||
(default #f))
|
||||
(ignore-missing? batsignal-ignore-missing? ;boolean
|
||||
(default #f)))
|
||||
|
||||
(define (home-batsignal-shepherd-services config)
|
||||
(let ((warning-level (batsignal-warning-level config))
|
||||
(warning-message (batsignal-warning-message config))
|
||||
(critical-level (batsignal-critical-level config))
|
||||
(critical-message (batsignal-critical-message config))
|
||||
(danger-level (batsignal-danger-level config))
|
||||
(danger-command (batsignal-danger-command config))
|
||||
(full-level (batsignal-full-level config))
|
||||
(full-message (batsignal-full-message config))
|
||||
(batteries (batsignal-batteries config))
|
||||
(poll-delay (batsignal-poll-delay config))
|
||||
(icon (batsignal-icon config))
|
||||
(notifications? (batsignal-notifications? config))
|
||||
(notifications-expire? (batsignal-notifications-expire? config))
|
||||
(notification-command (batsignal-notification-command config))
|
||||
(ignore-missing? (batsignal-ignore-missing? config)))
|
||||
(list (shepherd-service
|
||||
(provision '(batsignal))
|
||||
(documentation "Run the batsignal battery-watching daemon.")
|
||||
(start #~(make-forkexec-constructor
|
||||
(append (list #$(file-append batsignal "/bin/batsignal")
|
||||
"-w" (number->string #$warning-level)
|
||||
"-c" (number->string #$critical-level)
|
||||
"-d" (number->string #$danger-level)
|
||||
"-m" (number->string #$poll-delay))
|
||||
(if #$warning-message
|
||||
(list "-W" #$warning-message)
|
||||
(list))
|
||||
(if #$critical-message
|
||||
(list "-C" #$critical-message)
|
||||
(list))
|
||||
(if #$danger-command
|
||||
(list "-D" #$danger-command)
|
||||
(list))
|
||||
(if #$full-level
|
||||
(list "-f" (number->string #$full-level))
|
||||
(list))
|
||||
(if #$full-message
|
||||
(list "-F" #$full-message)
|
||||
(list))
|
||||
(if (null? (list #$@batteries))
|
||||
(list)
|
||||
(list "-n" (string-join (list #$@batteries) ",")))
|
||||
(if #$icon
|
||||
(list "-I" #$icon)
|
||||
(list))
|
||||
(if #$notifications?
|
||||
(list)
|
||||
(list "-N"))
|
||||
(if #$notifications-expire?
|
||||
(list "-e")
|
||||
(list))
|
||||
(if #$notification-command
|
||||
(list "-M" #$notification-command)
|
||||
(list))
|
||||
(if #$ignore-missing?
|
||||
(list "-i")
|
||||
(list)))
|
||||
#:log-file (string-append
|
||||
(or (getenv "XDG_STATE_HOME")
|
||||
(format #f "~a/.local/state"
|
||||
(getenv "HOME")))
|
||||
"/log/batsignal.log")))
|
||||
(stop #~(make-kill-destructor))))))
|
||||
|
||||
(define home-batsignal-service-type
|
||||
(service-type
|
||||
(name 'home-batsignal)
|
||||
(extensions
|
||||
(list (service-extension home-shepherd-service-type
|
||||
home-batsignal-shepherd-services)))
|
||||
(default-value (home-batsignal-configuration))
|
||||
(description
|
||||
"Run batsignal, a battery watching and notification daemon.")))
|
||||
+114
-219
@@ -1,7 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
|
||||
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
|
||||
;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -20,14 +19,12 @@
|
||||
|
||||
(define-module (gnu home services shells)
|
||||
#:use-module (gnu services configuration)
|
||||
#:autoload (gnu system shadow) (%default-bashrc)
|
||||
#:use-module (gnu home services utils)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu packages shells)
|
||||
#:use-module (gnu packages bash)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix packages)
|
||||
#:use-module (guix records)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:use-module (ice-9 match)
|
||||
@@ -45,10 +42,7 @@
|
||||
|
||||
home-fish-service-type
|
||||
home-fish-configuration
|
||||
home-fish-extension
|
||||
|
||||
home-inputrc-service-type
|
||||
home-inputrc-configuration))
|
||||
home-fish-extension))
|
||||
|
||||
;;; Commentary:
|
||||
;;;
|
||||
@@ -83,7 +77,7 @@ user's customizations. Extend home-shell-profile service only if you
|
||||
really know what you do."))
|
||||
|
||||
(define (add-shell-profile-file config)
|
||||
`((".profile"
|
||||
`(("profile"
|
||||
,(mixed-text-file
|
||||
"shell-profile"
|
||||
"\
|
||||
@@ -117,7 +111,16 @@ service type can be extended with a list of file-like objects.")))
|
||||
|
||||
(define (serialize-boolean field-name val) "")
|
||||
(define (serialize-posix-env-vars field-name val)
|
||||
(environment-variable-shell-definitions val))
|
||||
#~(string-append
|
||||
#$@(map
|
||||
(match-lambda
|
||||
((key . #f)
|
||||
"")
|
||||
((key . #t)
|
||||
#~(string-append "export " #$key "\n"))
|
||||
((key . value)
|
||||
#~(string-append "export " #$key "=" #$value "\n")))
|
||||
val)))
|
||||
|
||||
|
||||
;;;
|
||||
@@ -137,7 +140,7 @@ Shell startup process will continue with
|
||||
(environment-variables
|
||||
(alist '())
|
||||
"Association list of environment variables to set for the Zsh session."
|
||||
(serializer serialize-posix-env-vars))
|
||||
serialize-posix-env-vars)
|
||||
(zshenv
|
||||
(text-config '())
|
||||
"List of file-like objects, which will be added to @file{.zshenv}.
|
||||
@@ -189,9 +192,9 @@ another process for example)."))
|
||||
(mixed-text-file
|
||||
"zprofile"
|
||||
"\
|
||||
# Set up the system, user profile, and related variables.
|
||||
# Setups system and user profiles and related variables
|
||||
source /etc/profile
|
||||
# Set up the home environment profile.
|
||||
# Setups home environment profile
|
||||
source ~/.profile
|
||||
|
||||
# It's only necessary if zsh is a login shell, otherwise profiles will
|
||||
@@ -208,18 +211,18 @@ source ~/.profile
|
||||
(zsh-serialize-field config field)))))
|
||||
|
||||
(define (zsh-get-configuration-files config)
|
||||
`((".zprofile" ,(zsh-file-by-field config 'zprofile)) ;; Always non-empty
|
||||
,@(if (or (zsh-field-not-empty? config 'zshenv)
|
||||
(zsh-field-not-empty? config 'environment-variables))
|
||||
`((".zshenv" ,(zsh-file-by-field config 'zshenv))) '())
|
||||
`(("zprofile" ,(zsh-file-by-field config 'zprofile)) ;; Always non-empty
|
||||
,@(if (and (zsh-field-not-empty? config 'zshenv)
|
||||
(zsh-field-not-empty? config 'environment-variables))
|
||||
`(("zshenv" ,(zsh-file-by-field config 'zshenv))) '())
|
||||
,@(if (zsh-field-not-empty? config 'zshrc)
|
||||
`((".zshrc" ,(zsh-file-by-field config 'zshrc))) '())
|
||||
`(("zshrc" ,(zsh-file-by-field config 'zshrc))) '())
|
||||
,@(if (zsh-field-not-empty? config 'zlogin)
|
||||
`((".zlogin" ,(zsh-file-by-field config 'zlogin))) '())
|
||||
`(("zlogin" ,(zsh-file-by-field config 'zlogin))) '())
|
||||
,@(if (zsh-field-not-empty? config 'zlogout)
|
||||
`((".zlogout" ,(zsh-file-by-field config 'zlogout))) '())))
|
||||
`(("zlogout" ,(zsh-file-by-field config 'zlogout))) '())))
|
||||
|
||||
(define (add-zsh-dot-configuration config)
|
||||
(define (zsh-home-files config)
|
||||
(define zshenv-auxiliary-file
|
||||
(mixed-text-file
|
||||
"zshenv-auxiliary"
|
||||
@@ -227,14 +230,14 @@ source ~/.profile
|
||||
"[[ -f $ZDOTDIR/.zshenv ]] && source $ZDOTDIR/.zshenv\n"))
|
||||
|
||||
(if (home-zsh-configuration-xdg-flavor? config)
|
||||
`((".zshenv" ,zshenv-auxiliary-file))
|
||||
`(("zshenv" ,zshenv-auxiliary-file))
|
||||
(zsh-get-configuration-files config)))
|
||||
|
||||
(define (add-zsh-xdg-configuration config)
|
||||
(define (zsh-xdg-configuration-files config)
|
||||
(if (home-zsh-configuration-xdg-flavor? config)
|
||||
(map
|
||||
(lambda (lst)
|
||||
(cons (string-append "zsh/" (car lst))
|
||||
(cons (string-append "zsh/." (car lst))
|
||||
(cdr lst)))
|
||||
(zsh-get-configuration-files config))
|
||||
'()))
|
||||
@@ -295,10 +298,10 @@ source ~/.profile
|
||||
(extensions
|
||||
(list (service-extension
|
||||
home-files-service-type
|
||||
add-zsh-dot-configuration)
|
||||
zsh-home-files)
|
||||
(service-extension
|
||||
home-xdg-configuration-files-service-type
|
||||
add-zsh-xdg-configuration)
|
||||
zsh-xdg-configuration-files)
|
||||
(service-extension
|
||||
home-profile-service-type
|
||||
add-zsh-packages)))
|
||||
@@ -313,24 +316,16 @@ source ~/.profile
|
||||
;;;
|
||||
|
||||
(define (bash-serialize-aliases field-name val)
|
||||
(with-shell-quotation-bindings
|
||||
#~(string-append
|
||||
#$@(map
|
||||
(match-lambda
|
||||
((key . #f)
|
||||
"")
|
||||
((key . #t)
|
||||
#~(string-append "alias " #$key "\n"))
|
||||
((key . (? literal-string? value))
|
||||
#~(string-append "alias " #$key "="
|
||||
(shell-single-quote
|
||||
#$(literal-string-value value))
|
||||
"\n"))
|
||||
((key . value)
|
||||
#~(string-append "alias " #$key "="
|
||||
(shell-double-quote #$value)
|
||||
"\n")))
|
||||
val))))
|
||||
#~(string-append
|
||||
#$@(map
|
||||
(match-lambda
|
||||
((key . #f)
|
||||
"")
|
||||
((key . #t)
|
||||
#~(string-append "alias " #$key "\n"))
|
||||
((key . value)
|
||||
#~(string-append "alias " #$key "=\"" #$value "\"\n")))
|
||||
val)))
|
||||
|
||||
(define-configuration home-bash-configuration
|
||||
(package
|
||||
@@ -346,7 +341,7 @@ source ~/.profile
|
||||
rules for the @code{home-environment-variables-service-type} apply
|
||||
here (@pxref{Essential Home Services}). The contents of this field will be
|
||||
added after the contents of the @code{bash-profile} field."
|
||||
(serializer serialize-posix-env-vars))
|
||||
serialize-posix-env-vars)
|
||||
(aliases
|
||||
(alist '())
|
||||
"Association list of aliases to set for the Bash session. The aliases will be
|
||||
@@ -363,7 +358,7 @@ turns into
|
||||
@example
|
||||
alias ls=\"ls -alF\"
|
||||
@end example"
|
||||
(serializer bash-serialize-aliases))
|
||||
bash-serialize-aliases)
|
||||
(bash-profile
|
||||
(text-config '())
|
||||
"List of file-like objects, which will be added to @file{.bash_profile}.
|
||||
@@ -383,6 +378,43 @@ Used for executing user's commands at the exit of login shell. It
|
||||
won't be read in some cases (if the shell terminates by exec'ing
|
||||
another process for example)."))
|
||||
|
||||
;; TODO: Use value from (gnu system shadow)
|
||||
(define guix-bashrc
|
||||
"\
|
||||
# Bash initialization for interactive non-login shells and
|
||||
# for remote shells (info \"(bash) Bash Startup Files\").
|
||||
|
||||
# Export 'SHELL' to child processes. Programs such as 'screen'
|
||||
# honor it and otherwise use /bin/sh.
|
||||
export SHELL
|
||||
|
||||
if [[ $- != *i* ]]
|
||||
then
|
||||
# We are being invoked from a non-interactive shell. If this
|
||||
# is an SSH session (as in \"ssh host command\"), source
|
||||
# /etc/profile so we get PATH and other essential variables.
|
||||
[[ -n \"$SSH_CLIENT\" ]] && source /etc/profile
|
||||
|
||||
# Don't do anything else.
|
||||
return
|
||||
fi
|
||||
|
||||
# Source the system-wide file.
|
||||
if [[ -e /etc/bashrc ]]; then
|
||||
source /etc/bashrc
|
||||
fi
|
||||
|
||||
# Adjust the prompt depending on whether we're in 'guix environment'.
|
||||
if [ -n \"$GUIX_ENVIRONMENT\" ]
|
||||
then
|
||||
PS1='\\u@\\h \\w [env]\\$ '
|
||||
else
|
||||
PS1='\\u@\\h \\w\\$ '
|
||||
fi
|
||||
alias ls='ls -p --color=auto'
|
||||
alias ll='ls -l'
|
||||
alias grep='grep --color=auto'\n")
|
||||
|
||||
(define (add-bash-configuration config)
|
||||
(define (filter-fields field)
|
||||
(filter-configuration-fields home-bash-configuration-fields
|
||||
@@ -398,7 +430,7 @@ another process for example)."))
|
||||
(field-obj (car (filter-fields field))))
|
||||
(if (or extra-content
|
||||
(not (null? ((configuration-field-getter field-obj) config))))
|
||||
`(,(string-append "." (object->snake-case-string file-name))
|
||||
`(,(object->snake-case-string file-name)
|
||||
,(apply mixed-text-file
|
||||
(object->snake-case-string file-name)
|
||||
(append (or extra-content '())
|
||||
@@ -407,35 +439,25 @@ another process for example)."))
|
||||
|
||||
(filter
|
||||
(compose not null?)
|
||||
`((".bash_profile"
|
||||
`(("bash_profile"
|
||||
,(mixed-text-file
|
||||
"bash_profile"
|
||||
"\
|
||||
# Set up the system, user profile, and related variables.
|
||||
# Setups system and user profiles and related variables
|
||||
# /etc/profile will be sourced by bash automatically
|
||||
# Set up the home environment profile.
|
||||
# Setups home environment profile
|
||||
if [ -f ~/.profile ]; then source ~/.profile; fi
|
||||
|
||||
# Honor per-interactive-shell startup file
|
||||
if [ -f ~/.bashrc ]; then source ~/.bashrc; fi
|
||||
"
|
||||
|
||||
;; The host distro might provide a bad 'PS1' default--e.g., not taking
|
||||
;; $GUIX_ENVIRONMENT into account. Provide a good default here when
|
||||
;; asked to. The default can be overridden below via
|
||||
;; 'environment-variables'.
|
||||
(if (home-bash-configuration-guix-defaults? config)
|
||||
"PS1='\\u@\\h \\w${GUIX_ENVIRONMENT:+ [env]}\\$ '\n"
|
||||
"")
|
||||
|
||||
(serialize-field 'bash-profile)
|
||||
(serialize-field 'environment-variables)))
|
||||
|
||||
,@(list (file-if-not-empty
|
||||
'bashrc
|
||||
(if (home-bash-configuration-guix-defaults? config)
|
||||
(list (serialize-field 'aliases)
|
||||
(plain-file-content %default-bashrc))
|
||||
(list (serialize-field 'aliases) guix-bashrc)
|
||||
(list (serialize-field 'aliases))))
|
||||
(file-if-not-empty 'bash-logout)))))
|
||||
|
||||
@@ -466,30 +488,31 @@ with text blocks from other extensions and the base service.")
|
||||
with text blocks from other extensions and the base service."))
|
||||
|
||||
(define (home-bash-extensions original-config extension-configs)
|
||||
(match-record original-config <home-bash-configuration>
|
||||
(environment-variables aliases bash-profile bashrc bash-logout)
|
||||
(home-bash-configuration
|
||||
(inherit original-config)
|
||||
(environment-variables
|
||||
(append environment-variables
|
||||
(append-map
|
||||
home-bash-extension-environment-variables extension-configs)))
|
||||
(aliases
|
||||
(append aliases
|
||||
(append-map
|
||||
home-bash-extension-aliases extension-configs)))
|
||||
(bash-profile
|
||||
(append bash-profile
|
||||
(append-map
|
||||
home-bash-extension-bash-profile extension-configs)))
|
||||
(bashrc
|
||||
(append bashrc
|
||||
(append-map
|
||||
home-bash-extension-bashrc extension-configs)))
|
||||
(bash-logout
|
||||
(append bash-logout
|
||||
(append-map
|
||||
home-bash-extension-bash-logout extension-configs))))))
|
||||
(match original-config
|
||||
(($ <home-bash-configuration> _ _ _ environment-variables aliases
|
||||
bash-profile bashrc bash-logout)
|
||||
(home-bash-configuration
|
||||
(inherit original-config)
|
||||
(environment-variables
|
||||
(append environment-variables
|
||||
(append-map
|
||||
home-bash-extension-environment-variables extension-configs)))
|
||||
(aliases
|
||||
(append aliases
|
||||
(append-map
|
||||
home-bash-extension-aliases extension-configs)))
|
||||
(bash-profile
|
||||
(append bash-profile
|
||||
(append-map
|
||||
home-bash-extension-bash-profile extension-configs)))
|
||||
(bashrc
|
||||
(append bashrc
|
||||
(append-map
|
||||
home-bash-extension-bashrc extension-configs)))
|
||||
(bash-logout
|
||||
(append bash-logout
|
||||
(append-map
|
||||
home-bash-extension-bash-logout extension-configs)))))))
|
||||
|
||||
(define home-bash-service-type
|
||||
(service-type (name 'home-bash)
|
||||
@@ -532,9 +555,9 @@ with text blocks from other extensions and the base service."))
|
||||
((key . #f)
|
||||
"")
|
||||
((key . #t)
|
||||
#~(string-append "set -x " #$key "\n"))
|
||||
#~(string-append "set " #$key "\n"))
|
||||
((key . value)
|
||||
#~(string-append "set -x " #$key " " #$value "\n")))
|
||||
#~(string-append "set " #$key " " #$value "\n")))
|
||||
val)))
|
||||
|
||||
(define-configuration home-fish-configuration
|
||||
@@ -548,22 +571,22 @@ with text blocks from other extensions and the base service."))
|
||||
(environment-variables
|
||||
(alist '())
|
||||
"Association list of environment variables to set in Fish."
|
||||
(serializer serialize-fish-env-vars))
|
||||
serialize-fish-env-vars)
|
||||
(aliases
|
||||
(alist '())
|
||||
"Association list of aliases for Fish, both the key and the value
|
||||
should be a string. An alias is just a simple function that wraps a
|
||||
command, If you want something more akin to @dfn{aliases} in POSIX
|
||||
shells, see the @code{abbreviations} field."
|
||||
(serializer serialize-fish-aliases))
|
||||
serialize-fish-aliases)
|
||||
(abbreviations
|
||||
(alist '())
|
||||
"Association list of abbreviations for Fish. These are words that,
|
||||
when typed in the shell, will automatically expand to the full text."
|
||||
(serializer serialize-fish-abbreviations)))
|
||||
serialize-fish-abbreviations))
|
||||
|
||||
(define (fish-files-service config)
|
||||
`(("fish/config.fish"
|
||||
`(("config/fish/config.fish"
|
||||
,(mixed-text-file
|
||||
"fish-config.fish"
|
||||
#~(string-append "\
|
||||
@@ -627,7 +650,7 @@ end\n\n")
|
||||
(service-type (name 'home-fish)
|
||||
(extensions
|
||||
(list (service-extension
|
||||
home-xdg-configuration-files-service-type
|
||||
home-files-service-type
|
||||
fish-files-service)
|
||||
(service-extension
|
||||
home-profile-service-type
|
||||
@@ -638,134 +661,6 @@ end\n\n")
|
||||
(description "\
|
||||
Install and configure Fish, the friendly interactive shell.")))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Readline.
|
||||
;;;
|
||||
|
||||
(define (serialize-inputrc-key-bindings field-name val)
|
||||
#~(string-append
|
||||
#$@(map
|
||||
(match-lambda
|
||||
((key . value)
|
||||
#~(string-append #$key ": " #$value "\n")))
|
||||
val)))
|
||||
|
||||
(define (serialize-inputrc-variables field-name val)
|
||||
#~(string-append
|
||||
#$@(map
|
||||
(match-lambda
|
||||
((key . #f)
|
||||
#~(string-append "set " #$key " off\n"))
|
||||
((key . #t)
|
||||
#~(string-append "set " #$key " on\n"))
|
||||
((key . value)
|
||||
#~(string-append "set " #$key " " #$value "\n")))
|
||||
val)))
|
||||
|
||||
(define (serialize-inputrc-conditional-constructs field-name val)
|
||||
#~(string-append
|
||||
#$@(map
|
||||
(match-lambda
|
||||
(("$endif" . _)
|
||||
"$endif\n")
|
||||
(("$include" . value)
|
||||
#~(string-append "$include " #$value "\n"))
|
||||
;; TODO: key can only be "$if" or "$else".
|
||||
((key . value)
|
||||
#~(string-append #$key "\n"
|
||||
#$(serialize-configuration
|
||||
value
|
||||
home-inputrc-configuration-fields))))
|
||||
val)))
|
||||
|
||||
(define (serialize-inputrc-extra-content field-name value)
|
||||
#~(if (string=? #$value "") "" (string-append #$value "\n")))
|
||||
|
||||
(define-configuration home-inputrc-configuration
|
||||
(key-bindings
|
||||
(alist '())
|
||||
"Association list of readline key bindings to be added to the
|
||||
@code{~/.inputrc} file. This is where code like this:
|
||||
|
||||
@lisp
|
||||
'((\"Control-l\" . \"clear-screen\"))
|
||||
@end lisp
|
||||
|
||||
turns into
|
||||
|
||||
@example
|
||||
Control-l: clear-screen
|
||||
@end example"
|
||||
(serializer serialize-inputrc-key-bindings))
|
||||
(variables
|
||||
(alist '())
|
||||
"Association list of readline variables to set. This is where configuration
|
||||
options like this:
|
||||
|
||||
@lisp
|
||||
'((\"bell-style\" . \"visible\")
|
||||
(\"colored-completion-prefix\" . #t))
|
||||
@end lisp
|
||||
|
||||
turns into
|
||||
|
||||
@example
|
||||
set bell-style visible
|
||||
set colored-completion-prefix on
|
||||
@end example"
|
||||
(serializer serialize-inputrc-variables))
|
||||
(conditional-constructs
|
||||
(alist '())
|
||||
"Association list of conditionals to add to the initialization file. This
|
||||
includes @command{$if}, @command{else}, @command{endif} and @command{include}
|
||||
and they receive a value of another @command{home-inputrc-configuration}.
|
||||
|
||||
@lisp
|
||||
(conditional-constructs
|
||||
`((\"$if mode=vi\" .
|
||||
,(home-inputrc-configuration
|
||||
(variables
|
||||
`((\"show-mode-in-prompt\" . #t)))))
|
||||
(\"$else\" .
|
||||
,(home-inputrc-configuration
|
||||
(key-bindings
|
||||
`((\"Control-l\" . \"clear-screen\")))))
|
||||
(\"$endif\" . #t)))
|
||||
@end lisp
|
||||
|
||||
turns into
|
||||
|
||||
@example
|
||||
$if mode=vi
|
||||
set show-mode-in-prompt on
|
||||
$else
|
||||
Control-l: clear-screen
|
||||
$endif
|
||||
@end example"
|
||||
(serializer serialize-inputrc-conditional-constructs))
|
||||
(extra-content
|
||||
(string "")
|
||||
"Extra content appended as-is to the configuration file. Run @command{man
|
||||
readline} for more information about all the configuration options."
|
||||
(serializer serialize-inputrc-extra-content)))
|
||||
|
||||
(define (home-inputrc-files config)
|
||||
(list
|
||||
`(".inputrc"
|
||||
,(mixed-text-file "inputrc"
|
||||
(serialize-configuration
|
||||
config
|
||||
home-inputrc-configuration-fields)))))
|
||||
|
||||
(define home-inputrc-service-type
|
||||
(service-type (name 'inputrc)
|
||||
(extensions
|
||||
(list (service-extension home-files-service-type
|
||||
home-inputrc-files)))
|
||||
(default-value (home-inputrc-configuration))
|
||||
(description "Configure readline in @code{.inputrc}.")))
|
||||
|
||||
|
||||
(define (generate-home-shell-profile-documentation)
|
||||
(generate-documentation
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2021, 2023 Andrew Tropin <andrew@trop.in>
|
||||
;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
|
||||
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
@@ -45,32 +45,28 @@
|
||||
shepherd-service-auto-start?
|
||||
shepherd-service-modules
|
||||
|
||||
shepherd-action
|
||||
shepherd-configuration-action))
|
||||
shepherd-action))
|
||||
|
||||
(define-record-type* <home-shepherd-configuration>
|
||||
home-shepherd-configuration make-home-shepherd-configuration
|
||||
home-shepherd-configuration?
|
||||
(shepherd home-shepherd-configuration-shepherd
|
||||
(default shepherd-0.10)) ; package
|
||||
(default shepherd)) ; package
|
||||
(auto-start? home-shepherd-configuration-auto-start?
|
||||
(default #t))
|
||||
(daemonize? home-shepherd-configuration-daemonize?
|
||||
(default #t))
|
||||
(services home-shepherd-configuration-services
|
||||
(default '())))
|
||||
|
||||
(define (home-shepherd-configuration-file config)
|
||||
(define (home-shepherd-configuration-file services shepherd)
|
||||
"Return the shepherd configuration file for SERVICES. SHEPHERD is used
|
||||
as shepherd package."
|
||||
(let* ((daemonize? (home-shepherd-configuration-daemonize? config))
|
||||
(services (home-shepherd-configuration-services config))
|
||||
(_ (assert-valid-graph services))
|
||||
(files (map shepherd-service-file services))
|
||||
;; TODO: Add compilation of services, it can improve start
|
||||
;; time.
|
||||
;; (scm->go (cute scm->go <> shepherd))
|
||||
)
|
||||
(assert-valid-graph services)
|
||||
|
||||
(let ((files (map shepherd-service-file services))
|
||||
;; TODO: Add compilation of services, it can improve start
|
||||
;; time.
|
||||
;; (scm->go (cute scm->go <> shepherd))
|
||||
)
|
||||
(define config
|
||||
#~(begin
|
||||
(use-modules (srfi srfi-34)
|
||||
@@ -80,54 +76,42 @@ as shepherd package."
|
||||
(map
|
||||
(lambda (file) (load file))
|
||||
'#$files))
|
||||
|
||||
#$@(if daemonize?
|
||||
`((action 'root 'daemonize))
|
||||
'())
|
||||
|
||||
(action 'root 'daemonize)
|
||||
(format #t "Starting services...~%")
|
||||
(let ((services-to-start
|
||||
'#$(append-map shepherd-service-provision
|
||||
(filter shepherd-service-auto-start?
|
||||
services))))
|
||||
(if (defined? 'start-in-the-background)
|
||||
(start-in-the-background services-to-start)
|
||||
(for-each start services-to-start))
|
||||
|
||||
(redirect-port (open-input-file "/dev/null")
|
||||
(current-input-port)))))
|
||||
(for-each
|
||||
(lambda (service) (start service))
|
||||
'#$(append-map shepherd-service-provision
|
||||
(filter shepherd-service-auto-start?
|
||||
services)))
|
||||
(newline)))
|
||||
|
||||
(scheme-file "shepherd.conf" config)))
|
||||
|
||||
(define (launch-shepherd-gexp config)
|
||||
(let* ((shepherd (home-shepherd-configuration-shepherd config)))
|
||||
(let* ((shepherd (home-shepherd-configuration-shepherd config))
|
||||
(services (home-shepherd-configuration-services config)))
|
||||
(if (home-shepherd-configuration-auto-start? config)
|
||||
(with-imported-modules '((guix build utils))
|
||||
#~(unless (file-exists?
|
||||
(string-append
|
||||
(or (getenv "XDG_RUNTIME_DIR")
|
||||
(format #f "/run/user/~a" (getuid)))
|
||||
"/shepherd/socket"))
|
||||
(let* ((state-dir (or (getenv "XDG_STATE_HOME")
|
||||
(format #f "~a/.local/state"
|
||||
(getenv "HOME"))))
|
||||
(log-dir (string-append state-dir "/log")))
|
||||
;; TODO: Remove it, 0.9.2 creates it automatically?
|
||||
((@ (guix build utils) mkdir-p) log-dir)
|
||||
(system*
|
||||
#$(file-append shepherd "/bin/shepherd")
|
||||
"--logfile"
|
||||
(string-append log-dir "/shepherd.log")
|
||||
"--config"
|
||||
#$(home-shepherd-configuration-file config)))))
|
||||
#~(let ((log-dir (or (getenv "XDG_LOG_HOME")
|
||||
(format #f "~a/.local/var/log" (getenv "HOME")))))
|
||||
((@ (guix build utils) mkdir-p) log-dir)
|
||||
(system*
|
||||
#$(file-append shepherd "/bin/shepherd")
|
||||
"--logfile"
|
||||
(string-append
|
||||
log-dir
|
||||
"/shepherd.log")
|
||||
"--config"
|
||||
#$(home-shepherd-configuration-file services shepherd))))
|
||||
#~"")))
|
||||
|
||||
(define (reload-configuration-gexp config)
|
||||
(let* ((shepherd (home-shepherd-configuration-shepherd config)))
|
||||
(let* ((shepherd (home-shepherd-configuration-shepherd config))
|
||||
(services (home-shepherd-configuration-services config)))
|
||||
#~(system*
|
||||
#$(file-append shepherd "/bin/herd")
|
||||
"load" "root"
|
||||
#$(home-shepherd-configuration-file config))))
|
||||
#$(home-shepherd-configuration-file services shepherd))))
|
||||
|
||||
(define (ensure-shepherd-gexp config)
|
||||
#~(if (file-exists?
|
||||
@@ -138,18 +122,12 @@ as shepherd package."
|
||||
#$(reload-configuration-gexp config)
|
||||
#$(launch-shepherd-gexp config)))
|
||||
|
||||
(define (shepherd-xdg-configuration-files config)
|
||||
`(("shepherd/init.scm" ,(home-shepherd-configuration-file config))))
|
||||
|
||||
(define home-shepherd-service-type
|
||||
(define-public home-shepherd-service-type
|
||||
(service-type (name 'home-shepherd)
|
||||
(extensions
|
||||
(list (service-extension
|
||||
home-run-on-first-login-service-type
|
||||
launch-shepherd-gexp)
|
||||
(service-extension
|
||||
home-xdg-configuration-files-service-type
|
||||
shepherd-xdg-configuration-files)
|
||||
(service-extension
|
||||
home-activation-service-type
|
||||
ensure-shepherd-gexp)
|
||||
@@ -168,6 +146,4 @@ as shepherd package."
|
||||
(default-value (home-shepherd-configuration))
|
||||
(description "Configure and install userland Shepherd.")))
|
||||
|
||||
(define-service-type-mapping
|
||||
shepherd-root-service-type => home-shepherd-service-type)
|
||||
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2023 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu home services sound)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu home services shepherd)
|
||||
#:use-module (guix records)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (ice-9 match)
|
||||
#:export (home-pulseaudio-rtp-sink-service-type
|
||||
home-pulseaudio-rtp-source-service-type
|
||||
%pulseaudio-rtp-multicast-address))
|
||||
|
||||
|
||||
;;;
|
||||
;;; PulseAudio support.
|
||||
;;;
|
||||
|
||||
(define (with-pulseaudio-connection sock exp)
|
||||
;; Wrap EXP in an expression where SOCK is bound to a socket connected to
|
||||
;; the user's PulseAudio command-line interface socket.
|
||||
#~(let* ((#$sock (socket AF_UNIX SOCK_STREAM 0))
|
||||
(pulse-user-file
|
||||
(lambda (name)
|
||||
(string-append "/run/user/" (number->string (getuid))
|
||||
"/pulse/" name)))
|
||||
(file (pulse-user-file "cli")))
|
||||
(let loop ((tries 0))
|
||||
(catch #t
|
||||
(lambda ()
|
||||
(connect #$sock AF_UNIX file)
|
||||
(let ((result #$exp))
|
||||
(close-port #$sock)
|
||||
result))
|
||||
(lambda (key . args)
|
||||
(if (and (eq? key 'system-error)
|
||||
(= ENOENT (system-error-errno (cons key args)))
|
||||
(< tries 3))
|
||||
;; The CLI socket doesn't exist yet, so send pulseaudio
|
||||
;; SIGUSR2 so that it creates it and listens to it.
|
||||
(let ((pid (call-with-input-file (pulse-user-file "pid")
|
||||
read)))
|
||||
(when (and (integer? pid) (> pid 1))
|
||||
(kill pid SIGUSR2))
|
||||
((@ (fibers) sleep) 1)
|
||||
(loop (+ tries 1)))
|
||||
(begin
|
||||
(close-port #$sock)
|
||||
(apply throw key args))))))))
|
||||
|
||||
(define %pulseaudio-rtp-multicast-address
|
||||
;; Default address used by 'module-rtp-sink' and 'module-rtp-recv'. This is
|
||||
;; a multicast address, for the Session Announcement Protocol (SAP) and the
|
||||
;; Session Description Protocol (SDP).
|
||||
"224.0.0.56")
|
||||
|
||||
(define (pulseaudio-rtp-sink-shepherd-services destination-ip)
|
||||
(list (shepherd-service
|
||||
(provision '(pulseaudio-rtp-sink))
|
||||
(start
|
||||
#~(lambda* (#:optional (destination-ip #$destination-ip))
|
||||
#$(with-pulseaudio-connection
|
||||
#~sock
|
||||
#~(begin
|
||||
(display "\
|
||||
load-module module-null-sink \
|
||||
sink_name=rtp sink_properties=\"device.description='RTP network output'\"\n"
|
||||
sock)
|
||||
(display (string-append "\
|
||||
load-module module-rtp-send source=rtp.monitor"
|
||||
(if destination-ip
|
||||
(string-append
|
||||
" destination_ip="
|
||||
destination-ip)
|
||||
"")
|
||||
"\n")
|
||||
sock)
|
||||
#t))))
|
||||
(stop
|
||||
#~(lambda (_)
|
||||
#$(with-pulseaudio-connection
|
||||
#~sock
|
||||
#~(begin
|
||||
(display "unload-module module-rtp-send\n"
|
||||
sock)
|
||||
(display "unload-module module-null-sink\n"
|
||||
sock)
|
||||
#f))))
|
||||
(auto-start? #f))))
|
||||
|
||||
(define home-pulseaudio-rtp-sink-service-type
|
||||
(service-type
|
||||
(name 'pulseaudio-rtp-sink)
|
||||
(extensions
|
||||
(list (service-extension home-shepherd-service-type
|
||||
pulseaudio-rtp-sink-shepherd-services)))
|
||||
(description
|
||||
"Define a PulseAudio sink to broadcast audio output over RTP, which can
|
||||
then by played by another PulseAudio instance.")
|
||||
|
||||
;; By default, send to the SAP multicast address, 224.0.0.56, which can be
|
||||
;; network-intensive.
|
||||
(default-value %pulseaudio-rtp-multicast-address)))
|
||||
|
||||
(define (pulseaudio-rtp-source-shepherd-services source-ip)
|
||||
(list (shepherd-service
|
||||
(provision '(pulseaudio-rtp-source))
|
||||
(start
|
||||
#~(lambda* (#:optional (source-ip #$source-ip))
|
||||
#$(with-pulseaudio-connection
|
||||
#~sock
|
||||
#~(begin
|
||||
(format sock "\
|
||||
load-module module-rtp-recv sap_address=~a\n" source-ip)
|
||||
#t))))
|
||||
(stop
|
||||
#~(lambda (_)
|
||||
#$(with-pulseaudio-connection
|
||||
#~sock
|
||||
#~(begin
|
||||
(display "unload-module module-rtp-recv\n"
|
||||
sock)
|
||||
#f))))
|
||||
(auto-start? #f))))
|
||||
|
||||
(define home-pulseaudio-rtp-source-service-type
|
||||
(service-type
|
||||
(name 'pulseaudio-rtp-source)
|
||||
(extensions
|
||||
(list (service-extension home-shepherd-service-type
|
||||
pulseaudio-rtp-source-shepherd-services)))
|
||||
(description
|
||||
"Define a PulseAudio source to receive audio broadcasted over RTP by
|
||||
another PulseAudio instance.")
|
||||
(default-value %pulseaudio-rtp-multicast-address)))
|
||||
@@ -1,463 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2022 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
|
||||
;;; Copyright © 2023 Nicolas Graves <ngraves@ngraves.fr>
|
||||
;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu home services ssh)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix records)
|
||||
#:use-module (guix deprecation)
|
||||
#:use-module (guix diagnostics)
|
||||
#:use-module (guix i18n)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services configuration)
|
||||
#:use-module (guix modules)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu home services shepherd)
|
||||
#:use-module ((gnu home services utils)
|
||||
#:select (object->camel-case-string))
|
||||
#:autoload (gnu packages base) (glibc-utf8-locales)
|
||||
#:use-module (gnu packages ssh)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-9)
|
||||
#:use-module (srfi srfi-9 gnu)
|
||||
#:use-module (srfi srfi-34)
|
||||
#:use-module (srfi srfi-35)
|
||||
#:use-module (ice-9 match)
|
||||
#:autoload (ice-9 regex) (string-match match:substring)
|
||||
#:export (home-openssh-configuration
|
||||
home-openssh-configuration-authorized-keys
|
||||
home-openssh-configuration-known-hosts
|
||||
home-openssh-configuration-hosts
|
||||
home-openssh-configuration-add-keys-to-agent
|
||||
home-openssh-configuration?
|
||||
|
||||
home-ssh-agent-configuration
|
||||
home-ssh-agent-openssh
|
||||
home-ssh-agent-socket-directory
|
||||
home-ssh-agent-extra-options
|
||||
home-ssh-agent-configuration?
|
||||
|
||||
openssh-host
|
||||
openssh-host-host-name
|
||||
openssh-host-match-criteria
|
||||
openssh-host-identity-file
|
||||
openssh-host-name
|
||||
openssh-host-port
|
||||
openssh-host-user
|
||||
openssh-host-forward-x11?
|
||||
openssh-host-forward-x11-trusted?
|
||||
openssh-host-forward-agent?
|
||||
openssh-host-compression?
|
||||
openssh-host-proxy-command
|
||||
openssh-host-host-key-algorithms
|
||||
openssh-host-accepted-key-types
|
||||
openssh-host-extra-content
|
||||
proxy-jump
|
||||
proxy-jump-host-name
|
||||
proxy-jump-port
|
||||
proxy-jump-user
|
||||
proxy-command
|
||||
proxy-command->string
|
||||
|
||||
home-openssh-service-type
|
||||
home-ssh-agent-service-type))
|
||||
|
||||
(define (serialize-field-name name)
|
||||
(match name
|
||||
('accepted-key-types "PubkeyAcceptedKeyTypes")
|
||||
(_
|
||||
(let ((name (let ((str (symbol->string name)))
|
||||
(if (string-suffix? "?" str)
|
||||
(string->symbol (string-drop-right str 1))
|
||||
name))))
|
||||
(object->camel-case-string name 'upper)))))
|
||||
|
||||
(define (serialize-string field value)
|
||||
(string-append " " (serialize-field-name field)
|
||||
" " value "\n"))
|
||||
|
||||
(define (address-family? obj)
|
||||
(memv obj (list AF_INET AF_INET6)))
|
||||
|
||||
(define-maybe address-family)
|
||||
|
||||
(define (serialize-address-family field family)
|
||||
(if (maybe-value-set? family)
|
||||
(string-append " " (serialize-field-name field) " "
|
||||
(cond ((= family AF_INET) "inet")
|
||||
((= family AF_INET6) "inet6")
|
||||
;; The 'else' branch is unreachable.
|
||||
(else
|
||||
(raise
|
||||
(formatted-message
|
||||
(G_ "~s: invalid address family value")
|
||||
family))))
|
||||
"\n")
|
||||
""))
|
||||
|
||||
(define (natural-number? obj)
|
||||
(and (integer? obj) (exact? obj) (> obj 0)))
|
||||
|
||||
(define (serialize-natural-number field value)
|
||||
(string-append " " (serialize-field-name field) " "
|
||||
(number->string value) "\n"))
|
||||
|
||||
(define-maybe boolean)
|
||||
|
||||
(define (serialize-boolean field value)
|
||||
(string-append " " (serialize-field-name field) " "
|
||||
(if value "yes" "no") "\n"))
|
||||
|
||||
(define-maybe string)
|
||||
(define-maybe natural-number)
|
||||
|
||||
(define (serialize-raw-configuration-string field value)
|
||||
(string-append value "\n"))
|
||||
(define raw-configuration-string? string?)
|
||||
|
||||
(define (string-list? lst)
|
||||
(and (pair? lst) (every string? lst)))
|
||||
(define (serialize-string-list field lst)
|
||||
(string-append " " (serialize-field-name field) " "
|
||||
(string-join lst ",") "\n"))
|
||||
|
||||
(define-maybe string-list)
|
||||
|
||||
(define-record-type <proxy-command>
|
||||
(proxy-command command)
|
||||
proxy-command?
|
||||
(command proxy-command->string))
|
||||
|
||||
(set-record-type-printer! <proxy-command>
|
||||
(lambda (obj port)
|
||||
(format port "#<proxy-command ~s>" (proxy-command->string obj))))
|
||||
|
||||
(define-configuration/no-serialization proxy-jump
|
||||
(user
|
||||
maybe-string
|
||||
"User name on the remote host.")
|
||||
(host-name
|
||||
(string)
|
||||
"Host name---e.g., @code{foo.example.org} or @code{192.168.1.2}.")
|
||||
(port
|
||||
maybe-natural-number
|
||||
"TCP port number to connect to."))
|
||||
|
||||
(define (proxy-jump->string proxy-jump)
|
||||
(match-record proxy-jump <proxy-jump>
|
||||
(host-name user port)
|
||||
(string-append
|
||||
(if (maybe-value-set? user) (string-append user "@") "")
|
||||
host-name
|
||||
(if (maybe-value-set? port) (string-append ":" (number->string port)) ""))))
|
||||
|
||||
(define (proxy-command-or-jump-list? x)
|
||||
(or (proxy-command? x)
|
||||
(and (list? x)
|
||||
(every proxy-jump? x))))
|
||||
|
||||
(define (serialize-proxy-command-or-jump-list field value)
|
||||
(if (proxy-command? value)
|
||||
(serialize-string 'proxy-command (proxy-command->string value))
|
||||
(serialize-string-list 'proxy-jump (map proxy-jump->string value))))
|
||||
|
||||
(define-maybe proxy-command-or-jump-list)
|
||||
|
||||
(define (sanitize-proxy-command properties)
|
||||
(lambda (value)
|
||||
(when (maybe-value-set? value)
|
||||
(warn-about-deprecation 'proxy-command properties #:replacement 'proxy))
|
||||
(unless (maybe-string? value)
|
||||
(configuration-field-error (source-properties->location properties) 'proxy-command value))
|
||||
value))
|
||||
|
||||
(define ssh-match-keywords
|
||||
'(canonical final exec host originalhost user localuser))
|
||||
|
||||
(define (match-criteria? str)
|
||||
;; Rule out the case of "all" keyword.
|
||||
(if (member str '("all"
|
||||
"canonical all"
|
||||
"final all"))
|
||||
#t
|
||||
(let* ((first (string-take str (string-index str #\ )))
|
||||
(keyword (string->symbol (if (string-prefix? "!" first)
|
||||
(string-drop first 1)
|
||||
first))))
|
||||
(memq keyword ssh-match-keywords))))
|
||||
|
||||
(define (serialize-match-criteria _ value)
|
||||
(string-append "Match " value "\n"))
|
||||
|
||||
(define-maybe match-criteria)
|
||||
|
||||
(define-configuration openssh-host
|
||||
(name
|
||||
maybe-string
|
||||
"Name of this host declaration. A @code{openssh-host} must define only
|
||||
@code{name} or @code{match-criteria}. Use host-name @code{\"*\"} for
|
||||
top-level options.")
|
||||
(host-name
|
||||
maybe-string
|
||||
"Host name---e.g., @code{\"foo.example.org\"} or @code{\"192.168.1.2\"}.")
|
||||
(match-criteria
|
||||
maybe-match-criteria
|
||||
"When specified, this string denotes the set of hosts to which the entry
|
||||
applies, superseding the @code{host-name} field. Its first element must be
|
||||
all or one of @code{ssh-match-keywords}. The rest of the elements are
|
||||
arguments for the keyword, or other criteria. A @code{openssh-host} must
|
||||
define only @code{name} or @code{match-criteria}. Other host configuration
|
||||
options will apply to all hosts matching @code{match-criteria}.")
|
||||
(address-family
|
||||
maybe-address-family
|
||||
"Address family to use when connecting to this host: one of
|
||||
@code{AF_INET} (for IPv4 only), @code{AF_INET6} (for IPv6 only).
|
||||
Additionally, the field can be left unset to allow any address family.")
|
||||
(identity-file
|
||||
maybe-string
|
||||
"The identity file to use---e.g.,
|
||||
@code{\"/home/charlie/.ssh/id_ed25519\"}.")
|
||||
(port
|
||||
maybe-natural-number
|
||||
"TCP port number to connect to.")
|
||||
(user
|
||||
maybe-string
|
||||
"User name on the remote host.")
|
||||
(forward-x11?
|
||||
maybe-boolean
|
||||
"Whether to forward remote client connections to the local X11 graphical
|
||||
display.")
|
||||
(forward-x11-trusted?
|
||||
maybe-boolean
|
||||
"Whether remote X11 clients have full access to the original X11 graphical
|
||||
display.")
|
||||
(forward-agent?
|
||||
maybe-boolean
|
||||
"Whether the authentication agent (if any) is forwarded to the remote
|
||||
machine.")
|
||||
(compression?
|
||||
maybe-boolean
|
||||
"Whether to compress data in transit.")
|
||||
(proxy-command
|
||||
maybe-string
|
||||
"The command to use to connect to the server. As an example, a command
|
||||
to connect via an HTTP proxy at 192.0.2.0 would be: @code{\"nc -X
|
||||
connect -x 192.0.2.0:8080 %h %p\"}. Using 'proxy-command' is deprecated, use
|
||||
'proxy' instead."
|
||||
(sanitizer (sanitize-proxy-command (current-source-location))))
|
||||
(proxy
|
||||
maybe-proxy-command-or-jump-list
|
||||
"The command to use to connect to the server or a list of SSH hosts to jump
|
||||
through before connecting to the server.")
|
||||
(host-key-algorithms
|
||||
maybe-string-list
|
||||
"The list of accepted host key algorithms---e.g.,
|
||||
@code{'(\"ssh-ed25519\")}.")
|
||||
(accepted-key-types
|
||||
maybe-string-list
|
||||
"The list of accepted user public key types.")
|
||||
(extra-content
|
||||
(raw-configuration-string "")
|
||||
"Extra content appended as-is to this @code{Host} block in
|
||||
@file{~/.ssh/config}."))
|
||||
|
||||
(define (serialize-openssh-host config)
|
||||
(define (openssh-host-name-or-match-field? field)
|
||||
(or (eq? (configuration-field-name field) 'name)
|
||||
(eq? (configuration-field-name field) 'match-criteria)))
|
||||
|
||||
(string-append
|
||||
(if (maybe-value-set? (openssh-host-name config))
|
||||
(if (maybe-value-set? (openssh-host-match-criteria config))
|
||||
(raise
|
||||
(formatted-message
|
||||
(G_ "define either 'name' or 'match-criteria', not both")))
|
||||
(string-append "Host " (openssh-host-name config) "\n"))
|
||||
(if (maybe-value-set? (openssh-host-match-criteria config))
|
||||
(serialize-match-criteria #t (openssh-host-match-criteria config))
|
||||
(raise
|
||||
(formatted-message
|
||||
(G_ "define either 'name' or 'match-criteria' once")))))
|
||||
(string-concatenate
|
||||
(map (lambda (field)
|
||||
((configuration-field-serializer field)
|
||||
(configuration-field-name field)
|
||||
((configuration-field-getter field) config)))
|
||||
(remove openssh-host-name-or-match-field?
|
||||
openssh-host-fields)))))
|
||||
|
||||
(define-record-type* <home-openssh-configuration>
|
||||
home-openssh-configuration make-home-openssh-configuration
|
||||
home-openssh-configuration?
|
||||
(authorized-keys home-openssh-configuration-authorized-keys ;list of file-like
|
||||
(default #f))
|
||||
(known-hosts home-openssh-configuration-known-hosts ;unspec | list of file-like
|
||||
(default *unspecified*))
|
||||
(hosts home-openssh-configuration-hosts ;list of <openssh-host>
|
||||
(default '()))
|
||||
(add-keys-to-agent home-openssh-configuration-add-keys-to-agent ;string with limited values
|
||||
(default "no")))
|
||||
|
||||
(define (serialize-add-keys-to-agent value)
|
||||
(define (valid-time-string? str)
|
||||
(and (> (string-length str) 0)
|
||||
(equal?
|
||||
str
|
||||
(match:substring
|
||||
(string-match "\
|
||||
[0-9]+|([0-9]+[Ww])?([0-9]+[Dd])?([0-9]+[Hh])?([0-9]+[Mm])?([0-9]+[Ss])?"
|
||||
str)))))
|
||||
|
||||
(string-append "AddKeysToAgent "
|
||||
(cond ((member value '("yes" "no" "confirm" "ask")) value)
|
||||
((valid-time-string? value) value)
|
||||
((and (string-prefix? "confirm" value)
|
||||
(valid-time-string?
|
||||
(cdr (string-split value #\ )))) value)
|
||||
;; The 'else' branch is unreachable.
|
||||
(else
|
||||
(raise
|
||||
(formatted-message
|
||||
(G_ "~s: invalid 'add-keys-to-agent' value")
|
||||
value))))))
|
||||
|
||||
(define (openssh-configuration->string config)
|
||||
(string-join
|
||||
(cons* (serialize-add-keys-to-agent
|
||||
(home-openssh-configuration-add-keys-to-agent config))
|
||||
(map serialize-openssh-host
|
||||
(home-openssh-configuration-hosts config)))
|
||||
"\n"))
|
||||
|
||||
(define* (file-join name files #:optional (delimiter " "))
|
||||
"Return a file in the store called @var{name} that is the concatenation
|
||||
of all the file-like objects listed in @var{files}, with @var{delimited}
|
||||
inserted after each of them."
|
||||
(computed-file name
|
||||
(with-imported-modules '((guix build utils))
|
||||
#~(begin
|
||||
(use-modules (guix build utils))
|
||||
|
||||
;; Support non-ASCII file names.
|
||||
(setenv "GUIX_LOCPATH"
|
||||
#+(file-append glibc-utf8-locales
|
||||
"/lib/locale"))
|
||||
(setlocale LC_ALL "en_US.utf8")
|
||||
|
||||
(call-with-output-file #$output
|
||||
(lambda (output)
|
||||
(for-each (lambda (file)
|
||||
(call-with-input-file file
|
||||
(lambda (input)
|
||||
(dump-port input output)))
|
||||
(display #$delimiter output))
|
||||
'#$files)))))))
|
||||
|
||||
(define (openssh-configuration-files config)
|
||||
(let* ((ssh-config (plain-file "ssh.conf"
|
||||
(openssh-configuration->string config)))
|
||||
(known-hosts (home-openssh-configuration-known-hosts config))
|
||||
(authorized-keys (home-openssh-configuration-authorized-keys config))
|
||||
(authorized-keys (and
|
||||
authorized-keys
|
||||
(file-join "authorized_keys" authorized-keys "\n"))))
|
||||
`(,@(if authorized-keys
|
||||
`((".ssh/authorized_keys" ,authorized-keys))
|
||||
'())
|
||||
,@(if (unspecified? known-hosts)
|
||||
'()
|
||||
`((".ssh/known_hosts"
|
||||
,(file-join "known_hosts" known-hosts "\n"))))
|
||||
(".ssh/config" ,ssh-config))))
|
||||
|
||||
(define openssh-activation
|
||||
(with-imported-modules (source-module-closure
|
||||
'((gnu build activation)))
|
||||
#~(begin
|
||||
(use-modules (gnu build activation))
|
||||
|
||||
;; Make sure ~/.ssh is #o700.
|
||||
(let* ((home (getenv "HOME"))
|
||||
(dot-ssh (string-append home "/.ssh")))
|
||||
(mkdir-p/perms dot-ssh (getpw (getuid)) #o700)))))
|
||||
|
||||
(define home-openssh-service-type
|
||||
(service-type
|
||||
(name 'home-openssh)
|
||||
(extensions
|
||||
(list (service-extension home-files-service-type
|
||||
openssh-configuration-files)
|
||||
(service-extension home-activation-service-type
|
||||
(const openssh-activation))))
|
||||
(description "Configure the OpenSSH @acronym{SSH, secure shell} client
|
||||
by providing a @file{~/.ssh/config} file, which is honored by the OpenSSH
|
||||
client,@command{ssh}, and by other tools such as @command{guix deploy}.")
|
||||
(default-value (home-openssh-configuration))))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Ssh-agent.
|
||||
;;;
|
||||
(define-record-type* <home-ssh-agent-configuration>
|
||||
home-ssh-agent-configuration make-home-ssh-agent-configuration
|
||||
home-ssh-agent-configuration?
|
||||
(openssh home-ssh-agent-openssh ;file-like
|
||||
(default openssh))
|
||||
(socket-directory home-ssh-agent-socket-directory ;string
|
||||
(default #~(string-append %user-runtime-dir "/ssh-agent")))
|
||||
(extra-options home-ssh-agent-extra-options ;list of string
|
||||
(default '())))
|
||||
|
||||
(define (home-ssh-agent-services config)
|
||||
"Return a <shepherd-service> for an ssh-agent with CONFIG."
|
||||
(match-record config <home-ssh-agent-configuration>
|
||||
(openssh socket-directory extra-options)
|
||||
(let* ((ssh-agent (file-append openssh "/bin/ssh-agent"))
|
||||
(socket-file #~(string-append #$socket-directory "/socket"))
|
||||
(command #~`(#$ssh-agent
|
||||
"-D" "-a" ,#$socket-file
|
||||
#$@extra-options))
|
||||
(log-file #~(string-append %user-log-dir "/ssh-agent.log")))
|
||||
(list (shepherd-service
|
||||
(documentation "Run the ssh-agent.")
|
||||
(provision '(ssh-agent))
|
||||
(modules '((shepherd support))) ;for '%user-runtime-dir', etc.
|
||||
(start #~(lambda _
|
||||
(unless (file-exists? #$socket-directory)
|
||||
(mkdir-p #$socket-directory)
|
||||
(chmod #$socket-directory #o700))
|
||||
(fork+exec-command #$command #:log-file #$log-file)))
|
||||
(stop #~(make-kill-destructor)))))))
|
||||
|
||||
(define (home-ssh-agent-environment-variables config)
|
||||
'(("SSH_AUTH_SOCK"
|
||||
. "${SSH_AUTH_SOCK-${XDG_RUNTIME_DIR-$HOME/.cache}/ssh-agent/socket}")))
|
||||
|
||||
(define home-ssh-agent-service-type
|
||||
(service-type
|
||||
(name 'home-ssh-agent)
|
||||
(default-value (home-ssh-agent-configuration))
|
||||
(extensions
|
||||
(list (service-extension home-shepherd-service-type
|
||||
home-ssh-agent-services)
|
||||
(service-extension home-environment-variables-service-type
|
||||
home-ssh-agent-environment-variables)))
|
||||
(description
|
||||
"Install and configure @command{ssh-agent} as a Shepherd service.")))
|
||||
@@ -54,10 +54,6 @@
|
||||
(or (getenv "XDG_CONFIG_HOME")
|
||||
(string-append (getenv "HOME") "/.config")))
|
||||
|
||||
(define xdg-data-home
|
||||
(or (getenv "XDG_DATA_HOME")
|
||||
(string-append (getenv "HOME") "/.local/share")))
|
||||
|
||||
(define backup-directory
|
||||
(string-append home-directory "/" (number->string (current-time))
|
||||
"-guix-home-legacy-configs-backup"))
|
||||
@@ -65,30 +61,19 @@
|
||||
(define (preprocess-file file)
|
||||
"If file is in XDG-CONFIGURATION-FILES-DIRECTORY use
|
||||
subdirectory from XDG_CONFIG_HOME to generate a target path."
|
||||
(cond
|
||||
((string-prefix? #$xdg-configuration-files-directory file)
|
||||
(string-append
|
||||
(substring xdg-config-home
|
||||
(1+ (string-length home-directory)))
|
||||
(substring file
|
||||
(string-length #$xdg-configuration-files-directory))))
|
||||
((string-prefix? #$xdg-data-files-directory file)
|
||||
(string-append
|
||||
(substring xdg-data-home
|
||||
(1+ (string-length home-directory)))
|
||||
(substring file
|
||||
(string-length #$xdg-data-files-directory))))
|
||||
(else file)))
|
||||
(if (string-prefix? #$xdg-configuration-files-directory file)
|
||||
(string-append
|
||||
(substring xdg-config-home
|
||||
(1+ (string-length home-directory)))
|
||||
(substring file
|
||||
(string-length #$xdg-configuration-files-directory)))
|
||||
(string-append "." file)))
|
||||
|
||||
(define (target-file file)
|
||||
;; Return the target of FILE, a config file name sans leading dot
|
||||
;; such as "config/fontconfig/fonts.conf" or "bashrc".
|
||||
(string-append home-directory "/" (preprocess-file file)))
|
||||
|
||||
(define (no-follow-file-exists? file)
|
||||
"Return #t if file exists, even if it's a dangling symlink."
|
||||
(->bool (false-if-exception (lstat file))))
|
||||
|
||||
(define (symlink-to-store? file)
|
||||
(catch 'system-error
|
||||
(lambda ()
|
||||
@@ -127,7 +112,7 @@ subdirectory from XDG_CONFIG_HOME to generate a target path."
|
||||
(const #t)
|
||||
(lambda (file stat _) ;leaf
|
||||
(let ((file (target-file (strip file))))
|
||||
(when (no-follow-file-exists? file)
|
||||
(when (file-exists? file)
|
||||
;; DO NOT remove the file if it is no longer a symlink to
|
||||
;; the store, it will be backed up later during
|
||||
;; create-symlinks phase.
|
||||
@@ -157,7 +142,6 @@ subdirectory from XDG_CONFIG_HOME to generate a target path."
|
||||
#t
|
||||
(G_ "Skipping ~a (not an empty directory)... done\n")
|
||||
directory))
|
||||
((= ENOENT errno) #t)
|
||||
((= ENOTDIR errno) #t)
|
||||
(else
|
||||
(apply throw args)))))))))
|
||||
@@ -187,7 +171,7 @@ subdirectory from XDG_CONFIG_HOME to generate a target path."
|
||||
(lambda (file stat result) ;leaf
|
||||
(let ((source (source-file (strip file)))
|
||||
(target (target-file (strip file))))
|
||||
(when (no-follow-file-exists? target)
|
||||
(when (file-exists? target)
|
||||
(backup-file (strip file)))
|
||||
(format #t (G_ "Symlinking ~a -> ~a...")
|
||||
target source)
|
||||
@@ -196,7 +180,7 @@ subdirectory from XDG_CONFIG_HOME to generate a target path."
|
||||
(lambda (directory stat result) ;down
|
||||
(unless (string=? directory config-file-directory)
|
||||
(let ((target (target-file (strip directory))))
|
||||
(when (and (no-follow-file-exists? target)
|
||||
(when (and (file-exists? target)
|
||||
(not (file-is-directory? target)))
|
||||
(backup-file (strip directory)))
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2023 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||||
;;; under the terms of the GNU General Public License as published by
|
||||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||||
;;; your option) any later version.
|
||||
;;;
|
||||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;; GNU General Public License for more details.
|
||||
;;;
|
||||
;;; You should have received a copy of the GNU General Public License
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu home services syncthing)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu services syncthing)
|
||||
;; For the 'home-shepherd-service-type' mapping.
|
||||
#:use-module (gnu home services shepherd)
|
||||
#:export (home-syncthing-service-type)
|
||||
#:re-export (syncthing-configuration
|
||||
syncthing-configuration?))
|
||||
|
||||
(define home-syncthing-service-type
|
||||
(service-type
|
||||
(inherit (system->home-service-type syncthing-service-type))
|
||||
(default-value (for-home (syncthing-configuration)))))
|
||||
+48
-93
@@ -1,7 +1,6 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2021, 2022 Andrew Tropin <andrew@trop.in>
|
||||
;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
|
||||
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
|
||||
;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -23,9 +22,7 @@
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu packages freedesktop)
|
||||
#:use-module (gnu home services utils)
|
||||
#:use-module (guix deprecation)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix modules)
|
||||
#:use-module (guix records)
|
||||
#:use-module (guix i18n)
|
||||
#:use-module (guix diagnostics)
|
||||
@@ -37,24 +34,10 @@
|
||||
#:export (home-xdg-base-directories-service-type
|
||||
home-xdg-base-directories-configuration
|
||||
home-xdg-base-directories-configuration?
|
||||
home-xdg-base-directories-configuration-cache-home
|
||||
home-xdg-base-directories-configuration-config-home
|
||||
home-xdg-base-directories-configuration-data-home
|
||||
home-xdg-base-directories-configuration-state-home
|
||||
home-xdg-base-directories-configuration-log-home ; deprecated
|
||||
home-xdg-base-directories-configuration-runtime-dir
|
||||
|
||||
home-xdg-user-directories-service-type
|
||||
home-xdg-user-directories-configuration
|
||||
home-xdg-user-directories-configuration?
|
||||
home-xdg-user-directories-configuration-desktop
|
||||
home-xdg-user-directories-configuration-documents
|
||||
home-xdg-user-directories-configuration-download
|
||||
home-xdg-user-directories-configuration-music
|
||||
home-xdg-user-directories-configuration-pictures
|
||||
home-xdg-user-directories-configuration-publicshare
|
||||
home-xdg-user-directories-configuration-templates
|
||||
home-xdg-user-directories-configuration-videos
|
||||
|
||||
xdg-desktop-action
|
||||
xdg-desktop-entry
|
||||
@@ -79,7 +62,6 @@
|
||||
|
||||
(define (serialize-path field-name val) "")
|
||||
(define path? string?)
|
||||
(define-maybe path)
|
||||
|
||||
(define-configuration home-xdg-base-directories-configuration
|
||||
(cache-home
|
||||
@@ -100,23 +82,18 @@ read-only shared data, analogus to @file{/usr/share}, but for user.")
|
||||
(path "${XDG_RUNTIME_DIR:-/run/user/$UID}")
|
||||
"Base directory for programs to store user-specific runtime files,
|
||||
like sockets.")
|
||||
;; TODO: deprecated field, use $XDG_STATE_HOME(/log) instead.
|
||||
(log-home
|
||||
maybe-path
|
||||
(path "$HOME/.local/var/log")
|
||||
"Base directory for programs to store log files, analogus to
|
||||
@file{/var/log}, but for user. It is not a part of XDG Base Directory
|
||||
Specification, but helps to make implementation of home services more
|
||||
consistent."
|
||||
(lambda (field-name val)
|
||||
(when (maybe-value-set? val)
|
||||
(warn-about-deprecation field-name #f #:replacement 'state-home))
|
||||
(serialize-path field-name val)))
|
||||
consistent.")
|
||||
(state-home
|
||||
(path "$HOME/.local/state")
|
||||
"Base directory for programs to store state data that should persist
|
||||
between (application) restarts, such as logs, but are not important or
|
||||
portable enough to the user to warrant storing them in
|
||||
@env{XDG_DATA_HOME}."))
|
||||
(path "$HOME/.local/var/lib")
|
||||
"Base directory for programs to store state files, like databases,
|
||||
analogus to @file{/var/lib}, but for user. It is not a part of XDG
|
||||
Base Directory Specification, but helps to make implementation of home
|
||||
services more consistent."))
|
||||
|
||||
(define (home-xdg-base-directories-environment-variables-service config)
|
||||
(map
|
||||
@@ -125,41 +102,19 @@ portable enough to the user to warrant storing them in
|
||||
#f "XDG_~a"
|
||||
(object->snake-case-string (configuration-field-name field) 'upper))
|
||||
((configuration-field-getter field) config)))
|
||||
;; XXX: deprecated field, remove later
|
||||
(if (maybe-value-set?
|
||||
(home-xdg-base-directories-configuration-log-home config))
|
||||
home-xdg-base-directories-configuration-fields
|
||||
(filter-configuration-fields
|
||||
home-xdg-base-directories-configuration-fields
|
||||
'(log-home) #t))))
|
||||
home-xdg-base-directories-configuration-fields))
|
||||
|
||||
(define (ensure-xdg-base-dirs-on-activation config)
|
||||
(with-imported-modules '((guix build utils))
|
||||
#~(begin
|
||||
(use-modules (guix build utils))
|
||||
(map (lambda (xdg-base-dir-variable)
|
||||
(mkdir-p
|
||||
(getenv
|
||||
xdg-base-dir-variable)))
|
||||
'#$(filter-map
|
||||
(lambda (field)
|
||||
(let ((variable
|
||||
(string-append
|
||||
"XDG_"
|
||||
(object->snake-case-string
|
||||
(configuration-field-name field) 'upper))))
|
||||
;; XDG_RUNTIME_DIR shouldn't be created during activation
|
||||
;; and will be provided by elogind or other service.
|
||||
(and (not (string=? "XDG_RUNTIME_DIR" variable))
|
||||
variable)))
|
||||
;; XXX: deprecated field, remove later
|
||||
(if (maybe-value-set?
|
||||
(home-xdg-base-directories-configuration-log-home
|
||||
config))
|
||||
home-xdg-base-directories-configuration-fields
|
||||
(filter-configuration-fields
|
||||
home-xdg-base-directories-configuration-fields
|
||||
'(log-home) #t)))))))
|
||||
#~(map (lambda (xdg-base-dir-variable)
|
||||
((@@ (guix build utils) mkdir-p)
|
||||
(getenv
|
||||
xdg-base-dir-variable)))
|
||||
'#$(map (lambda (field)
|
||||
(format
|
||||
#f "XDG_~a"
|
||||
(object->snake-case-string
|
||||
(configuration-field-name field) 'upper)))
|
||||
home-xdg-base-directories-configuration-fields)))
|
||||
|
||||
(define (last-extension-or-cfg config extensions)
|
||||
"Picks configuration value from last provided extension. If there
|
||||
@@ -178,10 +133,13 @@ are no extensions use configuration instead."
|
||||
(default-value (home-xdg-base-directories-configuration))
|
||||
(compose identity)
|
||||
(extend last-extension-or-cfg)
|
||||
(description "Configure XDG base directories. The
|
||||
services of this service-type is instantiated by default, to provide
|
||||
non-default value, extend the service-type (using @code{simple-service}
|
||||
for example).")))
|
||||
(description "Configure XDG base directories. This
|
||||
service introduces two additional variables @env{XDG_STATE_HOME},
|
||||
@env{XDG_LOG_HOME}. They are not a part of XDG specification, at
|
||||
least yet, but are convenient to have, it improves the consistency
|
||||
between different home services. The services of this service-type is
|
||||
instantiated by default, to provide non-default value, extend the
|
||||
service-type (using @code{simple-service} for example).")))
|
||||
|
||||
(define (generate-home-xdg-base-directories-documentation)
|
||||
(generate-documentation
|
||||
@@ -249,8 +207,8 @@ pre-populated content.")
|
||||
home-xdg-user-directories-configuration-fields)))
|
||||
#~(let ((ensure-dir
|
||||
(lambda (path)
|
||||
((@ (guix build utils) mkdir-p)
|
||||
((@ (ice-9 string-fun) string-replace-substring)
|
||||
(mkdir-p
|
||||
((@@ (ice-9 string-fun) string-replace-substring)
|
||||
path "$HOME" (getenv "HOME"))))))
|
||||
(display "Creating XDG user directories...")
|
||||
(map ensure-dir '#$dirs)
|
||||
@@ -266,8 +224,6 @@ pre-populated content.")
|
||||
home-activation-service-type
|
||||
home-xdg-user-directories-activation-service)))
|
||||
(default-value (home-xdg-user-directories-configuration))
|
||||
(compose identity)
|
||||
(extend last-extension-or-cfg)
|
||||
(description "Configure XDG user directories. To
|
||||
disable a directory, point it to the $HOME.")))
|
||||
|
||||
@@ -420,25 +376,25 @@ configuration."
|
||||
(define (serialize-alist config)
|
||||
(generic-serialize-alist append format-config config))
|
||||
|
||||
(define (serialize-xdg-desktop-action desktop-action)
|
||||
(match-record desktop-action <xdg-desktop-action>
|
||||
(action name config)
|
||||
`(,(format #f "[Desktop Action ~a]\n"
|
||||
(string-capitalize (maybe-object->string action)))
|
||||
,(format #f "Name=~a\n" name)
|
||||
,@(serialize-alist config))))
|
||||
(define (serialize-xdg-desktop-action action)
|
||||
(match action
|
||||
(($ <xdg-desktop-action> action name config)
|
||||
`(,(format #f "[Desktop Action ~a]\n"
|
||||
(string-capitalize (maybe-object->string action)))
|
||||
,(format #f "Name=~a\n" name)
|
||||
,@(serialize-alist config)))))
|
||||
|
||||
(match-record entry <xdg-desktop-entry>
|
||||
(file name type config actions)
|
||||
(list (if (string-suffix? file ".desktop")
|
||||
file
|
||||
(string-append file ".desktop"))
|
||||
`("[Desktop Entry]\n"
|
||||
,(format #f "Name=~a\n" name)
|
||||
,(format #f "Type=~a\n"
|
||||
(string-capitalize (symbol->string type)))
|
||||
,@(serialize-alist config)
|
||||
,@(append-map serialize-xdg-desktop-action actions)))))
|
||||
(match entry
|
||||
(($ <xdg-desktop-entry> file name type config actions)
|
||||
(list (if (string-suffix? file ".desktop")
|
||||
file
|
||||
(string-append file ".desktop"))
|
||||
`("[Desktop Entry]\n"
|
||||
,(format #f "Name=~a\n" name)
|
||||
,(format #f "Type=~a\n"
|
||||
(string-capitalize (symbol->string type)))
|
||||
,@(serialize-alist config)
|
||||
,@(append-map serialize-xdg-desktop-action actions))))))
|
||||
|
||||
(define-configuration home-xdg-mime-applications-configuration
|
||||
(added
|
||||
@@ -465,8 +421,7 @@ that the application cannot open the specified MIME type.")
|
||||
(define (add-xdg-desktop-entry-file entry)
|
||||
(let ((file (first entry))
|
||||
(config (second entry)))
|
||||
;; TODO: Use xdg-data-files instead of home-files here
|
||||
(list (format #f "applications/~a" file)
|
||||
(list (format #f "local/share/applications/~a" file)
|
||||
(apply mixed-text-file
|
||||
(format #f "xdg-desktop-~a-entry" file)
|
||||
config))))
|
||||
@@ -513,7 +468,7 @@ that the application cannot open the specified MIME type.")
|
||||
(service-type (name 'home-xdg-mime-applications)
|
||||
(extensions
|
||||
(list (service-extension
|
||||
home-xdg-data-files-service-type
|
||||
home-files-service-type
|
||||
home-xdg-mime-applications-files)
|
||||
(service-extension
|
||||
home-xdg-configuration-files-service-type
|
||||
|
||||
+23
-127
@@ -1,5 +1,5 @@
|
||||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2020, 2022 Mathieu Othacehe <othacehe@gnu.org>
|
||||
;;; Copyright © 2020 Mathieu Othacehe <m.othacehe@gmail.com>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
@@ -17,13 +17,8 @@
|
||||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu image)
|
||||
#:use-module (guix platform)
|
||||
#:use-module (gnu platform)
|
||||
#:use-module (guix records)
|
||||
#:use-module (guix diagnostics)
|
||||
#:use-module (guix i18n)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-34)
|
||||
#:use-module (srfi srfi-35)
|
||||
#:export (partition
|
||||
partition?
|
||||
partition-device
|
||||
@@ -59,155 +54,61 @@
|
||||
os->image
|
||||
os+platform->image))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Sanitizers.
|
||||
;;;
|
||||
|
||||
;; Image and partition sizes can be either be a size in bytes or the 'guess
|
||||
;; symbol denoting that the size should be estimated by Guix, according to the
|
||||
;; image content.
|
||||
(define-with-syntax-properties (validate-size (value properties))
|
||||
(unless (and value
|
||||
(or (eq? value 'guess) (integer? value)))
|
||||
(raise
|
||||
(make-compound-condition
|
||||
(condition
|
||||
(&error-location
|
||||
(location (source-properties->location properties))))
|
||||
(formatted-message
|
||||
(G_ "size (~a) can only be 'guess or a numeric expression ~%")
|
||||
value 'field))))
|
||||
value)
|
||||
|
||||
|
||||
;;;
|
||||
;;; Partition record.
|
||||
;;;
|
||||
|
||||
;; The partition offset should be a bytes count as an integer.
|
||||
(define-with-syntax-properties (validate-partition-offset (value properties))
|
||||
(unless (and value (integer? value))
|
||||
(raise
|
||||
(make-compound-condition
|
||||
(condition
|
||||
(&error-location
|
||||
(location (source-properties->location properties))))
|
||||
(formatted-message
|
||||
(G_ "the partition offset (~a) can only be a \
|
||||
numeric expression ~%") value 'field))))
|
||||
value)
|
||||
|
||||
;; The supported partition flags.
|
||||
(define-with-syntax-properties (validate-partition-flags (value properties))
|
||||
(let ((bad-flags (lset-difference eq? value '(boot esp))))
|
||||
(unless (and (list? value) (null? bad-flags))
|
||||
(raise
|
||||
(make-compound-condition
|
||||
(condition
|
||||
(&error-location
|
||||
(location (source-properties->location properties))))
|
||||
(formatted-message
|
||||
(G_ "unsupported partition flag(s): ~a ~%") bad-flags)))))
|
||||
value)
|
||||
|
||||
(define-record-type* <partition> partition make-partition
|
||||
partition?
|
||||
(size partition-size ;size in bytes as integer or 'guess
|
||||
(default 'guess)
|
||||
(sanitize validate-size))
|
||||
(offset partition-offset
|
||||
(default 0) ;offset in bytes as integer
|
||||
(sanitize validate-partition-offset))
|
||||
(file-system partition-file-system
|
||||
(default "ext4")) ;string
|
||||
(device partition-device (default #f))
|
||||
(size partition-size)
|
||||
(offset partition-offset (default 0))
|
||||
(file-system partition-file-system (default "ext4"))
|
||||
(file-system-options partition-file-system-options
|
||||
(default '())) ;list of strings
|
||||
(label partition-label) ;string
|
||||
(uuid partition-uuid
|
||||
(default #false)) ;<uuid>
|
||||
(flags partition-flags
|
||||
(default '()) ;list of symbols
|
||||
(sanitize validate-partition-flags))
|
||||
(initializer partition-initializer
|
||||
(default #false))) ;gexp | #false
|
||||
(default '()))
|
||||
(label partition-label (default #f))
|
||||
(uuid partition-uuid (default #f))
|
||||
(flags partition-flags (default '()))
|
||||
(initializer partition-initializer (default #f)))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Image record.
|
||||
;;;
|
||||
|
||||
(define-syntax-rule (define-set-sanitizer name field set)
|
||||
"Define NAME as a procedure or macro that raises an error if passed a value
|
||||
that is not in SET, mentioning FIELD in the error message."
|
||||
(define-with-syntax-properties (name (value properties))
|
||||
(unless (memq value 'set)
|
||||
(raise
|
||||
(make-compound-condition
|
||||
(condition
|
||||
(&error-location
|
||||
(location (source-properties->location properties))))
|
||||
(formatted-message (G_ "~s: invalid '~a' value") value 'field))))
|
||||
value))
|
||||
|
||||
;; The supported image formats.
|
||||
(define-set-sanitizer validate-image-format format
|
||||
(disk-image compressed-qcow2 docker iso9660 tarball wsl2))
|
||||
|
||||
;; The supported partition table types.
|
||||
(define-set-sanitizer validate-partition-table-type partition-table-type
|
||||
(mbr gpt))
|
||||
|
||||
(define-record-type* <image>
|
||||
image make-image
|
||||
image?
|
||||
(name image-name ;symbol
|
||||
(default #false))
|
||||
(format image-format ;symbol
|
||||
(sanitize validate-image-format))
|
||||
(default #f))
|
||||
(format image-format) ;symbol
|
||||
(platform image-platform ;<platform>
|
||||
(default #false))
|
||||
(default #f))
|
||||
(size image-size ;size in bytes as integer
|
||||
(default 'guess)
|
||||
(sanitize validate-size))
|
||||
(operating-system image-operating-system) ;<operating-system>
|
||||
(default 'guess))
|
||||
(operating-system image-operating-system ;<operating-system>
|
||||
(default #f))
|
||||
(partition-table-type image-partition-table-type ; 'mbr or 'gpt
|
||||
(default 'mbr)
|
||||
(sanitize validate-partition-table-type))
|
||||
(default 'mbr))
|
||||
(partitions image-partitions ;list of <partition>
|
||||
(default '()))
|
||||
(compression? image-compression? ;boolean
|
||||
(default #true))
|
||||
(default #t))
|
||||
(volatile-root? image-volatile-root? ;boolean
|
||||
(default #true))
|
||||
(default #t))
|
||||
(shared-store? image-shared-store? ;boolean
|
||||
(default #false))
|
||||
(default #f))
|
||||
(shared-network? image-shared-network? ;boolean
|
||||
(default #false))
|
||||
(default #f))
|
||||
(substitutable? image-substitutable? ;boolean
|
||||
(default #true)))
|
||||
(default #t)))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Image type.
|
||||
;;;
|
||||
|
||||
;; The role of this record is to provide a constructor that is able to turn an
|
||||
;; <operating-system> record into an <image> record. Some basic <image-type>
|
||||
;; records are defined in the (gnu system image) module. They are able to
|
||||
;; turn an <operating-system> record into an EFI or an ISO 9660 bootable
|
||||
;; image, a Docker image or even a QCOW2 image.
|
||||
;;
|
||||
;; Other <image-type> records are defined in the (gnu system images ...)
|
||||
;; modules. They are dedicated to specific machines such as Novena and Pine64
|
||||
;; SoC boards that require specific images.
|
||||
;;
|
||||
;; All the available <image-type> records are collected by the 'image-modules'
|
||||
;; procedure. This allows the "guix system image" command to turn a given
|
||||
;; <operating-system> record into an image, thanks to the specified
|
||||
;; <image-type>. In that case, the <image-type> look up is done using the
|
||||
;; name field of the <image-type> record.
|
||||
|
||||
(define-record-type* <image-type>
|
||||
image-type make-image-type
|
||||
image-type?
|
||||
@@ -220,15 +121,10 @@ that is not in SET, mentioning FIELD in the error message."
|
||||
;;;
|
||||
|
||||
(define* (os->image os #:key type)
|
||||
"Use the image constructor from TYPE, an <image-type> record to turn the
|
||||
given OS, an <operating-system> record into an image and return it."
|
||||
(let ((constructor (image-type-constructor type)))
|
||||
(constructor os)))
|
||||
|
||||
(define* (os+platform->image os platform #:key type)
|
||||
"Use the image constructor from TYPE, an <image-type> record to turn the
|
||||
given OS, an <operating-system> record into an image targeting PLATFORM, a
|
||||
<platform> record and return it."
|
||||
(image
|
||||
(inherit (os->image os #:type type))
|
||||
(platform platform)))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user