gnu: guix: Update snapshot.
[jackhill/guix/guix.git] / guix / gexp.scm
CommitLineData
21b679f6 1;;; GNU Guix --- Functional package management for GNU
4a6e889f 2;;; Copyright © 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
21b679f6
LC
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 gexp)
e87f0591 20 #:use-module (guix store)
21b679f6 21 #:use-module (guix monads)
e87f0591 22 #:use-module (guix derivations)
7adf9b84 23 #:use-module (guix grafts)
aa72d9af 24 #:use-module (guix utils)
21b679f6
LC
25 #:use-module (srfi srfi-1)
26 #:use-module (srfi srfi-9)
7560b00b 27 #:use-module (srfi srfi-9 gnu)
21b679f6 28 #:use-module (srfi srfi-26)
3e43166f
LC
29 #:use-module (srfi srfi-34)
30 #:use-module (srfi srfi-35)
21b679f6
LC
31 #:use-module (ice-9 match)
32 #:export (gexp
33 gexp?
0bb9929e 34 with-imported-modules
0dbea56b
LC
35
36 gexp-input
37 gexp-input?
558e8b11 38
d9ae938f
LC
39 local-file
40 local-file?
74d441ab 41 local-file-file
9d3994f7 42 local-file-absolute-file-name
74d441ab
LC
43 local-file-name
44 local-file-recursive?
0dbea56b 45
558e8b11
LC
46 plain-file
47 plain-file?
48 plain-file-name
49 plain-file-content
50
91937029
LC
51 computed-file
52 computed-file?
53 computed-file-name
54 computed-file-gexp
91937029
LC
55 computed-file-options
56
15a01c72
LC
57 program-file
58 program-file?
59 program-file-name
60 program-file-gexp
15a01c72
LC
61 program-file-guile
62
e1c153e0
LC
63 scheme-file
64 scheme-file?
65 scheme-file-name
66 scheme-file-gexp
67
a9e5e92f
LC
68 file-append
69 file-append?
70 file-append-base
71 file-append-suffix
72
64fc9f65
RJ
73 load-path-expression
74 gexp-modules
75
21b679f6
LC
76 gexp->derivation
77 gexp->file
462a3fa3 78 gexp->script
aa72d9af 79 text-file*
b751cde3 80 mixed-text-file
dedb512f 81 file-union
d298c815 82 directory-union
aa72d9af
LC
83 imported-files
84 imported-modules
ff40e9b7
LC
85 compiled-modules
86
87 define-gexp-compiler
6b6298ae 88 gexp-compiler?
c2b84676 89 lower-object
6b6298ae 90
3e43166f
LC
91 lower-inputs
92
93 &gexp-error
94 gexp-error?
95 &gexp-input-error
96 gexp-input-error?
97 gexp-error-invalid-input))
21b679f6
LC
98
99;;; Commentary:
100;;;
101;;; This module implements "G-expressions", or "gexps". Gexps are like
102;;; S-expressions (sexps), with two differences:
103;;;
104;;; 1. References (un-quotations) to derivations or packages in a gexp are
667b2508
LC
105;;; replaced by the corresponding output file name; in addition, the
106;;; 'ungexp-native' unquote-like form allows code to explicitly refer to
107;;; the native code of a given package, in case of cross-compilation;
21b679f6
LC
108;;;
109;;; 2. Gexps embed information about the derivations they refer to.
110;;;
111;;; Gexps make it easy to write to files Scheme code that refers to store
112;;; items, or to write Scheme code to build derivations.
113;;;
114;;; Code:
115
116;; "G expressions".
117(define-record-type <gexp>
0bb9929e 118 (make-gexp references modules proc)
21b679f6 119 gexp?
affd7761 120 (references gexp-references) ;list of <gexp-input>
0bb9929e 121 (modules gexp-self-modules) ;list of module names
affd7761 122 (proc gexp-proc)) ;procedure
21b679f6 123
7560b00b
LC
124(define (write-gexp gexp port)
125 "Write GEXP on PORT."
126 (display "#<gexp " port)
2cf0ea0d
LC
127
128 ;; Try to write the underlying sexp. Now, this trick doesn't work when
129 ;; doing things like (ungexp-splicing (gexp ())) because GEXP's procedure
130 ;; tries to use 'append' on that, which fails with wrong-type-arg.
131 (false-if-exception
667b2508 132 (write (apply (gexp-proc gexp)
affd7761 133 (gexp-references gexp))
667b2508 134 port))
7560b00b
LC
135 (format port " ~a>"
136 (number->string (object-address gexp) 16)))
137
138(set-record-type-printer! <gexp> write-gexp)
139
bcb13287
LC
140\f
141;;;
142;;; Methods.
143;;;
144
145;; Compiler for a type of objects that may be introduced in a gexp.
146(define-record-type <gexp-compiler>
1cdecf24 147 (gexp-compiler type lower expand)
bcb13287 148 gexp-compiler?
1cdecf24 149 (type gexp-compiler-type) ;record type descriptor
ebdfd776 150 (lower gexp-compiler-lower)
1cdecf24 151 (expand gexp-compiler-expand)) ;#f | DRV -> sexp
bcb13287 152
3e43166f
LC
153(define-condition-type &gexp-error &error
154 gexp-error?)
155
156(define-condition-type &gexp-input-error &gexp-error
157 gexp-input-error?
158 (input gexp-error-invalid-input))
159
160
bcb13287 161(define %gexp-compilers
1cdecf24
LC
162 ;; 'eq?' mapping of record type descriptor to <gexp-compiler>.
163 (make-hash-table 20))
bcb13287 164
ebdfd776
LC
165(define (default-expander thing obj output)
166 "This is the default expander for \"things\" that appear in gexps. It
167returns its output file name of OBJ's OUTPUT."
168 (match obj
169 ((? derivation? drv)
170 (derivation->output-path drv output))
171 ((? string? file)
172 file)))
173
bcb13287
LC
174(define (register-compiler! compiler)
175 "Register COMPILER as a gexp compiler."
1cdecf24
LC
176 (hashq-set! %gexp-compilers
177 (gexp-compiler-type compiler) compiler))
bcb13287
LC
178
179(define (lookup-compiler object)
ebdfd776 180 "Search for a compiler for OBJECT. Upon success, return the three argument
bcb13287 181procedure to lower it; otherwise return #f."
1cdecf24
LC
182 (and=> (hashq-ref %gexp-compilers (struct-vtable object))
183 gexp-compiler-lower))
bcb13287 184
ebdfd776
LC
185(define (lookup-expander object)
186 "Search for an expander for OBJECT. Upon success, return the three argument
187procedure to expand it; otherwise return #f."
1cdecf24
LC
188 (and=> (hashq-ref %gexp-compilers (struct-vtable object))
189 gexp-compiler-expand))
ebdfd776 190
c2b84676
LC
191(define* (lower-object obj
192 #:optional (system (%current-system))
193 #:key target)
194 "Return as a value in %STORE-MONAD the derivation or store item
195corresponding to OBJ for SYSTEM, cross-compiling for TARGET if TARGET is true.
196OBJ must be an object that has an associated gexp compiler, such as a
197<package>."
3e43166f
LC
198 (match (lookup-compiler obj)
199 (#f
200 (raise (condition (&gexp-input-error (input obj)))))
201 (lower
202 (lower obj system target))))
c2b84676 203
ebdfd776
LC
204(define-syntax define-gexp-compiler
205 (syntax-rules (=> compiler expander)
206 "Define NAME as a compiler for objects matching PREDICATE encountered in
207gexps.
208
209In the simplest form of the macro, BODY must return a derivation for PARAM, an
210object that matches PREDICATE, for SYSTEM and TARGET (the latter of which is
211#f except when cross-compiling.)
212
213The more elaborate form allows you to specify an expander:
214
215 (define-gexp-compiler something something?
216 compiler => (lambda (param system target) ...)
217 expander => (lambda (param drv output) ...))
218
219The expander specifies how an object is converted to its sexp representation."
1cdecf24
LC
220 ((_ (name (param record-type) system target) body ...)
221 (define-gexp-compiler name record-type
ebdfd776
LC
222 compiler => (lambda (param system target) body ...)
223 expander => default-expander))
1cdecf24 224 ((_ name record-type
ebdfd776
LC
225 compiler => compile
226 expander => expand)
227 (begin
228 (define name
1cdecf24 229 (gexp-compiler record-type compile expand))
ebdfd776 230 (register-compiler! name)))))
bcb13287 231
1cdecf24 232(define-gexp-compiler (derivation-compiler (drv <derivation>) system target)
2924f0d6
LC
233 ;; Derivations are the lowest-level representation, so this is the identity
234 ;; compiler.
235 (with-monad %store-monad
236 (return drv)))
237
bcb13287 238\f
d9ae938f 239;;;
558e8b11 240;;; File declarations.
d9ae938f
LC
241;;;
242
9d3994f7
LC
243;; A local file name. FILE is the file name the user entered, which can be a
244;; relative file name, and ABSOLUTE is a promise that computes its canonical
245;; absolute file name. We keep it in a promise to compute it lazily and avoid
246;; repeated 'stat' calls.
d9ae938f 247(define-record-type <local-file>
0687fc9c 248 (%%local-file file absolute name recursive? select?)
d9ae938f
LC
249 local-file?
250 (file local-file-file) ;string
9d3994f7 251 (absolute %local-file-absolute-file-name) ;promise string
d9ae938f 252 (name local-file-name) ;string
0687fc9c
LC
253 (recursive? local-file-recursive?) ;Boolean
254 (select? local-file-select?)) ;string stat -> Boolean
255
256(define (true file stat) #t)
d9ae938f 257
9d3994f7 258(define* (%local-file file promise #:optional (name (basename file))
0687fc9c 259 #:key recursive? (select? true))
9d3994f7
LC
260 ;; This intermediate procedure is part of our ABI, but the underlying
261 ;; %%LOCAL-FILE is not.
0687fc9c 262 (%%local-file file promise name recursive? select?))
9d3994f7 263
9d3994f7
LC
264(define (absolute-file-name file directory)
265 "Return the canonical absolute file name for FILE, which lives in the
266vicinity of DIRECTORY."
267 (canonicalize-path
268 (cond ((string-prefix? "/" file) file)
269 ((not directory) file)
270 ((string-prefix? "/" directory)
271 (string-append directory "/" file))
272 (else file))))
273
302d46e6
LC
274(define-syntax local-file
275 (lambda (s)
276 "Return an object representing local file FILE to add to the store; this
9d3994f7
LC
277object can be used in a gexp. If FILE is a relative file name, it is looked
278up relative to the source file where this form appears. FILE will be added to
279the store under NAME--by default the base name of FILE.
d9ae938f
LC
280
281When RECURSIVE? is true, the contents of FILE are added recursively; if FILE
282designates a flat file and RECURSIVE? is true, its contents are added, and its
283permission bits are kept.
284
0687fc9c
LC
285When RECURSIVE? is true, call (SELECT? FILE STAT) for each directory entry,
286where FILE is the entry's absolute file name and STAT is the result of
287'lstat'; exclude entries for which SELECT? does not return true.
288
302d46e6
LC
289This is the declarative counterpart of the 'interned-file' monadic procedure.
290It is implemented as a macro to capture the current source directory where it
291appears."
292 (syntax-case s ()
293 ((_ file rest ...)
294 #'(%local-file file
295 (delay (absolute-file-name file (current-source-directory)))
296 rest ...))
297 ((_)
298 #'(syntax-error "missing file name"))
299 (id
300 (identifier? #'id)
301 ;; XXX: We could return #'(lambda (file . rest) ...). However,
302 ;; (syntax-source #'id) is #f so (current-source-directory) would not
303 ;; work. Thus, simply forbid this form.
304 #'(syntax-error
305 "'local-file' is a macro and cannot be used like this")))))
9d3994f7
LC
306
307(define (local-file-absolute-file-name file)
308 "Return the absolute file name for FILE, a <local-file> instance. A
309'system-error' exception is raised if FILE could not be found."
310 (force (%local-file-absolute-file-name file)))
d9ae938f 311
1cdecf24 312(define-gexp-compiler (local-file-compiler (file <local-file>) system target)
d9ae938f
LC
313 ;; "Compile" FILE by adding it to the store.
314 (match file
0687fc9c 315 (($ <local-file> file (= force absolute) name recursive? select?)
9d3994f7
LC
316 ;; Canonicalize FILE so that if it's a symlink, it is resolved. Failing
317 ;; to do that, when RECURSIVE? is #t, we could end up creating a dangling
318 ;; symlink in the store, and when RECURSIVE? is #f 'add-to-store' would
319 ;; just throw an error, both of which are inconvenient.
0687fc9c
LC
320 (interned-file absolute name
321 #:recursive? recursive? #:select? select?))))
d9ae938f 322
558e8b11
LC
323(define-record-type <plain-file>
324 (%plain-file name content references)
325 plain-file?
326 (name plain-file-name) ;string
327 (content plain-file-content) ;string
328 (references plain-file-references)) ;list (currently unused)
329
330(define (plain-file name content)
331 "Return an object representing a text file called NAME with the given
332CONTENT (a string) to be added to the store.
333
334This is the declarative counterpart of 'text-file'."
335 ;; XXX: For now just ignore 'references' because it's not clear how to use
336 ;; them in a declarative context.
337 (%plain-file name content '()))
338
1cdecf24 339(define-gexp-compiler (plain-file-compiler (file <plain-file>) system target)
558e8b11
LC
340 ;; "Compile" FILE by adding it to the store.
341 (match file
342 (($ <plain-file> name content references)
343 (text-file name content references))))
344
91937029 345(define-record-type <computed-file>
a769bffb 346 (%computed-file name gexp options)
91937029
LC
347 computed-file?
348 (name computed-file-name) ;string
349 (gexp computed-file-gexp) ;gexp
91937029
LC
350 (options computed-file-options)) ;list of arguments
351
352(define* (computed-file name gexp
a769bffb 353 #:key (options '(#:local-build? #t)))
91937029 354 "Return an object representing the store item NAME, a file or directory
a769bffb 355computed by GEXP. OPTIONS is a list of additional arguments to pass
91937029
LC
356to 'gexp->derivation'.
357
358This is the declarative counterpart of 'gexp->derivation'."
a769bffb 359 (%computed-file name gexp options))
91937029 360
1cdecf24 361(define-gexp-compiler (computed-file-compiler (file <computed-file>)
91937029
LC
362 system target)
363 ;; Compile FILE by returning a derivation whose build expression is its
364 ;; gexp.
365 (match file
a769bffb
LC
366 (($ <computed-file> name gexp options)
367 (apply gexp->derivation name gexp options))))
91937029 368
15a01c72 369(define-record-type <program-file>
9c14a487 370 (%program-file name gexp guile)
15a01c72
LC
371 program-file?
372 (name program-file-name) ;string
373 (gexp program-file-gexp) ;gexp
15a01c72
LC
374 (guile program-file-guile)) ;package
375
9c14a487 376(define* (program-file name gexp #:key (guile #f))
15a01c72 377 "Return an object representing the executable store item NAME that runs
9c14a487 378GEXP. GUILE is the Guile package used to execute that script.
15a01c72
LC
379
380This is the declarative counterpart of 'gexp->script'."
9c14a487 381 (%program-file name gexp guile))
15a01c72 382
1cdecf24 383(define-gexp-compiler (program-file-compiler (file <program-file>)
15a01c72
LC
384 system target)
385 ;; Compile FILE by returning a derivation that builds the script.
386 (match file
9c14a487 387 (($ <program-file> name gexp guile)
15a01c72 388 (gexp->script name gexp
15a01c72
LC
389 #:guile (or guile (default-guile))))))
390
e1c153e0
LC
391(define-record-type <scheme-file>
392 (%scheme-file name gexp)
393 scheme-file?
394 (name scheme-file-name) ;string
395 (gexp scheme-file-gexp)) ;gexp
396
397(define* (scheme-file name gexp)
398 "Return an object representing the Scheme file NAME that contains GEXP.
399
400This is the declarative counterpart of 'gexp->file'."
401 (%scheme-file name gexp))
402
1cdecf24 403(define-gexp-compiler (scheme-file-compiler (file <scheme-file>)
e1c153e0
LC
404 system target)
405 ;; Compile FILE by returning a derivation that builds the file.
406 (match file
407 (($ <scheme-file> name gexp)
408 (gexp->file name gexp))))
409
a9e5e92f
LC
410;; Appending SUFFIX to BASE's output file name.
411(define-record-type <file-append>
412 (%file-append base suffix)
413 file-append?
414 (base file-append-base) ;<package> | <derivation> | ...
415 (suffix file-append-suffix)) ;list of strings
416
417(define (file-append base . suffix)
418 "Return a <file-append> object that expands to the concatenation of BASE and
419SUFFIX."
420 (%file-append base suffix))
421
1cdecf24 422(define-gexp-compiler file-append-compiler <file-append>
a9e5e92f
LC
423 compiler => (lambda (obj system target)
424 (match obj
425 (($ <file-append> base _)
426 (lower-object base system #:target target))))
427 expander => (lambda (obj lowered output)
428 (match obj
429 (($ <file-append> base suffix)
430 (let* ((expand (lookup-expander base))
431 (base (expand base lowered output)))
432 (string-append base (string-concatenate suffix)))))))
433
d9ae938f 434\f
bcb13287
LC
435;;;
436;;; Inputs & outputs.
437;;;
438
e39d1461
LC
439;; The input of a gexp.
440(define-record-type <gexp-input>
0dbea56b 441 (%gexp-input thing output native?)
e39d1461
LC
442 gexp-input?
443 (thing gexp-input-thing) ;<package> | <origin> | <derivation> | ...
444 (output gexp-input-output) ;string
445 (native? gexp-input-native?)) ;Boolean
446
f7328634
LC
447(define (write-gexp-input input port)
448 (match input
449 (($ <gexp-input> thing output #f)
450 (format port "#<gexp-input ~s:~a>" thing output))
451 (($ <gexp-input> thing output #t)
452 (format port "#<gexp-input native ~s:~a>" thing output))))
453
454(set-record-type-printer! <gexp-input> write-gexp-input)
455
0dbea56b
LC
456(define* (gexp-input thing ;convenience procedure
457 #:optional (output "out")
458 #:key native?)
459 "Return a new <gexp-input> for the OUTPUT of THING; NATIVE? determines
460whether this should be considered a \"native\" input or not."
461 (%gexp-input thing output native?))
462
21b679f6
LC
463;; Reference to one of the derivation's outputs, for gexps used in
464;; derivations.
1e87da58
LC
465(define-record-type <gexp-output>
466 (gexp-output name)
467 gexp-output?
468 (name gexp-output-name))
21b679f6 469
f7328634
LC
470(define (write-gexp-output output port)
471 (match output
472 (($ <gexp-output> name)
473 (format port "#<gexp-output ~a>" name))))
474
475(set-record-type-printer! <gexp-output> write-gexp-output)
476
0bb9929e 477(define (gexp-modules gexp)
2363bdd7
LC
478 "Return the list of Guile module names GEXP relies on. If (gexp? GEXP) is
479false, meaning that GEXP is a plain Scheme object, return the empty list."
480 (if (gexp? gexp)
481 (delete-duplicates
482 (append (gexp-self-modules gexp)
483 (append-map (match-lambda
484 (($ <gexp-input> (? gexp? exp))
485 (gexp-modules exp))
486 (($ <gexp-input> (lst ...))
487 (append-map (lambda (item)
488 (if (gexp? item)
489 (gexp-modules item)
490 '()))
491 lst))
492 (_
493 '()))
494 (gexp-references gexp))))
495 '())) ;plain Scheme data type
0bb9929e 496
68a61e9f
LC
497(define* (lower-inputs inputs
498 #:key system target)
499 "Turn any package from INPUTS into a derivation for SYSTEM; return the
500corresponding input list as a monadic value. When TARGET is true, use it as
501the cross-compilation target triplet."
21b679f6
LC
502 (with-monad %store-monad
503 (sequence %store-monad
504 (map (match-lambda
2242ff45 505 (((? struct? thing) sub-drv ...)
c2b84676
LC
506 (mlet %store-monad ((drv (lower-object
507 thing system #:target target)))
2242ff45
LC
508 (return `(,drv ,@sub-drv))))
509 (input
510 (return input)))
21b679f6
LC
511 inputs))))
512
b53833b2
LC
513(define* (lower-reference-graphs graphs #:key system target)
514 "Given GRAPHS, a list of (FILE-NAME INPUT ...) lists for use as a
515#:reference-graphs argument, lower it such that each INPUT is replaced by the
516corresponding derivation."
517 (match graphs
518 (((file-names . inputs) ...)
519 (mlet %store-monad ((inputs (lower-inputs inputs
520 #:system system
521 #:target target)))
522 (return (map cons file-names inputs))))))
523
c8351d9a
LC
524(define* (lower-references lst #:key system target)
525 "Based on LST, a list of output names and packages, return a list of output
526names and file names suitable for the #:allowed-references argument to
527'derivation'."
c8351d9a
LC
528 (with-monad %store-monad
529 (define lower
530 (match-lambda
531 ((? string? output)
532 (return output))
accb682c 533 (($ <gexp-input> thing output native?)
c2b84676
LC
534 (mlet %store-monad ((drv (lower-object thing system
535 #:target (if native?
536 #f target))))
accb682c 537 (return (derivation->output-path drv output))))
bcb13287 538 (thing
c2b84676
LC
539 (mlet %store-monad ((drv (lower-object thing system
540 #:target target)))
c8351d9a
LC
541 (return (derivation->output-path drv))))))
542
543 (sequence %store-monad (map lower lst))))
544
ff40e9b7
LC
545(define default-guile-derivation
546 ;; Here we break the abstraction by talking to the higher-level layer.
547 ;; Thus, do the resolution lazily to hide the circular dependency.
548 (let ((proc (delay
549 (let ((iface (resolve-interface '(guix packages))))
550 (module-ref iface 'default-guile-derivation)))))
551 (lambda (system)
552 ((force proc) system))))
553
21b679f6
LC
554(define* (gexp->derivation name exp
555 #:key
68a61e9f 556 system (target 'current)
21b679f6
LC
557 hash hash-algo recursive?
558 (env-vars '())
559 (modules '())
4684f301 560 (module-path %load-path)
21b679f6 561 (guile-for-build (%guile-for-build))
ce45eb4c 562 (graft? (%graft?))
21b679f6 563 references-graphs
3f4ecf32 564 allowed-references disallowed-references
c0468155 565 leaked-env-vars
0309e1b0
LC
566 local-build? (substitutable? #t)
567 (script-name (string-append name "-builder")))
21b679f6 568 "Return a derivation NAME that runs EXP (a gexp) with GUILE-FOR-BUILD (a
0309e1b0
LC
569derivation) on SYSTEM; EXP is stored in a file called SCRIPT-NAME. When
570TARGET is true, it is used as the cross-compilation target triplet for
571packages referred to by EXP.
21b679f6 572
0bb9929e
LC
573MODULES is deprecated in favor of 'with-imported-modules'. Its meaning is to
574make MODULES available in the evaluation context of EXP; MODULES is a list of
4684f301 575names of Guile modules searched in MODULE-PATH to be copied in the store,
21b679f6
LC
576compiled, and made available in the load path during the execution of
577EXP---e.g., '((guix build utils) (guix build gnu-build-system)).
578
ce45eb4c
LC
579GRAFT? determines whether packages referred to by EXP should be grafted when
580applicable.
581
b53833b2
LC
582When REFERENCES-GRAPHS is true, it must be a list of tuples of one of the
583following forms:
584
585 (FILE-NAME PACKAGE)
586 (FILE-NAME PACKAGE OUTPUT)
587 (FILE-NAME DERIVATION)
588 (FILE-NAME DERIVATION OUTPUT)
589 (FILE-NAME STORE-ITEM)
590
591The right-hand-side of each element of REFERENCES-GRAPHS is automatically made
592an input of the build process of EXP. In the build environment, each
593FILE-NAME contains the reference graph of the corresponding item, in a simple
594text format.
595
c8351d9a
LC
596ALLOWED-REFERENCES must be either #f or a list of output names and packages.
597In the latter case, the list denotes store items that the result is allowed to
598refer to. Any reference to another store item will lead to a build error.
3f4ecf32
LC
599Similarly for DISALLOWED-REFERENCES, which can list items that must not be
600referenced by the outputs.
b53833b2 601
21b679f6 602The other arguments are as for 'derivation'."
0bb9929e
LC
603 (define %modules
604 (delete-duplicates
605 (append modules (gexp-modules exp))))
21b679f6
LC
606 (define outputs (gexp-outputs exp))
607
b53833b2
LC
608 (define (graphs-file-names graphs)
609 ;; Return a list of (FILE-NAME . STORE-PATH) pairs made from GRAPHS.
610 (map (match-lambda
2924f0d6 611 ;; TODO: Remove 'derivation?' special cases.
b53833b2
LC
612 ((file-name (? derivation? drv))
613 (cons file-name (derivation->output-path drv)))
614 ((file-name (? derivation? drv) sub-drv)
615 (cons file-name (derivation->output-path drv sub-drv)))
616 ((file-name thing)
617 (cons file-name thing)))
618 graphs))
619
ce45eb4c
LC
620 (mlet* %store-monad (;; The following binding forces '%current-system' and
621 ;; '%current-target-system' to be looked up at >>=
622 ;; time.
623 (graft? (set-grafting graft?))
68a61e9f 624
5d098459 625 (system -> (or system (%current-system)))
68a61e9f
LC
626 (target -> (if (eq? target 'current)
627 (%current-target-system)
628 target))
667b2508 629 (normals (lower-inputs (gexp-inputs exp)
68a61e9f
LC
630 #:system system
631 #:target target))
667b2508
LC
632 (natives (lower-inputs (gexp-native-inputs exp)
633 #:system system
634 #:target #f))
635 (inputs -> (append normals natives))
68a61e9f
LC
636 (sexp (gexp->sexp exp
637 #:system system
638 #:target target))
0309e1b0 639 (builder (text-file script-name
21b679f6
LC
640 (object->string sexp)))
641 (modules (if (pair? %modules)
642 (imported-modules %modules
643 #:system system
4684f301 644 #:module-path module-path
21b679f6
LC
645 #:guile guile-for-build)
646 (return #f)))
647 (compiled (if (pair? %modules)
648 (compiled-modules %modules
649 #:system system
4684f301 650 #:module-path module-path
21b679f6
LC
651 #:guile guile-for-build)
652 (return #f)))
b53833b2
LC
653 (graphs (if references-graphs
654 (lower-reference-graphs references-graphs
655 #:system system
656 #:target target)
657 (return #f)))
c8351d9a
LC
658 (allowed (if allowed-references
659 (lower-references allowed-references
660 #:system system
661 #:target target)
662 (return #f)))
3f4ecf32
LC
663 (disallowed (if disallowed-references
664 (lower-references disallowed-references
665 #:system system
666 #:target target)
667 (return #f)))
21b679f6
LC
668 (guile (if guile-for-build
669 (return guile-for-build)
ff40e9b7 670 (default-guile-derivation system))))
ce45eb4c
LC
671 (mbegin %store-monad
672 (set-grafting graft?) ;restore the initial setting
673 (raw-derivation name
674 (string-append (derivation->output-path guile)
675 "/bin/guile")
676 `("--no-auto-compile"
677 ,@(if (pair? %modules)
678 `("-L" ,(derivation->output-path modules)
679 "-C" ,(derivation->output-path compiled))
680 '())
681 ,builder)
682 #:outputs outputs
683 #:env-vars env-vars
684 #:system system
685 #:inputs `((,guile)
686 (,builder)
687 ,@(if modules
688 `((,modules) (,compiled) ,@inputs)
689 inputs)
690 ,@(match graphs
691 (((_ . inputs) ...) inputs)
692 (_ '())))
693 #:hash hash #:hash-algo hash-algo #:recursive? recursive?
694 #:references-graphs (and=> graphs graphs-file-names)
695 #:allowed-references allowed
3f4ecf32 696 #:disallowed-references disallowed
c0468155 697 #:leaked-env-vars leaked-env-vars
4a6aeb67
LC
698 #:local-build? local-build?
699 #:substitutable? substitutable?))))
21b679f6 700
1123759b
LC
701(define* (gexp-inputs exp #:key native?)
702 "Return the input list for EXP. When NATIVE? is true, return only native
703references; otherwise, return only non-native references."
21b679f6
LC
704 (define (add-reference-inputs ref result)
705 (match ref
1123759b
LC
706 (($ <gexp-input> (? gexp? exp) _ #t)
707 (if native?
708 (append (gexp-inputs exp)
709 (gexp-inputs exp #:native? #t)
710 result)
711 result))
712 (($ <gexp-input> (? gexp? exp) _ #f)
d343a60f
LC
713 (append (gexp-inputs exp #:native? native?)
714 result))
e39d1461
LC
715 (($ <gexp-input> (? string? str))
716 (if (direct-store-path? str)
717 (cons `(,str) result)
21b679f6 718 result))
5b14a790
LC
719 (($ <gexp-input> (? struct? thing) output n?)
720 (if (and (eqv? n? native?) (lookup-compiler thing))
bcb13287
LC
721 ;; THING is a derivation, or a package, or an origin, etc.
722 (cons `(,thing ,output) result)
723 result))
1123759b 724 (($ <gexp-input> (lst ...) output n?)
578dfbe0
LC
725 (fold-right add-reference-inputs result
726 ;; XXX: For now, automatically convert LST to a list of
727 ;; gexp-inputs. Inherit N?.
728 (map (match-lambda
729 ((? gexp-input? x)
730 (%gexp-input (gexp-input-thing x)
731 (gexp-input-output x)
732 n?))
733 (x
734 (%gexp-input x "out" n?)))
735 lst)))
21b679f6
LC
736 (_
737 ;; Ignore references to other kinds of objects.
738 result)))
739
740 (fold-right add-reference-inputs
741 '()
5b14a790 742 (gexp-references exp)))
667b2508
LC
743
744(define gexp-native-inputs
1123759b 745 (cut gexp-inputs <> #:native? #t))
21b679f6
LC
746
747(define (gexp-outputs exp)
748 "Return the outputs referred to by EXP as a list of strings."
749 (define (add-reference-output ref result)
750 (match ref
1e87da58 751 (($ <gexp-output> name)
21b679f6 752 (cons name result))
e39d1461 753 (($ <gexp-input> (? gexp? exp))
21b679f6 754 (append (gexp-outputs exp) result))
e39d1461
LC
755 (($ <gexp-input> (lst ...) output native?)
756 ;; XXX: Automatically convert LST.
0dbea56b
LC
757 (add-reference-output (map (match-lambda
758 ((? gexp-input? x) x)
759 (x (%gexp-input x "out" native?)))
760 lst)
e39d1461 761 result))
f9efe568
LC
762 ((lst ...)
763 (fold-right add-reference-output result lst))
21b679f6
LC
764 (_
765 result)))
766
7e75a673
LC
767 (delete-duplicates
768 (add-reference-output (gexp-references exp) '())))
21b679f6 769
68a61e9f
LC
770(define* (gexp->sexp exp #:key
771 (system (%current-system))
772 (target (%current-target-system)))
21b679f6
LC
773 "Return (monadically) the sexp corresponding to EXP for the given OUTPUT,
774and in the current monad setting (system type, etc.)"
667b2508 775 (define* (reference->sexp ref #:optional native?)
21b679f6
LC
776 (with-monad %store-monad
777 (match ref
1e87da58 778 (($ <gexp-output> output)
bfd9eed9
LC
779 ;; Output file names are not known in advance but the daemon defines
780 ;; an environment variable for each of them at build time, so use
781 ;; that trick.
782 (return `((@ (guile) getenv) ,output)))
e39d1461 783 (($ <gexp-input> (? gexp? exp) output n?)
667b2508
LC
784 (gexp->sexp exp
785 #:system system
e39d1461
LC
786 #:target (if (or n? native?) #f target)))
787 (($ <gexp-input> (refs ...) output n?)
667b2508 788 (sequence %store-monad
e39d1461
LC
789 (map (lambda (ref)
790 ;; XXX: Automatically convert REF to an gexp-input.
0dbea56b
LC
791 (reference->sexp
792 (if (gexp-input? ref)
793 ref
794 (%gexp-input ref "out" n?))
affd7761 795 (or n? native?)))
e39d1461 796 refs)))
bcb13287 797 (($ <gexp-input> (? struct? thing) output n?)
ebdfd776
LC
798 (let ((target (if (or n? native?) #f target))
799 (expand (lookup-expander thing)))
c2b84676
LC
800 (mlet %store-monad ((obj (lower-object thing system
801 #:target target)))
d9ae938f 802 ;; OBJ must be either a derivation or a store file name.
ebdfd776 803 (return (expand thing obj output)))))
e39d1461
LC
804 (($ <gexp-input> x)
805 (return x))
21b679f6
LC
806 (x
807 (return x)))))
808
809 (mlet %store-monad
810 ((args (sequence %store-monad
affd7761 811 (map reference->sexp (gexp-references exp)))))
21b679f6
LC
812 (return (apply (gexp-proc exp) args))))
813
21b679f6
LC
814(define (syntax-location-string s)
815 "Return a string representing the source code location of S."
816 (let ((props (syntax-source s)))
817 (if props
818 (let ((file (assoc-ref props 'filename))
819 (line (and=> (assoc-ref props 'line) 1+))
820 (column (assoc-ref props 'column)))
821 (if file
822 (simple-format #f "~a:~a:~a"
823 file line column)
824 (simple-format #f "~a:~a" line column)))
825 "<unknown location>")))
826
0bb9929e
LC
827(define-syntax-parameter current-imported-modules
828 ;; Current list of imported modules.
829 (identifier-syntax '()))
830
831(define-syntax-rule (with-imported-modules modules body ...)
832 "Mark the gexps defined in BODY... as requiring MODULES in their execution
833environment."
834 (syntax-parameterize ((current-imported-modules
835 (identifier-syntax modules)))
836 body ...))
837
21b679f6
LC
838(define-syntax gexp
839 (lambda (s)
840 (define (collect-escapes exp)
841 ;; Return all the 'ungexp' present in EXP.
842 (let loop ((exp exp)
843 (result '()))
607e1b51
LC
844 (syntax-case exp (ungexp
845 ungexp-splicing
846 ungexp-native
847 ungexp-native-splicing)
21b679f6
LC
848 ((ungexp _)
849 (cons exp result))
850 ((ungexp _ _)
851 (cons exp result))
852 ((ungexp-splicing _ ...)
853 (cons exp result))
607e1b51 854 ((ungexp-native _ ...)
667b2508
LC
855 (cons exp result))
856 ((ungexp-native-splicing _ ...)
857 (cons exp result))
5e2e4a51 858 ((exp0 . exp)
667b2508 859 (let ((result (loop #'exp0 result)))
5e2e4a51 860 (loop #'exp result)))
667b2508
LC
861 (_
862 result))))
863
21b679f6
LC
864 (define (escape->ref exp)
865 ;; Turn 'ungexp' form EXP into a "reference".
667b2508
LC
866 (syntax-case exp (ungexp ungexp-splicing
867 ungexp-native ungexp-native-splicing
868 output)
21b679f6 869 ((ungexp output)
1e87da58 870 #'(gexp-output "out"))
21b679f6 871 ((ungexp output name)
1e87da58 872 #'(gexp-output name))
21b679f6 873 ((ungexp thing)
0dbea56b 874 #'(%gexp-input thing "out" #f))
21b679f6 875 ((ungexp drv-or-pkg out)
0dbea56b 876 #'(%gexp-input drv-or-pkg out #f))
21b679f6 877 ((ungexp-splicing lst)
0dbea56b 878 #'(%gexp-input lst "out" #f))
667b2508 879 ((ungexp-native thing)
0dbea56b 880 #'(%gexp-input thing "out" #t))
667b2508 881 ((ungexp-native drv-or-pkg out)
0dbea56b 882 #'(%gexp-input drv-or-pkg out #t))
667b2508 883 ((ungexp-native-splicing lst)
0dbea56b 884 #'(%gexp-input lst "out" #t))))
21b679f6 885
667b2508
LC
886 (define (substitute-ungexp exp substs)
887 ;; Given EXP, an 'ungexp' or 'ungexp-native' form, substitute it with
888 ;; the corresponding form in SUBSTS.
889 (match (assoc exp substs)
890 ((_ id)
891 id)
4a6e889f
LC
892 (_ ;internal error
893 (with-syntax ((exp exp))
894 #'(syntax-error "error: no 'ungexp' substitution" exp)))))
667b2508
LC
895
896 (define (substitute-ungexp-splicing exp substs)
897 (syntax-case exp ()
898 ((exp rest ...)
899 (match (assoc #'exp substs)
900 ((_ id)
901 (with-syntax ((id id))
902 #`(append id
903 #,(substitute-references #'(rest ...) substs))))
904 (_
905 #'(syntax-error "error: no 'ungexp-splicing' substitution"
4a6e889f 906 exp))))))
667b2508 907
21b679f6
LC
908 (define (substitute-references exp substs)
909 ;; Return a variant of EXP where all the cars of SUBSTS have been
910 ;; replaced by the corresponding cdr.
667b2508
LC
911 (syntax-case exp (ungexp ungexp-native
912 ungexp-splicing ungexp-native-splicing)
21b679f6 913 ((ungexp _ ...)
667b2508
LC
914 (substitute-ungexp exp substs))
915 ((ungexp-native _ ...)
916 (substitute-ungexp exp substs))
21b679f6 917 (((ungexp-splicing _ ...) rest ...)
667b2508
LC
918 (substitute-ungexp-splicing exp substs))
919 (((ungexp-native-splicing _ ...) rest ...)
920 (substitute-ungexp-splicing exp substs))
5e2e4a51 921 ((exp0 . exp)
21b679f6 922 #`(cons #,(substitute-references #'exp0 substs)
5e2e4a51 923 #,(substitute-references #'exp substs)))
21b679f6
LC
924 (x #''x)))
925
926 (syntax-case s (ungexp output)
927 ((_ exp)
affd7761 928 (let* ((escapes (delete-duplicates (collect-escapes #'exp)))
21b679f6
LC
929 (formals (generate-temporaries escapes))
930 (sexp (substitute-references #'exp (zip escapes formals)))
affd7761
LC
931 (refs (map escape->ref escapes)))
932 #`(make-gexp (list #,@refs)
0bb9929e 933 current-imported-modules
21b679f6
LC
934 (lambda #,formals
935 #,sexp)))))))
936
937\f
aa72d9af
LC
938;;;
939;;; Module handling.
940;;;
941
df2d51f0
LC
942(define %utils-module
943 ;; This file provides 'mkdir-p', needed to implement 'imported-files' and
a9601e23
LC
944 ;; other primitives below. Note: We give the file name relative to this
945 ;; file you are currently reading; 'search-path' could return a file name
946 ;; relative to the current working directory.
947 (local-file "build/utils.scm"
df2d51f0 948 "build-utils.scm"))
aa72d9af
LC
949
950(define* (imported-files files
951 #:key (name "file-import")
952 (system (%current-system))
953 (guile (%guile-for-build)))
954 "Return a derivation that imports FILES into STORE. FILES must be a list
d938a58b
LC
955of (FINAL-PATH . FILE) pairs. Each FILE is mapped to FINAL-PATH in the
956resulting store path. FILE can be either a file name, or a file-like object,
957as returned by 'local-file' for example."
aa72d9af
LC
958 (define file-pair
959 (match-lambda
d938a58b 960 ((final-path . (? string? file-name))
aa72d9af
LC
961 (mlet %store-monad ((file (interned-file file-name
962 (basename final-path))))
d938a58b
LC
963 (return (list final-path file))))
964 ((final-path . file-like)
965 (mlet %store-monad ((file (lower-object file-like system)))
aa72d9af
LC
966 (return (list final-path file))))))
967
968 (mlet %store-monad ((files (sequence %store-monad
969 (map file-pair files))))
970 (define build
971 (gexp
972 (begin
df2d51f0 973 (primitive-load (ungexp %utils-module)) ;for 'mkdir-p'
aa72d9af
LC
974 (use-modules (ice-9 match))
975
aa72d9af
LC
976 (mkdir (ungexp output)) (chdir (ungexp output))
977 (for-each (match-lambda
978 ((final-path store-path)
979 (mkdir-p (dirname final-path))
980 (symlink store-path final-path)))
981 '(ungexp files)))))
982
983 ;; TODO: Pass FILES as an environment variable so that BUILD remains
984 ;; exactly the same regardless of FILES: less disk space, and fewer
985 ;; 'add-to-store' RPCs.
986 (gexp->derivation name build
987 #:system system
988 #:guile-for-build guile
989 #:local-build? #t)))
990
aa72d9af
LC
991(define* (imported-modules modules
992 #:key (name "module-import")
993 (system (%current-system))
994 (guile (%guile-for-build))
995 (module-path %load-path))
996 "Return a derivation that contains the source files of MODULES, a list of
d938a58b
LC
997module names such as `(ice-9 q)'. All of MODULES must be either names of
998modules to be found in the MODULE-PATH search path, or a module name followed
999by an arrow followed by a file-like object. For example:
1000
1001 (imported-modules `((guix build utils)
1002 (guix gcrypt)
1003 ((guix config) => ,(scheme-file …))))
1004
1005In this example, the first two modules are taken from MODULE-PATH, and the
1006last one is created from the given <scheme-file> object."
1007 (mlet %store-monad ((files
1008 (mapm %store-monad
1009 (match-lambda
1010 (((module ...) '=> file)
1011 (return
1012 (cons (module->source-file-name module)
1013 file)))
1014 ((module ...)
1015 (let ((f (module->source-file-name module)))
1016 (return
1017 (cons f (search-path* module-path f))))))
1018 modules)))
aa72d9af
LC
1019 (imported-files files #:name name #:system system
1020 #:guile guile)))
1021
1022(define* (compiled-modules modules
1023 #:key (name "module-import-compiled")
1024 (system (%current-system))
1025 (guile (%guile-for-build))
1026 (module-path %load-path))
1027 "Return a derivation that builds a tree containing the `.go' files
1028corresponding to MODULES. All the MODULES are built in a context where
1029they can refer to each other."
1030 (mlet %store-monad ((modules (imported-modules modules
1031 #:system system
1032 #:guile guile
1033 #:module-path
1034 module-path)))
1035 (define build
1036 (gexp
1037 (begin
df2d51f0
LC
1038 (primitive-load (ungexp %utils-module)) ;for 'mkdir-p'
1039
aa72d9af 1040 (use-modules (ice-9 ftw)
aa72d9af
LC
1041 (srfi srfi-26)
1042 (system base compile))
1043
aa72d9af
LC
1044 (define (regular? file)
1045 (not (member file '("." ".."))))
1046
1047 (define (process-directory directory output)
1048 (let ((entries (map (cut string-append directory "/" <>)
1049 (scandir directory regular?))))
1050 (for-each (lambda (entry)
1051 (if (file-is-directory? entry)
1052 (let ((output (string-append output "/"
1053 (basename entry))))
1054 (mkdir-p output)
1055 (process-directory entry output))
1056 (let* ((base (string-drop-right
1057 (basename entry)
1058 4)) ;.scm
1059 (output (string-append output "/" base
1060 ".go")))
1061 (compile-file entry
1062 #:output-file output
1063 #:opts
1064 %auto-compilation-options))))
1065 entries)))
1066
1067 (set! %load-path (cons (ungexp modules) %load-path))
1068 (mkdir (ungexp output))
1069 (chdir (ungexp modules))
1070 (process-directory "." (ungexp output)))))
1071
1072 ;; TODO: Pass MODULES as an environment variable.
1073 (gexp->derivation name build
1074 #:system system
1075 #:guile-for-build guile
1076 #:local-build? #t)))
1077
1078\f
21b679f6
LC
1079;;;
1080;;; Convenience procedures.
1081;;;
1082
53e89b17
LC
1083(define (default-guile)
1084 ;; Lazily resolve 'guile-final'. This module must not refer to (gnu …)
1085 ;; modules directly, to avoid circular dependencies, hence this hack.
bdb36958 1086 (module-ref (resolve-interface '(gnu packages commencement))
53e89b17
LC
1087 'guile-final))
1088
dd8d1a30
LC
1089(define (load-path-expression modules)
1090 "Return as a monadic value a gexp that sets '%load-path' and
1091'%load-compiled-path' to point to MODULES, a list of module names."
1092 (mlet %store-monad ((modules (imported-modules modules))
1093 (compiled (compiled-modules modules)))
1094 (return (gexp (eval-when (expand load eval)
1095 (set! %load-path
1096 (cons (ungexp modules) %load-path))
1097 (set! %load-compiled-path
1098 (cons (ungexp compiled)
1099 %load-compiled-path)))))))
1100
21b679f6 1101(define* (gexp->script name exp
9c14a487
LC
1102 #:key (guile (default-guile)))
1103 "Return an executable script NAME that runs EXP using GUILE, with EXP's
1104imported modules in its search path."
1105 (mlet %store-monad ((set-load-path
1106 (load-path-expression (gexp-modules exp))))
21b679f6
LC
1107 (gexp->derivation name
1108 (gexp
1109 (call-with-output-file (ungexp output)
1110 (lambda (port)
c17b5ab4
LC
1111 ;; Note: that makes a long shebang. When the store
1112 ;; is /gnu/store, that fits within the 128-byte
1113 ;; limit imposed by Linux, but that may go beyond
1114 ;; when running tests.
21b679f6
LC
1115 (format port
1116 "#!~a/bin/guile --no-auto-compile~%!#~%"
1117 (ungexp guile))
4a4cbd0b 1118
dd8d1a30 1119 (write '(ungexp set-load-path) port)
21b679f6
LC
1120 (write '(ungexp exp) port)
1121 (chmod port #o555)))))))
1122
2b418579
LC
1123(define* (gexp->file name exp #:key (set-load-path? #t))
1124 "Return a derivation that builds a file NAME containing EXP. When
1125SET-LOAD-PATH? is true, emit code in the resulting file to set '%load-path'
1126and '%load-compiled-path' to honor EXP's imported modules."
1127 (match (if set-load-path? (gexp-modules exp) '())
1128 (() ;zero modules
1129 (gexp->derivation name
1130 (gexp
1131 (call-with-output-file (ungexp output)
1132 (lambda (port)
1133 (write '(ungexp exp) port))))
1134 #:local-build? #t
1135 #:substitutable? #f))
1136 ((modules ...)
1137 (mlet %store-monad ((set-load-path (load-path-expression modules)))
1138 (gexp->derivation name
1139 (gexp
1140 (call-with-output-file (ungexp output)
1141 (lambda (port)
1142 (write '(ungexp set-load-path) port)
1143 (write '(ungexp exp) port))))
1144 #:local-build? #t
1145 #:substitutable? #f)))))
21b679f6 1146
462a3fa3
LC
1147(define* (text-file* name #:rest text)
1148 "Return as a monadic value a derivation that builds a text file containing
d9ae938f
LC
1149all of TEXT. TEXT may list, in addition to strings, objects of any type that
1150can be used in a gexp: packages, derivations, local file objects, etc. The
1151resulting store file holds references to all these."
462a3fa3
LC
1152 (define builder
1153 (gexp (call-with-output-file (ungexp output "out")
1154 (lambda (port)
1155 (display (string-append (ungexp-splicing text)) port)))))
1156
851b6f62
LC
1157 (gexp->derivation name builder
1158 #:local-build? #t
1159 #:substitutable? #f))
462a3fa3 1160
b751cde3
LC
1161(define* (mixed-text-file name #:rest text)
1162 "Return an object representing store file NAME containing TEXT. TEXT is a
1163sequence of strings and file-like objects, as in:
1164
1165 (mixed-text-file \"profile\"
1166 \"export PATH=\" coreutils \"/bin:\" grep \"/bin\")
1167
1168This is the declarative counterpart of 'text-file*'."
1169 (define build
1170 (gexp (call-with-output-file (ungexp output "out")
1171 (lambda (port)
1172 (display (string-append (ungexp-splicing text)) port)))))
1173
1174 (computed-file name build))
1175
dedb512f
LC
1176(define (file-union name files)
1177 "Return a <computed-file> that builds a directory containing all of FILES.
1178Each item in FILES must be a two-element list where the first element is the
1179file name to use in the new directory, and the second element is a gexp
1180denoting the target file. Here's an example:
1181
1182 (file-union \"etc\"
1183 `((\"hosts\" ,(plain-file \"hosts\"
1184 \"127.0.0.1 localhost\"))
1185 (\"bashrc\" ,(plain-file \"bashrc\"
1186 \"alias ls='ls --color'\"))))
1187
1188This yields an 'etc' directory containing these two files."
1189 (computed-file name
1190 (gexp
1191 (begin
1192 (mkdir (ungexp output))
1193 (chdir (ungexp output))
1194 (ungexp-splicing
1195 (map (match-lambda
1196 ((target source)
1197 (gexp
1198 (begin
1199 ;; Stat the source to abort early if it does
1200 ;; not exist.
1201 (stat (ungexp source))
1202
1203 (symlink (ungexp source)
1204 (ungexp target))))))
1205 files))))))
1206
d298c815
LC
1207(define (directory-union name things)
1208 "Return a directory that is the union of THINGS, where THINGS is a list of
1209file-like objects denoting directories. For example:
1210
1211 (directory-union \"guile+emacs\" (list guile emacs))
1212
1213yields a directory that is the union of the 'guile' and 'emacs' packages."
1214 (match things
1215 ((one)
1216 ;; Only one thing; return it.
1217 one)
1218 (_
1219 (computed-file name
1220 (with-imported-modules '((guix build union))
1221 (gexp (begin
1222 (use-modules (guix build union))
1223 (union-build (ungexp output)
1224 '(ungexp things)))))))))
1225
21b679f6
LC
1226\f
1227;;;
1228;;; Syntactic sugar.
1229;;;
1230
1231(eval-when (expand load eval)
667b2508
LC
1232 (define* (read-ungexp chr port #:optional native?)
1233 "Read an 'ungexp' or 'ungexp-splicing' form from PORT. When NATIVE? is
1234true, use 'ungexp-native' and 'ungexp-native-splicing' instead."
21b679f6
LC
1235 (define unquote-symbol
1236 (match (peek-char port)
1237 (#\@
1238 (read-char port)
667b2508
LC
1239 (if native?
1240 'ungexp-native-splicing
1241 'ungexp-splicing))
21b679f6 1242 (_
667b2508
LC
1243 (if native?
1244 'ungexp-native
1245 'ungexp))))
21b679f6
LC
1246
1247 (match (read port)
1248 ((? symbol? symbol)
1249 (let ((str (symbol->string symbol)))
1250 (match (string-index-right str #\:)
1251 (#f
1252 `(,unquote-symbol ,symbol))
1253 (colon
1254 (let ((name (string->symbol (substring str 0 colon)))
1255 (output (substring str (+ colon 1))))
1256 `(,unquote-symbol ,name ,output))))))
1257 (x
1258 `(,unquote-symbol ,x))))
1259
1260 (define (read-gexp chr port)
1261 "Read a 'gexp' form from PORT."
1262 `(gexp ,(read port)))
1263
1264 ;; Extend the reader
1265 (read-hash-extend #\~ read-gexp)
667b2508
LC
1266 (read-hash-extend #\$ read-ungexp)
1267 (read-hash-extend #\+ (cut read-ungexp <> <> #t)))
21b679f6
LC
1268
1269;;; gexp.scm ends here