gnu: higan: Update description.
[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>
d0f3a672
MO
5;;;
6;;; This file is part of GNU Guix.
7;;;
8;;; GNU Guix is free software; you can redistribute it and/or modify it
9;;; under the terms of the GNU General Public License as published by
10;;; the Free Software Foundation; either version 3 of the License, or (at
11;;; your option) any later version.
12;;;
13;;; GNU Guix is distributed in the hope that it will be useful, but
14;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;;; GNU General Public License for more details.
17;;;
18;;; You should have received a copy of the GNU General Public License
19;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
20
21(define-module (gnu installer)
69a934f2 22 #:use-module (guix discovery)
a49d633c
MO
23 #:use-module (guix packages)
24 #:use-module (guix gexp)
25 #:use-module (guix modules)
26 #:use-module (guix utils)
d0f3a672 27 #:use-module (guix ui)
a49d633c 28 #:use-module ((guix self) #:select (make-config.scm))
5ce84b17
LC
29 #:use-module (guix packages)
30 #:use-module (guix git-download)
5c04b00c 31 #:use-module (gnu installer utils)
a49d633c
MO
32 #:use-module (gnu packages admin)
33 #:use-module (gnu packages base)
34 #:use-module (gnu packages bash)
35 #:use-module (gnu packages connman)
bf304dbc 36 #:use-module (gnu packages cryptsetup)
69a934f2 37 #:use-module (gnu packages disk)
8fec416c 38 #:use-module (gnu packages file-systems)
a49d633c 39 #:use-module (gnu packages guile)
0791437f 40 #:use-module (gnu packages guile-xyz)
a49d633c
MO
41 #:autoload (gnu packages gnupg) (guile-gcrypt)
42 #:use-module (gnu packages iso-codes)
43 #:use-module (gnu packages linux)
44 #:use-module (gnu packages ncurses)
45 #:use-module (gnu packages package-management)
46 #:use-module (gnu packages xorg)
76269f6b 47 #:use-module (gnu system locale)
a49d633c 48 #:use-module (ice-9 match)
d0f3a672 49 #:use-module (srfi srfi-1)
a49d633c 50 #:export (installer-program))
d0f3a672 51
50247be5
LC
52(define module-to-import?
53 ;; Return true for modules that should be imported. For (gnu system …) and
54 ;; (gnu packages …) modules, we simply add the whole 'guix' package via
55 ;; 'with-extensions' (to avoid having to rebuild it all), which is why these
56 ;; modules are excluded here.
a49d633c
MO
57 (match-lambda
58 (('guix 'config) #f)
50247be5
LC
59 (('gnu 'installer _ ...) #t)
60 (('gnu 'build _ ...) #t)
61 (('guix 'build _ ...) #t)
62 (_ #f)))
a49d633c 63
99b23eab
LC
64(define not-config?
65 ;; Select (guix …) and (gnu …) modules, except (guix config).
66 (match-lambda
67 (('guix 'config) #f)
68 (('guix _ ...) #t)
69 (('gnu _ ...) #t)
70 (_ #f)))
71
a49d633c
MO
72(define* (build-compiled-file name locale-builder)
73 "Return a file-like object that evalutes the gexp LOCALE-BUILDER and store
74its result in the scheme file NAME. The derivation will also build a compiled
75version of this file."
76 (define set-utf8-locale
77 #~(begin
78 (setenv "LOCPATH"
79 #$(file-append glibc-utf8-locales "/lib/locale/"
80 (version-major+minor
81 (package-version glibc-utf8-locales))))
82 (setlocale LC_ALL "en_US.utf8")))
83
84 (define builder
81c3dc32 85 (with-extensions (list guile-json-3)
99b23eab
LC
86 (with-imported-modules `(,@(source-module-closure
87 '((gnu installer locale))
88 #:select? not-config?)
89 ((guix config) => ,(make-config.scm)))
a49d633c
MO
90 #~(begin
91 (use-modules (gnu installer locale))
92
93 ;; The locale files contain non-ASCII characters.
94 #$set-utf8-locale
95
96 (mkdir #$output)
97 (let ((locale-file
98 (string-append #$output "/" #$name ".scm"))
99 (locale-compiled-file
100 (string-append #$output "/" #$name ".go")))
101 (call-with-output-file locale-file
102 (lambda (port)
103 (write #$locale-builder port)))
104 (compile-file locale-file
105 #:output-file locale-compiled-file))))))
106 (computed-file name builder))
107
108(define apply-locale
109 ;; Install the specified locale.
c7dc6042
LC
110 (with-imported-modules (source-module-closure '((gnu services herd)))
111 #~(lambda (locale)
112 (false-if-exception
113 (setlocale LC_ALL locale))
114
115 ;; Restart the documentation viewer so it displays the manual in
b5c2d93d
MO
116 ;; language that corresponds to LOCALE. Make sure that nothing is
117 ;; printed on the console.
118 (parameterize ((shepherd-message-port
119 (%make-void-port "w")))
c7dc6042
LC
120 (lambda ()
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
c088b2e4
MO
173 ((layout variant)
174 (kmscon-update-keymap (default-keyboard-model)
175 layout variant))))
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)
786c9c39
MO
201 ((installer-help-menu current-installer)
202 (lambda ()
203 ((installer-help-page current-installer)
204 (lambda _
205 (#$(compute-keymap-step 'help)
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
238 ;; input. It is possible to update kmscon current keymap by sending it
239 ;; a keyboard model, layout and variant, in a somehow similar way as
240 ;; what is done with setxkbmap utility.
241 ;;
242 ;; So ask for a keyboard model, layout and variant to update the
243 ;; current kmscon keymap.
244 (installer-step
245 (id 'keymap)
246 (description (G_ "Keyboard mapping selection"))
247 (compute (lambda _
786c9c39
MO
248 (#$(compute-keymap-step 'default)
249 current-installer)))
3191b5f6 250 (configuration-formatter keyboard-layout->configuration))
a49d633c
MO
251
252 ;; Ask the user to input a hostname for the system.
253 (installer-step
254 (id 'hostname)
dc5f3275 255 (description (G_ "Hostname"))
a49d633c 256 (compute (lambda _
dc5f3275
MO
257 ((installer-hostname-page current-installer))))
258 (configuration-formatter hostname->configuration))
a49d633c
MO
259
260 ;; Provide an interface above connmanctl, so that the user can select
261 ;; a network susceptible to acces Internet.
262 (installer-step
263 (id 'network)
264 (description (G_ "Network selection"))
265 (compute (lambda _
266 ((installer-network-page current-installer)))))
267
268 ;; Prompt for users (name, group and home directory).
269 (installer-step
dc5f3275
MO
270 (id 'user)
271 (description (G_ "User creation"))
272 (compute (lambda _
273 ((installer-user-page current-installer))))
274 (configuration-formatter users->configuration))
275
b51bde71
MO
276 ;; Ask the user to choose one or many desktop environment(s).
277 (installer-step
278 (id 'services)
279 (description (G_ "Services"))
a49d633c 280 (compute (lambda _
b51bde71 281 ((installer-services-page current-installer))))
a274bba2 282 (configuration-formatter system-services->configuration))
dc5f3275 283
d4d27ddb
TGR
284 ;; Run a partitioning tool allowing the user to modify
285 ;; partition tables, partitions and their mount points.
286 ;; Do this last so the user has something to boot if any
287 ;; of the previous steps didn't go as expected.
288 (installer-step
289 (id 'partition)
290 (description (G_ "Partitioning"))
291 (compute (lambda _
292 ((installer-partition-page current-installer))))
293 (configuration-formatter user-partitions->configuration))
294
a274bba2 295 (installer-step
dc5f3275
MO
296 (id 'final)
297 (description (G_ "Configuration file"))
298 (compute
299 (lambda (result prev-steps)
300 ((installer-final-page current-installer)
b51bde71 301 result prev-steps))))))))
a49d633c 302
5ce84b17
LC
303(define guile-newt
304 ;; Guile-Newt with 'form-watch-fd'.
305 ;; TODO: Remove once a new release is out.
786c9c39
MO
306 (let ((commit "c3cdeb0b53ac71aedabee669f57d44563c662446")
307 (revision "2"))
5ce84b17
LC
308 (package
309 (inherit (@ (gnu packages guile-xyz) guile-newt))
310 (name "guile-newt")
311 (version (git-version "0.0.1" revision commit))
312 (source (origin
313 (method git-fetch)
314 (uri (git-reference
315 (url "https://gitlab.com/mothacehe/guile-newt")
316 (commit commit)))
317 (file-name (git-file-name name version))
318 (sha256
319 (base32
786c9c39 320 "1gksd1lzgjjh1p9vczghg8jw995d22hm34kbsiv8rcryirv2xy09")))))))
5ce84b17 321
a49d633c
MO
322(define (installer-program)
323 "Return a file-like object that runs the given INSTALLER."
324 (define init-gettext
325 ;; Initialize gettext support, so that installer messages can be
326 ;; translated.
327 #~(begin
328 (bindtextdomain "guix" (string-append #$guix "/share/locale"))
329 (textdomain "guix")))
330
331 (define set-installer-path
332 ;; Add the specified binary to PATH for later use by the installer.
333 #~(let* ((inputs
69a934f2
MO
334 '#$(append (list bash ;start subshells
335 connman ;call connmanctl
bf304dbc 336 cryptsetup
69a934f2
MO
337 dosfstools ;mkfs.fat
338 e2fsprogs ;mkfs.ext4
8fec416c
TGR
339 btrfs-progs ;mkfs.btrfs
340 jfsutils ;jfs_mkfs
69a934f2
MO
341 kbd ;chvt
342 guix ;guix system init call
343 util-linux ;mkwap
344 shadow)
a49d633c
MO
345 (map canonical-package (list coreutils)))))
346 (with-output-to-port (%make-void-port "w")
347 (lambda ()
348 (set-path-environment-variable "PATH" '("bin" "sbin") inputs)))))
349
350 (define steps (installer-steps))
69a934f2
MO
351 (define modules
352 (scheme-modules*
353 (string-append (current-source-directory) "/..")
354 "gnu/installer"))
a49d633c
MO
355
356 (define installer-builder
50247be5
LC
357 ;; Note: Include GUIX as an extension to get all the (gnu system …), (gnu
358 ;; packages …), etc. modules.
69a934f2
MO
359 (with-extensions (list guile-gcrypt guile-newt
360 guile-parted guile-bytestructures
81c3dc32 361 guile-json-3 guile-git guix)
a49d633c 362 (with-imported-modules `(,@(source-module-closure
69a934f2 363 `(,@modules
98f03548 364 (gnu services herd)
a49d633c 365 (guix build utils))
50247be5 366 #:select? module-to-import?)
a49d633c
MO
367 ((guix config) => ,(make-config.scm)))
368 #~(begin
369 (use-modules (gnu installer record)
370 (gnu installer keymap)
371 (gnu installer steps)
dc5f3275 372 (gnu installer final)
b4658c25 373 (gnu installer hostname)
a49d633c 374 (gnu installer locale)
dc5f3275
MO
375 (gnu installer parted)
376 (gnu installer services)
377 (gnu installer timezone)
378 (gnu installer user)
a49d633c 379 (gnu installer newt)
3191b5f6
LC
380 ((gnu installer newt keymap)
381 #:select (keyboard-layout->configuration))
c7dc6042 382 (gnu services herd)
a49d633c
MO
383 (guix i18n)
384 (guix build utils)
3114786e
MO
385 ((system repl debug)
386 #:select (terminal-width))
a49d633c
MO
387 (ice-9 match))
388
a49d633c
MO
389 ;; Initialize gettext support so that installers can use
390 ;; (guix i18n) module.
391 #$init-gettext
392
393 ;; Add some binaries used by the installers to PATH.
394 #$set-installer-path
395
7837a572
LC
396 ;; Arrange for language and territory name translations to be
397 ;; available. We need them at run time, not just compile time,
398 ;; because some territories have several corresponding languages
399 ;; (e.g., "French" is always displayed as "français", but
400 ;; "Belgium" could be translated to Dutch, French, or German.)
401 (bindtextdomain "iso_639-3" ;languages
402 #+(file-append iso-codes "/share/locale"))
403 (bindtextdomain "iso_3166-1" ;territories
404 #+(file-append iso-codes "/share/locale"))
405
feaa83a3
LC
406 ;; Likewise for XKB keyboard layout names.
407 (bindtextdomain "xkeyboard-config"
408 #+(file-append xkeyboard-config "/share/locale"))
409
3114786e
MO
410 ;; Initialize 'terminal-width' in (system repl debug)
411 ;; to a large-enough value to make backtrace more
412 ;; verbose.
413 (terminal-width 200)
414
dc5f3275
MO
415 (let* ((current-installer newt-installer)
416 (steps (#$steps current-installer)))
a49d633c
MO
417 ((installer-init current-installer))
418
419 (catch #t
420 (lambda ()
98f03548
LC
421 (define results
422 (run-installer-steps
423 #:rewind-strategy 'menu
424 #:menu-proc (installer-menu-page current-installer)
425 #:steps steps))
426
427 (match (result-step results 'final)
428 ('success
429 ;; We did it! Let's reboot!
430 (sync)
431 (stop-service 'root))
d008352b
MO
432 (_
433 ;; The installation failed, exit so that it is restarted
434 ;; by login.
98f03548 435 #f)))
a49d633c
MO
436 (const #f)
437 (lambda (key . args)
5c04b00c
LC
438 (syslog "crashing due to uncaught exception: ~s ~s~%"
439 key args)
133c401f
MO
440 (let ((error-file "/tmp/last-installer-error"))
441 (call-with-output-file error-file
442 (lambda (port)
443 (display-backtrace (make-stack #t) port)
444 (print-exception port
445 (stack-ref (make-stack #t) 1)
446 key args)))
447 ((installer-exit-error current-installer)
448 error-file key args))
dc5f3275
MO
449 (primitive-exit 1)))
450
451 ((installer-exit current-installer)))))))
d0f3a672 452
6b48825e
MO
453 (program-file
454 "installer"
455 #~(begin
456 ;; Set the default locale to install unicode support. For
457 ;; some reason, unicode support is not correctly installed
458 ;; when calling this in 'installer-builder'.
459 (setenv "LANG" "en_US.UTF-8")
6c849cdb
LC
460 (execl #$(program-file "installer-real" installer-builder)
461 "installer-real"))))