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