projects/guix·blob master · refs

1997 lines · 91.8 KiB

1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2014-2026 Ludovic Courtès <[email protected]>
3;;; Copyright © 2021-2022 Maxime Devos <[email protected]>
4;;; Copyright © 2026 David Elsing <[email protected]>
5;;;
6;;; This file is part of GNU Guix.
7;;;
8;;; GNU Guix is free software; you can redistribute it and/or modify it
9;;; under the terms of the GNU General Public License as published by
10;;; the Free Software Foundation; either version 3 of the License, or (at
11;;; your option) any later version.
12;;;
13;;; GNU Guix is distributed in the hope that it will be useful, but
14;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;;; GNU General Public License for more details.
17;;;
18;;; You should have received a copy of the GNU General Public License
19;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
20
21(define-module (test-gexp)
22 #:use-module (guix store)
23 #:use-module (guix monads)
24 #:use-module (guix gexp)
25 #:use-module ((guix grafts) #:select (%graft-with-utf8-locale?))
26 #:use-module (guix derivations)
27 #:use-module (guix packages)
28 #:use-module (guix build-system trivial)
29 #:use-module (guix tests)
30 #:use-module ((guix build utils) #:select (with-directory-excursion))
31 #:use-module ((guix utils) #:select (call-with-temporary-directory))
32 #:use-module ((guix ui) #:select (load*))
33 #:use-module (gnu packages)
34 #:use-module (gnu packages base)
35 #:use-module (gnu packages bootstrap)
36 #:use-module ((guix diagnostics) #:select (error-location
37 error-location?
38 guix-warning-port
39 source-properties->location))
40 #:use-module (srfi srfi-1)
41 #:use-module (srfi srfi-34)
42 #:use-module (srfi srfi-64)
43 #:use-module (rnrs io ports)
44 #:use-module (ice-9 match)
45 #:use-module (ice-9 regex)
46 #:use-module (ice-9 popen)
47 #:use-module (ice-9 ftw))
48
49;; Test the (guix gexp) module.
50
51(define %store
52 (open-connection-for-tests))
53
54(define (bootstrap-guile-effective-version)
55 ;; TODO The package version of %bootstrap-guile is incorrect for
56 ;; riscv64-linux
57 (if (string=? "riscv64-linux" (%current-system))
58 "3.0"
59 (package-version %bootstrap-guile)))
60
61;; Globally disable grafts because they can trigger early builds.
62(%graft? #f)
63
64;; When grafting, do not add dependency on 'glibc-utf8-locales'.
65(%graft-with-utf8-locale? #f)
66
67;; For white-box testing.
68(define (gexp-inputs x)
69 ((@@ (guix gexp) gexp-inputs) x))
70(define (gexp-outputs x)
71 ((@@ (guix gexp) gexp-outputs) x))
72(define (gexp->sexp . x)
73 (apply (@@ (guix gexp) gexp->sexp) x))
74
75(define* (gexp->sexp* exp #:optional target)
76 (run-with-store %store (gexp->sexp exp (%current-system) target)
77 #:guile-for-build (%guile-for-build)))
78
79(define (gexp-input->tuple input)
80 (list (gexp-input-thing input) (gexp-input-output input)
81 (gexp-input-native? input)))
82
83(define %extension-package
84 ;; Example of a package to use when testing 'with-extensions'.
85 (dummy-package "extension"
86 (build-system trivial-build-system)
87 (arguments
88 `(#:guile ,%bootstrap-guile
89 #:modules ((guix build utils))
90 #:builder
91 (begin
92 (use-modules (guix build utils))
93 (let* ((out (string-append (assoc-ref %outputs "out")
94 "/share/guile/site/"
95 (effective-version))))
96 (mkdir-p out)
97 (call-with-output-file (string-append out "/hg2g.scm")
98 (lambda (port)
99 (define defmod 'define-module) ;fool Geiser
100 (write `(,defmod (hg2g)
101 #:export (the-answer))
102 port)
103 (write '(define the-answer 42) port)))))))))
104
105
106(test-begin "gexp")
107
108(test-equal "no references"
109 '(display "hello gexp->approximate-sexp!")
110 (gexp->approximate-sexp #~(display "hello gexp->approximate-sexp!")))
111
112(test-equal "unquoted gexp"
113 '(display "hello")
114 (let ((inside #~"hello"))
115 (gexp->approximate-sexp #~(display #$inside))))
116
117(test-equal "unquoted gexp (native)"
118 '(display "hello")
119 (let ((inside #~"hello"))
120 (gexp->approximate-sexp #~(display #+inside))))
121
122(test-equal "spliced gexp"
123 '(display '(fresh vegetables))
124 (let ((inside #~(fresh vegetables)))
125 (gexp->approximate-sexp #~(display '(#$@inside)))))
126
127(test-equal "unspliced gexp, approximated"
128 ;; (*approximate*) is really an implementation detail
129 '(display '(*approximate*))
130 (let ((inside (file-append coreutils "/bin/hello")))
131 (gexp->approximate-sexp #~(display '(#$@inside)))))
132
133(test-equal "unquoted gexp, approximated"
134 '(display '(*approximate*))
135 (let ((inside (file-append coreutils "/bin/hello")))
136 (gexp->approximate-sexp #~(display '#$inside))))
137
138;; See <https://issues.guix.gnu.org/54236>.
139(test-equal "unquoted sexp (not a gexp!)"
140 '(list #(foo) (foo) () "foo" foo #xf00)
141 (let ((inside/vector #(foo))
142 (inside/list '(foo))
143 (inside/empty '())
144 (inside/string "foo")
145 (inside/symbol 'foo)
146 (inside/number #xf00))
147 (gexp->approximate-sexp
148 #~(list #$inside/vector #$inside/list #$inside/empty #$inside/string
149 #$inside/symbol #$inside/number))))
150
151(test-equal "no refs"
152 '(display "hello!")
153 (let ((exp (gexp (display "hello!"))))
154 (and (gexp? exp)
155 (null? (gexp-inputs exp))
156 (gexp->sexp* exp))))
157
158(test-equal "sexp->gexp"
159 '(a b (c d) e)
160 (let ((exp (sexp->gexp '(a b (c d) e))))
161 (and (gexp? exp)
162 (null? (gexp-inputs exp))
163 (gexp->sexp* exp))))
164
165(test-equal "gexp->approximate-sexp, outputs"
166 '(list 'out:foo (*approximate*) 'out:bar (*approximate*))
167 (gexp->approximate-sexp
168 #~(list 'out:foo #$output:foo 'out:bar #$output:bar)))
169
170(test-equal "unquote"
171 '(display `(foo ,(+ 2 3)))
172 (let ((exp (gexp (display `(foo ,(+ 2 3))))))
173 (and (gexp? exp)
174 (null? (gexp-inputs exp))
175 (gexp->sexp* exp))))
176
177(test-assert "one input package"
178 (let ((exp (gexp (display (ungexp coreutils)))))
179 (and (gexp? exp)
180 (match (gexp-inputs exp)
181 ((input)
182 (eq? (gexp-input-thing input) coreutils)))
183 (equal? `(display ,(derivation->output-path
184 (package-derivation %store coreutils)))
185 (gexp->sexp* exp)))))
186
187(test-assert "one input package, dotted list"
188 (let ((exp (gexp (coreutils . (ungexp coreutils)))))
189 (and (gexp? exp)
190 (match (gexp-inputs exp)
191 ((input)
192 (eq? (gexp-input-thing input) coreutils)))
193 (equal? `(coreutils . ,(derivation->output-path
194 (package-derivation %store coreutils)))
195 (gexp->sexp* exp)))))
196
197(test-assert "one input package, vector"
198 (let ((exp (gexp #((ungexp coreutils)))))
199 (and (gexp? exp)
200 (match (gexp-inputs exp)
201 ((input)
202 (eq? (gexp-input-thing input) coreutils)))
203 (equal? (vector (derivation->output-path
204 (package-derivation %store coreutils)))
205 (gexp->sexp* exp)))))
206
207(test-assert "one input origin"
208 (let ((exp (gexp (display (ungexp (package-source coreutils))))))
209 (and (gexp? exp)
210 (match (gexp-inputs exp)
211 ((input)
212 (and (eq? (gexp-input-thing input) (package-source coreutils))
213 (string=? (gexp-input-output input) "out"))))
214 (equal? `(display ,(derivation->output-path
215 (package-source-derivation
216 %store (package-source coreutils))))
217 (gexp->sexp* exp)))))
218
219(test-assert "one local file"
220 (let* ((file (search-path %load-path "guix.scm"))
221 (local (local-file file))
222 (exp (gexp (display (ungexp local))))
223 (intd (add-to-store %store (basename file) #f
224 "sha256" file)))
225 (and (gexp? exp)
226 (match (gexp-inputs exp)
227 ((input)
228 (and (eq? (gexp-input-thing input) local)
229 (string=? (gexp-input-output input) "out"))))
230 (equal? `(display ,intd) (gexp->sexp* exp)))))
231
232(test-assert "one local file, symlink"
233 (let ((file (search-path %load-path "guix.scm"))
234 (link (tmpnam)))
235 (dynamic-wind
236 (const #t)
237 (lambda ()
238 (symlink (canonicalize-path file) link)
239 (let* ((local (local-file link "my-file" #:recursive? #f))
240 (exp (gexp (display (ungexp local))))
241 (intd (add-to-store %store "my-file" #f
242 "sha256" file)))
243 (and (gexp? exp)
244 (match (gexp-inputs exp)
245 ((input)
246 (and (eq? (gexp-input-thing input) local)
247 (string=? (gexp-input-output input) "out"))))
248 (equal? `(display ,intd) (gexp->sexp* exp)))))
249 (lambda ()
250 (false-if-exception (delete-file link))))))
251
252(test-equal "local-file, relative file name"
253 (canonicalize-path (search-path %load-path "guix/base32.scm"))
254 (let ((directory (dirname (search-path %load-path
255 "guix/build-system/gnu.scm"))))
256 (with-directory-excursion directory
257 (let ((file (local-file "../guix/base32.scm")))
258 (local-file-absolute-file-name file)))))
259
260(test-equal "local-file, non-literal relative file name"
261 (canonicalize-path (search-path %load-path "guix/base32.scm"))
262 (let ((directory (dirname (search-path %load-path
263 "guix/build-system/gnu.scm"))))
264 (with-directory-excursion directory
265 (let ((file (local-file (string-copy "../base32.scm"))))
266 (local-file-absolute-file-name file)))))
267
268(test-equal "local-file, non-literal source relative file name"
269 (current-filename)
270 (let ((file (local-file (assume-source-relative-file-name
271 (string-append "gexp" ".scm")))))
272 (local-file-absolute-file-name file)))
273
274(test-assert "local-file, relative file name, within gexp"
275 (let* ((file (search-path %load-path "guix/base32.scm"))
276 (interned (add-to-store %store "base32.scm" #f "sha256" file)))
277 (equal? `(the file is ,interned)
278 (gexp->sexp*
279 #~(the file is #$(local-file "../guix/base32.scm"))))))
280
281(test-assert "local-file, relative file name, within gexp, compiled"
282 ;; In Guile 3.0.8, everything read by the #~ and #$ read hash extensions
283 ;; would lack source location info, which in turn would lead
284 ;; (current-source-directory), called by 'local-file', to return #f, thereby
285 ;; breaking 'local-file' resolution. See
286 ;; <https://issues.guix.gnu.org/54003>.
287 (let ((file (tmpnam)))
288 (call-with-output-file file
289 (lambda (port)
290 (display (string-append "#~(this file is #$(local-file \""
291 (basename file) "\" \"t.scm\"))")
292 port)))
293
294 (let* ((interned (add-to-store %store "t.scm" #f "sha256" file)))
295 (equal? `(this file is ,interned)
296 (gexp->sexp* (load* file '((guix gexp))))))))
297
298(test-assertm "local-file, #:select?"
299 (mlet* %store-monad ((select? -> (lambda (file stat)
300 (member (basename file)
301 '("guix.scm" "tests"
302 "gexp.scm"))))
303 (file -> (local-file ".." "directory"
304 #:recursive? #t
305 #:select? select?))
306 (dir (lower-object file)))
307 (return (and (store-path? dir)
308 (equal? (scandir dir)
309 '("." ".." "guix.scm" "tests"))
310 (equal? (scandir (string-append dir "/tests"))
311 '("." ".." "gexp.scm"))))))
312
313(test-assert "local-file, capture file at the right time"
314 (call-with-temporary-directory
315 (lambda (directory)
316 (call-with-output-file (in-vicinity directory "the-unique-file.txt")
317 (lambda (port)
318 (display "Hi!" port)))
319
320 (let ((file (with-directory-excursion directory
321 ;; If the argument to 'local-file' were resolved when
322 ;; 'local-file-absolute-file-name' is called, we'd get the
323 ;; wrong result.
324 (local-file (in-vicinity (getcwd)
325 "the-unique-file.txt")))))
326 (string=? (local-file-absolute-file-name file)
327 (in-vicinity directory "the-unique-file.txt"))))))
328
329(test-assert "local-file, load through symlink"
330 ;; See <https://issues.guix.gnu.org/72867>.
331 (call-with-temporary-directory
332 (lambda (tmp-dir)
333 (with-directory-excursion tmp-dir
334 ;; create content file
335 (call-with-output-file "content"
336 (lambda (port) (display "Hi!" port)))
337 ;; Create a module that calls 'local-file' with the "content" file and
338 ;; returns its absolute file name. An error is raised if the "content"
339 ;; file can't be found.
340 (call-with-output-file "test-local-file.scm"
341 (lambda (port) (display "\
342(define-module (test-local-file)
343 #:use-module (guix gexp))
344(define file (local-file \"content\" \"test-file\"))
345(local-file-absolute-file-name file)" port)))
346 (mkdir "dir")
347 (symlink "../test-local-file.scm" "dir/test-local-file.scm")
348 ;; 'local-file' in turn calls 'current-source-directory' which has an
349 ;; 'if' branching condition depending on whether 'file-name' is
350 ;; absolute or relative file name. To test both of these branches we
351 ;; execute 'test-local-file.scm' symlink first as a module (corresponds
352 ;; to relative file name):
353 (dynamic-wind
354 (lambda () (set! %load-path (cons "dir" %load-path)))
355 (lambda () (resolve-module '(test-local-file) #:ensure #f))
356 (lambda () (set! %load-path (cdr %load-path))))
357 ;; and then as a regular code (corresponds to absolute file name):
358 (load (string-append tmp-dir "/dir/test-local-file.scm"))))))
359
360(test-assert "one plain file"
361 (let* ((file (plain-file "hi" "Hello, world!"))
362 (exp (gexp (display (ungexp file))))
363 (expected (add-text-to-store %store "hi" "Hello, world!")))
364 (and (gexp? exp)
365 (match (gexp-inputs exp)
366 ((input)
367 (and (eq? (gexp-input-thing input) file)
368 (string=? (gexp-input-output input) "out"))))
369 (equal? `(display ,expected) (gexp->sexp* exp)))))
370
371(test-assert "same input twice"
372 (let ((exp (gexp (begin
373 (display (ungexp coreutils))
374 (display (ungexp coreutils))))))
375 (and (gexp? exp)
376 (match (gexp-inputs exp)
377 ((input)
378 (and (eq? (gexp-input-thing input) coreutils)
379 (string=? (gexp-input-output input) "out"))))
380 (let ((e `(display ,(derivation->output-path
381 (package-derivation %store coreutils)))))
382 (equal? `(begin ,e ,e) (gexp->sexp* exp))))))
383
384(test-assert "two input packages, one derivation, one file"
385 (let* ((drv (build-expression->derivation
386 %store "foo" 'bar
387 #:guile-for-build (package-derivation %store %bootstrap-guile)))
388 (txt (add-text-to-store %store "foo" "Hello, world!"))
389 (exp (gexp (begin
390 (display (ungexp coreutils))
391 (display (ungexp %bootstrap-guile))
392 (display (ungexp drv))
393 (display (ungexp txt))))))
394 (define (match-input thing)
395 (lambda (input)
396 (eq? (gexp-input-thing input) thing)))
397
398 (and (gexp? exp)
399 (= 4 (length (gexp-inputs exp)))
400 (every (lambda (input)
401 (find (match-input input) (gexp-inputs exp)))
402 (list drv coreutils %bootstrap-guile txt))
403 (let ((e0 `(display ,(derivation->output-path
404 (package-derivation %store coreutils))))
405 (e1 `(display ,(derivation->output-path
406 (package-derivation %store %bootstrap-guile))))
407 (e2 `(display ,(derivation->output-path drv)))
408 (e3 `(display ,txt)))
409 (equal? `(begin ,e0 ,e1 ,e2 ,e3) (gexp->sexp* exp))))))
410
411(test-assert "file-append"
412 (let* ((drv (package-derivation %store %bootstrap-guile))
413 (fa (file-append %bootstrap-guile "/bin/guile"))
414 (exp #~(here we go #$fa)))
415 (and (match (gexp->sexp* exp)
416 (('here 'we 'go (? string? result))
417 (string=? result
418 (string-append (derivation->output-path drv)
419 "/bin/guile"))))
420 (match (gexp-inputs exp)
421 ((input)
422 (and (eq? (gexp-input-thing input) fa)
423 (string=? (gexp-input-output input) "out")))))))
424
425(test-assert "file-append, output"
426 (let* ((drv (package-derivation %store glibc))
427 (fa (file-append glibc "/lib" "/debug"))
428 (exp #~(foo #$fa:debug)))
429 (and (match (gexp->sexp* exp)
430 (('foo (? string? result))
431 (string=? result
432 (string-append (derivation->output-path drv "debug")
433 "/lib/debug"))))
434 (match (gexp-inputs exp)
435 ((input)
436 (and (eq? (gexp-input-thing input) fa)
437 (string=? (gexp-input-output input) "debug")))))))
438
439(test-assert "file-append, nested"
440 (let* ((drv (package-derivation %store glibc))
441 (dir (file-append glibc "/bin"))
442 (slash (file-append dir "/"))
443 (file (file-append slash "getent"))
444 (exp #~(foo #$file)))
445 (and (match (gexp->sexp* exp)
446 (('foo (? string? result))
447 (string=? result
448 (string-append (derivation->output-path drv)
449 "/bin/getent"))))
450 (match (gexp-inputs exp)
451 ((input)
452 (eq? (gexp-input-thing input) file))))))
453
454(test-assert "file-append, raw store item"
455 (let* ((obj (plain-file "example.txt" "Hello!"))
456 (a (file-append obj "/a"))
457 (b (file-append a "/b"))
458 (c (file-append b "/c"))
459 (exp #~(list #$c))
460 (item (run-with-store %store (lower-object obj)))
461 (lexp (run-with-store %store (lower-gexp exp))))
462 (and (equal? (lowered-gexp-sexp lexp)
463 `(list ,(string-append item "/a/b/c")))
464 (equal? (lowered-gexp-sources lexp)
465 (list item))
466 (null? (lowered-gexp-inputs lexp)))))
467
468(test-equal "gexp references non-existent output"
469 "no-default-output"
470 (guard (c ((derivation-missing-output-error? c)
471 (derivation-name (derivation-error-derivation c))))
472 (let* ((obj (computed-file "no-default-output"
473 #~(mkdir #$output:bar)))
474 (exp #~(symlink #$obj #$output))
475 (drv (run-with-store %store (lower-gexp exp))))
476 (pk 'oops! drv #f))))
477
478(test-assert "gexp-input, as first-class input"
479 ;; Insert a <gexp-input> record in a gexp as a way to specify which output
480 ;; of OBJ should be used.
481 (let* ((obj (computed-file "foo" #~(mkdir #$output:bar)))
482 (exp #~(list #$(gexp-input obj "bar")))
483 (drv (run-with-store %store (lower-object obj)))
484 (item (derivation->output-path drv "bar"))
485 (lexp (run-with-store %store (lower-gexp exp))))
486 (and (match (lowered-gexp-inputs lexp)
487 ((input)
488 (eq? (derivation-input-derivation input) drv)))
489 (equal? (lowered-gexp-sexp lexp)
490 `(list ,item)))))
491
492(test-assertm "with-parameters for %current-system"
493 (mlet* %store-monad ((system -> (match (%current-system)
494 ("aarch64-linux" "x86_64-linux")
495 (_ "aarch64-linux")))
496 (drv (package->derivation coreutils system))
497 (obj -> (with-parameters ((%current-system system))
498 coreutils))
499 (result (lower-object obj)))
500 (return (string=? (derivation-file-name drv)
501 (derivation-file-name result)))))
502
503(test-assertm "with-parameters for %current-target-system"
504 (mlet* %store-monad ((target -> "riscv64-linux-gnu")
505 (drv (package->cross-derivation coreutils target))
506 (obj -> (with-parameters
507 ((%current-target-system target))
508 coreutils))
509 (result (lower-object obj)))
510 (return (string=? (derivation-file-name drv)
511 (derivation-file-name result)))))
512
513(test-assertm "with-parameters for %graft?"
514 (mlet* %store-monad ((replacement-pkg -> (package
515 (inherit %bootstrap-guile)
516 (name (string-upcase
517 (package-name
518 %bootstrap-guile)))))
519 (guile -> (package
520 (inherit %bootstrap-guile)
521 (replacement replacement-pkg)))
522 (drv0 (package->derivation %bootstrap-guile))
523 (drv1 (package->derivation replacement-pkg))
524 (obj0 -> (with-parameters ((%graft? #f))
525 guile))
526 (obj1 -> (with-parameters ((%graft? #t))
527 guile))
528 (result0 (lower-object obj0))
529 (result1 (lower-object obj1)))
530 (return (and (eq? drv0 result0)
531 (eq? drv1 result1)))))
532
533(test-assertm "delayed-object"
534 (let ((evaluated #f))
535 (mlet* %store-monad ((drv (package->derivation coreutils))
536 (obj -> (delayed-object
537 (begin
538 (set! evaluated #t)
539 coreutils)))
540 (first-evaluated -> evaluated)
541 (result (lower-object obj)))
542 (return (and (string=? (derivation-file-name drv)
543 (derivation-file-name result))
544 (not first-evaluated)
545 evaluated)))))
546
547(test-assert "with-parameters + file-append"
548 (let* ((system (match (%current-system)
549 ("aarch64-linux" "x86_64-linux")
550 (_ "aarch64-linux")))
551 (drv (package-derivation %store coreutils system))
552 (param (make-parameter 7))
553 (exp #~(here we go #$(with-parameters ((%current-system system)
554 (param 42))
555 (if (= (param) 42)
556 (file-append coreutils "/bin/touch")
557 %bootstrap-guile)))))
558 (match (gexp->sexp* exp)
559 (('here 'we 'go (? string? result))
560 (string=? result
561 (string-append (derivation->output-path drv)
562 "/bin/touch"))))))
563
564(test-assert "with-parameters + store item"
565 (let* ((file (add-text-to-store %store "hello.txt" "Hello, world!"))
566 (obj (with-parameters ((%current-system "aarch64-linux"))
567 file))
568 (lowered (run-with-store %store
569 (lower-object obj))))
570 (string=? lowered file)))
571
572(test-equal "let-system"
573 (list `(begin ,(%current-system) #t) '(system-binding)
574 'low '() '())
575 (let* ((exp #~(begin
576 #$(let-system system system)
577 #t))
578 (low (run-with-store %store (lower-gexp exp))))
579 (list (lowered-gexp-sexp low)
580 (match (gexp-inputs exp)
581 ((input)
582 (and (eq? (struct-vtable (gexp-input-thing input))
583 (@@ (guix gexp) <system-binding>))
584 (string=? (gexp-input-output input) "out")
585 '(system-binding)))
586 (x x))
587 'low
588 (lowered-gexp-inputs low)
589 (lowered-gexp-sources low))))
590
591(test-equal "let-system, target"
592 (list `(list ,(%current-system) #f)
593 `(list ,(%current-system) "aarch64-linux-gnu"))
594 (let ((exp #~(list #$@(let-system (system target)
595 (list system target)))))
596 (list (gexp->sexp* exp)
597 (gexp->sexp* exp "aarch64-linux-gnu"))))
598
599(test-equal "let-system, ungexp-native, target"
600 `(here it is: ,(%current-system) #f)
601 (let ((exp #~(here it is: #+@(let-system (system target)
602 (list system target)))))
603 (gexp->sexp* exp "aarch64-linux-gnu")))
604
605(test-equal "let-system, nested"
606 (list `(system* ,(string-append "qemu-system-" (%current-system))
607 "-m" "256")
608 '(system-binding))
609 (let ((exp #~(system*
610 #+(let-system (system target)
611 (file-append (@@ (gnu packages virtualization)
612 qemu)
613 "/bin/qemu-system-"
614 system))
615 "-m" "256")))
616 (list (match (gexp->sexp* exp)
617 (('system* command rest ...)
618 `(system* ,(and (string-prefix? (%store-prefix) command)
619 (basename command))
620 ,@rest))
621 (x x))
622 (match (gexp-inputs exp)
623 ((input)
624 (and (eq? (struct-vtable (gexp-input-thing input))
625 (@@ (guix gexp) <system-binding>))
626 (string=? (gexp-input-output input) "out")
627 (gexp-input-native? input)
628 '(system-binding)))
629 (x x)))))
630
631(test-assert "let-system in file-append"
632 (let ((mixed (file-append (let-system (system target)
633 (if (not target) grep sed))
634 "/bin"))
635 (grep (file-append grep "/bin"))
636 (sed (file-append sed "/bin")))
637 (and (equal? (gexp->sexp* #~(list #$mixed))
638 (gexp->sexp* #~(list #$grep)))
639 (equal? (gexp->sexp* #~(list #$mixed) "powerpc64le-linux-gnu")
640 (gexp->sexp* #~(list #$sed) "powerpc64le-linux-gnu")))))
641
642(test-assert "ungexp + ungexp-native"
643 (let* ((exp (gexp (list (ungexp-native %bootstrap-guile)
644 (ungexp coreutils)
645 (ungexp-native glibc)
646 (ungexp binutils))))
647 (target "mips64el-linux-gnu")
648 (guile (derivation->output-path
649 (package-derivation %store %bootstrap-guile)))
650 (cu (derivation->output-path
651 (package-cross-derivation %store coreutils target)))
652 (libc (derivation->output-path
653 (package-derivation %store glibc)))
654 (bu (derivation->output-path
655 (package-cross-derivation %store binutils target))))
656 (and (lset= equal?
657 `((,%bootstrap-guile "out" #t)
658 (,coreutils "out" #f)
659 (,glibc "out" #t)
660 (,binutils "out" #f))
661 (map gexp-input->tuple (gexp-inputs exp)))
662 (equal? `(list ,guile ,cu ,libc ,bu)
663 (gexp->sexp* exp target)))))
664
665(test-equal "ungexp + ungexp-native, nested"
666 `((,%bootstrap-guile "out" #f) (,coreutils "out" #t))
667 (let* ((exp (gexp (list (ungexp-native (gexp (ungexp coreutils)))
668 (ungexp %bootstrap-guile)))))
669 (map gexp-input->tuple (gexp-inputs exp))))
670
671(test-equal "ungexp + ungexp-native, nested, special mixture"
672 `((,coreutils "out" #t))
673
674 (let* ((foo (gexp (foo (ungexp-native coreutils))))
675 (exp (gexp (bar (ungexp foo)))))
676 (map gexp-input->tuple (gexp-inputs exp))))
677
678(test-assert "input list"
679 (let ((exp (gexp (display
680 '(ungexp (list %bootstrap-guile coreutils)))))
681 (guile (derivation->output-path
682 (package-derivation %store %bootstrap-guile)))
683 (cu (derivation->output-path
684 (package-derivation %store coreutils))))
685 (and (lset= equal?
686 `((,%bootstrap-guile "out" #f) (,coreutils "out" #f))
687 (map gexp-input->tuple (gexp-inputs exp)))
688 (equal? `(display '(,guile ,cu))
689 (gexp->sexp* exp)))))
690
691(test-assert "input list + ungexp-native"
692 (let* ((target "mips64el-linux-gnu")
693 (exp (gexp (display
694 (cons '(ungexp-native (list %bootstrap-guile coreutils))
695 '(ungexp (list glibc binutils))))))
696 (guile (derivation->output-path
697 (package-derivation %store %bootstrap-guile)))
698 (cu (derivation->output-path
699 (package-derivation %store coreutils)))
700 (xlibc (derivation->output-path
701 (package-cross-derivation %store glibc target)))
702 (xbu (derivation->output-path
703 (package-cross-derivation %store binutils target))))
704 (and (lset= equal?
705 `((,%bootstrap-guile "out" #t) (,coreutils "out" #t)
706 (,glibc "out" #f) (,binutils "out" #f))
707 (map gexp-input->tuple (gexp-inputs exp)))
708 (equal? `(display (cons '(,guile ,cu) '(,xlibc ,xbu)))
709 (gexp->sexp* exp target)))))
710
711(test-assert "input list splicing"
712 (let* ((inputs (list (gexp-input glibc "debug") %bootstrap-guile))
713 (outputs (list (derivation->output-path
714 (package-derivation %store glibc)
715 "debug")
716 (derivation->output-path
717 (package-derivation %store %bootstrap-guile))))
718 (exp (gexp (list (ungexp-splicing (cons (+ 2 3) inputs))))))
719 (and (lset= equal?
720 `((,glibc "debug" #f) (,%bootstrap-guile "out" #f))
721 (map gexp-input->tuple (gexp-inputs exp)))
722 (equal? (gexp->sexp* exp)
723 `(list ,@(cons 5 outputs))))))
724
725(test-assert "input list splicing + ungexp-native-splicing"
726 (let* ((inputs (list (gexp-input glibc "debug" #:native? #t)
727 %bootstrap-guile))
728 (exp (gexp (list (ungexp-native-splicing (cons (+ 2 3) inputs))))))
729 (and (lset= equal?
730 `((,glibc "debug" #t) (,%bootstrap-guile "out" #t))
731 (map gexp-input->tuple (gexp-inputs exp)))
732 (equal? (gexp->sexp* exp) ;native
733 (gexp->sexp* exp "mips64el-linux")))))
734
735(test-assert "gexp list splicing + ungexp-splicing"
736 (let* ((inner (gexp (ungexp-native glibc)))
737 (exp (gexp (list (ungexp-splicing (list inner))))))
738 (and (equal? `((,glibc "out" #t))
739 (map gexp-input->tuple (gexp-inputs exp)))
740 (equal? (gexp->sexp* exp) ;native
741 (gexp->sexp* exp "mips64el-linux")))))
742
743(test-equal "output list"
744 2
745 (let ((exp (gexp (begin (mkdir (ungexp output))
746 (mkdir (ungexp output "bar"))))))
747 (length (gexp-outputs exp)))) ;XXX: <output-ref> is private
748
749(test-assert "output list, combined gexps"
750 (let* ((exp0 (gexp (mkdir (ungexp output))))
751 (exp1 (gexp (mkdir (ungexp output "foo"))))
752 (exp2 (gexp (begin (display "hi!") (ungexp exp0) (ungexp exp1)))))
753 (and (lset= equal?
754 (append (gexp-outputs exp0) (gexp-outputs exp1))
755 (gexp-outputs exp2))
756 (= 2 (length (gexp-outputs exp2))))))
757
758(test-equal "output list, combined gexps, duplicate output"
759 1
760 (let* ((exp0 (gexp (mkdir (ungexp output))))
761 (exp1 (gexp (begin (mkdir (ungexp output)) (ungexp exp0))))
762 (exp2 (gexp (begin (mkdir (ungexp output)) (ungexp exp1)))))
763 (length (gexp-outputs exp2))))
764
765(test-assert "output list + ungexp-splicing list, combined gexps"
766 (let* ((exp0 (gexp (mkdir (ungexp output))))
767 (exp1 (gexp (mkdir (ungexp output "foo"))))
768 (exp2 (gexp (begin (display "hi!")
769 (ungexp-splicing (list exp0 exp1))))))
770 (and (lset= equal?
771 (append (gexp-outputs exp0) (gexp-outputs exp1))
772 (gexp-outputs exp2))
773 (= 2 (length (gexp-outputs exp2))))))
774
775(test-assertm "gexp->file"
776 (mlet* %store-monad ((exp -> (gexp (display (ungexp %bootstrap-guile))))
777 (guile (package-file %bootstrap-guile))
778 (sexp (gexp->sexp exp (%current-system) #f))
779 (drv (gexp->file "foo" exp
780 #:guile %bootstrap-guile))
781 (out -> (derivation->output-path drv))
782 (done (built-derivations (list drv)))
783 (refs (references* out)))
784 (return (and (equal? sexp (call-with-input-file out read))
785 (equal? (list guile) refs)))))
786
787(test-assertm "gexp->file + file-append"
788 (mlet* %store-monad ((exp -> #~#$(file-append %bootstrap-guile
789 "/bin/guile"))
790 (guile (package-file %bootstrap-guile))
791 (drv (gexp->file "foo" exp
792 #:guile %bootstrap-guile))
793 (out -> (derivation->output-path drv))
794 (done (built-derivations (list drv)))
795 (refs (references* out)))
796 (return (and (equal? (string-append guile "/bin/guile")
797 (call-with-input-file out read))
798 (equal? (list guile) refs)))))
799
800(test-assertm "gexp->file + #:splice?"
801 (mlet* %store-monad ((exp -> (list
802 #~(define foo 'bar)
803 #~(define guile #$%bootstrap-guile)))
804 (guile (package-file %bootstrap-guile))
805 (drv (gexp->file "splice" exp
806 #:splice? #t
807 #:guile %bootstrap-guile))
808 (out -> (derivation->output-path drv))
809 (done (built-derivations (list drv)))
810 (refs (references* out)))
811 (pk 'splice out)
812 (return (and (equal? `((define foo 'bar)
813 (define guile ,guile)
814 ,(call-with-input-string "" read))
815 (call-with-input-file out
816 (lambda (port)
817 (list (read port) (read port) (read port)))))
818 (equal? (list guile) refs)))))
819
820(test-assertm "gexp->derivation"
821 (mlet* %store-monad ((file (text-file "foo" "Hello, world!"))
822 (exp -> (gexp
823 (begin
824 (mkdir (ungexp output))
825 (chdir (ungexp output))
826 (symlink
827 (string-append (ungexp %bootstrap-guile)
828 "/bin/guile")
829 "foo")
830 (symlink (ungexp file)
831 (ungexp output "2nd")))))
832 (drv (gexp->derivation "foo" exp))
833 (out -> (derivation->output-path drv))
834 (out2 -> (derivation->output-path drv "2nd"))
835 (done (built-derivations (list drv)))
836 (refs (references* out))
837 (refs2 (references* out2))
838 (guile (package-file %bootstrap-guile "bin/guile")))
839 (return (and (string=? (readlink (string-append out "/foo")) guile)
840 (string=? (readlink out2) file)
841 (equal? refs (list (dirname (dirname guile))))
842 (equal? refs2 (list file))
843 (null? (derivation-properties drv))))))
844
845(test-assertm "gexp->derivation properties"
846 (mlet %store-monad ((drv (gexp->derivation "foo"
847 #~(mkdir #$output)
848 #:properties '((type . test)))))
849 (return (equal? '((type . test))
850 (derivation-properties drv)))))
851
852(test-assertm "gexp->derivation vs. grafts"
853 (mlet* %store-monad ((graft? (set-grafting #f))
854 (p0 -> (dummy-package "dummy"
855 (arguments
856 '(#:implicit-inputs? #f))))
857 (r -> (package (inherit p0) (name "DuMMY")))
858 (p1 -> (package (inherit p0) (replacement r)))
859 (exp0 -> (gexp (frob (ungexp p0) (ungexp output))))
860 (exp1 -> (gexp (frob (ungexp p1) (ungexp output))))
861 (void (set-guile-for-build %bootstrap-guile))
862 (drv0 (gexp->derivation "t" exp0 #:graft? #t))
863 (drv1 (gexp->derivation "t" exp1 #:graft? #t))
864 (drv1* (gexp->derivation "t" exp1 #:graft? #f))
865 (_ (set-grafting graft?)))
866 (return (and (not (string=? (derivation->output-path drv0)
867 (derivation->output-path drv1)))
868 (string=? (derivation->output-path drv0)
869 (derivation->output-path drv1*))))))
870
871(test-assertm "gexp->derivation, composed gexps"
872 (mlet* %store-monad ((exp0 -> (gexp (begin
873 (mkdir (ungexp output))
874 (chdir (ungexp output)))))
875 (exp1 -> (gexp (symlink
876 (string-append (ungexp %bootstrap-guile)
877 "/bin/guile")
878 "foo")))
879 (exp -> (gexp (begin (ungexp exp0) (ungexp exp1))))
880 (drv (gexp->derivation "foo" exp))
881 (out -> (derivation->output-path drv))
882 (done (built-derivations (list drv)))
883 (guile (package-file %bootstrap-guile "bin/guile")))
884 (return (string=? (readlink (string-append out "/foo"))
885 guile))))
886
887(test-assertm "gexp->derivation, default system"
888 ;; The default system should be the one at '>>=' time, not the one at
889 ;; invocation time. See <http://bugs.gnu.org/18002>.
890 (let ((system (%current-system))
891 (mdrv (parameterize ((%current-system "foobar64-linux"))
892 (gexp->derivation "foo"
893 (gexp
894 (mkdir (ungexp output)))))))
895 (mlet %store-monad ((drv mdrv))
896 (return (string=? system (derivation-system drv))))))
897
898(test-assertm "gexp->derivation, local-file"
899 (mlet* %store-monad ((file -> (search-path %load-path "guix.scm"))
900 (intd (interned-file file #:recursive? #f))
901 (local -> (local-file file))
902 (exp -> (gexp (begin
903 (stat (ungexp local))
904 (symlink (ungexp local)
905 (ungexp output)))))
906 (drv (gexp->derivation "local-file" exp)))
907 (mbegin %store-monad
908 (built-derivations (list drv))
909 (return (string=? (readlink (derivation->output-path drv))
910 intd)))))
911
912(test-assertm "gexp->derivation, cross-compilation"
913 (mlet* %store-monad ((target -> "mips64el-linux-gnu")
914 (exp -> (gexp (list (ungexp coreutils)
915 (ungexp output))))
916 (xdrv (gexp->derivation "foo" exp
917 #:target target))
918 (refs (references*
919 (derivation-file-name xdrv)))
920 (xcu (package->cross-derivation coreutils
921 target))
922 (cu (package->derivation coreutils)))
923 (return (and (member (derivation-file-name xcu) refs)
924 (not (member (derivation-file-name cu) refs))))))
925
926(test-assertm "gexp->derivation, ungexp-native"
927 (mlet* %store-monad ((target -> "mips64el-linux-gnu")
928 (exp -> (gexp (list (ungexp-native coreutils)
929 (ungexp output))))
930 (xdrv (gexp->derivation "foo" exp
931 #:target target))
932 (drv (gexp->derivation "foo" exp)))
933 (return (string=? (derivation-file-name drv)
934 (derivation-file-name xdrv)))))
935
936(test-assertm "gexp->derivation, ungexp + ungexp-native"
937 (mlet* %store-monad ((target -> "mips64el-linux-gnu")
938 (exp -> (gexp (list (ungexp-native coreutils)
939 (ungexp glibc)
940 (ungexp output))))
941 (xdrv (gexp->derivation "foo" exp
942 #:target target))
943 (refs (references*
944 (derivation-file-name xdrv)))
945 (xglibc (package->cross-derivation glibc target))
946 (cu (package->derivation coreutils)))
947 (return (and (member (derivation-file-name cu) refs)
948 (member (derivation-file-name xglibc) refs)))))
949
950(test-assertm "gexp->derivation, ungexp-native + composed gexps"
951 (mlet* %store-monad ((target -> "mips64el-linux-gnu")
952 (exp0 -> (gexp (list 1 2
953 (ungexp coreutils))))
954 (exp -> (gexp (list 0 (ungexp-native exp0))))
955 (xdrv (gexp->derivation "foo" exp
956 #:target target))
957 (drv (gexp->derivation "foo" exp)))
958 (return (string=? (derivation-file-name drv)
959 (derivation-file-name xdrv)))))
960
961(test-assertm "gexp->derivation, store copy"
962 (let ((build-one #~(call-with-output-file #$output
963 (lambda (port)
964 (display "This is the one." port))))
965 (build-two (lambda (one)
966 #~(begin
967 (mkdir #$output)
968 (symlink #$one (string-append #$output "/one"))
969 (call-with-output-file (string-append #$output "/two")
970 (lambda (port)
971 (display "This is the second one." port))))))
972 (build-drv
973 (with-imported-modules '((guix build store-copy)
974 (guix build syscalls)
975 (guix progress)
976 (guix records)
977 (guix sets)
978 (guix build utils))
979 #~(begin
980 (use-modules (guix build store-copy)
981 (guix build utils)
982 (srfi srfi-1))
983
984 (define (canonical-file? file)
985 ;; Copied from (guix tests).
986 (let ((st (lstat file)))
987 (or (not (string-prefix? (%store-directory) file))
988 (eq? 'symlink (stat:type st))
989 (and (= 1 (stat:mtime st))
990 (zero? (logand #o222 (stat:mode st)))))))
991
992 (mkdir #$output)
993 (populate-store '("graph") #$output
994 #:deduplicate? #f)
995
996 ;; Check whether 'populate-store' canonicalizes
997 ;; permissions and timestamps.
998 (unless (every canonical-file? (find-files #$output))
999 (error "not canonical!" #$output))))))
1000 (mlet* %store-monad ((one (gexp->derivation "one" build-one))
1001 (two (gexp->derivation "two" (build-two one)))
1002 (drv (gexp->derivation "store-copy" build-drv
1003 #:references-graphs
1004 `(("graph" ,two))))
1005 (ok? (built-derivations (list drv)))
1006 (out -> (derivation->output-path drv)))
1007 (let ((one (derivation->output-path one))
1008 (two (derivation->output-path two)))
1009 (return (and ok?
1010 (file-exists? (string-append out "/" one))
1011 (file-exists? (string-append out "/" two))
1012 (file-exists? (string-append out "/" two "/two"))
1013 (string=? (readlink (string-append out "/" two "/one"))
1014 one)))))))
1015
1016(test-assertm "imported-files"
1017 (mlet* %store-monad
1018 ((files -> `(("x" . ,(search-path %load-path "ice-9/q.scm"))
1019 ("a/b/c" . ,(search-path %load-path
1020 "guix/derivations.scm"))
1021 ("p/q" . ,(search-path %load-path "guix.scm"))
1022 ("p/z" . ,(search-path %load-path "guix/store.scm"))))
1023 (dir (imported-files files)))
1024 (mbegin %store-monad
1025 (return
1026 (every (match-lambda
1027 ((path . source)
1028 (equal? (call-with-input-file (string-append dir "/" path)
1029 get-bytevector-all)
1030 (call-with-input-file source
1031 get-bytevector-all))))
1032 files)))))
1033
1034(test-assertm "imported-files with file-like objects"
1035 (mlet* %store-monad ((plain -> (plain-file "foo" "bar!"))
1036 (q-scm -> (search-path %load-path "ice-9/q.scm"))
1037 (files -> `(("a/b/c" . ,q-scm)
1038 ("p/q" . ,plain)))
1039 (drv (imported-files files)))
1040 (mbegin %store-monad
1041 (built-derivations (list (pk 'drv drv)))
1042 (mlet %store-monad ((dir -> (derivation->output-path drv))
1043 (plain* (text-file "foo" "bar!"))
1044 (q-scm* (interned-file q-scm "c")))
1045 (return
1046 (and (file=? (string-append dir "/a/b/c") q-scm* stat)
1047 (file=? (string-append dir "/p/q") plain* stat)))))))
1048
1049(test-assert "imported-files does not create symlinks"
1050 ;; 'imported-files' should always produce a directory with regular files,
1051 ;; whether or not it's going through 'imported-files/derivation'.
1052 ;; See <https://issues.guix.gnu.org/73275>.
1053 (call-with-temporary-directory
1054 (lambda (directory)
1055 (symlink (search-path %load-path "guix/store.scm")
1056 (in-vicinity directory "store.scm"))
1057
1058 (run-with-store %store
1059 (mlet* %store-monad
1060 ((files1 -> `(("x" . ,(in-vicinity directory "store.scm"))))
1061 (files2 -> `(,@files1
1062 ("y" . ,(plain-file "foo.scm" "#t"))))
1063 (import1 (imported-files files1))
1064 (import2-drv (imported-files files2))
1065 (import2 -> (derivation->output-path import2-drv))
1066 (_ (built-derivations (list import2-drv))))
1067 (return (and (eq? (stat:type (lstat (in-vicinity import1 "x")))
1068 'regular)
1069 (eq? (stat:type (lstat (in-vicinity import2 "x")))
1070 'regular)
1071 (file=? (in-vicinity import1 "x")
1072 (search-path %load-path "guix/store.scm"))
1073 (file=? (in-vicinity import2 "x")
1074 (search-path %load-path "guix/store.scm")))))))))
1075
1076(test-equal "gexp-modules & ungexp"
1077 '((bar) (foo))
1078 ((@@ (guix gexp) gexp-modules)
1079 #~(foo #$(with-imported-modules '((foo)) #~+)
1080 #+(with-imported-modules '((bar)) #~-))))
1081
1082(test-equal "gexp-modules & ungexp-splicing"
1083 '((foo) (bar))
1084 ((@@ (guix gexp) gexp-modules)
1085 #~(foo #$@(list (with-imported-modules '((foo)) #~+)
1086 (with-imported-modules '((bar)) #~-)))))
1087
1088(test-assert "gexp-modules deletes duplicates" ;<https://bugs.gnu.org/32966>
1089 (let ((make-file (lambda ()
1090 ;; Use 'eval' to make sure we get an object that's not
1091 ;; 'eq?' nor 'equal?' due to the closures it embeds.
1092 (eval '(scheme-file "bar.scm" #~(define-module (bar))
1093 #:guile %bootstrap-guile)
1094 (current-module)))))
1095 (define result
1096 ((@@ (guix gexp) gexp-modules)
1097 (with-imported-modules `(((bar) => ,(make-file))
1098 ((bar) => ,(make-file))
1099 (foo) (foo))
1100 #~+)))
1101
1102 (match result
1103 (((('bar) '=> (? scheme-file?)) ('foo)) #t))))
1104
1105(test-equal "gexp-modules and literal Scheme object"
1106 '()
1107 (gexp-modules #t))
1108
1109(test-assert "gexp-modules, warning"
1110 (string-match "tests/gexp.scm:[0-9]+:[0-9]+: warning: \
1111importing.* \\(guix config\\) from the host"
1112 (call-with-output-string
1113 (lambda (port)
1114 (parameterize ((guix-warning-port port))
1115 (let* ((x (with-imported-modules '((guix config))
1116 #~(+ 1 2 3)))
1117 (y #~(+ 39 #$x)))
1118 (gexp-modules y)))))))
1119
1120(test-assertm "gexp->derivation #:modules"
1121 (mlet* %store-monad
1122 ((build -> #~(begin
1123 (use-modules (guix build utils))
1124 (mkdir-p (string-append #$output "/guile/guix/nix"))
1125 #t))
1126 (drv (gexp->derivation "test-with-modules" build
1127 #:modules '((guix build utils)))))
1128 (mbegin %store-monad
1129 (built-derivations (list drv))
1130 (let* ((p (derivation->output-path drv))
1131 (s (stat (string-append p "/guile/guix/nix"))))
1132 (return (eq? (stat:type s) 'directory))))))
1133
1134(test-assertm "gexp->derivation & with-imported-modules"
1135 ;; Same test as above, but using 'with-imported-modules'.
1136 (mlet* %store-monad
1137 ((build -> (with-imported-modules '((guix build utils))
1138 #~(begin
1139 (use-modules (guix build utils))
1140 (mkdir-p (string-append #$output "/guile/guix/nix"))
1141 #t)))
1142 (drv (gexp->derivation "test-with-modules" build)))
1143 (mbegin %store-monad
1144 (built-derivations (list drv))
1145 (let* ((p (derivation->output-path drv))
1146 (s (stat (string-append p "/guile/guix/nix"))))
1147 (return (eq? (stat:type s) 'directory))))))
1148
1149(test-assertm "gexp->derivation & nested with-imported-modules"
1150 (mlet* %store-monad
1151 ((build1 -> (with-imported-modules '((guix build utils))
1152 #~(begin
1153 (use-modules (guix build utils))
1154 (mkdir-p (string-append #$output "/guile/guix/nix"))
1155 #t)))
1156 (build2 -> (with-imported-modules '((guix build bournish))
1157 #~(begin
1158 (use-modules (guix build bournish)
1159 (system base compile))
1160 #+build1
1161 (call-with-output-file (string-append #$output "/b")
1162 (lambda (port)
1163 (write
1164 (read-and-compile (open-input-string "cd /foo")
1165 #:from %bournish-language
1166 #:to 'scheme)
1167 port))))))
1168 (drv (gexp->derivation "test-with-modules" build2)))
1169 (mbegin %store-monad
1170 (built-derivations (list drv))
1171 (let* ((p (derivation->output-path drv))
1172 (s (stat (string-append p "/guile/guix/nix")))
1173 (b (string-append p "/b")))
1174 (return (and (eq? (stat:type s) 'directory)
1175 (equal? '(chdir "/foo")
1176 (call-with-input-file b read))))))))
1177
1178(test-assertm "gexp->derivation & with-imported-module & computed module"
1179 (mlet* %store-monad
1180 ((module -> (scheme-file "x" #~(;; splice!
1181 (define-module (foo bar)
1182 #:export (the-answer))
1183
1184 (define the-answer 42))
1185 #:splice? #t
1186 #:guile %bootstrap-guile))
1187 (build -> (with-imported-modules `(((foo bar) => ,module)
1188 (guix build utils))
1189 #~(begin
1190 (use-modules (guix build utils)
1191 (foo bar))
1192 mkdir-p
1193 (call-with-output-file #$output
1194 (lambda (port)
1195 (write the-answer port))))))
1196 (drv (gexp->derivation "thing" build))
1197 (out -> (derivation->output-path drv)))
1198 (mbegin %store-monad
1199 (built-derivations (list drv))
1200 (return (= 42 (call-with-input-file out read))))))
1201
1202(test-equal "gexp-extensions & ungexp"
1203 (list sed grep)
1204 ((@@ (guix gexp) gexp-extensions)
1205 #~(foo #$(with-extensions (list grep) #~+)
1206 #+(with-extensions (list sed) #~-))))
1207
1208(test-equal "gexp-extensions & ungexp-splicing"
1209 (list grep sed)
1210 ((@@ (guix gexp) gexp-extensions)
1211 #~(foo #$@(list (with-extensions (list grep) #~+)
1212 (with-imported-modules '((foo))
1213 (with-extensions (list sed) #~-))))))
1214
1215(test-equal "gexp-extensions and literal Scheme object"
1216 '()
1217 ((@@ (guix gexp) gexp-extensions) #t))
1218
1219(test-assertm "gexp->derivation & with-extensions"
1220 ;; Create a fake Guile extension and make sure it is accessible both to the
1221 ;; imported modules and to the derivation build script.
1222 (mlet* %store-monad
1223 ((extension -> %extension-package)
1224 (module -> (scheme-file "x" #~( ;; splice!
1225 (define-module (foo)
1226 #:use-module (hg2g)
1227 #:export (multiply))
1228
1229 (define (multiply x)
1230 (* the-answer x)))
1231 #:splice? #t
1232 #:guile %bootstrap-guile))
1233 (build -> (with-extensions (list extension)
1234 (with-imported-modules `((guix build utils)
1235 ((foo) => ,module))
1236 #~(begin
1237 (use-modules (guix build utils)
1238 (hg2g) (foo))
1239 (call-with-output-file #$output
1240 (lambda (port)
1241 (write (list the-answer (multiply 2))
1242 port)))))))
1243 (drv (gexp->derivation "thingie" build
1244 #:effective-version
1245 (bootstrap-guile-effective-version)))
1246 (out -> (derivation->output-path drv)))
1247 (mbegin %store-monad
1248 (built-derivations (list drv))
1249 (return (equal? '(42 84) (call-with-input-file out read))))))
1250
1251(test-assertm "lower-gexp"
1252 (mlet* %store-monad
1253 ((extension -> %extension-package)
1254 (extension-drv (package->derivation %extension-package))
1255 (coreutils-drv (package->derivation coreutils))
1256 (exp -> (with-extensions (list extension)
1257 (with-imported-modules `((guix build utils))
1258 #~(begin
1259 (use-modules (guix build utils)
1260 (hg2g))
1261 #$coreutils:debug
1262 mkdir-p
1263 the-answer))))
1264 (lexp (lower-gexp exp
1265 #:effective-version
1266 (bootstrap-guile-effective-version))))
1267 (define (matching-input drv output)
1268 (lambda (input)
1269 (and (eq? (derivation-input-derivation input) drv)
1270 (equal? (derivation-input-sub-derivations input)
1271 (list output)))))
1272
1273 (mbegin %store-monad
1274 (return (and (find (matching-input extension-drv "out")
1275 (lowered-gexp-inputs (pk 'lexp lexp)))
1276 (find (matching-input coreutils-drv "debug")
1277 (lowered-gexp-inputs lexp))
1278 (member (string-append
1279 (derivation->output-path extension-drv)
1280 "/share/guile/site/"
1281 (bootstrap-guile-effective-version))
1282 (lowered-gexp-load-path lexp))
1283 (= 2 (length (lowered-gexp-load-path lexp)))
1284 (member (string-append
1285 (derivation->output-path extension-drv)
1286 "/lib/guile/"
1287 (bootstrap-guile-effective-version)
1288 "/site-ccache")
1289 (lowered-gexp-load-compiled-path lexp))
1290 (= 2 (length (lowered-gexp-load-compiled-path lexp)))
1291 (eq? (derivation-input-derivation (lowered-gexp-guile lexp))
1292 (%guile-for-build)))))))
1293
1294(test-assertm "lower-gexp, raw-derivation-file"
1295 (mlet* %store-monad ((thing -> (program-file "prog" #~(display "hi!")))
1296 (exp -> #~(list #$(raw-derivation-file thing)))
1297 (drv (lower-object thing))
1298 (lexp (lower-gexp
1299 exp
1300 #:effective-version
1301 (bootstrap-guile-effective-version))))
1302 (return (and (equal? `(list ,(derivation-file-name drv))
1303 (lowered-gexp-sexp lexp))
1304 (equal? (list (derivation-file-name drv))
1305 (lowered-gexp-sources lexp))
1306 (null? (lowered-gexp-inputs lexp))))))
1307
1308(test-eq "lower-gexp, non-self-quoting input"
1309 +
1310 (guard (c ((gexp-input-error? c)
1311 (gexp-error-invalid-input c)))
1312 (run-with-store %store
1313 (lower-gexp #~(foo #$+)))))
1314
1315(test-equal "lower-gexp, character literal"
1316 '(#\+)
1317 (lowered-gexp-sexp
1318 (run-with-store %store
1319 (lower-gexp #~(#\+)))))
1320
1321(let* ((g #~#$*unspecified*)
1322 (loc (current-source-location)) ;keep this alignment!
1323 (g-loc (source-properties->location
1324 `((line . ,(- (assq-ref loc 'line) 1))
1325 ,@(alist-delete 'line loc)))))
1326 (test-equal "lower-gexp, invalid input location"
1327 g-loc
1328 (guard (c ((and (gexp-input-error? c) (error-location? c))
1329 (error-location c)))
1330 (run-with-store %store
1331 (lower-gexp g)))))
1332
1333(test-assertm "gexp->derivation #:references-graphs"
1334 (mlet* %store-monad
1335 ((one (text-file "one" (random-text)))
1336 (two (gexp->derivation "two"
1337 #~(symlink #$one #$output:chbouib)))
1338 (build -> (with-imported-modules '((guix build store-copy)
1339 (guix progress)
1340 (guix records)
1341 (guix sets)
1342 (guix build utils))
1343 #~(begin
1344 (use-modules (guix build store-copy))
1345 (with-output-to-file #$output
1346 (lambda ()
1347 (write (map store-info-item
1348 (call-with-input-file "guile"
1349 read-reference-graph)))))
1350 (with-output-to-file #$output:one
1351 (lambda ()
1352 (write (map store-info-item
1353 (call-with-input-file "one"
1354 read-reference-graph)))))
1355 (with-output-to-file #$output:two
1356 (lambda ()
1357 (write (map store-info-item
1358 (call-with-input-file "two"
1359 read-reference-graph))))))))
1360 (drv (gexp->derivation "ref-graphs" build
1361 #:references-graphs `(("one" ,one)
1362 ("two" ,two "chbouib")
1363 ("guile" ,%bootstrap-guile))))
1364 (ok? (built-derivations (list drv)))
1365 (guile-drv (package->derivation %bootstrap-guile))
1366 (bash (interned-file (search-bootstrap-binary "bash"
1367 (%current-system))
1368 "bash" #:recursive? #t))
1369 (g-one -> (derivation->output-path drv "one"))
1370 (g-two -> (derivation->output-path drv "two"))
1371 (g-guile -> (derivation->output-path drv)))
1372 (return (and ok?
1373 (equal? (call-with-input-file g-one read) (list one))
1374 (lset= string=?
1375 (call-with-input-file g-two read)
1376 (list one (derivation->output-path two "chbouib")))
1377
1378 ;; Note: %BOOTSTRAP-GUILE depends on the bootstrap Bash.
1379 (lset= string=?
1380 (call-with-input-file g-guile read)
1381 (list (derivation->output-path guile-drv) bash))))))
1382
1383(test-assertm "gexp->derivation #:references-graphs cross-compilation"
1384 ;; The objects passed in #:references-graphs implicitly refer to
1385 ;; cross-compiled derivations. Make sure this is the case.
1386 (mlet* %store-monad ((drv1 (lower-object coreutils (%current-system)
1387 #:target "i586-pc-gnu"))
1388 (drv2 (lower-object coreutils (%current-system)
1389 #:target #f))
1390 (drv3 (gexp->derivation "three"
1391 #~(symlink #$coreutils #$output)
1392 #:target "i586-pc-gnu"
1393 #:references-graphs
1394 `(("coreutils" ,coreutils))))
1395 (refs (references* (derivation-file-name drv3))))
1396 (return (and (member (derivation-file-name drv1) refs)
1397 (not (member (derivation-file-name drv2) refs))))))
1398
1399(test-assertm "gexp->derivation #:allowed-references"
1400 (mlet %store-monad ((drv (gexp->derivation "allowed-refs"
1401 #~(begin
1402 (mkdir #$output)
1403 (chdir #$output)
1404 (symlink #$output "self")
1405 (symlink #$%bootstrap-guile
1406 "guile"))
1407 #:allowed-references
1408 (list "out" %bootstrap-guile))))
1409 (built-derivations (list drv))))
1410
1411(test-assertm "gexp->derivation #:allowed-references, specific output"
1412 (mlet* %store-monad ((in (gexp->derivation "thing"
1413 #~(begin
1414 (mkdir #$output:ok)
1415 (mkdir #$output:not-ok))))
1416 (drv (gexp->derivation "allowed-refs"
1417 #~(begin
1418 (pk #$in:not-ok)
1419 (mkdir #$output)
1420 (chdir #$output)
1421 (symlink #$output "self")
1422 (symlink #$in:ok "ok"))
1423 #:allowed-references
1424 (list "out"
1425 (gexp-input in "ok")))))
1426 (built-derivations (list drv))))
1427
1428(test-assert "gexp->derivation #:allowed-references, disallowed"
1429 (let ((drv (run-with-store %store
1430 (gexp->derivation "allowed-refs"
1431 #~(begin
1432 (mkdir #$output)
1433 (chdir #$output)
1434 (symlink #$%bootstrap-guile "guile"))
1435 #:allowed-references '()))))
1436 (guard (c ((store-protocol-error? c) #t))
1437 (build-derivations %store (list drv))
1438 #f)))
1439
1440(test-assertm "gexp->derivation #:disallowed-references, allowed"
1441 (mlet %store-monad ((drv (gexp->derivation "disallowed-refs"
1442 #~(begin
1443 (mkdir #$output)
1444 (chdir #$output)
1445 (symlink #$output "self")
1446 (symlink #$%bootstrap-guile
1447 "guile"))
1448 #:disallowed-references '())))
1449 (built-derivations (list drv))))
1450
1451
1452(test-assert "gexp->derivation #:disallowed-references"
1453 (let ((drv (run-with-store %store
1454 (gexp->derivation "disallowed-refs"
1455 #~(begin
1456 (mkdir #$output)
1457 (chdir #$output)
1458 (symlink #$%bootstrap-guile "guile"))
1459 #:disallowed-references (list %bootstrap-guile)))))
1460 (guard (c ((store-protocol-error? c) #t))
1461 (build-derivations %store (list drv))
1462 #f)))
1463
1464(define shebang
1465 (string-append "#!" (derivation->output-path (%guile-for-build))
1466 "/bin/guile --no-auto-compile"))
1467
1468;; If we're going to hit the silly shebang limit (128 chars on Linux-based
1469;; systems), then skip the following test.
1470(test-skip (if (> (string-length shebang) 127) 2 0))
1471
1472(test-assertm "gexp->script"
1473 (mlet* %store-monad ((n -> (random (expt 2 50)))
1474 (exp -> (gexp
1475 (system*
1476 (string-append (ungexp %bootstrap-guile)
1477 "/bin/guile")
1478 "-c" (object->string
1479 '(display (expt (ungexp n) 2))))))
1480 (drv (gexp->script "guile-thing" exp
1481 #:guile %bootstrap-guile))
1482 (out -> (derivation->output-path drv))
1483 (done (built-derivations (list drv))))
1484 (let* ((pipe (open-input-pipe out))
1485 (str (get-string-all pipe)))
1486 (return (and (zero? (close-pipe pipe))
1487 (= (expt n 2) (string->number str)))))))
1488
1489(test-assert "gexp->script #:module-path"
1490 (call-with-temporary-directory
1491 (lambda (directory)
1492 (define str
1493 "Fake (guix base32) module!")
1494
1495 (mkdir (string-append directory "/guix"))
1496 (call-with-output-file (string-append directory "/guix/base32.scm")
1497 (lambda (port)
1498 (write `(begin (define-module (guix base32))
1499 (define-public %fake! ,str))
1500 port)))
1501
1502 (run-with-store %store
1503 (mlet* %store-monad ((exp -> (with-imported-modules '((guix base32))
1504 (gexp (begin
1505 (use-modules (guix base32))
1506 (write (list %load-path
1507 %fake!))))))
1508 (drv (gexp->script "guile-thing" exp
1509 #:guile %bootstrap-guile
1510 #:module-path (list directory)))
1511 (out -> (derivation->output-path drv))
1512 (done (built-derivations (list drv))))
1513 (let* ((pipe (open-input-pipe out))
1514 (data (read pipe)))
1515 (return (and (zero? (close-pipe pipe))
1516 (match data
1517 ((load-path str*)
1518 (and (string=? str* str)
1519 (not (member directory load-path)))))))))))))
1520
1521(test-assertm "program-file"
1522 (let* ((n (random (expt 2 50)))
1523 (exp (with-imported-modules '((guix build utils))
1524 (gexp (begin
1525 (use-modules (guix build utils))
1526 (display (ungexp n))))))
1527 (file (program-file "program" exp
1528 #:guile %bootstrap-guile)))
1529 (mlet* %store-monad ((drv (lower-object file))
1530 (out -> (derivation->output-path drv)))
1531 (mbegin %store-monad
1532 (built-derivations (list drv))
1533 (let* ((pipe (open-input-pipe out))
1534 (str (get-string-all pipe)))
1535 (return (and (zero? (close-pipe pipe))
1536 (= n (string->number str)))))))))
1537
1538(test-assert "program-file #:module-path"
1539 (call-with-temporary-directory
1540 (lambda (directory)
1541 (define text (random-text))
1542
1543 (call-with-output-file (string-append directory "/stupid-module.scm")
1544 (lambda (port)
1545 (write `(begin (define-module (stupid-module))
1546 (define-public %stupid-thing ,text))
1547 port)))
1548
1549 (let* ((exp (with-imported-modules '((stupid-module))
1550 (gexp (begin
1551 (use-modules (stupid-module))
1552 (display %stupid-thing)))))
1553 (file (program-file "program" exp
1554 #:guile %bootstrap-guile
1555 #:module-path (list directory))))
1556 (run-with-store %store
1557 (mlet* %store-monad ((drv (lower-object file))
1558 (out -> (derivation->output-path drv)))
1559 (mbegin %store-monad
1560 (built-derivations (list drv))
1561 (let* ((pipe (open-input-pipe out))
1562 (str (get-string-all pipe)))
1563 (return (and (zero? (close-pipe pipe))
1564 (string=? text str)))))))))))
1565
1566(test-assertm "program-file & with-extensions"
1567 (let* ((exp (with-extensions (list %extension-package)
1568 (gexp (begin
1569 (use-modules (hg2g))
1570 (display the-answer)))))
1571 (file (program-file "program" exp
1572 #:guile %bootstrap-guile)))
1573 (mlet* %store-monad ((drv (lower-object file))
1574 (out -> (derivation->output-path drv)))
1575 (mbegin %store-monad
1576 (built-derivations (list drv))
1577 (let* ((pipe (open-input-pipe out))
1578 (str (get-string-all pipe)))
1579 (return (and (zero? (close-pipe pipe))
1580 (= 42 (string->number str)))))))))
1581
1582(test-assertm "program-file #:system"
1583 (let* ((exp (with-imported-modules '((guix build utils))
1584 (gexp (begin
1585 (use-modules (guix build utils))
1586 (display "hi!")))))
1587 (system (if (string=? (%current-system) "x86_64-linux")
1588 "armhf-linux"
1589 "x86_64-linux"))
1590 (file (program-file "program" exp)))
1591 (mlet %store-monad ((drv (lower-object file system)))
1592 (return (and (string=? (derivation-system drv) system)
1593 (find (lambda (input)
1594 (let ((drv (pk (derivation-input-derivation input))))
1595 (and (string=? (derivation-name drv)
1596 "module-import-compiled")
1597 (string=? (derivation-system drv)
1598 system))))
1599 (derivation-inputs drv)))))))
1600
1601(test-assertm "scheme-file"
1602 (let* ((text (plain-file "foo" "Hello, world!"))
1603 (scheme (scheme-file "bar" #~(list "foo" #$text)
1604 #:guile %bootstrap-guile)))
1605 (mlet* %store-monad ((drv (lower-object scheme))
1606 (text (lower-object text))
1607 (out -> (derivation->output-path drv)))
1608 (mbegin %store-monad
1609 (built-derivations (list drv))
1610 (mlet %store-monad ((refs (references* out)))
1611 (return (and (equal? refs (list text))
1612 (equal? `(list "foo" ,text)
1613 (call-with-input-file out read)))))))))
1614
1615(test-assertm "raw-derivation-file"
1616 (let* ((exp #~(let ((drv #$(raw-derivation-file coreutils)))
1617 (when (file-exists? drv)
1618 (symlink drv #$output)))))
1619 (mlet* %store-monad ((dep (lower-object coreutils))
1620 (drv (gexp->derivation "drv-ref" exp))
1621 (out -> (derivation->output-path drv)))
1622 (mbegin %store-monad
1623 (built-derivations (list drv))
1624 (mlet %store-monad ((refs (references* out)))
1625 (return (and (member (derivation-file-name dep)
1626 (derivation-sources drv))
1627 (not (member (derivation-file-name dep)
1628 (map derivation-input-path
1629 (derivation-inputs drv))))
1630 (equal? (readlink out) (derivation-file-name dep))
1631 (equal? refs (list (derivation-file-name dep))))))))))
1632
1633(test-assert "text-file*"
1634 (run-with-store %store
1635 (mlet* %store-monad
1636 ((drv (package->derivation %bootstrap-guile))
1637 (guile -> (derivation->output-path drv))
1638 (file (text-file "bar" "This is bar."))
1639 (text (text-file* "foo"
1640 %bootstrap-guile "/bin/guile "
1641 (gexp-input %bootstrap-guile "out") "/bin/guile "
1642 drv "/bin/guile "
1643 file))
1644 (done (built-derivations (list text)))
1645 (out -> (derivation->output-path text))
1646 (refs (references* out)))
1647 ;; Make sure we get the right references and the right content.
1648 (return (and (lset= string=? refs (list guile file))
1649 (equal? (call-with-input-file out get-string-all)
1650 (string-append guile "/bin/guile "
1651 guile "/bin/guile "
1652 guile "/bin/guile "
1653 file)))))
1654 #:guile-for-build (package-derivation %store %bootstrap-guile)))
1655
1656(test-assertm "mixed-text-file"
1657 (mlet* %store-monad ((file -> (mixed-text-file "mixed"
1658 #:guile %bootstrap-guile
1659 "export PATH="
1660 %bootstrap-guile "/bin"))
1661 (drv (lower-object file))
1662 (out -> (derivation->output-path drv))
1663 (guile-drv (package->derivation %bootstrap-guile))
1664 (guile -> (derivation->output-path guile-drv)))
1665 (mbegin %store-monad
1666 (built-derivations (list drv))
1667 (mlet %store-monad ((refs (references* out)))
1668 (return (and (string=? (string-append "export PATH=" guile "/bin")
1669 (call-with-input-file out get-string-all))
1670 (equal? refs (list guile))))))))
1671
1672(test-assertm "file-union"
1673 (mlet* %store-monad ((union -> (file-union "union"
1674 `(("a" ,(plain-file "a" "1"))
1675 ("b/c/d" ,(plain-file "d" "2"))
1676 ("e" ,(plain-file "e" "3")))
1677 #:guile %bootstrap-guile))
1678 (drv (lower-object union))
1679 (out -> (derivation->output-path drv)))
1680 (define (contents=? file str)
1681 (string=? (call-with-input-file (string-append out "/" file)
1682 get-string-all)
1683 str))
1684
1685 (mbegin %store-monad
1686 (built-derivations (list drv))
1687 (return (and (contents=? "a" "1")
1688 (contents=? "b/c/d" "2")
1689 (contents=? "e" "3"))))))
1690
1691(test-assert "gexp->derivation vs. %current-target-system"
1692 (let ((mval (gexp->derivation "foo"
1693 #~(begin
1694 (mkdir #$output)
1695 (foo #+gnu-make))
1696 #:target #f)))
1697 ;; The value of %CURRENT-TARGET-SYSTEM at bind-time should have no
1698 ;; influence.
1699 (parameterize ((%current-target-system "fooooo"))
1700 (derivation? (run-with-store %store mval)))))
1701
1702(test-assertm "lower-object"
1703 (mlet %store-monad ((drv1 (lower-object %bootstrap-guile))
1704 (drv2 (lower-object (package-source coreutils)))
1705 (item (lower-object (plain-file "foo" "Hello!"))))
1706 (return (and (derivation? drv1) (derivation? drv2)
1707 (store-path? item)))))
1708
1709(test-assertm "lower-object, computed-file"
1710 (let* ((text (plain-file "foo" "Hello!"))
1711 (exp #~(begin
1712 (mkdir #$output)
1713 (symlink #$%bootstrap-guile
1714 (string-append #$output "/guile"))
1715 (symlink #$text (string-append #$output "/text"))))
1716 (computed (computed-file "computed" exp
1717 #:guile %bootstrap-guile)))
1718 (mlet* %store-monad ((text (lower-object text))
1719 (guile-drv (lower-object %bootstrap-guile))
1720 (comp-drv (lower-object computed))
1721 (comp -> (derivation->output-path comp-drv)))
1722 (mbegin %store-monad
1723 (built-derivations (list comp-drv))
1724 (return (and (string=? (readlink (string-append comp "/guile"))
1725 (derivation->output-path guile-drv))
1726 (string=? (readlink (string-append comp "/text"))
1727 text)))))))
1728
1729(test-assert "lower-object, computed-file + grafts"
1730 ;; The reference graph should refer to grafted packages when grafts are
1731 ;; enabled. See <https://issues.guix.gnu.org/50676>.
1732 (let* ((base (package
1733 (inherit (dummy-package "trivial"))
1734 (build-system trivial-build-system)
1735 (arguments
1736 `(#:guile ,%bootstrap-guile
1737 #:builder (mkdir %output)))))
1738 (pkg (package
1739 (inherit base)
1740 (version "1.1")
1741 (replacement (package
1742 (inherit base)
1743 (version "9.9")))))
1744 (exp #~(begin
1745 (use-modules (ice-9 rdelim))
1746 (let ((item (call-with-input-file "graph" read-line)))
1747 (call-with-output-file #$output
1748 (lambda (port)
1749 (display item port))))))
1750 (computed (computed-file "computed" exp
1751 #:options
1752 `(#:references-graphs (("graph" ,pkg)))
1753 #:guile %bootstrap-guile))
1754 (drv0 (package-derivation %store pkg #:graft? #t))
1755 (drv1 (parameterize ((%graft? #t))
1756 (run-with-store %store
1757 (lower-object computed)))))
1758 (build-derivations %store (list drv1))
1759
1760 ;; The graph obtained in COMPUTED should refer to the grafted version of
1761 ;; PKG, not to PKG itself.
1762 (string=? (call-with-input-file (derivation->output-path drv1)
1763 get-string-all)
1764 (derivation->output-path drv0))))
1765
1766(test-equal "lower-object, computed-file, #:system"
1767 '("mips64el-linux")
1768 (run-with-store %store
1769 (let* ((exp #~(symlink #$coreutils #$output))
1770 (computed (computed-file "computed" exp
1771 #:guile %bootstrap-guile)))
1772 ;; Make sure that the SYSTEM argument to 'lower-object' is honored.
1773 (mlet* %store-monad ((drv (lower-object computed "mips64el-linux"))
1774 (refs (references* (derivation-file-name drv))))
1775 (return (delete-duplicates
1776 (filter-map (lambda (file)
1777 (and (string-suffix? ".drv" file)
1778 (let ((drv (read-derivation-from-file
1779 file)))
1780 (derivation-system drv))))
1781 (cons (derivation-file-name drv)
1782 refs))))))))
1783
1784(test-assertm "lower-object, computed-file, #:target"
1785 (let* ((target "i586-pc-gnu")
1786 (computed (computed-file "computed-cross"
1787 #~(symlink #$coreutils output)
1788 #:guile (default-guile))))
1789 ;; When lowered to TARGET, the derivation of COMPUTED should run natively,
1790 ;; using a native Guile, but it should refer to the target COREUTILS.
1791 (mlet* %store-monad ((drv (lower-object computed (%current-system)
1792 #:target target))
1793 (refs (references* (derivation-file-name drv)))
1794 (guile (lower-object (default-guile)
1795 (%current-system)
1796 #:target #f))
1797 (cross (lower-object coreutils #:target target))
1798 (native (lower-object coreutils #:target #f)))
1799 (return (and (string=? (derivation-system (pk 'drv drv)) (%current-system))
1800 (string=? (derivation-builder drv)
1801 (string-append (derivation->output-path guile)
1802 "/bin/guile"))
1803 (not (member (derivation-file-name native) refs))
1804 (member (derivation-file-name cross) refs))))))
1805
1806(test-assertm "lower-object, with-transformation"
1807 (mlet* %store-monad ((file -> (computed-file "coreutils-transformed"
1808 #~(symlink #$coreutils
1809 #$output)
1810 #:guile %bootstrap-guile))
1811 (drv (with-transformation (lambda (obj)
1812 (if (eq? obj coreutils)
1813 grep
1814 obj))
1815 (lower-object file)))
1816 (bad (lower-object coreutils))
1817 (good (lower-object grep))
1818 (refs (references* (derivation-file-name drv))))
1819 (return (and (member (derivation-file-name good) refs)
1820 (not (member (derivation-file-name bad) refs))))))
1821
1822(test-assertm "lower-object, with-transformation, file-append"
1823 (mlet* %store-monad ((file -> (computed-file "coreutils-transformed"
1824 #~(symlink
1825 #$(file-append coreutils
1826 "/bin/true")
1827 #$output)
1828 #:guile %bootstrap-guile))
1829 (drv1 (with-transformation (lambda (obj)
1830 (if (eq? obj coreutils)
1831 coreutils-minimal
1832 obj))
1833 (lower-object file)))
1834 (drv2 (lower-object file)) ;cache must be invalidated
1835 (bad (lower-object coreutils))
1836 (good (lower-object coreutils-minimal))
1837 (refs (references* (derivation-file-name drv1))))
1838 (return (and (member (derivation-file-name good) refs)
1839 (not (member (derivation-file-name bad) refs))))))
1840
1841(test-assertm "lower-object, with-transformation, list"
1842 (mlet* %store-monad ((file -> (computed-file "coreutils-transformed"
1843 #~(symlink
1844 (car '#$(list coreutils))
1845 #$output)
1846 #:guile %bootstrap-guile))
1847 (drv (with-transformation (lambda (obj)
1848 (if (eq? obj coreutils)
1849 grep
1850 obj))
1851 (lower-object file)))
1852 (bad (lower-object coreutils))
1853 (good (lower-object grep))
1854 (refs (references* (derivation-file-name drv))))
1855 (return (and (member (derivation-file-name good) refs)
1856 (not (member (derivation-file-name bad) refs))))))
1857
1858(test-assertm "references-file"
1859 (let* ((exp #~(symlink #$%bootstrap-guile #$output))
1860 (computed (computed-file "computed" exp
1861 #:guile %bootstrap-guile))
1862 (refs (references-file computed "refs"
1863 #:guile %bootstrap-guile)))
1864 (mlet* %store-monad ((drv0 (lower-object %bootstrap-guile))
1865 (drv1 (lower-object computed))
1866 (drv2 (lower-object refs)))
1867 (mbegin %store-monad
1868 (built-derivations (list drv2))
1869 (mlet %store-monad ((refs ((store-lift requisites)
1870 (list (derivation->output-path drv1)))))
1871 (return (lset= string=?
1872 (call-with-input-file (derivation->output-path drv2)
1873 read)
1874 refs)))))))
1875
1876(test-assertm "references-file, non-default output"
1877 (let* ((exp #~(begin
1878 (mkdir #$output)
1879 (symlink #$%bootstrap-guile #$output:extra)))
1880 (computed (computed-file "computed" exp
1881 #:guile %bootstrap-guile))
1882 (refs1 (references-file computed
1883 #:guile %bootstrap-guile))
1884 ;; Wrap COMPUTE in 'gexp-input' to get the "extra" output.
1885 (refs2 (references-file (gexp-input computed "extra")
1886 #:guile %bootstrap-guile)))
1887 (mlet* %store-monad ((drv0 (lower-object %bootstrap-guile))
1888 (drv1 (lower-object computed))
1889 (drv2 (lower-object refs2))
1890 (drv3 (lower-object refs1)))
1891 (mbegin %store-monad
1892 (built-derivations (list drv2 drv3))
1893 (mlet %store-monad ((refs ((store-lift requisites)
1894 (list (derivation->output-path
1895 drv1 "extra")))))
1896 (return
1897 (and (lset= string=?
1898 (call-with-input-file (derivation->output-path drv2)
1899 read)
1900 refs)
1901 (lset= string=?
1902 (call-with-input-file (derivation->output-path drv3)
1903 read)
1904 (list (derivation->output-path drv1))))))))))
1905
1906(test-assert "lower-object & gexp-input-error?"
1907 (guard (c ((gexp-input-error? c)
1908 (gexp-error-invalid-input c)))
1909 (run-with-store %store
1910 (lower-object (current-module))
1911 #:guile-for-build (%guile-for-build))))
1912
1913(test-assert "printer"
1914 (string-match "^#<gexp \\(string-append .*#<package coreutils.*\
1915 \"/bin/uname\"\\) [[:graph:]]+tests/gexp\\.scm:[0-9]+:[0-9]+ [[:xdigit:]]+>$"
1916 (with-output-to-string
1917 (lambda ()
1918 (write
1919 (gexp (string-append (ungexp coreutils)
1920 "/bin/uname")))))))
1921
1922(test-assert "printer vs. ungexp-splicing"
1923 (string-match "^#<gexp .* [[:xdigit:]]+>$"
1924 (with-output-to-string
1925 (lambda ()
1926 ;; #~(begin #$@#~())
1927 (write
1928 (gexp (begin (ungexp-splicing (gexp ())))))))))
1929
1930(test-equal "sugar"
1931 '(gexp (foo (ungexp bar) (ungexp baz "out")
1932 (ungexp (chbouib 42))
1933 (ungexp-splicing (list x y z))
1934 (ungexp-native foo) (ungexp-native foo "out")
1935 (ungexp-native (chbouib 42))
1936 (ungexp-native-splicing (list x y z))))
1937 '#~(foo #$bar #$baz:out #$(chbouib 42) #$@(list x y z)
1938 #+foo #+foo:out #+(chbouib 42) #+@(list x y z)))
1939
1940(test-assertm "gexp->file, cross-compilation"
1941 (mlet* %store-monad ((target -> "aarch64-linux-gnu")
1942 (exp -> (gexp (list (ungexp coreutils))))
1943 (xdrv (gexp->file "foo" exp
1944 #:target target
1945 #:guile %bootstrap-guile))
1946 (refs (references*
1947 (derivation-file-name xdrv)))
1948 (xcu (package->cross-derivation coreutils
1949 target))
1950 (cu (package->derivation coreutils)))
1951 (return (and (member (derivation-file-name xcu) refs)
1952 (not (member (derivation-file-name cu) refs))))))
1953
1954(test-assertm "gexp->file, cross-compilation with default target"
1955 (mlet* %store-monad ((target -> "aarch64-linux-gnu")
1956 (_ (set-current-target target))
1957 (exp -> (gexp (list (ungexp coreutils))))
1958 (xdrv (gexp->file "foo" exp
1959 #:guile %bootstrap-guile))
1960 (refs (references*
1961 (derivation-file-name xdrv)))
1962 (xcu (package->cross-derivation coreutils
1963 target))
1964 (cu (package->derivation coreutils)))
1965 (return (and (member (derivation-file-name xcu) refs)
1966 (not (member (derivation-file-name cu) refs))))))
1967
1968(test-assertm "gexp->script, cross-compilation"
1969 (mlet* %store-monad ((target -> "aarch64-linux-gnu")
1970 (exp -> (gexp (list (ungexp coreutils))))
1971 (xdrv (gexp->script "foo" exp #:target target))
1972 (refs (references*
1973 (derivation-file-name xdrv)))
1974 (xcu (package->cross-derivation coreutils
1975 target))
1976 (cu (package->derivation coreutils)))
1977 (return (and (member (derivation-file-name xcu) refs)
1978 (not (member (derivation-file-name cu) refs))))))
1979
1980(test-assertm "gexp->script, cross-compilation with default target"
1981 (mlet* %store-monad ((target -> "aarch64-linux-gnu")
1982 (_ (set-current-target target))
1983 (exp -> (gexp (list (ungexp coreutils))))
1984 (xdrv (gexp->script "foo" exp))
1985 (refs (references*
1986 (derivation-file-name xdrv)))
1987 (xcu (package->cross-derivation coreutils
1988 target))
1989 (cu (package->derivation coreutils)))
1990 (return (and (member (derivation-file-name xcu) refs)
1991 (not (member (derivation-file-name cu) refs))))))
1992
1993(test-end "gexp")
1994
1995;; Local Variables:
1996;; eval: (put 'test-assertm 'scheme-indent-function 1)
1997;; End: