gnu: add spirv-cross.
[jackhill/guix/guix.git] / gnu / installer.scm
CommitLineData
d0f3a672 1;;; GNU Guix --- Functional package management for GNU
d008352b 2;;; Copyright © 2018, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
5c04b00c 3;;; Copyright © 2019, 2020 Ludovic Courtès <ludo@gnu.org>
8fec416c 4;;; Copyright © 2019, 2020 Tobias Geerinckx-Rice <me@tobias.gr>
91c231a2 5;;; Copyright © 2020 Florian Pelz <pelzflorian@pelzflorian.de>
d0f3a672
MO
6;;;
7;;; This file is part of GNU Guix.
8;;;
9;;; GNU Guix is free software; you can redistribute it and/or modify it
10;;; under the terms of the GNU General Public License as published by
11;;; the Free Software Foundation; either version 3 of the License, or (at
12;;; your option) any later version.
13;;;
14;;; GNU Guix is distributed in the hope that it will be useful, but
15;;; WITHOUT ANY WARRANTY; without even the implied warranty of
16;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;;; GNU General Public License for more details.
18;;;
19;;; You should have received a copy of the GNU General Public License
20;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
21
22(define-module (gnu installer)
69a934f2 23 #:use-module (guix discovery)
a49d633c
MO
24 #:use-module (guix packages)
25 #:use-module (guix gexp)
26 #:use-module (guix modules)
27 #:use-module (guix utils)
d0f3a672 28 #:use-module (guix ui)
a49d633c 29 #:use-module ((guix self) #:select (make-config.scm))
5ce84b17
LC
30 #:use-module (guix packages)
31 #:use-module (guix git-download)
5c04b00c 32 #:use-module (gnu installer utils)
a49d633c
MO
33 #:use-module (gnu packages admin)
34 #:use-module (gnu packages base)
35 #:use-module (gnu packages bash)
36 #:use-module (gnu packages connman)
bf304dbc 37 #:use-module (gnu packages cryptsetup)
69a934f2 38 #:use-module (gnu packages disk)
8fec416c 39 #:use-module (gnu packages file-systems)
a49d633c 40 #:use-module (gnu packages guile)
0791437f 41 #:use-module (gnu packages guile-xyz)
a49d633c
MO
42 #:autoload (gnu packages gnupg) (guile-gcrypt)
43 #:use-module (gnu packages iso-codes)
44 #:use-module (gnu packages linux)
45 #:use-module (gnu packages ncurses)
46 #:use-module (gnu packages package-management)
47 #:use-module (gnu packages xorg)
76269f6b 48 #:use-module (gnu system locale)
a49d633c 49 #:use-module (ice-9 match)
d0f3a672 50 #:use-module (srfi srfi-1)
a49d633c 51 #:export (installer-program))
d0f3a672 52
50247be5
LC
53(define module-to-import?
54 ;; Return true for modules that should be imported. For (gnu system …) and
55 ;; (gnu packages …) modules, we simply add the whole 'guix' package via
56 ;; 'with-extensions' (to avoid having to rebuild it all), which is why these
57 ;; modules are excluded here.
a49d633c
MO
58 (match-lambda
59 (('guix 'config) #f)
50247be5
LC
60 (('gnu 'installer _ ...) #t)
61 (('gnu 'build _ ...) #t)
62 (('guix 'build _ ...) #t)
63 (_ #f)))
a49d633c 64
99b23eab
LC
65(define not-config?
66 ;; Select (guix …) and (gnu …) modules, except (guix config).
67 (match-lambda
68 (('guix 'config) #f)
69 (('guix _ ...) #t)
70 (('gnu _ ...) #t)
71 (_ #f)))
72
a49d633c
MO
73(define* (build-compiled-file name locale-builder)
74 "Return a file-like object that evalutes the gexp LOCALE-BUILDER and store
75its result in the scheme file NAME. The derivation will also build a compiled
76version of this file."
77 (define set-utf8-locale
78 #~(begin
79 (setenv "LOCPATH"
80 #$(file-append glibc-utf8-locales "/lib/locale/"
81 (version-major+minor
82 (package-version glibc-utf8-locales))))
83 (setlocale LC_ALL "en_US.utf8")))
84
85 (define builder
81c3dc32 86 (with-extensions (list guile-json-3)
99b23eab
LC
87 (with-imported-modules `(,@(source-module-closure
88 '((gnu installer locale))
89 #:select? not-config?)
90 ((guix config) => ,(make-config.scm)))
a49d633c
MO
91 #~(begin
92 (use-modules (gnu installer locale))
93
94 ;; The locale files contain non-ASCII characters.
95 #$set-utf8-locale
96
97 (mkdir #$output)
98 (let ((locale-file
99 (string-append #$output "/" #$name ".scm"))
100 (locale-compiled-file
101 (string-append #$output "/" #$name ".go")))
102 (call-with-output-file locale-file
103 (lambda (port)
104 (write #$locale-builder port)))
105 (compile-file locale-file
106 #:output-file locale-compiled-file))))))
107 (computed-file name builder))
108
109(define apply-locale
110 ;; Install the specified locale.
c7dc6042
LC
111 (with-imported-modules (source-module-closure '((gnu services herd)))
112 #~(lambda (locale)
113 (false-if-exception
114 (setlocale LC_ALL locale))
115
116 ;; Restart the documentation viewer so it displays the manual in
b5c2d93d
MO
117 ;; language that corresponds to LOCALE. Make sure that nothing is
118 ;; printed on the console.
119 (parameterize ((shepherd-message-port
120 (%make-void-port "w")))
893651af
LC
121 (stop-service 'term-tty2)
122 (start-service 'term-tty2 (list locale))))))
a49d633c
MO
123
124(define* (compute-locale-step #:key
125 locales-name
126 iso639-languages-name
127 iso3166-territories-name)
128 "Return a gexp that run the locale-page of INSTALLER, and install the
129selected locale. The list of locales, languages and territories passed to
130locale-page are computed in derivations named respectively LOCALES-NAME,
131ISO639-LANGUAGES-NAME and ISO3166-TERRITORIES-NAME. Those lists are compiled,
132so that when the installer is run, all the lengthy operations have already
133been performed at build time."
134 (define (compiled-file-loader file name)
135 #~(load-compiled
136 (string-append #$file "/" #$name ".go")))
137
138 (let* ((supported-locales #~(supported-locales->locales
76269f6b 139 #+(glibc-supported-locales)))
a49d633c
MO
140 (iso-codes #~(string-append #$iso-codes "/share/iso-codes/json/"))
141 (iso639-3 #~(string-append #$iso-codes "iso_639-3.json"))
142 (iso639-5 #~(string-append #$iso-codes "iso_639-5.json"))
143 (iso3166 #~(string-append #$iso-codes "iso_3166-1.json"))
144 (locales-file (build-compiled-file
145 locales-name
146 #~`(quote ,#$supported-locales)))
147 (iso639-file (build-compiled-file
148 iso639-languages-name
149 #~`(quote ,(iso639->iso639-languages
150 #$supported-locales
151 #$iso639-3 #$iso639-5))))
152 (iso3166-file (build-compiled-file
153 iso3166-territories-name
154 #~`(quote ,(iso3166->iso3166-territories #$iso3166))))
155 (locales-loader (compiled-file-loader locales-file
156 locales-name))
157 (iso639-loader (compiled-file-loader iso639-file
158 iso639-languages-name))
159 (iso3166-loader (compiled-file-loader iso3166-file
160 iso3166-territories-name)))
161 #~(lambda (current-installer)
162 (let ((result
163 ((installer-locale-page current-installer)
164 #:supported-locales #$locales-loader
165 #:iso639-languages #$iso639-loader
166 #:iso3166-territories #$iso3166-loader)))
dc5f3275
MO
167 (#$apply-locale result)
168 result))))
a49d633c
MO
169
170(define apply-keymap
c088b2e4 171 ;; Apply the specified keymap. Use the default keyboard model.
a49d633c 172 #~(match-lambda
91c231a2 173 ((layout variant options)
c088b2e4 174 (kmscon-update-keymap (default-keyboard-model)
91c231a2 175 layout variant options))))
a49d633c 176
786c9c39 177(define* (compute-keymap-step context)
a49d633c
MO
178 "Return a gexp that runs the keymap-page of INSTALLER and install the
179selected keymap."
180 #~(lambda (current-installer)
181 (let ((result
182 (call-with-values
183 (lambda ()
184 (xkb-rules->models+layouts
185 (string-append #$xkeyboard-config
186 "/share/X11/xkb/rules/base.xml")))
187 (lambda (models layouts)
188 ((installer-keymap-page current-installer)
786c9c39 189 layouts '#$context)))))
3191b5f6
LC
190 (#$apply-keymap result)
191 result)))
a49d633c
MO
192
193(define (installer-steps)
194 (let ((locale-step (compute-locale-step
195 #:locales-name "locales"
196 #:iso639-languages-name "iso639-languages"
197 #:iso3166-territories-name "iso3166-territories"))
a49d633c
MO
198 (timezone-data #~(string-append #$tzdata
199 "/share/zoneinfo/zone.tab")))
200 #~(lambda (current-installer)
07a53bd5 201 ((installer-parameters-menu current-installer)
786c9c39 202 (lambda ()
07a53bd5 203 ((installer-parameters-page current-installer)
786c9c39 204 (lambda _
07a53bd5 205 (#$(compute-keymap-step 'param)
786c9c39 206 current-installer)))))
a49d633c 207 (list
6efd8430
MO
208 ;; Ask the user to choose a locale among those supported by
209 ;; the glibc. Install the selected locale right away, so that
210 ;; the user may benefit from any available translation for the
211 ;; installer messages.
a49d633c
MO
212 (installer-step
213 (id 'locale)
dc5f3275 214 (description (G_ "Locale"))
a49d633c 215 (compute (lambda _
dc5f3275
MO
216 (#$locale-step current-installer)))
217 (configuration-formatter locale->configuration))
a49d633c 218
850ddf94
LC
219 ;; Welcome the user and ask them to choose between manual
220 ;; installation and graphical install.
221 (installer-step
222 (id 'welcome)
223 (compute (lambda _
224 ((installer-welcome-page current-installer)
225 #$(local-file "installer/aux-files/logo.txt")))))
226
a49d633c
MO
227 ;; Ask the user to select a timezone under glibc format.
228 (installer-step
229 (id 'timezone)
dc5f3275 230 (description (G_ "Timezone"))
a49d633c
MO
231 (compute (lambda _
232 ((installer-timezone-page current-installer)
dc5f3275
MO
233 #$timezone-data)))
234 (configuration-formatter posix-tz->configuration))
a49d633c
MO
235
236 ;; The installer runs in a kmscon virtual terminal where loadkeys
237 ;; won't work. kmscon uses libxkbcommon as a backend for keyboard
91c231a2
FP
238 ;; input. It is possible to update kmscon current keymap by sending
239 ;; it a keyboard model, layout, variant and options, in a somehow
240 ;; similar way as what is done with setxkbmap utility.
a49d633c
MO
241 ;;
242 ;; So ask for a keyboard model, layout and variant to update the
91c231a2
FP
243 ;; current kmscon keymap. For non-Latin layouts, we add an
244 ;; appropriate second layout and toggle via Alt+Shift.
a49d633c
MO
245 (installer-step
246 (id 'keymap)
247 (description (G_ "Keyboard mapping selection"))
248 (compute (lambda _
786c9c39
MO
249 (#$(compute-keymap-step 'default)
250 current-installer)))
3191b5f6 251 (configuration-formatter keyboard-layout->configuration))
a49d633c
MO
252
253 ;; Ask the user to input a hostname for the system.
254 (installer-step
255 (id 'hostname)
dc5f3275 256 (description (G_ "Hostname"))
a49d633c 257 (compute (lambda _
dc5f3275
MO
258 ((installer-hostname-page current-installer))))
259 (configuration-formatter hostname->configuration))
a49d633c
MO
260
261 ;; Provide an interface above connmanctl, so that the user can select
262 ;; a network susceptible to acces Internet.
263 (installer-step
264 (id 'network)
265 (description (G_ "Network selection"))
266 (compute (lambda _
267 ((installer-network-page current-installer)))))
268
269 ;; Prompt for users (name, group and home directory).
270 (installer-step
dc5f3275
MO
271 (id 'user)
272 (description (G_ "User creation"))
273 (compute (lambda _
274 ((installer-user-page current-installer))))
275 (configuration-formatter users->configuration))
276
b51bde71
MO
277 ;; Ask the user to choose one or many desktop environment(s).
278 (installer-step
279 (id 'services)
280 (description (G_ "Services"))
a49d633c 281 (compute (lambda _
b51bde71 282 ((installer-services-page current-installer))))
a274bba2 283 (configuration-formatter system-services->configuration))
dc5f3275 284
d4d27ddb
TGR
285 ;; Run a partitioning tool allowing the user to modify
286 ;; partition tables, partitions and their mount points.
287 ;; Do this last so the user has something to boot if any
288 ;; of the previous steps didn't go as expected.
289 (installer-step
290 (id 'partition)
291 (description (G_ "Partitioning"))
292 (compute (lambda _
293 ((installer-partition-page current-installer))))
294 (configuration-formatter user-partitions->configuration))
295
a274bba2 296 (installer-step
dc5f3275
MO
297 (id 'final)
298 (description (G_ "Configuration file"))
299 (compute
300 (lambda (result prev-steps)
301 ((installer-final-page current-installer)
b51bde71 302 result prev-steps))))))))
a49d633c
MO
303
304(define (installer-program)
305 "Return a file-like object that runs the given INSTALLER."
306 (define init-gettext
307 ;; Initialize gettext support, so that installer messages can be
308 ;; translated.
309 #~(begin
310 (bindtextdomain "guix" (string-append #$guix "/share/locale"))
311 (textdomain "guix")))
312
313 (define set-installer-path
314 ;; Add the specified binary to PATH for later use by the installer.
315 #~(let* ((inputs
dfc8ccbf
MO
316 '#$(list bash ;start subshells
317 connman ;call connmanctl
318 cryptsetup
319 dosfstools ;mkfs.fat
320 e2fsprogs ;mkfs.ext4
321 btrfs-progs
322 jfsutils ;jfs_mkfs
323 kbd ;chvt
324 guix ;guix system init call
325 util-linux ;mkwap
326 shadow
327 coreutils)))
a49d633c
MO
328 (with-output-to-port (%make-void-port "w")
329 (lambda ()
330 (set-path-environment-variable "PATH" '("bin" "sbin") inputs)))))
331
332 (define steps (installer-steps))
69a934f2
MO
333 (define modules
334 (scheme-modules*
335 (string-append (current-source-directory) "/..")
336 "gnu/installer"))
a49d633c
MO
337
338 (define installer-builder
50247be5
LC
339 ;; Note: Include GUIX as an extension to get all the (gnu system …), (gnu
340 ;; packages …), etc. modules.
69a934f2
MO
341 (with-extensions (list guile-gcrypt guile-newt
342 guile-parted guile-bytestructures
81c3dc32 343 guile-json-3 guile-git guix)
a49d633c 344 (with-imported-modules `(,@(source-module-closure
69a934f2 345 `(,@modules
98f03548 346 (gnu services herd)
a49d633c 347 (guix build utils))
50247be5 348 #:select? module-to-import?)
a49d633c
MO
349 ((guix config) => ,(make-config.scm)))
350 #~(begin
351 (use-modules (gnu installer record)
352 (gnu installer keymap)
353 (gnu installer steps)
dc5f3275 354 (gnu installer final)
b4658c25 355 (gnu installer hostname)
a49d633c 356 (gnu installer locale)
dc5f3275
MO
357 (gnu installer parted)
358 (gnu installer services)
359 (gnu installer timezone)
360 (gnu installer user)
1a9af96b 361 (gnu installer utils)
a49d633c 362 (gnu installer newt)
3191b5f6
LC
363 ((gnu installer newt keymap)
364 #:select (keyboard-layout->configuration))
c7dc6042 365 (gnu services herd)
a49d633c
MO
366 (guix i18n)
367 (guix build utils)
3114786e
MO
368 ((system repl debug)
369 #:select (terminal-width))
a49d633c
MO
370 (ice-9 match))
371
a49d633c
MO
372 ;; Initialize gettext support so that installers can use
373 ;; (guix i18n) module.
374 #$init-gettext
375
376 ;; Add some binaries used by the installers to PATH.
377 #$set-installer-path
378
7837a572
LC
379 ;; Arrange for language and territory name translations to be
380 ;; available. We need them at run time, not just compile time,
381 ;; because some territories have several corresponding languages
382 ;; (e.g., "French" is always displayed as "français", but
383 ;; "Belgium" could be translated to Dutch, French, or German.)
384 (bindtextdomain "iso_639-3" ;languages
385 #+(file-append iso-codes "/share/locale"))
386 (bindtextdomain "iso_3166-1" ;territories
387 #+(file-append iso-codes "/share/locale"))
388
feaa83a3
LC
389 ;; Likewise for XKB keyboard layout names.
390 (bindtextdomain "xkeyboard-config"
391 #+(file-append xkeyboard-config "/share/locale"))
392
3114786e
MO
393 ;; Initialize 'terminal-width' in (system repl debug)
394 ;; to a large-enough value to make backtrace more
395 ;; verbose.
396 (terminal-width 200)
397
dc5f3275
MO
398 (let* ((current-installer newt-installer)
399 (steps (#$steps current-installer)))
a49d633c
MO
400 ((installer-init current-installer))
401
402 (catch #t
403 (lambda ()
98f03548
LC
404 (define results
405 (run-installer-steps
406 #:rewind-strategy 'menu
407 #:menu-proc (installer-menu-page current-installer)
408 #:steps steps))
409
410 (match (result-step results 'final)
411 ('success
412 ;; We did it! Let's reboot!
413 (sync)
414 (stop-service 'root))
d008352b
MO
415 (_
416 ;; The installation failed, exit so that it is restarted
417 ;; by login.
98f03548 418 #f)))
a49d633c
MO
419 (const #f)
420 (lambda (key . args)
5c04b00c
LC
421 (syslog "crashing due to uncaught exception: ~s ~s~%"
422 key args)
133c401f
MO
423 (let ((error-file "/tmp/last-installer-error"))
424 (call-with-output-file error-file
425 (lambda (port)
426 (display-backtrace (make-stack #t) port)
427 (print-exception port
428 (stack-ref (make-stack #t) 1)
429 key args)))
430 ((installer-exit-error current-installer)
431 error-file key args))
dc5f3275
MO
432 (primitive-exit 1)))
433
434 ((installer-exit current-installer)))))))
d0f3a672 435
6b48825e
MO
436 (program-file
437 "installer"
438 #~(begin
439 ;; Set the default locale to install unicode support. For
440 ;; some reason, unicode support is not correctly installed
441 ;; when calling this in 'installer-builder'.
442 (setenv "LANG" "en_US.UTF-8")
3f44034e
MO
443 (execl #$(program-file "installer-real" installer-builder
444 #:guile guile-3.0-latest)
6c849cdb 445 "installer-real"))))