Merge branch 'master' into staging
[jackhill/guix/guix.git] / guix / self.scm
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
3 ;;;
4 ;;; This file is part of GNU Guix.
5 ;;;
6 ;;; GNU Guix is free software; you can redistribute it and/or modify it
7 ;;; under the terms of the GNU General Public License as published by
8 ;;; the Free Software Foundation; either version 3 of the License, or (at
9 ;;; your option) any later version.
10 ;;;
11 ;;; GNU Guix is distributed in the hope that it will be useful, but
12 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ;;; GNU General Public License for more details.
15 ;;;
16 ;;; You should have received a copy of the GNU General Public License
17 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19 (define-module (guix self)
20 #:use-module (guix config)
21 #:use-module (guix i18n)
22 #:use-module (guix modules)
23 #:use-module (guix gexp)
24 #:use-module (guix store)
25 #:use-module (guix monads)
26 #:use-module (guix discovery)
27 #:use-module (guix packages)
28 #:use-module (guix sets)
29 #:use-module (guix modules)
30 #:use-module ((guix build utils) #:select (find-files))
31 #:use-module ((guix build compile) #:select (%lightweight-optimizations))
32 #:use-module (srfi srfi-1)
33 #:use-module (srfi srfi-9)
34 #:use-module (srfi srfi-35)
35 #:use-module (ice-9 match)
36 #:export (make-config.scm
37 whole-package ;for internal use in 'guix pull'
38 compiled-guix
39 guix-derivation))
40
41 \f
42 ;;;
43 ;;; Dependency handling.
44 ;;;
45
46 (define specification->package
47 ;; Use our own variant of that procedure because that of (gnu packages)
48 ;; would traverse all the .scm files, which is wasteful.
49 (let ((ref (lambda (module variable)
50 (module-ref (resolve-interface module) variable))))
51 (match-lambda
52 ("guile" (ref '(gnu packages commencement) 'guile-final))
53 ("guile-json" (ref '(gnu packages guile) 'guile-json))
54 ("guile-ssh" (ref '(gnu packages ssh) 'guile-ssh))
55 ("guile-git" (ref '(gnu packages guile) 'guile-git))
56 ("guile-sqlite3" (ref '(gnu packages guile) 'guile-sqlite3))
57 ("guile-gcrypt" (ref '(gnu packages gnupg) 'guile-gcrypt))
58 ("gnutls" (ref '(gnu packages tls) 'gnutls))
59 ("zlib" (ref '(gnu packages compression) 'zlib))
60 ("gzip" (ref '(gnu packages compression) 'gzip))
61 ("bzip2" (ref '(gnu packages compression) 'bzip2))
62 ("xz" (ref '(gnu packages compression) 'xz))
63 ("po4a" (ref '(gnu packages gettext) 'po4a))
64 ("gettext" (ref '(gnu packages gettext) 'gettext-minimal))
65 (_ #f)))) ;no such package
66
67 \f
68 ;;;
69 ;;; Derivations.
70 ;;;
71
72 ;; Node in a DAG of build tasks. Each node maps to a derivation, but it's
73 ;; easier to express things this way.
74 (define-record-type <node>
75 (node name modules source dependencies compiled)
76 node?
77 (name node-name) ;string
78 (modules node-modules) ;list of module names
79 (source node-source) ;list of source files
80 (dependencies node-dependencies) ;list of nodes
81 (compiled node-compiled)) ;node -> lowerable object
82
83 ;; File mappings are essentially an alist as passed to 'imported-files'.
84 (define-record-type <file-mapping>
85 (file-mapping name alist)
86 file-mapping?
87 (name file-mapping-name)
88 (alist file-mapping-alist))
89
90 (define-gexp-compiler (file-mapping-compiler (mapping <file-mapping>)
91 system target)
92 ;; Here we use 'imported-files', which can arrange to directly import all
93 ;; the files instead of creating a derivation, when possible.
94 (imported-files (map (match-lambda
95 ((destination (? local-file? file))
96 (cons destination
97 (local-file-absolute-file-name file)))
98 ((destination source)
99 (cons destination source))) ;silliness
100 (file-mapping-alist mapping))
101 #:name (file-mapping-name mapping)
102 #:system system))
103
104 (define (node-source+compiled node)
105 "Return a \"bundle\" containing both the source code and object files for
106 NODE's modules, under their FHS directories: share/guile/site and lib/guile."
107 (define build
108 (with-imported-modules '((guix build utils))
109 #~(begin
110 (use-modules (guix build utils))
111
112 (define source
113 (string-append #$output "/share/guile/site/"
114 (effective-version)))
115
116 (define object
117 (string-append #$output "/lib/guile/" (effective-version)
118 "/site-ccache"))
119
120 (mkdir-p (dirname source))
121 (symlink #$(node-source node) source)
122 (mkdir-p (dirname object))
123 (symlink #$(node-compiled node) object))))
124
125 (computed-file (string-append (node-name node) "-modules")
126 build))
127
128 (define (node-fold proc init nodes)
129 (let loop ((nodes nodes)
130 (visited (setq))
131 (result init))
132 (match nodes
133 (() result)
134 ((head tail ...)
135 (if (set-contains? visited head)
136 (loop tail visited result)
137 (loop tail (set-insert head visited)
138 (proc head result)))))))
139
140 (define (node-modules/recursive nodes)
141 (node-fold (lambda (node modules)
142 (append (node-modules node) modules))
143 '()
144 nodes))
145
146 (define* (closure modules #:optional (except '()))
147 (source-module-closure modules
148 #:select?
149 (match-lambda
150 (('guix 'config)
151 #f)
152 ((and module
153 (or ('guix _ ...) ('gnu _ ...)))
154 (not (member module except)))
155 (rest #f))))
156
157 (define module->import
158 ;; Return a file-name/file-like object pair for the specified module and
159 ;; suitable for 'imported-files'.
160 (match-lambda
161 ((module '=> thing)
162 (let ((file (module-name->file-name module)))
163 (list file thing)))
164 (module
165 (let ((file (module-name->file-name module)))
166 (list file
167 (local-file (search-path %load-path file)))))))
168
169 (define* (scheme-node name modules #:optional (dependencies '())
170 #:key (extra-modules '()) (extra-files '())
171 (extensions '())
172 parallel? guile-for-build)
173 "Return a node that builds the given Scheme MODULES, and depends on
174 DEPENDENCIES (a list of nodes). EXTRA-MODULES is a list of additional modules
175 added to the source, and EXTRA-FILES is a list of additional files.
176 EXTENSIONS is a set of full-blown Guile packages (e.g., 'guile-json') that
177 must be present in the search path."
178 (let* ((modules (append extra-modules
179 (closure modules
180 (node-modules/recursive dependencies))))
181 (module-files (map module->import modules))
182 (source (file-mapping (string-append name "-source")
183 (append module-files extra-files))))
184 (node name modules source dependencies
185 (compiled-modules name source
186 (map car module-files)
187 (map node-source dependencies)
188 (map node-compiled dependencies)
189 #:extensions extensions
190 #:parallel? parallel?
191 #:guile-for-build guile-for-build))))
192
193 (define (file-imports directory sub-directory pred)
194 "List all the files matching PRED under DIRECTORY/SUB-DIRECTORY. Return a
195 list of file-name/file-like objects suitable as inputs to 'imported-files'."
196 (map (lambda (file)
197 (list (string-drop file (+ 1 (string-length directory)))
198 (local-file file #:recursive? #t)))
199 (find-files (string-append directory "/" sub-directory) pred)))
200
201 (define* (file-append* item file #:key (recursive? #t))
202 "Return FILE within ITEM, which may be a file name or a file-like object.
203 When ITEM is a plain file name (a string), simply return a 'local-file'
204 record with the new file name."
205 (match item
206 ((? string?)
207 ;; This is the optimal case: we return a new "source". Thus, a
208 ;; derivation that depends on this sub-directory does not depend on ITEM
209 ;; itself.
210 (local-file (string-append item "/" file)
211 #:recursive? recursive?))
212 ;; TODO: Add 'local-file?' case.
213 (_
214 ;; In this case, anything that refers to the result also depends on ITEM,
215 ;; which isn't great.
216 (file-append item "/" file))))
217
218 (define* (locale-data source domain
219 #:optional (directory domain))
220 "Return the locale data from 'po/DIRECTORY' in SOURCE, corresponding to
221 DOMAIN, a gettext domain."
222 (define gettext
223 (module-ref (resolve-interface '(gnu packages gettext))
224 'gettext-minimal))
225
226 (define build
227 (with-imported-modules '((guix build utils))
228 #~(begin
229 (use-modules (guix build utils)
230 (srfi srfi-26)
231 (ice-9 match) (ice-9 ftw))
232
233 (define po-directory
234 #+(file-append* source (string-append "po/" directory)))
235
236 (define (compile language)
237 (let ((gmo (string-append #$output "/" language "/LC_MESSAGES/"
238 #$domain ".mo")))
239 (mkdir-p (dirname gmo))
240 (invoke #+(file-append gettext "/bin/msgfmt")
241 "-c" "--statistics" "--verbose"
242 "-o" gmo
243 (string-append po-directory "/" language ".po"))))
244
245 (define (linguas)
246 ;; Return the list of languages. Note: don't read 'LINGUAS'
247 ;; because it contains things like 'en@boldquot' that do not have
248 ;; a corresponding .po file.
249 (map (cut basename <> ".po")
250 (scandir po-directory
251 (cut string-suffix? ".po" <>))))
252
253 (for-each compile (linguas)))))
254
255 (computed-file (string-append "guix-locale-" domain)
256 build))
257
258 (define (translate-texi-manuals source)
259 "Return the translated texinfo manuals built from SOURCE."
260 (define po4a
261 (specification->package "po4a"))
262
263 (define gettext
264 (specification->package "gettext"))
265
266 (define glibc-utf8-locales
267 (module-ref (resolve-interface '(gnu packages base))
268 'glibc-utf8-locales))
269
270 (define documentation
271 (file-append* source "doc"))
272
273 (define documentation-po
274 (file-append* source "po/doc"))
275
276 (define build
277 (with-imported-modules '((guix build utils) (guix build po))
278 #~(begin
279 (use-modules (guix build utils) (guix build po)
280 (ice-9 match) (ice-9 regex) (ice-9 textual-ports)
281 (srfi srfi-1))
282
283 (mkdir #$output)
284
285 (copy-recursively #$documentation "."
286 #:log (%make-void-port "w"))
287
288 (for-each
289 (lambda (file)
290 (copy-file file (basename file)))
291 (find-files #$documentation-po ".*.po$"))
292
293 (setenv "GUIX_LOCPATH"
294 #+(file-append glibc-utf8-locales "/lib/locale"))
295 (setenv "PATH" #+(file-append gettext "/bin"))
296 (setenv "LC_ALL" "en_US.UTF-8")
297 (setlocale LC_ALL "en_US.UTF-8")
298
299 (define (translate-tmp-texi po source output)
300 "Translate Texinfo file SOURCE using messages from PO, and write
301 the result to OUTPUT."
302 (invoke #+(file-append po4a "/bin/po4a-translate")
303 "-M" "UTF-8" "-L" "UTF-8" "-k" "0" "-f" "texinfo"
304 "-m" source "-p" po "-l" output))
305
306 (define (make-ref-regex msgid end)
307 (make-regexp (string-append
308 "ref\\{"
309 (string-join (string-split (regexp-quote msgid) #\ )
310 "[ \n]+")
311 end)))
312
313 (define (translate-cross-references content translations)
314 "Take CONTENT, a string representing a .texi file and translate any
315 cross-reference in it (@ref, @xref and @pxref) that have a translation in
316 TRANSLATIONS, an alist of msgid and msgstr."
317 (fold
318 (lambda (elem content)
319 (match elem
320 ((msgid . msgstr)
321 ;; Empty translations and strings containing some special characters
322 ;; cannot be the name of a section.
323 (if (or (equal? msgstr "")
324 (string-any (lambda (chr)
325 (member chr '(#\{ #\} #\( #\) #\newline #\,)))
326 msgid))
327 content
328 ;; Otherwise, they might be the name of a section, so we
329 ;; need to translate any occurence in @(p?x?)ref{...}.
330 (let ((regexp1 (make-ref-regex msgid ","))
331 (regexp2 (make-ref-regex msgid "\\}")))
332 (regexp-substitute/global
333 #f regexp2
334 (regexp-substitute/global
335 #f regexp1 content 'pre "ref{" msgstr "," 'post)
336 'pre "ref{" msgstr "}" 'post))))))
337 content translations))
338
339 (define (translate-texi po lang)
340 "Translate the manual for one language LANG using the PO file."
341 (let ((translations (call-with-input-file po read-po-file)))
342 (translate-tmp-texi po "guix.texi"
343 (string-append "guix." lang ".texi.tmp"))
344 (translate-tmp-texi po "contributing.texi"
345 (string-append "contributing." lang ".texi.tmp"))
346 (let* ((texi-name (string-append "guix." lang ".texi"))
347 (tmp-name (string-append texi-name ".tmp")))
348 (with-output-to-file texi-name
349 (lambda _
350 (format #t "~a"
351 (translate-cross-references
352 (call-with-input-file tmp-name get-string-all)
353 translations)))))
354 (let* ((texi-name (string-append "contributing." lang ".texi"))
355 (tmp-name (string-append texi-name ".tmp")))
356 (with-output-to-file texi-name
357 (lambda _
358 (format #t "~a"
359 (translate-cross-references
360 (call-with-input-file tmp-name get-string-all)
361 translations)))))))
362
363 (for-each (lambda (po)
364 (match (reverse (string-split po #\.))
365 ((_ lang _ ...)
366 (translate-texi po lang))))
367 (find-files "." "^guix-manual\\.[a-z]{2}(_[A-Z]{2})?\\.po$"))
368
369 (for-each
370 (lambda (file)
371 (copy-file file (string-append #$output "/" file)))
372 (append
373 (find-files "." "contributing\\..*\\.texi$")
374 (find-files "." "guix\\..*\\.texi$"))))))
375
376 (computed-file "guix-translated-texinfo" build))
377
378 (define (info-manual source)
379 "Return the Info manual built from SOURCE."
380 (define texinfo
381 (module-ref (resolve-interface '(gnu packages texinfo))
382 'texinfo))
383
384 (define graphviz
385 (module-ref (resolve-interface '(gnu packages graphviz))
386 'graphviz))
387
388 (define glibc-utf8-locales
389 (module-ref (resolve-interface '(gnu packages base))
390 'glibc-utf8-locales))
391
392 (define documentation
393 (file-append* source "doc"))
394
395 (define examples
396 (file-append* source "gnu/system/examples"))
397
398 (define build
399 (with-imported-modules '((guix build utils))
400 #~(begin
401 (use-modules (guix build utils))
402
403 (mkdir #$output)
404
405 ;; Create 'version.texi'.
406 ;; XXX: Can we use a more meaningful version string yet one that
407 ;; doesn't change at each commit?
408 (call-with-output-file "version.texi"
409 (lambda (port)
410 (let ((version "0.0-git"))
411 (format port "
412 @set UPDATED 1 January 1970
413 @set UPDATED-MONTH January 1970
414 @set EDITION ~a
415 @set VERSION ~a\n" version version))))
416
417 ;; Copy configuration templates that the manual includes.
418 (for-each (lambda (template)
419 (copy-file template
420 (string-append
421 "os-config-"
422 (basename template ".tmpl")
423 ".texi")))
424 (find-files #$examples "\\.tmpl$"))
425
426 ;; Build graphs.
427 (mkdir-p (string-append #$output "/images"))
428 (for-each (lambda (dot-file)
429 (invoke #+(file-append graphviz "/bin/dot")
430 "-Tpng" "-Gratio=.9" "-Gnodesep=.005"
431 "-Granksep=.00005" "-Nfontsize=9"
432 "-Nheight=.1" "-Nwidth=.1"
433 "-o" (string-append #$output "/images/"
434 (basename dot-file ".dot")
435 ".png")
436 dot-file))
437 (find-files (string-append #$documentation "/images")
438 "\\.dot$"))
439
440 ;; Copy other PNGs.
441 (for-each (lambda (png-file)
442 (install-file png-file
443 (string-append #$output "/images")))
444 (find-files (string-append #$documentation "/images")
445 "\\.png$"))
446
447 ;; Finally build the manual. Copy it the Texinfo files to $PWD and
448 ;; add a symlink to the 'images' directory so that 'makeinfo' can
449 ;; see those images and produce image references in the Info output.
450 (copy-recursively #$documentation "."
451 #:log (%make-void-port "w"))
452 (copy-recursively #+(translate-texi-manuals source) "."
453 #:log (%make-void-port "w"))
454 (delete-file-recursively "images")
455 (symlink (string-append #$output "/images") "images")
456
457 ;; Provide UTF-8 locales needed by the 'xspara.c' code in makeinfo.
458 (setenv "GUIX_LOCPATH"
459 #+(file-append glibc-utf8-locales "/lib/locale"))
460
461 (for-each (lambda (texi)
462 (unless (string=? "guix.texi" texi)
463 ;; Create 'version-LL.texi'.
464 (let* ((base (basename texi ".texi"))
465 (dot (string-index base #\.))
466 (tag (string-drop base (+ 1 dot))))
467 (symlink "version.texi"
468 (string-append "version-" tag ".texi"))))
469
470 (invoke #+(file-append texinfo "/bin/makeinfo")
471 texi "-I" #$documentation
472 "-I" "."
473 "-o" (string-append #$output "/"
474 (basename texi ".texi")
475 ".info")))
476 (cons "guix.texi"
477 (find-files "." "^guix\\.[a-z]{2}(_[A-Z]{2})?\\.texi$")))
478
479 ;; Compress Info files.
480 (setenv "PATH"
481 #+(file-append (specification->package "gzip") "/bin"))
482 (for-each (lambda (file)
483 (invoke "gzip" "-9n" file))
484 (find-files #$output "\\.info(-[0-9]+)?$")))))
485
486 (computed-file "guix-manual" build))
487
488 (define* (guile-module-union things #:key (name "guix-module-union"))
489 "Return the union of the subset of THINGS (packages, computed files, etc.)
490 that provide Guile modules."
491 (define build
492 (with-imported-modules '((guix build union))
493 #~(begin
494 (use-modules (guix build union))
495
496 (define (modules directory)
497 (string-append directory "/share/guile/site"))
498
499 (define (objects directory)
500 (string-append directory "/lib/guile"))
501
502 (union-build #$output
503 (filter (lambda (directory)
504 (or (file-exists? (modules directory))
505 (file-exists? (objects directory))))
506 '#$things)
507
508 #:log-port (%make-void-port "w")))))
509
510 (computed-file name build))
511
512 (define* (guix-command modules
513 #:key source (dependencies '())
514 guile (guile-version (effective-version)))
515 "Return the 'guix' command such that it adds MODULES and DEPENDENCIES in its
516 load path."
517 (define glibc-utf8-locales
518 (module-ref (resolve-interface '(gnu packages base))
519 'glibc-utf8-locales))
520
521 (define module-directory
522 ;; To minimize the number of 'stat' calls needed to locate a module,
523 ;; create the union of all the module directories.
524 (guile-module-union (cons modules dependencies)))
525
526 (program-file "guix-command"
527 #~(begin
528 (set! %load-path
529 (cons (string-append #$module-directory
530 "/share/guile/site/"
531 (effective-version))
532 %load-path))
533
534 (set! %load-compiled-path
535 (cons (string-append #$module-directory
536 "/lib/guile/"
537 (effective-version)
538 "/site-ccache")
539 %load-compiled-path))
540
541 ;; To maximize the chances that locales are set up right
542 ;; out-of-the-box, bundle "common" UTF-8 locales.
543 (let ((locpath (getenv "GUIX_LOCPATH")))
544 (setenv "GUIX_LOCPATH"
545 (string-append (if locpath
546 (string-append locpath ":")
547 "")
548 #$(file-append glibc-utf8-locales
549 "/lib/locale"))))
550
551 (let ((guix-main (module-ref (resolve-interface '(guix ui))
552 'guix-main)))
553 #$(if source
554 #~(begin
555 (bindtextdomain "guix"
556 #$(locale-data source "guix"))
557 (bindtextdomain "guix-packages"
558 #$(locale-data source
559 "guix-packages"
560 "packages")))
561 #t)
562
563 ;; XXX: It would be more convenient to change it to:
564 ;; (exit (apply guix-main (command-line)))
565 (apply guix-main (command-line))))
566 #:guile guile))
567
568 (define (miscellaneous-files source)
569 "Return data files taken from SOURCE."
570 (file-mapping "guix-misc"
571 `(("etc/bash_completion.d/guix"
572 ,(file-append* source "/etc/completion/bash/guix"))
573 ("etc/bash_completion.d/guix-daemon"
574 ,(file-append* source "/etc/completion/bash/guix-daemon"))
575 ("share/zsh/site-functions/_guix"
576 ,(file-append* source "/etc/completion/zsh/_guix"))
577 ("share/fish/vendor_completions.d/guix.fish"
578 ,(file-append* source "/etc/completion/fish/guix.fish"))
579 ("share/guix/hydra.gnu.org.pub"
580 ,(file-append* source
581 "/etc/substitutes/hydra.gnu.org.pub"))
582 ("share/guix/berlin.guixsd.org.pub"
583 ,(file-append* source
584 "/etc/substitutes/berlin.guixsd.org.pub"))
585 ("share/guix/ci.guix.gnu.org.pub" ;alias
586 ,(file-append* source "/etc/substitutes/berlin.guixsd.org.pub"))
587 ("share/guix/ci.guix.info.pub" ;alias
588 ,(file-append* source "/etc/substitutes/berlin.guixsd.org.pub")))))
589
590 (define* (whole-package name modules dependencies
591 #:key
592 (guile-version (effective-version))
593 info daemon miscellany
594 guile
595 (command (guix-command modules
596 #:dependencies dependencies
597 #:guile guile
598 #:guile-version guile-version)))
599 "Return the whole Guix package NAME that uses MODULES, a derivation of all
600 the modules (under share/guile/site and lib/guile), and DEPENDENCIES, a list
601 of packages depended on. COMMAND is the 'guix' program to use; INFO is the
602 Info manual."
603 (define (wrap daemon)
604 (program-file "guix-daemon"
605 #~(begin
606 (setenv "GUIX" #$command)
607 (apply execl #$(file-append daemon "/bin/guix-daemon")
608 "guix-daemon" (cdr (command-line))))))
609
610 (computed-file name
611 (with-imported-modules '((guix build utils))
612 #~(begin
613 (use-modules (guix build utils))
614
615 (define daemon
616 #$(and daemon (wrap daemon)))
617
618 (mkdir-p (string-append #$output "/bin"))
619 (symlink #$command
620 (string-append #$output "/bin/guix"))
621
622 (when daemon
623 (symlink daemon
624 (string-append #$output "/bin/guix-daemon")))
625
626 (let ((share (string-append #$output "/share"))
627 (lib (string-append #$output "/lib"))
628 (info #$info))
629 (mkdir-p share)
630 (symlink #$(file-append modules "/share/guile")
631 (string-append share "/guile"))
632 (when info
633 (symlink #$info (string-append share "/info")))
634
635 (mkdir-p lib)
636 (symlink #$(file-append modules "/lib/guile")
637 (string-append lib "/guile")))
638
639 (when #$miscellany
640 (copy-recursively #$miscellany #$output
641 #:log (%make-void-port "w")))))))
642
643 (define* (compiled-guix source #:key (version %guix-version)
644 (pull-version 1)
645 (name (string-append "guix-" version))
646 (guile-version (effective-version))
647 (guile-for-build (default-guile))
648 (zlib (specification->package "zlib"))
649 (gzip (specification->package "gzip"))
650 (bzip2 (specification->package "bzip2"))
651 (xz (specification->package "xz"))
652 (guix (specification->package "guix")))
653 "Return a file-like object that contains a compiled Guix."
654 (define guile-json
655 (specification->package "guile-json"))
656
657 (define guile-ssh
658 (specification->package "guile-ssh"))
659
660 (define guile-git
661 (specification->package "guile-git"))
662
663 (define guile-sqlite3
664 (specification->package "guile-sqlite3"))
665
666 (define guile-gcrypt
667 (specification->package "guile-gcrypt"))
668
669 (define gnutls
670 (specification->package "gnutls"))
671
672 (define dependencies
673 (match (append-map (lambda (package)
674 (cons (list "x" package)
675 (package-transitive-propagated-inputs package)))
676 (list guile-gcrypt gnutls guile-git guile-json
677 guile-ssh guile-sqlite3))
678 (((labels packages _ ...) ...)
679 packages)))
680
681 (define *core-modules*
682 (scheme-node "guix-core"
683 '((guix)
684 (guix monad-repl)
685 (guix packages)
686 (guix download)
687 (guix discovery)
688 (guix profiles)
689 (guix build-system gnu)
690 (guix build-system trivial)
691 (guix build profiles)
692 (guix build gnu-build-system))
693
694 ;; Provide a dummy (guix config) with the default version
695 ;; number, storedir, etc. This is so that "guix-core" is the
696 ;; same across all installations and doesn't need to be
697 ;; rebuilt when the version changes, which in turn means we
698 ;; can have substitutes for it.
699 #:extra-modules
700 `(((guix config) => ,(make-config.scm)))
701
702 ;; (guix man-db) is needed at build-time by (guix profiles)
703 ;; but we don't need to compile it; not compiling it allows
704 ;; us to avoid an extra dependency on guile-gdbm-ffi.
705 #:extra-files
706 `(("guix/man-db.scm" ,(local-file "../guix/man-db.scm"))
707 ("guix/build/po.scm" ,(local-file "../guix/build/po.scm"))
708 ("guix/store/schema.sql"
709 ,(local-file "../guix/store/schema.sql")))
710
711 #:extensions (list guile-gcrypt)
712 #:guile-for-build guile-for-build))
713
714 (define *extra-modules*
715 (scheme-node "guix-extra"
716 (filter-map (match-lambda
717 (('guix 'scripts _ ..1) #f)
718 (('guix 'man-db) #f)
719 (name name))
720 (scheme-modules* source "guix"))
721 (list *core-modules*)
722 #:extensions dependencies
723 #:guile-for-build guile-for-build))
724
725 (define *core-package-modules*
726 (scheme-node "guix-packages-base"
727 `((gnu packages)
728 (gnu packages base))
729 (list *core-modules* *extra-modules*)
730 #:extensions dependencies
731
732 ;; Add all the non-Scheme files here. We must do it here so
733 ;; that 'search-patches' & co. can find them. Ideally we'd
734 ;; keep them next to the .scm files that use them but it's
735 ;; difficult to do (XXX).
736 #:extra-files
737 (file-imports source "gnu/packages"
738 (lambda (file stat)
739 (and (eq? 'regular (stat:type stat))
740 (not (string-suffix? ".scm" file))
741 (not (string-suffix? ".go" file))
742 (not (string-prefix? ".#" file))
743 (not (string-suffix? "~" file)))))
744 #:guile-for-build guile-for-build))
745
746 (define *package-modules*
747 (scheme-node "guix-packages"
748 (scheme-modules* source "gnu/packages")
749 (list *core-modules* *extra-modules* *core-package-modules*)
750 #:extensions dependencies
751 #:guile-for-build guile-for-build))
752
753 (define *system-modules*
754 (scheme-node "guix-system"
755 `((gnu system)
756 (gnu services)
757 ,@(scheme-modules* source "gnu/bootloader")
758 ,@(scheme-modules* source "gnu/system")
759 ,@(scheme-modules* source "gnu/services"))
760 (list *core-package-modules* *package-modules*
761 *extra-modules* *core-modules*)
762 #:extensions dependencies
763 #:extra-files
764 (append (file-imports source "gnu/system/examples"
765 (const #t))
766
767 ;; All the installer code is on the build-side.
768 (file-imports source "gnu/installer/"
769 (const #t))
770 ;; Build-side code that we don't build. Some of
771 ;; these depend on guile-rsvg, the Shepherd, etc.
772 (file-imports source "gnu/build" (const #t)))
773 #:guile-for-build
774 guile-for-build))
775
776 (define *cli-modules*
777 (scheme-node "guix-cli"
778 (append (scheme-modules* source "/guix/scripts")
779 `((gnu ci)))
780 (list *core-modules* *extra-modules*
781 *core-package-modules* *package-modules*
782 *system-modules*)
783 #:extensions dependencies
784 #:guile-for-build guile-for-build))
785
786 (define *system-test-modules*
787 ;; Ship these modules mostly so (gnu ci) can discover them.
788 (scheme-node "guix-system-tests"
789 `((gnu tests)
790 ,@(scheme-modules* source "gnu/tests"))
791 (list *core-package-modules* *package-modules*
792 *extra-modules* *system-modules* *core-modules*
793 *cli-modules*) ;for (guix scripts pack), etc.
794 #:extensions dependencies
795 #:guile-for-build guile-for-build))
796
797 (define *config*
798 (scheme-node "guix-config"
799 '()
800 #:extra-modules
801 `(((guix config)
802 => ,(make-config.scm #:zlib zlib
803 #:gzip gzip
804 #:bzip2 bzip2
805 #:xz xz
806 #:package-name
807 %guix-package-name
808 #:package-version
809 version
810 #:bug-report-address
811 %guix-bug-report-address
812 #:home-page-url
813 %guix-home-page-url)))
814 #:guile-for-build guile-for-build))
815
816 (define (built-modules node-subset)
817 (directory-union (string-append name "-modules")
818 (append-map node-subset
819
820 ;; Note: *CONFIG* comes first so that it
821 ;; overrides the (guix config) module that
822 ;; comes with *CORE-MODULES*.
823 (list *config*
824 *cli-modules*
825 *system-test-modules*
826 *system-modules*
827 *package-modules*
828 *core-package-modules*
829 *extra-modules*
830 *core-modules*))
831
832 ;; Silently choose the first entry upon collision so that
833 ;; we choose *CONFIG*.
834 #:resolve-collision 'first
835
836 ;; When we do (add-to-store "utils.scm"), "utils.scm" must
837 ;; be a regular file, not a symlink. Thus, arrange so that
838 ;; regular files appear as regular files in the final
839 ;; output.
840 #:copy? #t
841 #:quiet? #t))
842
843 ;; Version 0 of 'guix pull' meant we'd just return Scheme modules.
844 ;; Version 1 is when we return the full package.
845 (cond ((= 1 pull-version)
846 ;; The whole package, with a standard file hierarchy.
847 (let* ((modules (built-modules (compose list node-source+compiled)))
848 (command (guix-command modules
849 #:source source
850 #:dependencies dependencies
851 #:guile guile-for-build
852 #:guile-version guile-version)))
853 (whole-package name modules dependencies
854 #:command command
855 #:guile guile-for-build
856
857 ;; Include 'guix-daemon'. XXX: Here we inject an
858 ;; older snapshot of guix-daemon, but that's a good
859 ;; enough approximation for now.
860 #:daemon (module-ref (resolve-interface
861 '(gnu packages
862 package-management))
863 'guix-daemon)
864
865 #:info (info-manual source)
866 #:miscellany (miscellaneous-files source)
867 #:guile-version guile-version)))
868 ((= 0 pull-version)
869 ;; Legacy 'guix pull': return the .scm and .go files as one
870 ;; directory.
871 (built-modules (lambda (node)
872 (list (node-source node)
873 (node-compiled node)))))
874 (else
875 ;; Unsupported 'guix pull' version.
876 #f)))
877
878 \f
879 ;;;
880 ;;; Generating (guix config).
881 ;;;
882
883 (define %persona-variables
884 ;; (guix config) variables that define Guix's persona.
885 '(%guix-package-name
886 %guix-version
887 %guix-bug-report-address
888 %guix-home-page-url))
889
890 (define %config-variables
891 ;; (guix config) variables corresponding to Guix configuration.
892 (letrec-syntax ((variables (syntax-rules ()
893 ((_)
894 '())
895 ((_ variable rest ...)
896 (cons `(variable . ,variable)
897 (variables rest ...))))))
898 (variables %localstatedir %storedir %sysconfdir)))
899
900 (define* (make-config.scm #:key zlib gzip xz bzip2
901 (package-name "GNU Guix")
902 (package-version "0")
903 (bug-report-address "bug-guix@gnu.org")
904 (home-page-url "https://gnu.org/s/guix"))
905
906 ;; Hack so that Geiser is not confused.
907 (define defmod 'define-module)
908
909 (scheme-file "config.scm"
910 #~(;; The following expressions get spliced.
911 (#$defmod (guix config)
912 #:export (%guix-package-name
913 %guix-version
914 %guix-bug-report-address
915 %guix-home-page-url
916 %system
917 %store-directory
918 %state-directory
919 %store-database-directory
920 %config-directory
921 %libz
922 ;; TODO: %liblz
923 %gzip
924 %bzip2
925 %xz))
926
927 (define %system
928 #$(%current-system))
929
930 #$@(map (match-lambda
931 ((name . value)
932 #~(define-public #$name #$value)))
933 %config-variables)
934
935 (define %store-directory
936 (or (and=> (getenv "NIX_STORE_DIR") canonicalize-path)
937 %storedir))
938
939 (define %state-directory
940 ;; This must match `NIX_STATE_DIR' as defined in
941 ;; `nix/local.mk'.
942 (or (getenv "GUIX_STATE_DIRECTORY")
943 (string-append %localstatedir "/guix")))
944
945 (define %store-database-directory
946 (or (getenv "GUIX_DATABASE_DIRECTORY")
947 (string-append %state-directory "/db")))
948
949 (define %config-directory
950 ;; This must match `GUIX_CONFIGURATION_DIRECTORY' as
951 ;; defined in `nix/local.mk'.
952 (or (getenv "GUIX_CONFIGURATION_DIRECTORY")
953 (string-append %sysconfdir "/guix")))
954
955 (define %guix-package-name #$package-name)
956 (define %guix-version #$package-version)
957 (define %guix-bug-report-address #$bug-report-address)
958 (define %guix-home-page-url #$home-page-url)
959
960 (define %gzip
961 #+(and gzip (file-append gzip "/bin/gzip")))
962 (define %bzip2
963 #+(and bzip2 (file-append bzip2 "/bin/bzip2")))
964 (define %xz
965 #+(and xz (file-append xz "/bin/xz")))
966
967 (define %libz
968 #+(and zlib
969 (file-append zlib "/lib/libz"))))
970
971 ;; Guile 2.0 *requires* the 'define-module' to be at the
972 ;; top-level or the 'toplevel-ref' in the resulting .go file are
973 ;; made relative to a nonexistent anonymous module.
974 #:splice? #t))
975
976 \f
977 ;;;
978 ;;; Building.
979 ;;;
980
981 (define* (compiled-modules name module-tree module-files
982 #:optional
983 (dependencies '())
984 (dependencies-compiled '())
985 #:key
986 (extensions '()) ;full-blown Guile packages
987 parallel?
988 guile-for-build)
989 "Build all the MODULE-FILES from MODULE-TREE. MODULE-FILES must be a list
990 like '(\"guix/foo.scm\" \"gnu/bar.scm\") and MODULE-TREE is the directory
991 containing MODULE-FILES and possibly other files as well."
992 ;; This is a non-monadic, enhanced version of 'compiled-file' from (guix
993 ;; gexp).
994 (define build
995 (with-imported-modules (source-module-closure
996 '((guix build compile)
997 (guix build utils)))
998 #~(begin
999 (use-modules (srfi srfi-26)
1000 (ice-9 match)
1001 (ice-9 format)
1002 (ice-9 threads)
1003 (guix build compile)
1004 (guix build utils))
1005
1006 (define (regular? file)
1007 (not (member file '("." ".."))))
1008
1009 (define (report-load file total completed)
1010 (display #\cr)
1011 (format #t
1012 "[~3@a/~3@a] loading...\t~5,1f% of ~d files"
1013
1014 ;; Note: Multiply TOTAL by two to account for the
1015 ;; compilation phase that follows.
1016 completed (* total 2)
1017
1018 (* 100. (/ completed total)) total)
1019 (force-output))
1020
1021 (define (report-compilation file total completed)
1022 (display #\cr)
1023 (format #t "[~3@a/~3@a] compiling...\t~5,1f% of ~d files"
1024
1025 ;; Add TOTAL to account for the load phase that came
1026 ;; before.
1027 (+ total completed) (* total 2)
1028
1029 (* 100. (/ completed total)) total)
1030 (force-output))
1031
1032 (define (process-directory directory files output)
1033 ;; Hide compilation warnings.
1034 (parameterize ((current-warning-port (%make-void-port "w")))
1035 (compile-files directory #$output files
1036 #:workers (parallel-job-count)
1037 #:report-load report-load
1038 #:report-compilation report-compilation)))
1039
1040 (setvbuf (current-output-port) 'line)
1041 (setvbuf (current-error-port) 'line)
1042
1043 (set! %load-path (cons #+module-tree %load-path))
1044 (set! %load-path
1045 (append '#+dependencies
1046 (map (lambda (extension)
1047 (string-append extension "/share/guile/site/"
1048 (effective-version)))
1049 '#+extensions)
1050 %load-path))
1051
1052 (set! %load-compiled-path
1053 (append '#+dependencies-compiled
1054 (map (lambda (extension)
1055 (string-append extension "/lib/guile/"
1056 (effective-version)
1057 "/site-ccache"))
1058 '#+extensions)
1059 %load-compiled-path))
1060
1061 ;; Load the compiler modules upfront.
1062 (compile #f)
1063
1064 (mkdir #$output)
1065 (chdir #+module-tree)
1066 (process-directory "." '#+module-files #$output)
1067 (newline))))
1068
1069 (computed-file name build
1070 #:guile guile-for-build
1071 #:options
1072 `(#:local-build? #f ;allow substitutes
1073
1074 ;; Don't annoy people about _IONBF deprecation.
1075 ;; Initialize 'terminal-width' in (system repl debug)
1076 ;; to a large-enough value to make backtrace more
1077 ;; verbose.
1078 #:env-vars (("GUILE_WARN_DEPRECATED" . "no")
1079 ("COLUMNS" . "200")))))
1080
1081 \f
1082 ;;;
1083 ;;; Building.
1084 ;;;
1085
1086 (define* (guix-derivation source version
1087 #:optional (guile-version (effective-version))
1088 #:key (pull-version 0))
1089 "Return, as a monadic value, the derivation to build the Guix from SOURCE
1090 for GUILE-VERSION. Use VERSION as the version string. PULL-VERSION specifies
1091 the version of the 'guix pull' protocol. Return #f if this PULL-VERSION value
1092 is not supported."
1093 (define (shorten version)
1094 (if (and (string-every char-set:hex-digit version)
1095 (> (string-length version) 9))
1096 (string-take version 9) ;Git commit
1097 version))
1098
1099 (define guile
1100 ;; When PULL-VERSION >= 1, produce a self-contained Guix and use Guile 2.2
1101 ;; unconditionally.
1102 (default-guile))
1103
1104 (when (and (< pull-version 1)
1105 (not (string=? (package-version guile) guile-version)))
1106 ;; Guix < 0.15.0 has PULL-VERSION = 0, where the host Guile is reused and
1107 ;; can be any version. When that happens and Guile is not current (e.g.,
1108 ;; it's Guile 2.0), just bail out.
1109 (raise (condition
1110 (&message
1111 (message "Guix is too old and cannot be upgraded")))))
1112
1113 (mbegin %store-monad
1114 (set-guile-for-build guile)
1115 (let ((guix (compiled-guix source
1116 #:version version
1117 #:name (string-append "guix-"
1118 (shorten version))
1119 #:pull-version pull-version
1120 #:guile-version (if (>= pull-version 1)
1121 "2.2" guile-version)
1122 #:guile-for-build guile)))
1123 (if guix
1124 (lower-object guix)
1125 (return #f)))))