diff options
| -rw-r--r-- | .dir-locals.el | 1 | ||||
| -rw-r--r-- | NEWS | 7 | ||||
| -rw-r--r-- | doc/guix.texi | 5 | ||||
| -rw-r--r-- | guix/scripts/pack.scm | 180 | ||||
| -rw-r--r-- | tests/pack.scm | 75 |
5 files changed, 265 insertions, 3 deletions
diff --git a/.dir-locals.el b/.dir-locals.el index 8f07a08eb5b..a4fcbfe7ca9 100644 --- a/.dir-locals.el +++ b/.dir-locals.el | |||
| @@ -75,6 +75,7 @@ | |||
| 75 | (eval . (put 'origin 'scheme-indent-function 0)) | 75 | (eval . (put 'origin 'scheme-indent-function 0)) |
| 76 | (eval . (put 'build-system 'scheme-indent-function 0)) | 76 | (eval . (put 'build-system 'scheme-indent-function 0)) |
| 77 | (eval . (put 'bag 'scheme-indent-function 0)) | 77 | (eval . (put 'bag 'scheme-indent-function 0)) |
| 78 | (eval . (put 'gexp->derivation 'scheme-indent-function 1)) | ||
| 78 | (eval . (put 'graft 'scheme-indent-function 0)) | 79 | (eval . (put 'graft 'scheme-indent-function 0)) |
| 79 | (eval . (put 'operating-system 'scheme-indent-function 0)) | 80 | (eval . (put 'operating-system 'scheme-indent-function 0)) |
| 80 | (eval . (put 'file-system 'scheme-indent-function 0)) | 81 | (eval . (put 'file-system 'scheme-indent-function 0)) |
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> | 5 | Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> |
| 6 | Copyright © 2016, 2017, 2018 Ricardo Wurmus <rekado@elephly.net> | 6 | Copyright © 2016, 2017, 2018 Ricardo Wurmus <rekado@elephly.net> |
| 7 | Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com> | ||
| 7 | 8 | ||
| 8 | Copying and distribution of this file, with or without modification, | 9 | Copying and distribution of this file, with or without modification, |
| 9 | are permitted in any medium without royalty provided the copyright | 10 | are permitted in any medium without royalty provided the copyright |
| @@ -11,10 +12,12 @@ Copyright © 2016, 2017, 2018 Ricardo Wurmus <rekado@elephly.net> | |||
| 11 | 12 | ||
| 12 | Please send Guix bug reports to bug-guix@gnu.org. | 13 | Please send Guix bug reports to bug-guix@gnu.org. |
| 13 | 14 | ||
| 14 | * Changes in 1.3.0 (since 1.2.0) | 15 | * Changes in 1.4.0 (since 1.3.0) |
| 15 | |||
| 16 | ** Package management | 16 | ** Package management |
| 17 | * New 'deb' format for the 'guix pack' command | ||
| 17 | 18 | ||
| 19 | * Changes in 1.3.0 (since 1.2.0) | ||
| 20 | ** Package management | ||
| 18 | *** POWER9 (powerpc64le-linux) is now supported as a technology preview | 21 | *** POWER9 (powerpc64le-linux) is now supported as a technology preview |
| 19 | *** New ‘--export-manifest’ and ‘--export-channels’ options of ‘guix package’ | 22 | *** New ‘--export-manifest’ and ‘--export-channels’ options of ‘guix package’ |
| 20 | *** New ‘--profile’ option for ‘guix environment’ | 23 | *** New ‘--profile’ option for ‘guix environment’ |
diff --git a/doc/guix.texi b/doc/guix.texi index 37936bb0f3d..e0668b1f5f4 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -6028,6 +6028,11 @@ This produces a SquashFS image containing all the specified binaries and | |||
| 6028 | symlinks, as well as empty mount points for virtual file systems like | 6028 | symlinks, as well as empty mount points for virtual file systems like |
| 6029 | procfs. | 6029 | procfs. |
| 6030 | 6030 | ||
| 6031 | @item deb | ||
| 6032 | This produces a Debian archive (a package with the @samp{.deb} file | ||
| 6033 | extension) containing all the specified binaries and symbolic links, | ||
| 6034 | that can be installed on top of any dpkg-based GNU/Linux distribution. | ||
| 6035 | |||
| 6031 | @quotation Note | 6036 | @quotation Note |
| 6032 | Singularity @emph{requires} you to provide @file{/bin/sh} in the image. | 6037 | Singularity @emph{requires} you to provide @file{/bin/sh} in the image. |
| 6033 | For that reason, @command{guix pack -f squashfs} always implies @code{-S | 6038 | For that reason, @command{guix pack -f squashfs} always implies @code{-S |
diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm index cee14441103..6d8b70d1c70 100644 --- a/guix/scripts/pack.scm +++ b/guix/scripts/pack.scm | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | ;;; Copyright © 2018 Efraim Flashner <efraim@flashner.co.il> | 6 | ;;; Copyright © 2018 Efraim Flashner <efraim@flashner.co.il> |
| 7 | ;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr> | 7 | ;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr> |
| 8 | ;;; Copyright © 2020 Eric Bavier <bavier@posteo.net> | 8 | ;;; Copyright © 2020 Eric Bavier <bavier@posteo.net> |
| 9 | ;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com> | ||
| 9 | ;;; | 10 | ;;; |
| 10 | ;;; This file is part of GNU Guix. | 11 | ;;; This file is part of GNU Guix. |
| 11 | ;;; | 12 | ;;; |
| @@ -65,6 +66,7 @@ | |||
| 65 | %compressors | 66 | %compressors |
| 66 | lookup-compressor | 67 | lookup-compressor |
| 67 | self-contained-tarball | 68 | self-contained-tarball |
| 69 | debian-archive | ||
| 68 | docker-image | 70 | docker-image |
| 69 | squashfs-image | 71 | squashfs-image |
| 70 | 72 | ||
| @@ -346,6 +348,10 @@ added to the pack." | |||
| 346 | #:target target | 348 | #:target target |
| 347 | #:references-graphs `(("profile" ,profile)))) | 349 | #:references-graphs `(("profile" ,profile)))) |
| 348 | 350 | ||
| 351 | |||
| 352 | ;;; | ||
| 353 | ;;; Singularity. | ||
| 354 | ;;; | ||
| 349 | (define (singularity-environment-file profile) | 355 | (define (singularity-environment-file profile) |
| 350 | "Return a shell script that defines the environment variables corresponding | 356 | "Return a shell script that defines the environment variables corresponding |
| 351 | to the search paths of PROFILE." | 357 | to the search paths of PROFILE." |
| @@ -372,6 +378,10 @@ to the search paths of PROFILE." | |||
| 372 | 378 | ||
| 373 | (computed-file "singularity-environment.sh" build)) | 379 | (computed-file "singularity-environment.sh" build)) |
| 374 | 380 | ||
| 381 | |||
| 382 | ;;; | ||
| 383 | ;;; SquashFS image format. | ||
| 384 | ;;; | ||
| 375 | (define* (squashfs-image name profile | 385 | (define* (squashfs-image name profile |
| 376 | #:key target | 386 | #:key target |
| 377 | (profile-name "guix-profile") | 387 | (profile-name "guix-profile") |
| @@ -546,6 +556,10 @@ added to the pack." | |||
| 546 | #:target target | 556 | #:target target |
| 547 | #:references-graphs `(("profile" ,profile)))) | 557 | #:references-graphs `(("profile" ,profile)))) |
| 548 | 558 | ||
| 559 | |||
| 560 | ;;; | ||
| 561 | ;;; Docker image format. | ||
| 562 | ;;; | ||
| 549 | (define* (docker-image name profile | 563 | (define* (docker-image name profile |
| 550 | #:key target | 564 | #:key target |
| 551 | (profile-name "guix-profile") | 565 | (profile-name "guix-profile") |
| @@ -635,6 +649,167 @@ the image." | |||
| 635 | 649 | ||
| 636 | 650 | ||
| 637 | ;;; | 651 | ;;; |
| 652 | ;;; Debian archive format. | ||
| 653 | ;;; | ||
| 654 | ;;; TODO: When relocatable option is selected, install to a unique prefix. | ||
| 655 | ;;; This would enable installation of multiple deb packs with conflicting | ||
| 656 | ;;; files at the same time. | ||
| 657 | ;;; TODO: Allow passing a custom control file from the CLI. | ||
| 658 | ;;; TODO: Allow providing a postinst script. | ||
| 659 | (define* (debian-archive name profile | ||
| 660 | #:key target | ||
| 661 | (profile-name "guix-profile") | ||
| 662 | deduplicate? | ||
| 663 | entry-point | ||
| 664 | (compressor (first %compressors)) | ||
| 665 | localstatedir? | ||
| 666 | (symlinks '()) | ||
| 667 | (archiver tar)) | ||
| 668 | "Return a Debian archive (.deb) containing a store initialized with the | ||
| 669 | closure of PROFILE, a derivation. The archive contains /gnu/store; if | ||
| 670 | LOCALSTATEDIR? is true, it also contains /var/guix, including /var/guix/db | ||
| 671 | with a properly initialized store database. The supported compressors are | ||
| 672 | \"none\", \"gz\" or \"xz\". | ||
| 673 | |||
| 674 | SYMLINKS must be a list of (SOURCE -> TARGET) tuples denoting symlinks to be | ||
| 675 | added to the pack." | ||
| 676 | ;; For simplicity, limit the supported compressors to the superset of | ||
| 677 | ;; compressors able to compress both the control file (gz or xz) and the | ||
| 678 | ;; data tarball (gz, bz2 or xz). | ||
| 679 | (define %valid-compressors '("gzip" "xz" "none")) | ||
| 680 | |||
| 681 | (let ((compressor-name (compressor-name compressor))) | ||
| 682 | (unless (member compressor-name %valid-compressors) | ||
| 683 | (leave (G_ "~a is not a valid Debian archive compressor. \ | ||
| 684 | Valid compressors are: ~a~%") compressor-name %valid-compressors))) | ||
| 685 | |||
| 686 | (when entry-point | ||
| 687 | (warning (G_ "entry point not supported in the '~a' format~%") | ||
| 688 | 'deb)) | ||
| 689 | |||
| 690 | (define data-tarball | ||
| 691 | (computed-file (string-append "data.tar" | ||
| 692 | (compressor-extension compressor)) | ||
| 693 | (self-contained-tarball/builder | ||
| 694 | profile | ||
| 695 | #:profile-name profile-name | ||
| 696 | #:compressor compressor | ||
| 697 | #:localstatedir? localstatedir? | ||
| 698 | #:symlinks symlinks | ||
| 699 | #:archiver archiver) | ||
| 700 | #:local-build? #f ;allow offloading | ||
| 701 | #:options (list #:references-graphs `(("profile" ,profile)) | ||
| 702 | #:target target))) | ||
| 703 | |||
| 704 | (define build | ||
| 705 | (with-extensions (list guile-gcrypt) | ||
| 706 | (with-imported-modules `(((guix config) => ,(make-config.scm)) | ||
| 707 | ,@(source-module-closure | ||
| 708 | `((guix build pack) | ||
| 709 | (guix build utils) | ||
| 710 | (guix profiles)) | ||
| 711 | #:select? not-config?)) | ||
| 712 | #~(begin | ||
| 713 | (use-modules (guix build pack) | ||
| 714 | (guix build utils) | ||
| 715 | (guix profiles) | ||
| 716 | (ice-9 match) | ||
| 717 | (srfi srfi-1)) | ||
| 718 | |||
| 719 | (define machine-type | ||
| 720 | ;; Extract the machine type from the specified target, else from the | ||
| 721 | ;; current system. | ||
| 722 | (and=> (or #$target %host-type) (lambda (triplet) | ||
| 723 | (first (string-split triplet #\-))))) | ||
| 724 | |||
| 725 | (define (gnu-machine-type->debian-machine-type type) | ||
| 726 | "Translate machine TYPE from the GNU to Debian terminology." | ||
| 727 | ;; Debian has its own jargon, different from the one used in GNU, for | ||
| 728 | ;; machine types (see data/cputable in the sources of dpkg). | ||
| 729 | (match type | ||
| 730 | ("i586" "i386") | ||
| 731 | ("i486" "i386") | ||
| 732 | ("i686" "i386") | ||
| 733 | ("x86_64" "amd64") | ||
| 734 | ("aarch64" "arm64") | ||
| 735 | ("mipsisa32r6" "mipsr6") | ||
| 736 | ("mipsisa32r6el" "mipsr6el") | ||
| 737 | ("mipsisa64r6" "mips64r6") | ||
| 738 | ("mipsisa64r6el" "mips64r6el") | ||
| 739 | ("powerpcle" "powerpcel") | ||
| 740 | ("powerpc64" "ppc64") | ||
| 741 | ("powerpc64le" "ppc64el") | ||
| 742 | (machine machine))) | ||
| 743 | |||
| 744 | (define architecture | ||
| 745 | (gnu-machine-type->debian-machine-type machine-type)) | ||
| 746 | |||
| 747 | #$(procedure-source manifest->friendly-name) | ||
| 748 | |||
| 749 | (define manifest (profile-manifest #$profile)) | ||
| 750 | |||
| 751 | (define single-entry ;manifest entry | ||
| 752 | (match (manifest-entries manifest) | ||
| 753 | ((entry) | ||
| 754 | entry) | ||
| 755 | (() #f))) | ||
| 756 | |||
| 757 | (define package-name (or (and=> single-entry manifest-entry-name) | ||
| 758 | (manifest->friendly-name manifest))) | ||
| 759 | |||
| 760 | (define package-version | ||
| 761 | (or (and=> single-entry manifest-entry-version) | ||
| 762 | "0.0.0")) | ||
| 763 | |||
| 764 | (define debian-format-version "2.0") | ||
| 765 | |||
| 766 | ;; Generate the debian-binary file. | ||
| 767 | (call-with-output-file "debian-binary" | ||
| 768 | (lambda (port) | ||
| 769 | (format port "~a~%" debian-format-version))) | ||
| 770 | |||
| 771 | (define data-tarball-file-name (strip-store-file-name | ||
| 772 | #+data-tarball)) | ||
| 773 | |||
| 774 | (copy-file #+data-tarball data-tarball-file-name) | ||
| 775 | |||
| 776 | (define control-tarball-file-name | ||
| 777 | (string-append "control.tar" | ||
| 778 | #$(compressor-extension compressor))) | ||
| 779 | |||
| 780 | ;; Write the compressed control tarball. Only the control file is | ||
| 781 | ;; mandatory (see: 'man deb' and 'man deb-control'). | ||
| 782 | (call-with-output-file "control" | ||
| 783 | (lambda (port) | ||
| 784 | (format port "\ | ||
| 785 | Package: ~a | ||
| 786 | Version: ~a | ||
| 787 | Description: Debian archive generated by GNU Guix. | ||
| 788 | Maintainer: GNU Guix | ||
| 789 | Architecture: ~a | ||
| 790 | ~%" package-name package-version architecture))) | ||
| 791 | |||
| 792 | (define tar (string-append #+archiver "/bin/tar")) | ||
| 793 | |||
| 794 | (apply invoke tar | ||
| 795 | `(,@(tar-base-options | ||
| 796 | #:tar tar | ||
| 797 | #:compressor '#+(and=> compressor compressor-command)) | ||
| 798 | "-cvf" ,control-tarball-file-name | ||
| 799 | "control")) | ||
| 800 | |||
| 801 | ;; Create the .deb archive using GNU ar. | ||
| 802 | (invoke (string-append #+binutils "/bin/ar") "-rv" #$output | ||
| 803 | "debian-binary" | ||
| 804 | control-tarball-file-name data-tarball-file-name))))) | ||
| 805 | |||
| 806 | (gexp->derivation (string-append name ".deb") | ||
| 807 | build | ||
| 808 | #:target target | ||
| 809 | #:references-graphs `(("profile" ,profile)))) | ||
| 810 | |||
| 811 | |||
| 812 | ;;; | ||
| 638 | ;;; Compiling C programs. | 813 | ;;; Compiling C programs. |
| 639 | ;;; | 814 | ;;; |
| 640 | 815 | ||
| @@ -965,7 +1140,8 @@ last resort for relocation." | |||
| 965 | ;; Supported pack formats. | 1140 | ;; Supported pack formats. |
| 966 | `((tarball . ,self-contained-tarball) | 1141 | `((tarball . ,self-contained-tarball) |
| 967 | (squashfs . ,squashfs-image) | 1142 | (squashfs . ,squashfs-image) |
| 968 | (docker . ,docker-image))) | 1143 | (docker . ,docker-image) |
| 1144 | (deb . ,debian-archive))) | ||
| 969 | 1145 | ||
| 970 | (define (show-formats) | 1146 | (define (show-formats) |
| 971 | ;; Print the supported pack formats. | 1147 | ;; Print the supported pack formats. |
| @@ -977,6 +1153,8 @@ last resort for relocation." | |||
| 977 | squashfs Squashfs image suitable for Singularity")) | 1153 | squashfs Squashfs image suitable for Singularity")) |
| 978 | (display (G_ " | 1154 | (display (G_ " |
| 979 | docker Tarball ready for 'docker load'")) | 1155 | docker Tarball ready for 'docker load'")) |
| 1156 | (display (G_ " | ||
| 1157 | deb Debian archive installable via dpkg/apt")) | ||
| 980 | (newline)) | 1158 | (newline)) |
| 981 | 1159 | ||
| 982 | (define %options | 1160 | (define %options |
diff --git a/tests/pack.scm b/tests/pack.scm index ae6247a1d51..9473d4f384d 100644 --- a/tests/pack.scm +++ b/tests/pack.scm | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> | 2 | ;;; Copyright © 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> |
| 3 | ;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net> | 3 | ;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net> |
| 4 | ;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com> | ||
| 4 | ;;; | 5 | ;;; |
| 5 | ;;; This file is part of GNU Guix. | 6 | ;;; This file is part of GNU Guix. |
| 6 | ;;; | 7 | ;;; |
| @@ -32,6 +33,7 @@ | |||
| 32 | #:use-module ((gnu packages base) #:select (glibc-utf8-locales)) | 33 | #:use-module ((gnu packages base) #:select (glibc-utf8-locales)) |
| 33 | #:use-module (gnu packages bootstrap) | 34 | #:use-module (gnu packages bootstrap) |
| 34 | #:use-module ((gnu packages compression) #:select (squashfs-tools)) | 35 | #:use-module ((gnu packages compression) #:select (squashfs-tools)) |
| 36 | #:use-module ((gnu packages debian) #:select (dpkg)) | ||
| 35 | #:use-module ((gnu packages guile) #:select (guile-sqlite3)) | 37 | #:use-module ((gnu packages guile) #:select (guile-sqlite3)) |
| 36 | #:use-module ((gnu packages gnupg) #:select (guile-gcrypt)) | 38 | #:use-module ((gnu packages gnupg) #:select (guile-gcrypt)) |
| 37 | #:use-module (srfi srfi-64)) | 39 | #:use-module (srfi srfi-64)) |
| @@ -56,6 +58,8 @@ | |||
| 56 | 58 | ||
| 57 | (define %tar-bootstrap %bootstrap-coreutils&co) | 59 | (define %tar-bootstrap %bootstrap-coreutils&co) |
| 58 | 60 | ||
| 61 | (define %ar-bootstrap %bootstrap-binutils) | ||
| 62 | |||
| 59 | 63 | ||
| 60 | (test-begin "pack") | 64 | (test-begin "pack") |
| 61 | 65 | ||
| @@ -270,6 +274,77 @@ | |||
| 270 | 1) | 274 | 1) |
| 271 | (pk 'guilelink (readlink "bin")))) | 275 | (pk 'guilelink (readlink "bin")))) |
| 272 | (mkdir #$output)))))))) | 276 | (mkdir #$output)))))))) |
| 277 | (built-derivations (list check)))) | ||
| 278 | |||
| 279 | (unless store (test-skip 1)) | ||
| 280 | (test-assertm "deb archive with symlinks" store | ||
| 281 | (mlet* %store-monad | ||
| 282 | ((guile (set-guile-for-build (default-guile))) | ||
| 283 | (profile (profile-derivation (packages->manifest | ||
| 284 | (list %bootstrap-guile)) | ||
| 285 | #:hooks '() | ||
| 286 | #:locales? #f)) | ||
| 287 | (deb (debian-archive "deb-pack" profile | ||
| 288 | #:compressor %gzip-compressor | ||
| 289 | #:symlinks '(("/opt/gnu/bin" -> "bin")) | ||
| 290 | #:archiver %tar-bootstrap)) | ||
| 291 | (check | ||
| 292 | (gexp->derivation "check-deb-pack" | ||
| 293 | (with-imported-modules '((guix build utils)) | ||
| 294 | #~(begin | ||
| 295 | (use-modules (guix build utils) | ||
| 296 | (ice-9 match) | ||
| 297 | (ice-9 popen) | ||
| 298 | (ice-9 rdelim) | ||
| 299 | (ice-9 textual-ports) | ||
| 300 | (rnrs base)) | ||
| 301 | |||
| 302 | (setenv "PATH" (string-join | ||
| 303 | (list (string-append #+%tar-bootstrap "/bin") | ||
| 304 | (string-append #+dpkg "/bin") | ||
| 305 | (string-append #+%ar-bootstrap "/bin")) | ||
| 306 | ":")) | ||
| 307 | |||
| 308 | ;; Validate the output of 'dpkg --info'. | ||
| 309 | (let* ((port (open-pipe* OPEN_READ "dpkg" "--info" #$deb)) | ||
| 310 | (info (get-string-all port)) | ||
| 311 | (exit-val (status:exit-val (close-pipe port)))) | ||
| 312 | (assert (zero? exit-val)) | ||
| 313 | |||
| 314 | (assert (string-contains | ||
| 315 | info | ||
| 316 | (string-append "Package: " | ||
| 317 | #+(package-name %bootstrap-guile)))) | ||
| 318 | |||
| 319 | (assert (string-contains | ||
| 320 | info | ||
| 321 | (string-append "Version: " | ||
| 322 | #+(package-version %bootstrap-guile))))) | ||
| 323 | |||
| 324 | ;; Sanity check .deb contents. | ||
| 325 | (invoke "ar" "-xv" #$deb) | ||
| 326 | (assert (file-exists? "debian-binary")) | ||
| 327 | (assert (file-exists? "data.tar.gz")) | ||
| 328 | (assert (file-exists? "control.tar.gz")) | ||
| 329 | |||
| 330 | ;; Verify there are no hard links in data.tar.gz, as hard | ||
| 331 | ;; links would cause dpkg to fail unpacking the archive. | ||
| 332 | (define hard-links | ||
| 333 | (let ((port (open-pipe* OPEN_READ "tar" "-tvf" "data.tar.gz"))) | ||
| 334 | (let loop ((hard-links '())) | ||
| 335 | (match (read-line port) | ||
| 336 | ((? eof-object?) | ||
| 337 | (assert (zero? (status:exit-val (close-pipe port)))) | ||
| 338 | hard-links) | ||
| 339 | (line | ||
| 340 | (if (string-prefix? "u" line) | ||
| 341 | (loop (cons line hard-links)) | ||
| 342 | (loop hard-links))))))) | ||
| 343 | |||
| 344 | (unless (null? hard-links) | ||
| 345 | (error "hard links found in data.tar.gz" hard-links)) | ||
| 346 | |||
| 347 | (mkdir #$output)))))) | ||
| 273 | (built-derivations (list check))))) | 348 | (built-derivations (list check))))) |
| 274 | 349 | ||
| 275 | (test-end) | 350 | (test-end) |
