doc: Create "Version Control Services" section.
[guix.git] / tests / derivations.scm
blob36afd42d05cfac87c4b121a3f3ff10528d2ae6e3
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
3 ;;;
4 ;;; This file is part of GNU Guix.
5 ;;;
6 ;;; GNU Guix is free software; you can redistribute it and/or modify it
7 ;;; under the terms of the GNU General Public License as published by
8 ;;; the Free Software Foundation; either version 3 of the License, or (at
9 ;;; your option) any later version.
10 ;;;
11 ;;; GNU Guix is distributed in the hope that it will be useful, but
12 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ;;; GNU General Public License for more details.
15 ;;;
16 ;;; You should have received a copy of the GNU General Public License
17 ;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
19 (unsetenv "http_proxy")
21 (define-module (test-derivations)
22   #:use-module (guix derivations)
23   #:use-module (guix grafts)
24   #:use-module (guix store)
25   #:use-module (guix utils)
26   #:use-module (guix hash)
27   #:use-module (guix base32)
28   #:use-module (guix tests)
29   #:use-module (guix tests http)
30   #:use-module ((guix packages) #:select (package-derivation base32))
31   #:use-module ((guix build utils) #:select (executable-file?))
32   #:use-module ((gnu packages) #:select (search-bootstrap-binary))
33   #:use-module (gnu packages bootstrap)
34   #:use-module ((gnu packages guile) #:select (guile-1.8))
35   #:use-module (srfi srfi-1)
36   #:use-module (srfi srfi-11)
37   #:use-module (srfi srfi-26)
38   #:use-module (srfi srfi-34)
39   #:use-module (srfi srfi-64)
40   #:use-module (rnrs io ports)
41   #:use-module (rnrs bytevectors)
42   #:use-module (web uri)
43   #:use-module (ice-9 rdelim)
44   #:use-module (ice-9 regex)
45   #:use-module (ice-9 ftw)
46   #:use-module (ice-9 match))
48 (define %store
49   (open-connection-for-tests))
51 ;; Globally disable grafts because they can trigger early builds.
52 (%graft? #f)
54 (define (bootstrap-binary name)
55   (let ((bin (search-bootstrap-binary name (%current-system))))
56     (and %store
57          (add-to-store %store name #t "sha256" bin))))
59 (define %bash
60   (bootstrap-binary "bash"))
61 (define %mkdir
62   (bootstrap-binary "mkdir"))
64 (define* (directory-contents dir #:optional (slurp get-bytevector-all))
65   "Return an alist representing the contents of DIR."
66   (define prefix-len (string-length dir))
67   (sort (file-system-fold (const #t)                   ; enter?
68                           (lambda (path stat result)   ; leaf
69                             (alist-cons (string-drop path prefix-len)
70                                         (call-with-input-file path slurp)
71                                         result))
72                           (lambda (path stat result) result)      ; down
73                           (lambda (path stat result) result)      ; up
74                           (lambda (path stat result) result)      ; skip
75                           (lambda (path stat errno result) result) ; error
76                           '()
77                           dir)
78         (lambda (e1 e2)
79           (string<? (car e1) (car e2)))))
81 ;; Avoid collisions with other tests.
82 (%http-server-port 10500)
85 (test-begin "derivations")
87 (test-assert "parse & export"
88   (let* ((f  (search-path %load-path "tests/test.drv"))
89          (b1 (call-with-input-file f get-bytevector-all))
90          (d1 (read-derivation (open-bytevector-input-port b1)))
91          (b2 (call-with-bytevector-output-port (cut write-derivation d1 <>)))
92          (d2 (read-derivation (open-bytevector-input-port b2))))
93     (and (equal? b1 b2)
94          (equal? d1 d2))))
96 (test-skip (if %store 0 12))
98 (test-assert "add-to-store, flat"
99   (let* ((file (search-path %load-path "language/tree-il/spec.scm"))
100          (drv  (add-to-store %store "flat-test" #f "sha256" file)))
101     (and (eq? 'regular (stat:type (stat drv)))
102          (valid-path? %store drv)
103          (equal? (call-with-input-file file get-bytevector-all)
104                  (call-with-input-file drv get-bytevector-all)))))
106 (test-assert "add-to-store, recursive"
107   (let* ((dir (dirname (search-path %load-path "language/tree-il/spec.scm")))
108          (drv (add-to-store %store "dir-tree-test" #t "sha256" dir)))
109     (and (eq? 'directory (stat:type (stat drv)))
110          (valid-path? %store drv)
111          (equal? (directory-contents dir)
112                  (directory-contents drv)))))
114 (test-assert "derivation with no inputs"
115   (let* ((builder  (add-text-to-store %store "my-builder.sh"
116                                       "echo hello, world\n"
117                                       '()))
118          (drv      (derivation %store "foo"
119                                %bash `("-e" ,builder)
120                                #:env-vars '(("HOME" . "/homeless")))))
121     (and (store-path? (derivation-file-name drv))
122          (valid-path? %store (derivation-file-name drv)))))
124 (test-assert "build derivation with 1 source"
125   (let* ((builder (add-text-to-store %store "my-builder.sh"
126                                      "echo hello, world > \"$out\"\n"
127                                      '()))
128          (drv     (derivation %store "foo"
129                               %bash `(,builder)
130                               #:env-vars '(("HOME" . "/homeless")
131                                            ("zzz"  . "Z!")
132                                            ("AAA"  . "A!"))
133                               #:inputs `((,%bash) (,builder))))
134          (succeeded?
135           (build-derivations %store (list drv))))
136     (and succeeded?
137          (let ((path (derivation->output-path drv)))
138            (and (valid-path? %store path)
139                 (string=? (call-with-input-file path read-line)
140                           "hello, world"))))))
142 (test-assert "derivation with local file as input"
143   (let* ((builder    (add-text-to-store
144                       %store "my-builder.sh"
145                       "(while read line ; do echo \"$line\" ; done) < $in > $out"
146                       '()))
147          (input      (search-path %load-path "ice-9/boot-9.scm"))
148          (input*     (add-to-store %store (basename input)
149                                    #t "sha256" input))
150          (drv        (derivation %store "derivation-with-input-file"
151                                  %bash `(,builder)
153                                  ;; Cheat to pass the actual file name to the
154                                  ;; builder.
155                                  #:env-vars `(("in" . ,input*))
157                                  #:inputs `((,%bash)
158                                             (,builder)
159                                             (,input))))) ; ← local file name
160     (and (build-derivations %store (list drv))
161          ;; Note: we can't compare the files because the above trick alters
162          ;; the contents.
163          (valid-path? %store (derivation->output-path drv)))))
165 (test-assert "derivation fails but keep going"
166   ;; In keep-going mode, 'build-derivations' should fail because of D1, but it
167   ;; must return only after D2 has succeeded.
168   (with-store store
169     (let* ((d1 (derivation %store "fails"
170                            %bash `("-c" "false")
171                            #:inputs `((,%bash))))
172            (d2 (build-expression->derivation %store "sleep-then-succeed"
173                                              `(begin
174                                                 ,(random-text)
175                                                 ;; XXX: Hopefully that's long
176                                                 ;; enough that D1 has already
177                                                 ;; failed.
178                                                 (sleep 2)
179                                                 (mkdir %output)))))
180       (set-build-options %store
181                          #:use-substitutes? #f
182                          #:keep-going? #t)
183       (guard (c ((nix-protocol-error? c)
184                  (and (= 100 (nix-protocol-error-status c))
185                       (string-contains (nix-protocol-error-message c)
186                                        (derivation-file-name d1))
187                       (not (valid-path? %store (derivation->output-path d1)))
188                       (valid-path? %store (derivation->output-path d2)))))
189         (build-derivations %store (list d1 d2))
190         #f))))
192 (test-assert "identical files are deduplicated"
193   (let* ((build1  (add-text-to-store %store "one.sh"
194                                      "echo hello, world > \"$out\"\n"
195                                      '()))
196          (build2  (add-text-to-store %store "two.sh"
197                                      "# Hey!\necho hello, world > \"$out\"\n"
198                                      '()))
199          (drv1    (derivation %store "foo"
200                               %bash `(,build1)
201                               #:inputs `((,%bash) (,build1))))
202          (drv2    (derivation %store "bar"
203                               %bash `(,build2)
204                               #:inputs `((,%bash) (,build2)))))
205     (and (build-derivations %store (list drv1 drv2))
206          (let ((file1 (derivation->output-path drv1))
207                (file2 (derivation->output-path drv2)))
208            (and (valid-path? %store file1) (valid-path? %store file2)
209                 (string=? (call-with-input-file file1 get-string-all)
210                           "hello, world\n")
211                 (= (stat:ino (lstat file1))
212                    (stat:ino (lstat file2))))))))
214 (test-equal "built-in-builders"
215   '("download")
216   (built-in-builders %store))
218 (test-assert "unknown built-in builder"
219   (let ((drv (derivation %store "ohoh" "builtin:does-not-exist" '())))
220     (guard (c ((nix-protocol-error? c)
221                (string-contains (nix-protocol-error-message c) "failed")))
222       (build-derivations %store (list drv))
223       #f)))
225 (unless (http-server-can-listen?)
226   (test-skip 1))
227 (test-assert "'download' built-in builder"
228   (let ((text (random-text)))
229     (with-http-server 200 text
230       (let* ((drv (derivation %store "world"
231                               "builtin:download" '()
232                               #:env-vars `(("url"
233                                             . ,(object->string (%local-url))))
234                               #:hash-algo 'sha256
235                               #:hash (sha256 (string->utf8 text)))))
236         (and (build-derivations %store (list drv))
237              (string=? (call-with-input-file (derivation->output-path drv)
238                          get-string-all)
239                        text))))))
241 (unless (http-server-can-listen?)
242   (test-skip 1))
243 (test-assert "'download' built-in builder, invalid hash"
244   (with-http-server 200 "hello, world!"
245     (let* ((drv (derivation %store "world"
246                             "builtin:download" '()
247                             #:env-vars `(("url"
248                                           . ,(object->string (%local-url))))
249                             #:hash-algo 'sha256
250                             #:hash (sha256 (random-bytevector 100))))) ;wrong
251       (guard (c ((nix-protocol-error? c)
252                  (string-contains (nix-protocol-error-message c) "failed")))
253         (build-derivations %store (list drv))
254         #f))))
256 (unless (http-server-can-listen?)
257   (test-skip 1))
258 (test-assert "'download' built-in builder, not found"
259   (with-http-server 404 "not found"
260     (let* ((drv (derivation %store "will-never-be-found"
261                             "builtin:download" '()
262                             #:env-vars `(("url"
263                                           . ,(object->string (%local-url))))
264                             #:hash-algo 'sha256
265                             #:hash (sha256 (random-bytevector 100)))))
266       (guard (c ((nix-protocol-error? c)
267                  (string-contains (nix-protocol-error-message (pk c)) "failed")))
268         (build-derivations %store (list drv))
269         #f))))
271 (test-assert "'download' built-in builder, not fixed-output"
272   (let* ((source (add-text-to-store %store "hello" "hi!"))
273          (url    (string-append "file://" source))
274          (drv    (derivation %store "world"
275                              "builtin:download" '()
276                              #:env-vars `(("url" . ,(object->string url))))))
277     (guard (c ((nix-protocol-error? c)
278                (string-contains (nix-protocol-error-message c) "failed")))
279       (build-derivations %store (list drv))
280       #f)))
282 (unless (http-server-can-listen?)
283   (test-skip 1))
284 (test-assert "'download' built-in builder, check mode"
285   ;; Make sure rebuilding the 'builtin:download' derivation in check mode
286   ;; works.  See <http://bugs.gnu.org/25089>.
287   (let* ((text (random-text))
288          (drv (derivation %store "world"
289                           "builtin:download" '()
290                           #:env-vars `(("url"
291                                         . ,(object->string (%local-url))))
292                           #:hash-algo 'sha256
293                           #:hash (sha256 (string->utf8 text)))))
294     (and (with-http-server 200 text
295            (build-derivations %store (list drv)))
296          (with-http-server 200 text
297            (build-derivations %store (list drv)
298                               (build-mode check)))
299          (string=? (call-with-input-file (derivation->output-path drv)
300                      get-string-all)
301                    text))))
303 (test-equal "derivation-name"
304   "foo-0.0"
305   (let ((drv (derivation %store "foo-0.0" %bash '())))
306     (derivation-name drv)))
308 (test-equal "derivation-output-names"
309   '(("out") ("bar" "chbouib"))
310   (let ((drv1 (derivation %store "foo-0.0" %bash '()))
311         (drv2 (derivation %store "foo-0.0" %bash '()
312                           #:outputs '("bar" "chbouib"))))
313     (list (derivation-output-names drv1)
314           (derivation-output-names drv2))))
316 (test-assert "offloadable-derivation?"
317   (and (offloadable-derivation? (derivation %store "foo" %bash '()))
318        (offloadable-derivation?               ;see <http://bugs.gnu.org/18747>
319         (derivation %store "foo" %bash '()
320                     #:substitutable? #f))
321        (not (offloadable-derivation?
322              (derivation %store "foo" %bash '()
323                          #:local-build? #t)))))
325 (test-assert "substitutable-derivation?"
326   (and (substitutable-derivation? (derivation %store "foo" %bash '()))
327        (substitutable-derivation?             ;see <http://bugs.gnu.org/18747>
328         (derivation %store "foo" %bash '()
329                     #:local-build? #t))
330        (not (substitutable-derivation?
331              (derivation %store "foo" %bash '()
332                          #:substitutable? #f)))))
334 (test-assert "fixed-output-derivation?"
335   (let* ((builder    (add-text-to-store %store "my-fixed-builder.sh"
336                                         "echo -n hello > $out" '()))
337          (hash       (sha256 (string->utf8 "hello")))
338          (drv        (derivation %store "fixed"
339                                  %bash `(,builder)
340                                  #:inputs `((,builder))
341                                  #:hash hash #:hash-algo 'sha256)))
342     (fixed-output-derivation? drv)))
344 (test-assert "fixed-output derivation"
345   (let* ((builder    (add-text-to-store %store "my-fixed-builder.sh"
346                                         "echo -n hello > $out" '()))
347          (hash       (sha256 (string->utf8 "hello")))
348          (drv        (derivation %store "fixed"
349                                  %bash `(,builder)
350                                  #:inputs `((,builder)) ; optional
351                                  #:hash hash #:hash-algo 'sha256))
352          (succeeded? (build-derivations %store (list drv))))
353     (and succeeded?
354          (let ((p (derivation->output-path drv)))
355            (and (equal? (string->utf8 "hello")
356                         (call-with-input-file p get-bytevector-all))
357                 (bytevector? (query-path-hash %store p)))))))
359 (test-assert "fixed-output derivation: output paths are equal"
360   (let* ((builder1   (add-text-to-store %store "fixed-builder1.sh"
361                                         "echo -n hello > $out" '()))
362          (builder2   (add-text-to-store %store "fixed-builder2.sh"
363                                         "echo hey; echo -n hello > $out" '()))
364          (hash       (sha256 (string->utf8 "hello")))
365          (drv1       (derivation %store "fixed"
366                                  %bash `(,builder1)
367                                  #:hash hash #:hash-algo 'sha256))
368          (drv2       (derivation %store "fixed"
369                                  %bash `(,builder2)
370                                  #:hash hash #:hash-algo 'sha256))
371          (succeeded? (build-derivations %store (list drv1 drv2))))
372     (and succeeded?
373          (equal? (derivation->output-path drv1)
374                  (derivation->output-path drv2)))))
376 (test-assert "fixed-output derivation, recursive"
377   (let* ((builder    (add-text-to-store %store "my-fixed-builder.sh"
378                                         "echo -n hello > $out" '()))
379          (hash       (sha256 (string->utf8 "hello")))
380          (drv        (derivation %store "fixed-rec"
381                                  %bash `(,builder)
382                                  #:inputs `((,builder))
383                                  #:hash (base32 "0sg9f58l1jj88w6pdrfdpj5x9b1zrwszk84j81zvby36q9whhhqa")
384                                  #:hash-algo 'sha256
385                                  #:recursive? #t))
386          (succeeded? (build-derivations %store (list drv))))
387     (and succeeded?
388          (let ((p (derivation->output-path drv)))
389            (and (equal? (string->utf8 "hello")
390                         (call-with-input-file p get-bytevector-all))
391                 (bytevector? (query-path-hash %store p)))))))
393 (test-assert "derivation with a fixed-output input"
394   ;; A derivation D using a fixed-output derivation F doesn't has the same
395   ;; output path when passed F or F', as long as F and F' have the same output
396   ;; path.
397   (let* ((builder1   (add-text-to-store %store "fixed-builder1.sh"
398                                         "echo -n hello > $out" '()))
399          (builder2   (add-text-to-store %store "fixed-builder2.sh"
400                                         "echo hey; echo -n hello > $out" '()))
401          (hash       (sha256 (string->utf8 "hello")))
402          (fixed1     (derivation %store "fixed"
403                                  %bash `(,builder1)
404                                  #:hash hash #:hash-algo 'sha256))
405          (fixed2     (derivation %store "fixed"
406                                  %bash `(,builder2)
407                                  #:hash hash #:hash-algo 'sha256))
408          (fixed-out  (derivation->output-path fixed1))
409          (builder3   (add-text-to-store
410                       %store "final-builder.sh"
411                       ;; Use Bash hackery to avoid Coreutils.
412                       "echo $in ; (read -u 3 c; echo $c) 3< $in > $out" '()))
413          (final1     (derivation %store "final"
414                                  %bash `(,builder3)
415                                  #:env-vars `(("in" . ,fixed-out))
416                                  #:inputs `((,%bash) (,builder3) (,fixed1))))
417          (final2     (derivation %store "final"
418                                  %bash `(,builder3)
419                                  #:env-vars `(("in" . ,fixed-out))
420                                  #:inputs `((,%bash) (,builder3) (,fixed2))))
421          (succeeded? (build-derivations %store
422                                         (list final1 final2))))
423     (and succeeded?
424          (equal? (derivation->output-path final1)
425                  (derivation->output-path final2)))))
427 (test-assert "multiple-output derivation"
428   (let* ((builder    (add-text-to-store %store "my-fixed-builder.sh"
429                                         "echo one > $out ; echo two > $second"
430                                         '()))
431          (drv        (derivation %store "fixed"
432                                  %bash `(,builder)
433                                  #:env-vars '(("HOME" . "/homeless")
434                                               ("zzz"  . "Z!")
435                                               ("AAA"  . "A!"))
436                                  #:inputs `((,%bash) (,builder))
437                                  #:outputs '("out" "second")))
438          (succeeded? (build-derivations %store (list drv))))
439     (and succeeded?
440          (let ((one (derivation->output-path drv "out"))
441                (two (derivation->output-path drv "second")))
442            (and (lset= equal?
443                        (derivation->output-paths drv)
444                        `(("out" . ,one) ("second" . ,two)))
445                 (eq? 'one (call-with-input-file one read))
446                 (eq? 'two (call-with-input-file two read)))))))
448 (test-assert "multiple-output derivation, non-alphabetic order"
449   ;; Here, the outputs are not listed in alphabetic order.  Yet, the store
450   ;; path computation must reorder them first.
451   (let* ((builder    (add-text-to-store %store "my-fixed-builder.sh"
452                                         "echo one > $out ; echo two > $AAA"
453                                         '()))
454          (drv        (derivation %store "fixed"
455                                  %bash `(,builder)
456                                  #:inputs `((,%bash) (,builder))
457                                  #:outputs '("out" "AAA")))
458          (succeeded? (build-derivations %store (list drv))))
459     (and succeeded?
460          (let ((one (derivation->output-path drv "out"))
461                (two (derivation->output-path drv "AAA")))
462            (and (eq? 'one (call-with-input-file one read))
463                 (eq? 'two (call-with-input-file two read)))))))
465 (test-assert "read-derivation vs. derivation"
466   ;; Make sure 'derivation' and 'read-derivation' return objects that are
467   ;; identical.
468   (let* ((sources (unfold (cut >= <> 10)
469                           (lambda (n)
470                             (add-text-to-store %store
471                                                (format #f "input~a" n)
472                                                (random-text)))
473                           1+
474                           0))
475          (inputs  (map (lambda (file)
476                          (derivation %store "derivation-input"
477                                      %bash '()
478                                      #:inputs `((,%bash) (,file))))
479                        sources))
480          (builder (add-text-to-store %store "builder.sh"
481                                      "echo one > $one ; echo two > $two"
482                                      '()))
483          (drv     (derivation %store "derivation"
484                               %bash `(,builder)
485                               #:inputs `((,%bash) (,builder)
486                                          ,@(map list (append sources inputs)))
487                               #:outputs '("two" "one")))
488          (drv*    (call-with-input-file (derivation-file-name drv)
489                     read-derivation)))
490     (equal? drv* drv)))
492 (test-assert "multiple-output derivation, derivation-path->output-path"
493   (let* ((builder    (add-text-to-store %store "builder.sh"
494                                         "echo one > $out ; echo two > $second"
495                                         '()))
496          (drv        (derivation %store "multiple"
497                                  %bash `(,builder)
498                                  #:outputs '("out" "second")))
499          (drv-file   (derivation-file-name drv))
500          (one        (derivation->output-path drv "out"))
501          (two        (derivation->output-path drv "second"))
502          (first      (derivation-path->output-path drv-file "out"))
503          (second     (derivation-path->output-path drv-file "second")))
504     (and (not (string=? one two))
505          (string-suffix? "-second" two)
506          (string=? first one)
507          (string=? second two))))
509 (test-assert "user of multiple-output derivation"
510   ;; Check whether specifying several inputs coming from the same
511   ;; multiple-output derivation works.
512   (let* ((builder1   (add-text-to-store %store "my-mo-builder.sh"
513                                         "echo one > $out ; echo two > $two"
514                                         '()))
515          (mdrv       (derivation %store "multiple-output"
516                                  %bash `(,builder1)
517                                  #:inputs `((,%bash) (,builder1))
518                                  #:outputs '("out" "two")))
519          (builder2   (add-text-to-store %store "my-mo-user-builder.sh"
520                                         "read x < $one;
521                                          read y < $two;
522                                          echo \"($x $y)\" > $out"
523                                         '()))
524          (udrv       (derivation %store "multiple-output-user"
525                                  %bash `(,builder2)
526                                  #:env-vars `(("one"
527                                                . ,(derivation->output-path
528                                                    mdrv "out"))
529                                               ("two"
530                                                . ,(derivation->output-path
531                                                    mdrv "two")))
532                                  #:inputs `((,%bash)
533                                             (,builder2)
534                                             ;; two occurrences of MDRV:
535                                             (,mdrv)
536                                             (,mdrv "two")))))
537     (and (build-derivations %store (list (pk 'udrv udrv)))
538          (let ((p (derivation->output-path udrv)))
539            (and (valid-path? %store p)
540                 (equal? '(one two) (call-with-input-file p read)))))))
542 (test-assert "derivation with #:references-graphs"
543   (let* ((input1  (add-text-to-store %store "foo" "hello"
544                                      (list %bash)))
545          (input2  (add-text-to-store %store "bar"
546                                      (number->string (random 7777))
547                                      (list input1)))
548          (builder (add-text-to-store %store "build-graph"
549                                      (format #f "
550 ~a $out
551  (while read l ; do echo $l ; done) < bash > $out/bash
552  (while read l ; do echo $l ; done) < input1 > $out/input1
553  (while read l ; do echo $l ; done) < input2 > $out/input2"
554                                              %mkdir)
555                                      (list %mkdir)))
556          (drv     (derivation %store "closure-graphs"
557                               %bash `(,builder)
558                               #:references-graphs
559                               `(("bash" . ,%bash)
560                                 ("input1" . ,input1)
561                                 ("input2" . ,input2))
562                               #:inputs `((,%bash) (,builder))))
563          (out     (derivation->output-path drv)))
564     (define (deps path . deps)
565       (let ((count (length deps)))
566         (string-append path "\n\n" (number->string count) "\n"
567                        (string-join (sort deps string<?) "\n")
568                        (if (zero? count) "" "\n"))))
570     (and (build-derivations %store (list drv))
571          (equal? (directory-contents out get-string-all)
572                  `(("/bash"   . ,(string-append %bash "\n\n0\n"))
573                    ("/input1" . ,(if (string>? input1 %bash)
574                                      (string-append (deps %bash)
575                                                     (deps input1 %bash))
576                                      (string-append (deps input1 %bash)
577                                                     (deps %bash))))
578                    ("/input2" . ,(string-concatenate
579                                   (map cdr
580                                        (sort
581                                         (map (lambda (p d)
582                                                (cons p (apply deps p d)))
583                                              (list %bash input1 input2)
584                                              (list '() (list %bash) (list input1)))
585                                         (lambda (x y)
586                                           (match x
587                                             ((p1 . _)
588                                              (match y
589                                                ((p2 . _)
590                                                 (string<? p1 p2)))))))))))))))
592 (test-assert "derivation #:allowed-references, ok"
593   (let ((drv (derivation %store "allowed" %bash
594                          '("-c" "echo hello > $out")
595                          #:inputs `((,%bash))
596                          #:allowed-references '())))
597     (build-derivations %store (list drv))))
599 (test-assert "derivation #:allowed-references, not allowed"
600   (let* ((txt (add-text-to-store %store "foo" "Hello, world."))
601          (drv (derivation %store "disallowed" %bash
602                           `("-c" ,(string-append "echo " txt "> $out"))
603                           #:inputs `((,%bash) (,txt))
604                           #:allowed-references '())))
605     (guard (c ((nix-protocol-error? c)
606                ;; There's no specific error message to check for.
607                #t))
608       (build-derivations %store (list drv))
609       #f)))
611 (test-assert "derivation #:allowed-references, self allowed"
612   (let ((drv (derivation %store "allowed" %bash
613                          '("-c" "echo $out > $out")
614                          #:inputs `((,%bash))
615                          #:allowed-references '("out"))))
616     (build-derivations %store (list drv))))
618 (test-assert "derivation #:allowed-references, self not allowed"
619   (let ((drv (derivation %store "disallowed" %bash
620                          `("-c" ,"echo $out > $out")
621                          #:inputs `((,%bash))
622                          #:allowed-references '())))
623     (guard (c ((nix-protocol-error? c)
624                ;; There's no specific error message to check for.
625                #t))
626       (build-derivations %store (list drv))
627       #f)))
629 (test-assert "derivation #:disallowed-references, ok"
630   (let ((drv (derivation %store "disallowed" %bash
631                          '("-c" "echo hello > $out")
632                          #:inputs `((,%bash))
633                          #:disallowed-references '("out"))))
634     (build-derivations %store (list drv))))
636 (test-assert "derivation #:disallowed-references, not ok"
637   (let* ((txt (add-text-to-store %store "foo" "Hello, world."))
638          (drv (derivation %store "disdisallowed" %bash
639                           `("-c" ,(string-append "echo " txt "> $out"))
640                           #:inputs `((,%bash) (,txt))
641                           #:disallowed-references (list txt))))
642     (guard (c ((nix-protocol-error? c)
643                ;; There's no specific error message to check for.
644                #t))
645       (build-derivations %store (list drv))
646       #f)))
648 ;; Here we should get the value of $NIX_STATE_DIR that the daemon sees, which
649 ;; is a unique value for each test process; this value is the same as the one
650 ;; we see in the process executing this file since it is set by 'test-env'.
651 (test-equal "derivation #:leaked-env-vars"
652   (getenv "NIX_STATE_DIR")
653   (let* ((value (getenv "NIX_STATE_DIR"))
654          (drv   (derivation %store "leaked-env-vars" %bash
655                             '("-c" "echo -n $NIX_STATE_DIR > $out")
656                             #:hash (sha256 (string->utf8 value))
657                             #:hash-algo 'sha256
658                             #:inputs `((,%bash))
659                             #:leaked-env-vars '("NIX_STATE_DIR"))))
660     (and (build-derivations %store (list drv))
661          (call-with-input-file (derivation->output-path drv)
662            get-string-all))))
665 (define %coreutils
666   (false-if-exception
667    (and (network-reachable?)
668         (package-derivation %store %bootstrap-coreutils&co))))
670 (test-skip (if %coreutils 0 1))
672 (test-assert "build derivation with coreutils"
673   (let* ((builder
674           (add-text-to-store %store "build-with-coreutils.sh"
675                              "echo $PATH ; mkdir --version ; mkdir $out ; touch $out/good"
676                              '()))
677          (drv
678           (derivation %store "foo"
679                       %bash `(,builder)
680                       #:env-vars `(("PATH" .
681                                     ,(string-append
682                                       (derivation->output-path %coreutils)
683                                       "/bin")))
684                       #:inputs `((,builder)
685                                  (,%coreutils))))
686          (succeeded?
687           (build-derivations %store (list drv))))
688     (and succeeded?
689          (let ((p (derivation->output-path drv)))
690            (and (valid-path? %store p)
691                 (file-exists? (string-append p "/good")))))))
693 (test-skip (if (%guile-for-build) 0 8))
695 (test-equal "build-expression->derivation and invalid module name"
696   '(file-search-error "guix/module/that/does/not/exist.scm")
697   (guard (c ((file-search-error? c)
698              (list 'file-search-error
699                    (file-search-error-file-name c))))
700     (build-expression->derivation %store "foo" #t
701                                   #:modules '((guix module that
702                                                     does not exist)))))
704 (test-equal "build-expression->derivation and builder encoding"
705   '("UTF-8" #t)
706   (let* ((exp '(λ (α) (+ α 1)))
707          (drv (build-expression->derivation %store "foo" exp)))
708     (match (derivation-builder-arguments drv)
709       ((... builder)
710        (with-fluids ((%default-port-encoding "UTF-8"))
711          (call-with-input-file builder
712            (lambda (port)
713              (list (port-encoding port)
714                    (->bool
715                     (string-contains (get-string-all port)
716                                      "(λ (α) (+ α 1))"))))))))))
718 (test-assert "build-expression->derivation and derivation-prerequisites"
719   (let ((drv (build-expression->derivation %store "fail" #f)))
720     (any (match-lambda
721           (($ <derivation-input> path)
722            (string=? path (derivation-file-name (%guile-for-build)))))
723          (derivation-prerequisites drv))))
725 (test-assert "derivation-prerequisites and valid-derivation-input?"
726   (let* ((a (build-expression->derivation %store "a" '(mkdir %output)))
727          (b (build-expression->derivation %store "b" `(list ,(random-text))))
728          (c (build-expression->derivation %store "c" `(mkdir %output)
729                                           #:inputs `(("a" ,a) ("b" ,b)))))
730     ;; Make sure both A and %BOOTSTRAP-GUILE are built (the latter could have
731     ;; be removed by tests/guix-gc.sh.)
732     (build-derivations %store
733                        (list a (package-derivation %store %bootstrap-guile)))
735     (match (derivation-prerequisites c
736                                      (cut valid-derivation-input? %store
737                                           <>))
738       ((($ <derivation-input> file ("out")))
739        (string=? file (derivation-file-name b)))
740       (x
741        (pk 'fail x #f)))))
743 (test-assert "build-expression->derivation without inputs"
744   (let* ((builder    '(begin
745                         (mkdir %output)
746                         (call-with-output-file (string-append %output "/test")
747                           (lambda (p)
748                             (display '(hello guix) p)))))
749          (drv        (build-expression->derivation %store "goo" builder))
750          (succeeded? (build-derivations %store (list drv))))
751     (and succeeded?
752          (let ((p (derivation->output-path drv)))
753            (equal? '(hello guix)
754                    (call-with-input-file (string-append p "/test") read))))))
756 (test-assert "build-expression->derivation and max-silent-time"
757   (let* ((store      (let ((s (open-connection)))
758                        (set-build-options s #:max-silent-time 1)
759                        s))
760          (builder    '(begin (sleep 100) (mkdir %output) #t))
761          (drv        (build-expression->derivation store "silent" builder))
762          (out-path   (derivation->output-path drv)))
763     (guard (c ((nix-protocol-error? c)
764                (and (string-contains (nix-protocol-error-message c)
765                                      "failed")
766                     (not (valid-path? store out-path)))))
767       (build-derivations store (list drv))
768       #f)))
770 (test-assert "build-expression->derivation and timeout"
771   (let* ((store      (let ((s (open-connection)))
772                        (set-build-options s #:timeout 1)
773                        s))
774          (builder    '(begin (sleep 100) (mkdir %output) #t))
775          (drv        (build-expression->derivation store "slow" builder))
776          (out-path   (derivation->output-path drv)))
777     (guard (c ((nix-protocol-error? c)
778                (and (string-contains (nix-protocol-error-message c)
779                                      "failed")
780                     (not (valid-path? store out-path)))))
781       (build-derivations store (list drv))
782       #f)))
784 (test-assert "build-expression->derivation and derivation-prerequisites-to-build"
785   (let ((drv (build-expression->derivation %store "fail" #f)))
786     ;; The only direct dependency is (%guile-for-build) and it's already
787     ;; built.
788     (null? (derivation-prerequisites-to-build %store drv))))
790 (test-assert "derivation-prerequisites-to-build when outputs already present"
791   (let* ((builder    '(begin (mkdir %output) #t))
792          (input-drv  (build-expression->derivation %store "input" builder))
793          (input-path (derivation-output-path
794                       (assoc-ref (derivation-outputs input-drv)
795                                  "out")))
796          (drv        (build-expression->derivation %store "something" builder
797                                                    #:inputs
798                                                    `(("i" ,input-drv))))
799          (output     (derivation->output-path drv)))
800     ;; Make sure these things are not already built.
801     (when (valid-path? %store input-path)
802       (delete-paths %store (list input-path)))
803     (when (valid-path? %store output)
804       (delete-paths %store (list output)))
806     (and (equal? (map derivation-input-path
807                       (derivation-prerequisites-to-build %store drv))
808                  (list (derivation-file-name input-drv)))
810          ;; Build DRV and delete its input.
811          (build-derivations %store (list drv))
812          (delete-paths %store (list input-path))
813          (not (valid-path? %store input-path))
815          ;; Now INPUT-PATH is missing, yet it shouldn't be listed as a
816          ;; prerequisite to build because DRV itself is already built.
817          (null? (derivation-prerequisites-to-build %store drv)))))
819 (test-assert "derivation-prerequisites-to-build and substitutes"
820   (let* ((store  (open-connection))
821          (drv    (build-expression->derivation store "prereq-subst"
822                                                (random 1000)))
823          (output (derivation->output-path drv)))
825     ;; Make sure substitutes are usable.
826     (set-build-options store #:use-substitutes? #t
827                        #:substitute-urls (%test-substitute-urls))
829     (with-derivation-narinfo drv
830       (let-values (((build download)
831                     (derivation-prerequisites-to-build store drv))
832                    ((build* download*)
833                     (derivation-prerequisites-to-build store drv
834                                                        #:substitutable-info
835                                                        (const #f))))
836         (and (null? build)
837              (equal? (map substitutable-path download) (list output))
838              (null? download*)
839              (null? build*))))))
841 (test-assert "derivation-prerequisites-to-build and substitutes, non-substitutable build"
842   (let* ((store  (open-connection))
843          (drv    (build-expression->derivation store "prereq-no-subst"
844                                                (random 1000)
845                                                #:substitutable? #f))
846          (output (derivation->output-path drv)))
848     ;; Make sure substitutes are usable.
849     (set-build-options store #:use-substitutes? #t
850                        #:substitute-urls (%test-substitute-urls))
852     (with-derivation-narinfo drv
853       (let-values (((build download)
854                     (derivation-prerequisites-to-build store drv)))
855         ;; Despite being available as a substitute, DRV will be built locally
856         ;; due to #:substitutable? #f.
857         (and (null? download)
858              (match build
859                (((? derivation-input? input))
860                 (string=? (derivation-input-path input)
861                           (derivation-file-name drv)))))))))
863 (test-assert "derivation-prerequisites-to-build and substitutes, local build"
864   (with-store store
865     (let* ((drv    (build-expression->derivation store "prereq-subst-local"
866                                                  (random 1000)
867                                                  #:local-build? #t))
868            (output (derivation->output-path drv)))
870       ;; Make sure substitutes are usable.
871       (set-build-options store #:use-substitutes? #t
872                          #:substitute-urls (%test-substitute-urls))
874       (with-derivation-narinfo drv
875         (let-values (((build download)
876                       (derivation-prerequisites-to-build store drv)))
877           ;; #:local-build? is *not* synonymous with #:substitutable?, so we
878           ;; must be able to substitute DRV's output.
879           ;; See <http://bugs.gnu.org/18747>.
880           (and (null? build)
881                (match download
882                  (((= substitutable-path item))
883                   (string=? item (derivation->output-path drv))))))))))
885 (test-assert "derivation-prerequisites-to-build in 'check' mode"
886   (with-store store
887     (let* ((dep (build-expression->derivation store "dep"
888                                               `(begin ,(random-text)
889                                                       (mkdir %output))))
890            (drv (build-expression->derivation store "to-check"
891                                               '(mkdir %output)
892                                               #:inputs `(("dep" ,dep)))))
893       (build-derivations store (list drv))
894       (delete-paths store (list (derivation->output-path dep)))
896       ;; In 'check' mode, DEP must be rebuilt.
897       (and (null? (derivation-prerequisites-to-build store drv))
898            (match (derivation-prerequisites-to-build store drv
899                                                      #:mode (build-mode
900                                                              check))
901              ((input)
902               (string=? (derivation-input-path input)
903                         (derivation-file-name dep))))))))
905 (test-assert "substitution-oracle and #:substitute? #f"
906   (with-store store
907     (let* ((dep   (build-expression->derivation store "dep"
908                                                 `(begin ,(random-text)
909                                                         (mkdir %output))))
910            (drv   (build-expression->derivation store "not-subst"
911                                                 `(begin ,(random-text)
912                                                         (mkdir %output))
913                                                 #:substitutable? #f
914                                                 #:inputs `(("dep" ,dep))))
915            (query #f))
916       (define (record-substitutable-path-query store paths)
917         (when query
918           (error "already called!" query))
919         (set! query paths)
920         '())
922       (mock ((guix store) substitutable-path-info
923              record-substitutable-path-query)
925             (let ((pred (substitution-oracle store (list drv))))
926               (pred (derivation->output-path drv))))
928       ;; Make sure the oracle didn't try to get substitute info for DRV since
929       ;; DRV is mark as non-substitutable.  Assume that GUILE-FOR-BUILD is
930       ;; already in store and thus not part of QUERY.
931       (equal? (pk 'query query)
932               (list (derivation->output-path dep))))))
934 (test-assert "build-expression->derivation with expression returning #f"
935   (let* ((builder  '(begin
936                       (mkdir %output)
937                       #f))                        ; fail!
938          (drv      (build-expression->derivation %store "fail" builder))
939          (out-path (derivation->output-path drv)))
940     (guard (c ((nix-protocol-error? c)
941                ;; Note that the output path may exist at this point, but it
942                ;; is invalid.
943                (and (string-match "build .* failed"
944                                   (nix-protocol-error-message c))
945                     (not (valid-path? %store out-path)))))
946       (build-derivations %store (list drv))
947       #f)))
949 (test-assert "build-expression->derivation with two outputs"
950   (let* ((builder    '(begin
951                         (call-with-output-file (assoc-ref %outputs "out")
952                           (lambda (p)
953                             (display '(hello) p)))
954                         (call-with-output-file (assoc-ref %outputs "second")
955                           (lambda (p)
956                             (display '(world) p)))))
957          (drv        (build-expression->derivation %store "double" builder
958                                                    #:outputs '("out"
959                                                                "second")))
960          (succeeded? (build-derivations %store (list drv))))
961     (and succeeded?
962          (let ((one (derivation->output-path drv))
963                (two (derivation->output-path drv "second")))
964            (and (equal? '(hello) (call-with-input-file one read))
965                 (equal? '(world) (call-with-input-file two read)))))))
967 (test-skip (if %coreutils 0 1))
968 (test-assert "build-expression->derivation with one input"
969   (let* ((builder    '(call-with-output-file %output
970                         (lambda (p)
971                           (let ((cu (assoc-ref %build-inputs "cu")))
972                             (close 1)
973                             (dup2 (port->fdes p) 1)
974                             (execl (string-append cu "/bin/uname")
975                                    "uname" "-a")))))
976          (drv        (build-expression->derivation %store "uname" builder
977                                                    #:inputs
978                                                    `(("cu" ,%coreutils))))
979          (succeeded? (build-derivations %store (list drv))))
980     (and succeeded?
981          (let ((p (derivation->output-path drv)))
982            (string-contains (call-with-input-file p read-line) "GNU")))))
984 (test-assert "build-expression->derivation with modules"
985   (let* ((builder  `(begin
986                       (use-modules (guix build utils))
987                       (let ((out (assoc-ref %outputs "out")))
988                         (mkdir-p (string-append out "/guile/guix/nix"))
989                         #t)))
990          (drv      (build-expression->derivation %store "test-with-modules"
991                                                  builder
992                                                  #:modules
993                                                  '((guix build utils)))))
994     (and (build-derivations %store (list drv))
995          (let* ((p (derivation->output-path drv))
996                 (s (stat (string-append p "/guile/guix/nix"))))
997            (eq? (stat:type s) 'directory)))))
999 (test-assert "build-expression->derivation: same fixed-output path"
1000   (let* ((builder1   '(call-with-output-file %output
1001                         (lambda (p)
1002                           (write "hello" p))))
1003          (builder2   '(call-with-output-file (pk 'difference-here! %output)
1004                         (lambda (p)
1005                           (write "hello" p))))
1006          (hash       (sha256 (string->utf8 "hello")))
1007          (input1     (build-expression->derivation %store "fixed" builder1
1008                                                    #:hash hash
1009                                                    #:hash-algo 'sha256))
1010          (input2     (build-expression->derivation %store "fixed" builder2
1011                                                    #:hash hash
1012                                                    #:hash-algo 'sha256))
1013          (succeeded? (build-derivations %store (list input1 input2))))
1014     (and succeeded?
1015          (not (string=? (derivation-file-name input1)
1016                         (derivation-file-name input2)))
1017          (string=? (derivation->output-path input1)
1018                    (derivation->output-path input2)))))
1020 (test-assert "build-expression->derivation with a fixed-output input"
1021   (let* ((builder1   '(call-with-output-file %output
1022                         (lambda (p)
1023                           (write "hello" p))))
1024          (builder2   '(call-with-output-file (pk 'difference-here! %output)
1025                         (lambda (p)
1026                           (write "hello" p))))
1027          (hash       (sha256 (string->utf8 "hello")))
1028          (input1     (build-expression->derivation %store "fixed" builder1
1029                                                    #:hash hash
1030                                                    #:hash-algo 'sha256))
1031          (input2     (build-expression->derivation %store "fixed" builder2
1032                                                    #:hash hash
1033                                                    #:hash-algo 'sha256))
1034          (builder3  '(let ((input (assoc-ref %build-inputs "input")))
1035                        (call-with-output-file %output
1036                          (lambda (out)
1037                            (format #f "My input is ~a.~%" input)))))
1038          (final1    (build-expression->derivation %store "final" builder3
1039                                                   #:inputs
1040                                                   `(("input" ,input1))))
1041          (final2    (build-expression->derivation %store "final" builder3
1042                                                   #:inputs
1043                                                   `(("input" ,input2)))))
1044     (and (string=? (derivation->output-path final1)
1045                    (derivation->output-path final2))
1046          (string=? (derivation->output-path final1)
1047                    (derivation-path->output-path
1048                     (derivation-file-name final1)))
1049          (build-derivations %store (list final1 final2)))))
1051 (test-assert "build-expression->derivation produces recursive fixed-output"
1052   (let* ((builder '(begin
1053                      (use-modules (srfi srfi-26))
1054                      (mkdir %output)
1055                      (chdir %output)
1056                      (call-with-output-file "exe"
1057                        (cut display "executable" <>))
1058                      (chmod "exe" #o777)
1059                      (symlink "exe" "symlink")
1060                      (mkdir "subdir")))
1061          (drv     (build-expression->derivation %store "fixed-rec" builder
1062                                                 #:hash-algo 'sha256
1063                                                 #:hash (base32
1064                                                         "10k1lw41wyrjf9mxydi0is5nkpynlsvgslinics4ppir13g7d74p")
1065                                                 #:recursive? #t)))
1066     (and (build-derivations %store (list drv))
1067          (let* ((dir    (derivation->output-path drv))
1068                 (exe    (string-append dir "/exe"))
1069                 (link   (string-append dir "/symlink"))
1070                 (subdir (string-append dir "/subdir")))
1071            (and (executable-file? exe)
1072                 (string=? "executable"
1073                           (call-with-input-file exe get-string-all))
1074                 (string=? "exe" (readlink link))
1075                 (file-is-directory? subdir))))))
1077 (test-assert "build-expression->derivation uses recursive fixed-output"
1078   (let* ((builder '(call-with-output-file %output
1079                      (lambda (port)
1080                        (display "hello" port))))
1081          (fixed   (build-expression->derivation %store "small-fixed-rec"
1082                                                 builder
1083                                                 #:hash-algo 'sha256
1084                                                 #:hash (base32
1085                                                         "0sg9f58l1jj88w6pdrfdpj5x9b1zrwszk84j81zvby36q9whhhqa")
1086                                                 #:recursive? #t))
1087          (in      (derivation->output-path fixed))
1088          (builder `(begin
1089                      (mkdir %output)
1090                      (chdir %output)
1091                      (symlink ,in "symlink")))
1092          (drv     (build-expression->derivation %store "fixed-rec-user"
1093                                                 builder
1094                                                 #:inputs `(("fixed" ,fixed)))))
1095     (and (build-derivations %store (list drv))
1096          (let ((out (derivation->output-path drv)))
1097            (string=? (readlink (string-append out "/symlink")) in)))))
1099 (test-assert "build-expression->derivation with #:references-graphs"
1100   (let* ((input   (add-text-to-store %store "foo" "hello"
1101                                      (list %bash %mkdir)))
1102          (builder '(copy-file "input" %output))
1103          (drv     (build-expression->derivation %store "references-graphs"
1104                                                 builder
1105                                                 #:references-graphs
1106                                                 `(("input" . ,input))))
1107          (out     (derivation->output-path drv)))
1108     (define (deps path . deps)
1109       (let ((count (length deps)))
1110         (string-append path "\n\n" (number->string count) "\n"
1111                        (string-join (sort deps string<?) "\n")
1112                        (if (zero? count) "" "\n"))))
1114     (and (build-derivations %store (list drv))
1115          (equal? (call-with-input-file out get-string-all)
1116                  (string-concatenate
1117                   (map cdr
1118                        (sort (map (lambda (p d)
1119                                     (cons p (apply deps p d)))
1120                                   (list input %bash %mkdir)
1121                                   (list (list %bash %mkdir)
1122                                         '() '()))
1123                              (lambda (x y)
1124                                (match x
1125                                  ((p1 . _)
1126                                   (match y
1127                                     ((p2 . _)
1128                                      (string<? p1 p2)))))))))))))
1130 (test-equal "map-derivation"
1131   "hello"
1132   (let* ((joke (package-derivation %store guile-1.8))
1133          (good (package-derivation %store %bootstrap-guile))
1134          (drv1 (build-expression->derivation %store "original-drv1"
1135                                              #f   ; systematically fail
1136                                              #:guile-for-build joke))
1137          (drv2 (build-expression->derivation %store "original-drv2"
1138                                              '(call-with-output-file %output
1139                                                 (lambda (p)
1140                                                   (display "hello" p)))))
1141          (drv3 (build-expression->derivation %store "drv-to-remap"
1142                                              '(let ((in (assoc-ref
1143                                                          %build-inputs "in")))
1144                                                 (copy-file in %output))
1145                                              #:inputs `(("in" ,drv1))
1146                                              #:guile-for-build joke))
1147          (drv4 (map-derivation %store drv3 `((,drv1 . ,drv2)
1148                                              (,joke . ,good))))
1149          (out  (derivation->output-path drv4)))
1150     (and (build-derivations %store (list (pk 'remapped drv4)))
1151          (call-with-input-file out get-string-all))))
1153 (test-equal "map-derivation, sources"
1154   "hello"
1155   (let* ((script1   (add-text-to-store %store "fail.sh" "exit 1"))
1156          (script2   (add-text-to-store %store "hi.sh" "echo -n hello > $out"))
1157          (bash-full (package-derivation %store (@ (gnu packages bash) bash)))
1158          (drv1      (derivation %store "drv-to-remap"
1160                                 ;; XXX: This wouldn't work in practice, but if
1161                                 ;; we append "/bin/bash" then we can't replace
1162                                 ;; it with the bootstrap bash, which is a
1163                                 ;; single file.
1164                                 (derivation->output-path bash-full)
1166                                 `("-e" ,script1)
1167                                 #:inputs `((,bash-full) (,script1))))
1168          (drv2      (map-derivation %store drv1
1169                                     `((,bash-full . ,%bash)
1170                                       (,script1 . ,script2))))
1171          (out       (derivation->output-path drv2)))
1172     (and (build-derivations %store (list (pk 'remapped* drv2)))
1173          (call-with-input-file out get-string-all))))
1175 (test-end)
1177 ;; Local Variables:
1178 ;; eval: (put 'with-http-server 'scheme-indent-function 2)
1179 ;; End: