#+TITLE: Configuration of the Izumi computer #+AUTHOR: Marek Paśnikowski #+STARTUP: content #+PROPERTY: header-args:scheme :noweb yes #+PROPERTY: header-args:scheme+ :noweb-prefix yes * DONE The Monolith #+NAME: OPERATING-SYSTEM #+BEGIN_SRC scheme :tangle system-configuration.scm ( define-module ( systems izumi system-configuration ) ) ( use-modules ( marek ) ( gnu ) ( guix records ) ( ice-9 match ) ( nongnu packages linux ) ( nongnu system linux-initrd ) ) ( use-package-modules admin certs kde-frameworks kde-multimedia kde-pim kde-plasma kde-utils mail version-control ) ( use-service-modules base certbot cgit desktop mail shepherd ssh version-control web xorg ) ( define-record-type* dkimproxy-out-signature-configuration make-dkimproxy-out-signature-configuration dkimproxy-out-signature-configuration? ( type dkimproxy-out-signature-configuration-type ( default 'dkim ) ) ( key dkimproxy-out-signature-configuration-key ( default #f ) ) ( algorithm dkimproxy-out-signature-configuration-algorithm ( default #f ) ) ( method dkimproxy-out-signature-configuration-method ( default #f) ) ( domain dkimproxy-out-signature-configuration-domain ( default #f ) ) ( identity dkimproxy-out-signature-configuration-identity ( default #f ) ) ( selector dkimproxy-out-signature-configuration-selector ( default #f ) ) ) ( define generate-dkimproxy-out-signature-configuration ( match-lambda ( ( $ type key algorithm method domain identity selector ) ( string-append ( match type ( 'dkim "dkim" ) ( 'domainkeys "domainkeys" ) ) ( if ( or key algorithm method domain identity selector ) ( string-append "(" ( string-join `( ,@ ( if key ( list ( string-append "key=" key ) ) '() ) ,@ ( if algorithm ( list ( string-append "a=" algorithm ) ) '() ) ,@ ( if method ( list ( string-append "c=" method ) ) '() ) ,@ ( if domain ( list ( string-append "d=" domain ) ) '() ) ,@ ( if identity ( list ( string-append "i=" identity ) ) '() ) ,@ ( if selector ( list ( string-append "s=" selector ) ) '() ) ) "," ) ")" ) "" ) ) ) ) ) ( define-record-type* dkimproxy-out-configuration make-dkimproxy-out-configuration dkimproxy-out-configuration? ( package dkimproxy-out-configuration-package ( default dkimproxy ) ) ( listen dkimproxy-out-configuration-listen ( default #f ) ) ( relay dkimproxy-out-configuration-relay ( default #f ) ) ( list-id-map dkimproxy-out-configuration-list-id-map ( default '() ) ) ( sender-map dkimproxy-out-configuration-sender-map ( default '() ) ) ( reject-error? dkimproxy-out-configuration-sender-reject-error? ( default #f ) ) ( config-file dkimproxy-out-configuration-config-file ( default #f ) ) ) ( define ( generate-map-file config filename ) ( apply plain-file filename ( map ( lambda ( config ) ( match config ( ( selector ( config ... ) ) ( string-append selector " " ( string-join ( map generate-dkimproxy-out-signature-configuration config ) "\n") ) ) ( ( selector config ) ( string-append selector " " ( generate-dkimproxy-out-signature-configuration config ) ) ) ) ) config ) ) ) ( define dkimproxy-out-shepherd-service ( match-lambda ( ( $ package listen relay list-id-map sender-map reject-error? config-file ) ( list ( shepherd-service ( provision '( dkimproxy-out ) ) ( requirement '( loopback ) ) ( documentation "Outbound DKIM proxy." ) ( start ( let ( ( proxy ( file-append package "/bin/dkimproxy.out" ) ) ) ( if config-file #~ ( make-forkexec-constructor ( list #$ proxy ( string-append "--conf_file=" #$ config-file ) "--pidfile=/var/run/dkimproxy.out.pid" "--user=dkimproxy" "--group=dkimproxy" ) #:pid-file "/var/run/dkimproxy.out.pid" ) ( let* ( ( first-signature ( match sender-map ( ( ( sender ( signature _ ... ) ) _ ... ) signature ) ( ( ( sender signature ) _ ... ) signature ) ) ) ( domains ( apply append ( map ( lambda ( sender ) ( match sender ( ( ( domains ... ) config ) domains ) ( ( domain config ) domain ) ) ) sender-map ) ) ) ( sender-map ( generate-map-file sender-map "sender.map" ) ) ( listid-map ( if ( null? list-id-map ) #f ( generate-map-file list-id-map "listid.map" ) ) ) ( keyfile ( dkimproxy-out-signature-configuration-key first-signature ) ) ( selector ( dkimproxy-out-signature-configuration-selector first-signature ) ) ( method ( dkimproxy-out-signature-configuration-method first-signature ) ) ( signature ( match ( dkimproxy-out-signature-configuration-type first-signature ) ( 'dkim "dkim" ) ( 'domainkeys "domainkeys" ) ) ) ) #~ ( make-forkexec-constructor `( ,#$ proxy "--pidfile=/var/run/dkimproxy.out.pid" "--user=dkimproxy" "--group=dkimproxy" ,( string-append "--listen=" #$ listen ) ,( string-append "--relay=" #$ relay ) ,( string-append "--sender_map=" #$ sender-map ) ,@ ( if #$ listid-map ( list ( string-append "--listid_map=" #$ listid-map ) ) '() ) ,( string-append "--domain=" #$ domains ) ,( string-append "--keyfile=" #$ keyfile ) ,( string-append "--selector=" #$ selector ) ,@ ( if #$ method ( list ( string-append "--method=" #$ method ) ) '() ) ,@ ( if #$ reject-error? '( "--reject_error" ) '() ) ,@ ( if #$ signature ( list ( string-append "--signature=" #$ signature ) ) '() ) ) ) ) ) ) ) ( stop #~ ( make-kill-destructor ) ) ) ) ) ) ) ( define %dkimproxy-accounts ( list ( user-group ( name "dkimproxy" ) ( system? #t ) ) ( user-account ( name "dkimproxy" ) ( group "dkimproxy" ) ( system? #t ) ( comment "Dkimproxy user" ) ( home-directory "/var/empty" ) ( shell ( file-append shadow "/sbin/nologin" ) ) ) ) ) ( define dkimproxy-out-service-type ( service-type ( name 'dkimproxy-out ) ( description "stub" ) ( extensions ( list ( service-extension account-service-type ( const %dkimproxy-accounts ) ) ( service-extension shepherd-root-service-type dkimproxy-out-shepherd-service ) ) ) ) ) ( define aliases-file ( mixed-text-file "aliases" "@ vmail\n" ) ) ( define relays-file ( mixed-text-file "other-relays" "mx1.forwardemail.net\n" "mx2.forwardemail.net\n" ) ) ( define blacklist-file ( mixed-text-file "blacklist" "@yahoo.com.cn\n" "@qq.com\n" "@fnac.com\n" "@just-aero.us\n" "@elitetorrent1.com\n" ) ) ( define ( opensmtpd-conf interface domain ) ( mixed-text-file "smtpd.conf" "# This is the smtpd server system-wide configuration file.\n" "# See smtpd.conf(5) for more information.\n" "\n" "# My TLS certificate and key\n" "pki marekpasnikowski.pl cert \"/etc/letsencrypt/live/" domain "/fullchain.pem\"\n" "pki marekpasnikowski.pl key \"/etc/letsencrypt/live/" domain "/privkey.pem\"\n" "\n" "# Edit this file to add add more virtual users (passwords are read in that file\n" "# instead of /etc/passwd\n" "table passwd file:" smtpd-keys "\n" "\n" "table other-relays file:" relays-file "\n" "table blacklist file:" blacklist-file "\n" "\n" "# A simple spam filter\n" "# filter spam-filter phase mail-from match mail-from reject \"555\"\n" "\n" "# port 25 is used only for receiving from external servers, and they may start\n" "# a TLS session if they want.\n" "listen on " interface " port 25 # tls pki marekpasnikowski.pl filter spam-filter\n" "\n" "# For sending messages from outside of this server, you need to authenticate and\n" "# use TLS.\n" "listen on " interface " port 465 smtps pki marekpasnikowski.pl mask-src auth \n" "\n" "# Localhost is used by the .onion, so we use the same configuration for \n" "# local connections." "listen on lo port 25 tls pki marekpasnikowski.pl filter spam-filter\n" "# Since incoming connection uses tor, we don't need tls, but still require\n" "# authentication; we're not a relay\n" "# listen on lo port 587 tls pki marekpasnikowski.pl mask-src auth \n" "\n" "# DKIMproxy\n" "listen on lo port 10028 tag DKIM_OUT\n" "\n" "# The socket is considered an internal connection\n" "listen on socket mask-src\n" "\n" "# Maybe it'll work better if we connect to gmail only with v4?\n" "# limit mta for domain gmail.com inet4\n" "\n" "# TODO: manage these files directly in the configuration?\n" "# If you edit the file, you have to run \"smtpctl update table aliases\"\n" "table aliases file:" aliases-file "\n" "\n" "# We define some actions\n" "action receive lmtp \"/var/run/dovecot/lmtp\" rcpt-to virtual \n" "action outbound relay helo \"" domain "\"\n" "action godkim relay host smtp://127.0.0.1:10027\n" "\n" "# We accept to relay any mail from authenticated users\n" "match for any from any auth action godkim\n" "match tag DKIM_OUT for any action outbound\n" "\n" "# Then, we reject on some other conditions:\n" "\n" "# If the mail tries to impersonate us\n" "# match !from src mail-from \"@marekpasnikowski.pl\" for any reject\n" "\n" "# If it comes from someone on the blacklist\n" "match from any mail-from reject\n" "\n" "# Finally, if we accept incoming messages\n" "match from any for domain \"marekpasnikowski.pl\" action receive\n" "match for local action receive\n" ) ) ( define ( wip-dkim-service domain ) ( service dkimproxy-out-service-type ( dkimproxy-out-configuration ( listen "127.0.0.1:10027" ) ( relay "127.0.0.1:10028" ) ( sender-map `( ( ,domain ( ,( dkimproxy-out-signature-configuration ( algorithm "rsa-sha256" ) ( key "/etc/mail/dkim/marekpasnikowski.pl.key" ) ( method "relaxed" ) ( selector "dkim" ) ( type 'dkim ) ) ,( dkimproxy-out-signature-configuration ( method "mofws" ) ( type 'domainkeys ) ) ) ) ) ) ) ) ) ( define ( wip-imap-service domain ) ( service dovecot-service-type ( dovecot-configuration ( disable-plaintext-auth? #t ) ( mail-location "maildir:~/Maildir" ) ( namespaces ( list ( namespace-configuration ( name "inbox" ) ( inbox? #t ) ( mailboxes ( list ( mailbox-configuration ( name "Archive" ) ( auto "subscribe" ) ( special-use ( list "\\Archive" ) ) ) ( mailbox-configuration ( name "Drafts" ) ( auto "subscribe" ) ( special-use ( list "\\Drafts" ) ) ) ( mailbox-configuration ( name "Junk" ) ( auto "subscribe" ) ( special-use ( list "\\Junk" ) ) ) ( mailbox-configuration ( name "Sent" ) ( auto "subscribe" ) ( special-use ( list "\\Sent" ) ) ) ( mailbox-configuration ( name "Trash" ) ( auto "subscribe" ) ( special-use ( list "\\Trash" ) ) ) ) ) ) ) ) ( passdbs ( list ( passdb-configuration ( args ( list "username_format=%n" "/etc/dovecot-passwd" ) ) ( driver "passwd-file" ) ) ) ) ( protocols ( list ( protocol-configuration ( name "imap" ) ) ( protocol-configuration ( name "lmtp" ) ) ) ) ( services ( list ( service-configuration ( kind "lmtp" ) ( listeners ( list ( inet-listener-configuration ( address "192.168.10.2 127.0.0.1" ) ( port 24 ) ( protocol "lmtp" ) ) ( unix-listener-configuration ( group "vmail" ) ( mode "0666" ) ( path "lmtp" ) ( user "vmail" ) ) ) ) ) ( service-configuration ( kind "imap-login" ) ( listeners ( list ( inet-listener-configuration ( address "192.168.10.2" ) ( port 993 ) ( protocol "imaps" ) ;; How does the boolean type map to ;; the three configuration options? ;; ( ssl? "required" ) ) ) ) ) ) ) ( ssl? "required" ) ( ssl-cert ( string-append " ( elogind-configuration ( inherit configuration ) ( handle-lid-switch 'ignore ) ( handle-lid-switch-docked 'ignore ) ( handle-lid-switch-external-power 'ignore ) ) ) ( gdm-service-type configuration => ( gdm-configuration ( inherit configuration ) ( auto-suspend? #f ) ( wayland? #t ) ) ) ( guix-service-type configuration => ( let* ( ( non-guix.pub ( string-append "( public-key ( ecc ( curve Ed25519 )" "( q #C1FD53E5D4CE971933EC50C9F307AE2171A2D3B52C804642A7A35F84F3A4EA98# ) ) )" ) ) ( authorized-keys ( append %default-authorized-guix-keys ( list ( plain-file "non-guix.pub" non-guix.pub ) ) ) ) ( extra-options ( list "--gc-keep-derivations=yes" "--gc-keep-outputs=yes" ) ) ( substitute-urls ( append %default-substitute-urls ( list "https://substitutes.nonguix.org" ) ) ) ) ( guix-configuration ( inherit configuration ) ( authorized-keys authorized-keys ) ( extra-options extra-options ) ( substitute-urls substitute-urls ) ) ) ) ) ( wip-mail-services #:interface "enp1s0" #:domain "marekpasnikowski.pl" ) ( list ( service certbot-service-type ( certbot-configuration ( certificates ( list ( certificate-configuration ( deploy-hook ( program-file "nginx-deploy-hook" #~ ( let ( ( pid ( call-with-input-file "/var/run/nginx/pid" read ) ) ) ( kill pid SIGHUP ) ) ) ) ( domains ( list "marekpasnikowski.pl" "git.marekpasnikowski.pl" "radicale.marekpasnikowski.pl" ) ) ) ) ) ( email certbot-mail ) ( webroot "/srv/www/marek/marekpasnikowski.pl" ) ) ) ( service cgit-service-type ( cgit-configuration ( nginx ( list ( nginx-server-configuration ( locations ( list ( git-http-nginx-location-configuration ( git-http-configuration ( git-root "/var/lib/gitolite/repositories" ) ( uri-path "/git" ) ) ) ( nginx-location-configuration ( body ( list "fastcgi_param HTTP_HOST $server_name ;" "fastcgi_param PATH_INFO $uri ;" "fastcgi_param QUERY_STRING $args ;" "fastcgi_param SCRIPT_FILENAME $document_root/lib/cgit/cgit.cgi ;" "fastcgi_pass 127.0.0.1:9000 ;" ) ) ( uri "@cgit" ) ) ( nginx-location-configuration ( body ( list "root /srv/www/marek/marekpasnikowski.pl/ ;" ) ) ( uri "/.well-known" ) ) ) ) ( listen ( list "192.168.10.2:443 ssl" ) ) ( root cgit ) ( server-name ( list "git.marekpasnikowski.pl" ) ) ( ssl-certificate "/etc/letsencrypt/live/marekpasnikowski.pl/fullchain.pem" ) ( ssl-certificate-key "/etc/letsencrypt/live/marekpasnikowski.pl/privkey.pem" ) ( try-files ( list "$uri" "@cgit" ) ) ) ) ) ( repositories ( list ( repository-cgit-configuration ( hide? #t ) ( path "/srv/git/marek/packages" ) ) ) ) ( repository-directory "/var/lib/gitolite/repositories" ) ) ) ( service fcgiwrap-service-type ) ( service gitolite-service-type ( gitolite-configuration ( admin-pubkey gitolite-keys ) ( rc-file ( gitolite-rc-file ( umask #o0022 ) ) ) ) ) ( service gnome-desktop-service-type ) ( service nginx-service-type ( nginx-configuration ( server-blocks ( list ;; Top-Level ( nginx-server-configuration ( locations ( list ( nginx-location-configuration ( uri "/.well-known" ) ( body ( list "root /srv/www/marek/marekpasnikowski.pl ;" ) ) ) ) ) ( listen ( list "192.168.10.2:443 ssl" ) ) ( root "/srv/www/marek/marekpasnikowski.pl" ) ( server-name ( list "marekpasnikowski.pl" ) ) ( ssl-certificate "/etc/letsencrypt/live/marekpasnikowski.pl/fullchain.pem" ) ( ssl-certificate-key "/etc/letsencrypt/live/marekpasnikowski.pl/privkey.pem" ) ) ;; Radicale ( nginx-server-configuration ( locations ( list ( nginx-location-configuration ( body ( list "proxy_pass http://localhost:5232/ ;" "proxy_set_header X-Script-Name \"\" ;" "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;" "proxy_set_header Host $http_host ;" "proxy_pass_header Authorization ;" ) ) ( uri "/" ) ) ( nginx-location-configuration ( body ( list "root /srv/www/marek/marekpasnikowski.pl ;" ) ) ( uri "/.well-known" ) ) ) ) ( listen ( list "192.168.10.2:443 ssl" ) ) ( server-name ( list "radicale.marekpasnikowski.pl" ) ) ) ) ) ) ) ( service openssh-service-type ) ( service radicale-service-type ( radicale-configuration ( config-file ( mixed-text-file "radicale.conf" "[auth]\n" "type = htpasswd\n" "htpasswd_filename = " radicale-keys "\n" "htpasswd_encryption = plain\n" "\n" "[server]\n" "hosts = localhost:5232\n" ) ) ) ) ( simple-service 'base-profile profile-service-type ( append %base-packages ( list ) ) ) ( simple-service 'nss-profile profile-service-type ( list nss-certs ) ) ( simple-service 'etc-files etc-service-type ( list `( "mailname" ,( plain-file "mailname" "marekpasnikowski.pl\n" ) ) `( "dovecot-passwd" ,dovecot-keys ) ) ) ) ) ) ( sudoers-file ( local-file "system-files/sudoers" ) ) ( swap-devices ( list ( swap-space ( target "/dev/sda3" ) ) ) ) ( timezone "Europe/Warsaw" ) ( users ( append %base-user-accounts ( list ( user-account ( comment "vmail" ) ( group "vmail" ) ( home-directory "/home/vmail" ) ( name "vmail" ) ( system? #t ) ) ( user-account ( comment "Marek Paśnikowski" ) ( group "users" ) ( home-directory "/home/marek" ) ( name "marek" ) ( supplementary-groups ( list "audio" "netdev" "video" "wheel" ) ) ) ) ) ) ) #+END_SRC #+NAME: OPENSMTPD-CONFIGURATION-FILE #+BEGIN_SRC conf :tangle system-files/smtpd.conf # The prefix on GUIX is not the default one — it is /etc . table aliases file:/etc/aliases # The mail certificates are issued by Let‘s Encrypt and served by NGINX pki marekpasnikowski.pl cert "/etc/letsencrypt/live/marekpasnikowski.pl/fullchain.pem" pki marekpasnikowski.pl key "/etc/letsencrypt/live/marekpasnikowski.pl/privkey.pem" # Listen for local messages. listen on lo # Listen for messages from the internet. listen on enp1s0 tls port 25 pki "marekpasnikowski.pl" listen on enp1s0 smtps port 465 pki "marekpasnikowski.pl" # There is no filtering in the design, so the two actions are enough. action receive maildir alias action send relay # Match incoming messages. match from local for local action receive match from any for domain "marekpasnikowski.pl" action receive # Match outgoing messages. match for any action send #+END_SRC * [[https://guix.gnu.org/manual/en/html_node/Home-Configuration.html][13 Home Configuration]] #+BEGIN_SRC scheme :tangle home-configuration.scm (define-module (systems izumi home-configuration)) (use-modules (gnu home) (gnu home services shells) (gnu packages) (gnu packages compression) (gnu packages emacs) (gnu packages fonts) (gnu packages gnome) (gnu packages gnupg) (gnu packages noweb) (gnu packages version-control) (nongnu packages mozilla)) <> <> <> <> (home-environment (packages (list dconf-editor emacs emacs-org-modern emacs-paredit firefox font-google-noto font-google-noto-emoji font-google-noto-sans-cjk font-google-noto-serif-cjk git gnupg gnome-tweaks noweb pinentry pwgen unzip zip)) (services (append <> <>))) #+END_SRC ** [[https://guix.gnu.org/manual/en/html_node/Home-Services.html][13.3 Home Services]] #+NAME: ESSENTIAL-HOME-SERVICES #+BEGIN_SRC scheme (list <> <> (simple-service 'environment-variables home-environment-variables-service-type `(("EDITOR" . "emacsclient -nw")))) #+END_SRC #+NAME: SHELLS #+BEGIN_SRC scheme (list <>) #+END_SRC *** [[https://guix.gnu.org/manual/en/html_node/Essential-Home-Services.html][13.3.1 Essential Home Services]] #+NAME: ESSENTIAL-HOME-MODULES #+BEGIN_SRC scheme (use-modules (gnu services) (gnu home services) (gnu packages password-utils) (guix gexp)) #+END_SRC #+NAME: EMACS-HOME-PROFILE #+BEGIN_SRC scheme (simple-service 'emacs-home-profile home-profile-service-type (append <> <>)) #+END_SRC #+NAME: HOME-FILES-SERVICE-TYPE #+BEGIN_SRC scheme ( simple-service 'home-files home-files-service-type ( list ( list ".emacs" ( local-file "home-files/emacs-configuration.el" ) ) ( list ".config/guix/channels.scm" ( local-file "channels.scm" ) ) ( list ".gitconfig" ( local-file "home-files/gitconfig")) ( list ".config/git/ignore" ;; https://github.com/github/gitignore/blob/main/Global/Emacs.gitignore ( local-file "home-files/git-ignore.conf" ) ) ) ) #+END_SRC *** [[https://guix.gnu.org/manual/en/html_node/Shells-Home-Services.html][13.3.2 Shells]] #+NAME: SHELLS-MODULES #+BEGIN_SRC scheme (use-modules (gnu home services shells) (gnu services)) #+END_SRC #+NAME: HOME-BASH-SERVICE-TYPE #+BEGIN_SRC scheme (let* ((and "&& ") (collect-garbage "sudo guix gc -d 7d ") (configuration-prefix "/home/marek/src/channel/systems/izumi/") (pull-guix "guix pull ") (reconfigure-home (string-append "guix home reconfigure " configuration-prefix "home-configuration.scm ")) (reconfigure-system (string-append "sudo guix system reconfigure " configuration-prefix "system-configuration.scm " and "sudo chmod 751 /var/lib/gitolite " and "echo 'WARNING: Upstream the correct permission bits to gitolite.'")) (update-system (string-append pull-guix and reconfigure-system and reconfigure-home and collect-garbage))) (simple-service 'bash-extension home-bash-service-type (home-bash-extension (aliases `(("collect-garbage" . ,collect-garbage) ("edit" . "$EDITOR") ("pull-guix" . ,pull-guix) ("reconfigure-home" . ,reconfigure-home) ("reconfigure-system" . ,reconfigure-system) ("update-system" . ,update-system))) (bashrc (list (plain-file "source-home-profile" "source ~/.profile\n")))))) #+END_SRC * [[https://www.leonrische.me/fc/][Emacs-Org-FC-TN]] #+NAME: EMACS-ORG-FC-TN-MODULES #+BEGIN_SRC scheme (use-modules (gnu) (gnu home services) (guix build-system emacs) (guix git-download) ((guix licenses) #:prefix license:) (guix packages)) (use-package-modules base emacs-xyz gawk) #+END_SRC #+NAME: EMACS-ORG-FC-TN-PACKAGES #+BEGIN_SRC scheme (list (let ((commit* "wip-algo-tn")) (package (name "emacs-org-fc") (version (git-version "0.1.0" "0" commit*)) (source (origin (method git-fetch) (uri (git-reference (url "https://git.marekpasnikowski.pl/org-fc.git") (commit commit*))) (file-name (git-file-name name version)) (sha256 (base32 "0x8bxjh4r1wqh48f69x8k6gxfpixhwci365n0rh827csfjaqs5hg")))) (build-system emacs-build-system) (arguments (list #:include #~ (cons* "\\.awk$" "\\.org$" %default-include) #:exclude #~ (cons "^test/" %default-exclude) #:tests? #t #:test-command #~ (list "emacs" "--batch" "-L" "." "-L" "tests/" "-l" "tests/org-fc-filter-test.el" "-l" "tests/org-fc-indexer-test.el" "-l" "tests/org-fc-review-data-test.el" "-f" "ert-run-tests-batch-and-exit") #:phases #~ (modify-phases %standard-phases (add-after 'unpack 'qualify-paths (lambda* (#:key inputs #:allow-other-keys) (substitute* "org-fc-awk.el" (("\"find ") (string-append "\"" (search-input-file inputs "/bin/find") " ")) (("\"gawk ") (string-append "\"" (search-input-file inputs "/bin/gawk") " ")) (("\"xargs ") (string-append "\"" (search-input-file inputs "/bin/xargs") " ")))))))) (inputs (list findutils gawk)) (propagated-inputs (list emacs-hydra)) (home-page "https://www.leonrische.me/fc/index.html") (synopsis "Spaced repetition system for Emacs Org mode") (description (string-append "Org-fc is a spaced-repetition system for Emacs' Org mode.\n" "It allows you to mark headlines in a file as flashcards, turning pieces of\n" "knowledge you want to learn into a question-answer test. These cards are\n" "reviewed at regular interval. After each review, the next review interval is\n" "calculated based on how well you remembered the contents of the card.\n")) (license license:gpl3+)))) #+END_SRC * [[https://emacs-guix.gitlab.io/website/manual/latest/html_node/index.html][Emacs-Guix]] ** [[https://emacs-guix.gitlab.io/website/manual/latest/html_node/Installation.html][2. Installation]] #+NAME: EMACS-GUIX-MODULES #+BEGIN_SRC scheme (use-modules (gnu) (gnu home services)) (use-package-modules emacs-xyz) (use-service-modules) #+END_SRC #+NAME: EMACS-GUIX-PACKAGES #+BEGIN_SRC scheme (list emacs-guix emacs-nix-mode) #+END_SRC * EOF