aboutsummaryrefslogtreecommitdiff
path: root/gnu/home.scm
blob: b390c8d534885a06e079a876cf4693fe8354d2eb (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
;;; Copyright © 2022, 2024 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)
  #:use-module (gnu home services)
  #:use-module (gnu home services symlink-manager)
  #:use-module (gnu home services shells)
  #:use-module (gnu home services xdg)
  #:use-module (gnu home services fontutils)
  #:use-module (gnu services)
  #:use-module (guix records)
  #: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))

;;; Comment:
;;;
;;; This module provides a <home-environment> record for managing
;;; per-user packages and configuration files in the similar way as
;;; <operating-system> do for system packages and configuration files.
;;;
;;; Code:

(define-record-type* <home-environment> home-environment
  make-home-environment
  home-environment?
  this-home-environment

  (packages           home-environment-packages            ; list of (PACKAGE OUTPUT...)
                      (default '()))

  (essential-services home-environment-essential-services  ; list of services
                      (thunked)
                      (default (home-environment-default-essential-services
                                this-home-environment)))

  (services           home-environment-user-services
                      (default '())
                      (sanitize validate-service-list))

  (location           home-environment-location            ; <location>
                      (default (and=> (current-source-location)
                                      source-properties->location))
                      (innate)))

(define (home-environment-default-essential-services he)
  "Return the list of essential services for home environment."
  (list
   (service home-run-on-first-login-service-type)
   (service home-activation-service-type)
   (service home-environment-variables-service-type)

   (service home-symlink-manager-service-type)

   (service home-fontconfig-service-type)
   (service home-xdg-base-directories-service-type)
   (service home-shell-profile-service-type)

   (service home-service-type)
   (service home-profile-service-type (home-environment-packages he))))

(define* (home-environment-services he)
  "Return all the services of home environment."
  (instantiate-missing-services
   (append (home-environment-user-services he)
           (home-environment-essential-services he))))

(define* (home-environment-derivation he)
  "Return a derivation that builds home environment."
  (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)))
  "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."
  (home-environment
    (inherit he)
    (services (cons (service home-provenance-service-type config-file)
                    (home-environment-user-services he)))))

(define-gexp-compiler (home-environment-compiler (he <home-environment>)
                                                 system target)
  ((store-lift
    (lambda (store)
      (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)))))
se creation" (marionette-eval '(begin (use-modules (guix build utils)) (current-output-port (open-file "/dev/console" "w0")) (invoke #$(file-append postgresql "/bin/psql") "-tA" "-c" "CREATE DATABASE test")) marionette)) (test-assert "load extension" (marionette-eval '(begin (current-output-port (open-file "/dev/console" "w0")) ;; Capture stderr for the next test. (current-error-port (open-file "timescaledb.stderr" "w0")) (invoke #$(file-append postgresql "/bin/psql") "-tA" "-c" "CREATE EXTENSION timescaledb" "test")) marionette)) (test-assert "telemetry is disabled" (marionette-eval '(begin (string-contains (call-with-input-file "timescaledb.stderr" (lambda (port) (get-string-all port))) "Please enable telemetry")) marionette)) (test-assert "create hypertable" (marionette-eval '(begin (current-output-port (open-file "/dev/console" "w0")) (invoke #$(file-append postgresql "/bin/psql") "-tA" "-c" "CREATE TABLE ht ( time TIMESTAMP NOT NULL, data double PRECISION NULL )" "test") (invoke #$(file-append postgresql "/bin/psql") "-tA" "-c" "SELECT create_hypertable('ht','time')" "test")) marionette)) (test-end)))) (gexp->derivation "timescaledb-test" test)) (define %test-timescaledb (system-test (name "timescaledb") (description "Test the TimescaleDB PostgreSQL extension.") (value (run-timescaledb-test)))) ;;; ;;; The MySQL service. ;;; (define %mysql-os (simple-operating-system (service mysql-service-type (mysql-configuration ;; Disable O_DIRECT since it's not supported on overlayfs. ;; See <https://jira.mariadb.org/browse/MDEV-28751>. (extra-content "innodb-flush-method = fsync"))))) (define* (run-mysql-test) "Run tests in %MYSQL-OS." (define os (marionette-operating-system %mysql-os #:imported-modules '((gnu services herd) (guix combinators)))) (define vm (virtual-machine (operating-system os) (memory-size 512))) (define test (with-imported-modules '((gnu build marionette)) #~(begin (use-modules (srfi srfi-11) (srfi srfi-64) (gnu build marionette)) (define marionette (make-marionette (list #$vm))) (test-runner-current (system-test-runner #$output)) (test-begin "mysql") (test-assert "service running" (marionette-eval '(begin (use-modules (gnu services herd)) (match (start-service 'mysql) (#f #f) (('service response-parts ...) (match (assq-ref response-parts 'running) ((pid) pid))))) marionette)) (test-assert "mysql_upgrade completed" (wait-for-file "/var/lib/mysql/mysql_upgrade_info" marionette)) (test-assert "socket is ready" (wait-for-unix-socket "/run/mysqld/mysqld.sock" marionette)) (test-eq "create database" 0 (marionette-eval '(begin (system* #$(file-append mariadb "/bin/mysql") "-e" "CREATE DATABASE guix;")) marionette)) (test-eq "create table" 0 (marionette-eval '(begin (system* #$(file-append mariadb "/bin/mysql") "guix" "-e" "CREATE TABLE facts (id INT, data VARCHAR(12));")) marionette)) (test-eq "insert data" 0 (marionette-eval '(begin (system* #$(file-append mariadb "/bin/mysql") "guix" "-e" "INSERT INTO facts VALUES (1, 'awesome')")) marionette)) (test-equal "retrieve data" "awesome\n" (marionette-eval '(begin (use-modules (ice-9 popen) (rnrs io ports)) (let* ((port (open-pipe* OPEN_READ #$(file-append mariadb "/bin/mysql") "guix" "-NB" "-e" "SELECT data FROM facts WHERE id=1;")) (output (get-string-all port))) (close-pipe port) output)) marionette)) (test-end)))) (gexp->derivation "mysql-test" test)) (define %test-mysql (system-test (name "mysql") (description "Start the MySQL service.") (value (run-mysql-test))))