diff options
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | TODO | 13 | ||||
-rw-r--r-- | distro/packages/algebra.scm | 27 | ||||
-rw-r--r-- | distro/packages/aspell.scm | 54 | ||||
-rw-r--r-- | distro/packages/dejagnu.scm | 87 | ||||
-rw-r--r-- | distro/packages/global.scm | 58 | ||||
-rw-r--r-- | distro/packages/tcl.scm | 96 | ||||
-rw-r--r-- | doc/guix.texi | 235 | ||||
-rw-r--r-- | guix-package.in | 35 | ||||
-rw-r--r-- | guix/build/union.scm | 66 | ||||
-rw-r--r-- | guix/derivations.scm | 52 | ||||
-rw-r--r-- | guix/gnu-maintenance.scm | 138 | ||||
-rw-r--r-- | guix/snix.scm | 35 | ||||
-rw-r--r-- | nix/nix-daemon/guix-daemon.cc | 8 | ||||
-rw-r--r-- | tests/derivations.scm | 38 | ||||
-rw-r--r-- | tests/guix-package.sh | 12 | ||||
-rw-r--r-- | tests/snix.scm | 4 | ||||
-rw-r--r-- | tests/union.scm | 19 |
18 files changed, 919 insertions, 62 deletions
diff --git a/Makefile.am b/Makefile.am index 4e80325e98..487ac05ec4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -46,6 +46,7 @@ MODULES = \ distro.scm \ distro/packages/acl.scm \ distro/packages/algebra.scm \ + distro/packages/aspell.scm \ distro/packages/attr.scm \ distro/packages/autotools.scm \ distro/packages/base.scm \ @@ -57,12 +58,14 @@ MODULES = \ distro/packages/compression.scm \ distro/packages/cpio.scm \ distro/packages/bdb.scm \ + distro/packages/dejagnu.scm \ distro/packages/ddrescue.scm \ distro/packages/ed.scm \ distro/packages/flex.scm \ distro/packages/gawk.scm \ distro/packages/gdbm.scm \ distro/packages/gettext.scm \ + distro/packages/global.scm \ distro/packages/gnupg.scm \ distro/packages/gnutls.scm \ distro/packages/gperf.scm \ @@ -96,6 +99,7 @@ MODULES = \ distro/packages/rsync.scm \ distro/packages/shishi.scm \ distro/packages/system.scm \ + distro/packages/tcl.scm \ distro/packages/texinfo.scm \ distro/packages/time.scm \ distro/packages/wget.scm \ @@ -1,6 +1,6 @@ -*- mode: org; coding: utf-8; -*- -Copyright © 2012 Ludovic Courtès <ludo@gnu.org> +Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org> Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -23,6 +23,16 @@ X.509 SubjectPublicKeyInfo. These can be decoded with the [[http://lists.gnu.or GnuTLS]], but not yet with its Guile bindings. There’s also ‘gnutls_privkey_sign_data’ to sign, and related functions. +** Add a binary cache substituter + +Like scripts/download-from-binary-cache.pl in Nix, but written in +Scheme. Substituters allow pre-built binaries to be downloaded when +they are available from a trusted source. + +** Add a remote build hook + +Like scripts/build-remote.pl in Nix. + * infrastructure ** have a Hydra instance build Guix packages @@ -101,7 +111,6 @@ Would allow build expressions to have system-dependent code, like [[file:~/src/nix/src/libstore/build.cc::if%20(drv.env.find("allowedReferences")%20!%3D%20drv.env.end())%20{][See how Nix implements that internally]]. - * union Support sophisticated collision handling when building a union: check diff --git a/distro/packages/algebra.scm b/distro/packages/algebra.scm index f348955094..0cbc5c4597 100644 --- a/distro/packages/algebra.scm +++ b/distro/packages/algebra.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2012 Andreas Enge <andreas@enge.fr> +;;; Copyright © 2013 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -74,3 +75,29 @@ multiplication routines such as Toom–Cook and the FFT. ") solve the shortest vector problem.") (license lgpl2.1+) (home-page "http://perso.ens-lyon.fr/damien.stehle/fplll/"))) + +(define-public gsl + (package + (name "gsl") + (version "1.15") + (source + (origin + (method url-fetch) + (uri (string-append "mirror://gnu/gsl/gsl-" + version ".tar.gz")) + (sha256 + (base32 + "18qf6jzz1r3mzb5qynywv4xx3z9g61hgkbpkdrhbgqh2g7jhgfc5")))) + (build-system gnu-build-system) + (home-page "http://www.gnu.org/software/gsl/") + (synopsis "The GNU Scientific Library, a large numerical library") + (description + "The GNU Scientific Library (GSL) is a numerical library for C +and C++ programmers. It is free software under the GNU General +Public License. + +The library provides a wide range of mathematical routines such +as random number generators, special functions and least-squares +fitting. There are over 1000 functions in total with an +extensive test suite.") + (license gpl3+))) diff --git a/distro/packages/aspell.scm b/distro/packages/aspell.scm new file mode 100644 index 0000000000..a4c14c092c --- /dev/null +++ b/distro/packages/aspell.scm @@ -0,0 +1,54 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2013 Ludovic Courtès <ludo@gnu.org> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (distro packages aspell) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix build-system gnu) + #:use-module (guix licenses) + #:use-module (distro packages perl)) + +(define-public aspell + (package + (name "aspell") + (version "0.60.6.1") + (source + (origin + (method url-fetch) + (uri (string-append "mirror://gnu/aspell/aspell-" + version ".tar.gz")) + (sha256 + (base32 + "1qgn5psfyhbrnap275xjfrzppf5a83fb67gpql0kfqv37al869gm")))) + (build-system gnu-build-system) + (inputs `(("perl" ,perl))) + (home-page "http://aspell.net/") + (synopsis + "GNU Aspell, A spell checker for many languages") + (description + "GNU Aspell is a free spell checker designed to eventually replace +Ispell. It can either be used as a library or as an independent spell +checker. Its main feature is that it does a superior job of suggesting +possible replacements for a misspelled word than just about any other +spell checker out there for the English language. Unlike Ispell, Aspell +can also easily check documents in UTF-8 without having to use a special +dictionary. Aspell will also do its best to respect the current locale +setting. Other advantages over Ispell include support for using +multiple dictionaries at once and intelligently handling personal +dictionaries when more than one Aspell process is open at once.") + (license lgpl2.1+))) diff --git a/distro/packages/dejagnu.scm b/distro/packages/dejagnu.scm new file mode 100644 index 0000000000..bb735bfe37 --- /dev/null +++ b/distro/packages/dejagnu.scm @@ -0,0 +1,87 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2013 Ludovic Courtès <ludo@gnu.org> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (distro packages dejagnu) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix build-system gnu) + #:use-module (guix licenses) + #:use-module (distro packages tcl)) + +(define-public dejagnu + (package + (name "dejagnu") + (version "1.5") + (source + (origin + (method url-fetch) + (uri (string-append "mirror://gnu/dejagnu/dejagnu-" + version ".tar.gz")) + (sha256 + (base32 + "1nx3x3h96a82q92q108q71giv2nz9xmbbn2nrlr3wvvs6l45id68")))) + (build-system gnu-build-system) + (inputs `(("expect" ,expect))) + (arguments + '(#:phases (alist-replace + 'check + (lambda _ + ;; Note: The test-suite *requires* /dev/pts among the + ;; `build-chroot-dirs' of the build daemon when + ;; building in a chroot. See + ;; <http://thread.gmane.org/gmane.linux.distributions.nixos/1036> + ;; for details. + (if (and (directory-exists? "/dev/pts") + (directory-exists? "/proc")) + (begin + ;; Provide `runtest' with a log name, otherwise + ;; it tries to run `whoami', which fails when in + ;; a chroot. + (setenv "LOGNAME" "guix-builder") + + ;; The test-suite needs to have a non-empty stdin: + ;; <http://lists.gnu.org/archive/html/bug-dejagnu/2003-06/msg00002.html>. + (zero? + (system "make check < /dev/zero"))) + (begin + (display "test suite cannot be run, skipping\n") + #t))) + (alist-cons-after + 'install 'post-install + (lambda* (#:key inputs outputs #:allow-other-keys) + ;; Use the right `expect' binary. + (let ((out (assoc-ref outputs "out")) + (expect (assoc-ref inputs "expect"))) + (substitute* (string-append out "/bin/runtest") + (("expectbin=expect") + (string-append "expectbin=" + expect "/bin/expect"))))) + %standard-phases)))) + (home-page + "http://www.gnu.org/software/dejagnu/") + (synopsis "The DejaGNU testing framework") + (description + "DejaGnu is a framework for testing other programs. Its purpose +is to provide a single front end for all tests. Think of it as a +custom library of Tcl procedures crafted to support writing a +test harness. A test harness is the testing infrastructure that +is created to support a specific program or tool. Each program +can have multiple testsuites, all supported by a single test +harness. DejaGnu is written in Expect, which in turn uses Tcl -- +Tool command language.") + (license gpl2+))) diff --git a/distro/packages/global.scm b/distro/packages/global.scm new file mode 100644 index 0000000000..ddd28c2887 --- /dev/null +++ b/distro/packages/global.scm @@ -0,0 +1,58 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2013 Ludovic Courtès <ludo@gnu.org> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (distro packages global) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix build-system gnu) + #:use-module (guix licenses) + #:use-module (distro packages ncurses) + #:use-module (distro packages autotools) + #:use-module (distro)) + +(define-public global ; a global variable + (package + (name "global") + (version "6.2.7") + (source + (origin + (method url-fetch) + (uri (string-append "mirror://gnu/global/global-" + version ".tar.gz")) + (sha256 + (base32 + "1dr250kz65wqpbms4lhz857mzmvmpmiaxgyqxvxkb4b0s840i14i")))) + (build-system gnu-build-system) + (inputs `(("ncurses" ,ncurses) + ("libtool" ,libtool))) + (arguments + `(#:configure-flags + (list (string-append "--with-ncurses=" + (assoc-ref %build-inputs "ncurses"))))) + (home-page "http://www.gnu.org/software/global/") + (synopsis "GNU GLOBAL source code tag system") + (description + "GNU GLOBAL is a source code tagging system that works the same way +across diverse environments (Emacs, vi, less, Bash, web browser, etc). +You can locate specified objects in source files and move there easily. +It is useful for hacking a large project containing many +subdirectories, many #ifdef and many main() functions. It is similar +to ctags or etags but is different from them at the point of +independence of any editor. It runs on a UNIX (POSIX) compatible +operating system like GNU and BSD.") + (license "GPLv3+"))) diff --git a/distro/packages/tcl.scm b/distro/packages/tcl.scm new file mode 100644 index 0000000000..369c986ffb --- /dev/null +++ b/distro/packages/tcl.scm @@ -0,0 +1,96 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2013 Ludovic Courtès <ludo@gnu.org> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (distro packages tcl) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix build-system gnu) + #:use-module (guix licenses)) + +(define-public tcl + (package + (name "tcl") + (version "8.6.0") + (source + (origin + (method url-fetch) + (uri (string-append "mirror://sourceforge/tcl/Tcl/" + version "/tcl" version "-src.tar.gz")) + (sha256 + (base32 + "1pnabp3xsja4rc8c01l9q1avb65a3zhdzci3j54qa5krqjwj4i1m")))) + (build-system gnu-build-system) + (arguments + '(#:phases (alist-cons-before + 'configure 'pre-configure + (lambda _ + (chdir "unix")) + (alist-cons-after + 'install 'install-private-headers + (lambda _ + ;; Private headers are needed by Expect. + (zero? (system* "make" "install-private-headers"))) + %standard-phases)) + #:tests? #f)) ; FIXME: use #:test-target "test" + (home-page "http://www.tcl.tk/") + (synopsis "The Tcl scripting language") + (description "The Tcl (Tool Command Language) scripting language.") + (license (bsd-style "http://www.tcl.tk/software/tcltk/license.html" + "Tcl/Tk license")))) + + +(define-public expect + (package + (name "expect") + (version "5.45") + (source + (origin + (method url-fetch) + (uri (string-append "mirror://sourceforge/expect/Expect/" + version "/expect" version ".tar.gz")) + (sha256 + (base32 + "0h60bifxj876afz4im35rmnbnxjx4lbdqp2ja3k30fwa8a8cm3dj")))) + (build-system gnu-build-system) + (inputs + `(;; TODO: Add these optional dependencies. + ;; ("libX11" ,libX11) + ;; ("xproto" ,xproto) + ;; ("tk" ,tk) + ("tcl" ,tcl))) + (arguments + '(#:configure-flags + (list (string-append "--with-tcl=" + (assoc-ref %build-inputs "tcl") + "/lib") + (string-append "--with-tclinclude=" + (assoc-ref %build-inputs "tcl") + "/include") + (string-append "--exec-prefix=" + (assoc-ref %outputs "out"))) + #:tests? #f)) ; FIXME: use #:test-target "test" + (home-page "http://expect.nist.gov/") + (synopsis + "A tool for automating interactive applications") + (description + "Expect is a tool for automating interactive applications such as +telnet, ftp, passwd, fsck, rlogin, tip, etc. Expect really makes this +stuff trivial. Expect is also useful for testing these same +applications. And by adding Tk, you can wrap interactive applications in +X11 GUIs.") + (license public-domain))) ; as written in `license.terms' diff --git a/doc/guix.texi b/doc/guix.texi index c7f6683677..2af0c88133 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -8,6 +8,7 @@ @c %**end of header @include version.texi +@set YEARS 2012, 2013 @dircategory Package management @direntry @@ -28,7 +29,7 @@ Edition @value{EDITION} @* @value{UPDATED} @* -Copyright @copyright{} 2012 Ludovic Court@`es +Copyright @copyright{} @value{YEARS} Ludovic Court@`es @quotation Permission is granted to copy, distribute and/or modify this document @@ -43,7 +44,7 @@ Documentation License''. @copying This manual documents GNU Guix version @value{VERSION}. -Copyright (C) 2012, 2013 Ludovic Courtès +Copyright @copyright{} @value{YEARS} Ludovic Courtès Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -62,8 +63,20 @@ Documentation License.'' This document describes GNU Guix version @value{VERSION}, a functional package management tool written for the GNU system. +@quotation +Copyright @copyright{} @value{YEARS} Ludovic Courtès + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.3 or +any later version published by the Free Software Foundation; with no +Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A +copy of the license is included in the section entitled ``GNU Free +Documentation License.'' +@end quotation + @menu * Introduction:: What is Guix about? +* Installation:: Installing Guix. * Package Management:: Package installation, upgrade, etc. * Programming Interface:: Using Guix in Scheme. * Utilities:: Package management commands. @@ -119,6 +132,212 @@ upgrade, and remove packages, as well as a Scheme programming interface. The remainder of this manual describes them. @c ********************************************************************* +@node Installation +@chapter Installation + +This section describes the software requirements of Guix, as well as how +to install it and get ready to use it. + +@menu +* Requirements:: Software needed to build and run Guix. +* Setting Up the Daemon:: Preparing the build daemon's environment. +* Invoking guix-daemon:: Running the build daemon. +@end menu + +@node Requirements +@section Requirements + +GNU Guix depends on the following packages: + +@itemize +@item @url{http://gnu.org/software/guile/, GNU Guile 2.0.x}; +@item @url{http://gnupg.org/, GNU libgcrypt} +@end itemize + +Unless @code{--disable-daemon} was passed to @command{configure}, the +following packages are also needed: + +@itemize +@item @url{http://sqlite.org, SQLite 3} +@item @url{http://www.bzip.org, libbz2} +@item @url{http://gcc.gnu.org, GCC's g++} +@end itemize + +When a working installation of the Nix package manager is available, you +can instead configure Guix with @code{--disable-daemon}. In that case, +@url{http://nixos.org/nix/, Nix} replaces the three dependencies above. + +@node Setting Up the Daemon +@section Setting Up the Daemon + +@cindex daemon +Operations such as building a package or running the garbage collector +are all performed by a specialized process, the @dfn{Guix daemon}, on +behalf of clients. Only the daemon may access the store and its +associated database. Thus, any operation that manipulates the store +goes through the daemon. For instance, command-line tools such as +@command{guix-package} and @command{guix-build} communicate with the +daemon (@i{via} remote procedure calls) to instruct it what to do. + +In a standard multi-user setup, Guix and its daemon---the +@command{guix-daemon} program---are installed by the system +administrator; @file{/nix/store} is owned by @code{root} and +@command{guix-daemon} runs as @code{root}. Unprivileged users may use +Guix tools to build packages or otherwise access the store, and the +daemon will do it on their behalf, ensuring that the store is kept in a +consistent state, and allowing built packages to be shared among users. + +@cindex build users +When @command{guix-daemon} runs as @code{root}, you may not want package +build processes themselves to run as @code{root} too, for obvious +security reasons. To avoid that, a special pool of @dfn{build users} +should be created for use by build processes started by the daemon. +These build users need not have a shell and a home directory: they will +just be used when the daemon drops @code{root} privileges in build +processes. Having several such users allows the daemon to launch +distinct build processes under separate UIDs, which guarantees that they +do not interfere with each other---an essential feature since builds are +regarded as pure functions (@pxref{Introduction}). + +On a GNU/Linux system, a build user pool may be created like this (using +Bash syntax and the @code{shadow} commands): + +@example +# groupadd guix-builder +# for i in `seq 1 10`; + do + useradd -g guix-builder -d /var/empty -s `which nologin` \ + -m "Guix build user $i" guix-builder$i; + done +@end example + +@noindent +The @code{guix-daemon} program may then be run as @code{root} with: + +@example +# guix-daemon --build-users-group=guix-builder +@end example + +Guix may also be used in a single-user setup, with @command{guix-daemon} +running as a unprivileged user. However, to maximize non-interference +of build processes, the daemon still needs to perform certain operations +that are restricted to @code{root} on GNU/Linux: it should be able to +run build processes in a chroot, and to run them under different UIDs. +To that end, the @command{nix-setuid-helper} program is provided; it is +a small C program (less than 300 lines) that, if it is made setuid +@code{root}, can be executed by the daemon to perform these operations +on its behalf. The @code{root}-owned @file{/etc/nix-setuid.conf} file +is read by @command{nix-setuid-helper}; it should contain exactly two +words: the user name under which the authorized @command{guix-daemon} +runs, and the name of the build users group. + +If you are installing Guix as an unprivileged user and do not have the +ability to make @file{nix-setuid-helper} setuid-@code{root}, it is still +possible to run @command{guix-daemon}. However, build processes will +not be isolated from one another, and not from the rest of the system. +Thus, build processes may interfere with each other, and may access +programs, libraries, and other files available on the system---making it +much harder to view them as @emph{pure} functions. + +@node Invoking guix-daemon +@section Invoking @command{guix-daemon} + +The @command{guix-daemon} program implements all the functionality to +access the store. This includes launching build processes, running the +garbage collector, querying the availability of a build result, etc. It +is normally run as @code{root} like this: + +@example +# guix-daemon --build-users-group=guix-builder +@end example + +@noindent +For details on how to set it up, @ref{Setting Up the Daemon}. + +By default, @command{guix-daemon} launches build processes under +different UIDs, taken from the build group specified with +@code{--build-users-group}. In addition, each build process is run in a +chroot environment that only contains the subset of the store that the +build process depends on, as specified by its derivation +(@pxref{Programming Interface, derivation}), plus a set of specific +system directories. By default, the latter contains @file{/dev} and +@file{/dev/pts}. + +The following command-line options are supported: + +@table @code +@item --build-users-group=@var{group} +Take users from @var{group} to run build processes (@pxref{Setting Up +the Daemon, build users}). + +@item --cache-failures +Cache build failures. By default, only successful builds are cached. + +@item --cores=@var{n} +@itemx -c @var{n} +Use @var{n} CPU cores to build each derivation; @code{0} means as many +as available. + +The default value is @code{1}, but it may be overridden by clients, such +as the @code{--cores} option of @command{guix-build} (@pxref{Invoking +guix-build}). + +The effect is to define the @code{NIX_BUILD_CORES} environment variable +in the build process, which can then use it to exploit internal +parallelism---for instance, by running @code{make -j$NIX_BUILD_CORES}. + +@item --max-jobs=@var{n} +@itemx -M @var{n} +Allow at most @var{n} build jobs in parallel. The default value is +@code{1}. + +@item --debug +Produce debugging output. + +This is useful to debug daemon start-up issues, but then it may be +overridden by clients, for example the @code{--verbosity} option of +@command{guix-build} (@pxref{Invoking guix-build}). + +@item --chroot-directory=@var{dir} +Add @var{dir} to the build chroot. + +Doing this may change the result of build processes---for instance if +they use optional dependencies found in @var{dir} when it is available, +and not otherwise. For that reason, it is not recommended to do so. +Instead, make sure that each derivation declares all the inputs that it +needs. + +@item --disable-chroot +Disable chroot builds. + +Using this option is not recommended since, again, it would allow build +processes to gain access to undeclared dependencies. + +@item --disable-log-compression +Disable compression of the build logs. + +@item --disable-store-optimization +Disable automatic file ``deduplication'' in the store. + +@item --impersonate-linux-2.6 +On Linux-based systems, impersonate Linux 2.6. This means that the +kernel's @code{uname} system call will report 2.6 as the release number. + +This might be helpful to build programs that (usually wrongfully) depend +on the kernel version number. + +@item --lose-logs +Do not keep build logs. By default they are kept under +@code{@var{localstatedir}/nix/log}. + +@item --system=@var{system} +Assume @var{system} as the current system type. By default it is the +architecture/kernel pair found at configure time, such as +@code{x86_64-linux}. +@end table + + +@c ********************************************************************* @node Package Management @chapter Package Management @@ -209,6 +428,12 @@ the transaction. Upon completion, a new profile is created, but previous generations of the profile remain available, should the user want to roll back. +For each user, a symlink to the user's default profile is automatically +created in @file{$HOME/.guix-profile}. This symlink always point to the +current generation of the user's default profile. Thus, users can add +@file{$HOME/.guix-profile/bin} to their @code{PATH} environment +variable, and so on. + @table @code @item --install=@var{package} @@ -217,7 +442,7 @@ Install @var{package}. @var{package} may specify either a simple package name, such as @code{guile}, or a package name followed by a hyphen and version number, -such as @code{guile-1.8}. In addition, @var{package} may contain a +such as @code{guile-1.8.8}. In addition, @var{package} may contain a colon, followed by the name of one of the outputs of the package, as in @code{gcc:doc} or @code{binutils-2.22:lib}. @@ -272,7 +497,9 @@ List packages currently available in the software distribution. When matches @var{regexp}. For each package, print the following items separated by tabs: its name, -its version string, and the source location of its definition. +its version string, the parts of the package (@code{out} for the main +files, @code{lib} for libraries and possibly headers, etc.), and the +source location of its definition. @end table diff --git a/guix-package.in b/guix-package.in index 4dc625778b..450d09e081 100644 --- a/guix-package.in +++ b/guix-package.in @@ -46,7 +46,8 @@ exec ${GUILE-@GUILE@} -L "@guilemoduledir@" -l "$0" \ #:use-module (srfi srfi-34) #:use-module (srfi srfi-37) #:use-module (distro) - #:use-module (distro packages guile) + #:use-module ((distro packages base) #:select (guile-final)) + #:use-module ((distro packages bootstrap) #:select (%bootstrap-guile)) #:export (guix-package)) (define %store @@ -201,7 +202,7 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (display (_ " -n, --dry-run show what would be done without actually doing it")) (display (_ " - -b, --bootstrap use the bootstrap Guile to build the profile")) + --bootstrap use the bootstrap Guile to build the profile")) (display (_ " --verbose produce verbose output")) (newline) @@ -242,7 +243,7 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (option '(#\n "dry-run") #f #f (lambda (opt name arg result) (alist-cons 'dry-run? #t result))) - (option '(#\b "bootstrap") #f #f + (option '("bootstrap") #f #f (lambda (opt name arg result) (alist-cons 'bootstrap? #t result))) (option '("verbose") #f #f @@ -272,6 +273,11 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (alist-cons 'argument arg result)) %default-options)) + (define (guile-missing?) + ;; Return #t if %GUILE-FOR-BUILD is not available yet. + (let ((out (derivation-path->output-path (%guile-for-build)))) + (not (valid-path? %store out)))) + (define (show-what-to-build drv dry-run?) ;; Show what will/would be built in realizing the derivations listed ;; in DRV. @@ -393,7 +399,9 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (if (string=? old-prof prof) (format (current-error-port) (_ "nothing to be done~%")) (and (parameterize ((current-build-output-port - (if verbose? + ;; Output something when Guile + ;; needs to be built. + (if (or verbose? (guile-missing?)) (current-error-port) (%make-void-port "w")))) (build-derivations %store (list prof-drv))) @@ -432,9 +440,10 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (cons p r)))) '()))) (for-each (lambda (p) - (format #t "~a\t~a\t~a~%" + (format #t "~a\t~a\t~a\t~a~%" (package-name p) (package-version p) + (string-join (package-outputs p) ",") (location->string (package-location p)))) (sort available (lambda (p1 p2) @@ -449,16 +458,18 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (setvbuf (current-error-port) _IOLBF) (let ((opts (parse-options))) + + ;; Create ~/.guix-profile if it doesn't exist yet. + (when (and %user-environment-directory + %current-profile + (not (file-exists? %user-environment-directory))) + (symlink %current-profile %user-environment-directory)) + (with-error-handling (or (process-query opts) (parameterize ((%guile-for-build (package-derivation %store (if (assoc-ref opts 'bootstrap?) - (@@ (distro packages base) - %bootstrap-guile) - guile-2.0)))) + %bootstrap-guile + guile-final)))) (process-actions opts)))))) - -;; Local Variables: -;; eval: (put 'guard 'scheme-indent-function 1) -;; End: diff --git a/guix/build/union.scm b/guix/build/union.scm index 317c38a1d5..234964dba5 100644 --- a/guix/build/union.scm +++ b/guix/build/union.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2012 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -19,9 +19,11 @@ (define-module (guix build union) #:use-module (ice-9 ftw) #:use-module (ice-9 match) + #:use-module (ice-9 format) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) #:export (tree-union + delete-duplicate-leaves union-build)) ;;; Commentary: @@ -56,6 +58,48 @@ itself a tree. " '() (delete-duplicates (map car dirs))))))))) +(define* (delete-duplicate-leaves tree + #:optional + (leaf=? equal?) + (delete-duplicates (match-lambda + ((head _ ...) head)))) + "Delete duplicate leaves from TREE. Two leaves are considered equal +when LEAF=? applied to them returns #t. Each collision (list of leaves +that are LEAF=?) is passed to DELETE-DUPLICATES, which must return a +single leaf." + (let loop ((tree tree)) + (match tree + ((dir children ...) + (let ((dirs (filter pair? children)) + (leaves (remove pair? children))) + (define collisions + (fold (lambda (leaf result) + (define same? + (cut leaf=? leaf <>)) + + (if (any (cut find same? <>) result) + result + (match (filter same? leaves) + ((_) + result) + ((collision ...) + (cons collision result))))) + '() + leaves)) + + (define non-collisions + (filter (lambda (leaf) + (match (filter (cut leaf=? leaf <>) leaves) + ((_) #t) + ((_ _ ..1) #f))) + leaves)) + + `(,dir + ,@non-collisions + ,@(map delete-duplicates collisions) + ,@(map loop dirs)))) + (leaf leaf)))) + (define* (union-build output directories) "Build in the OUTPUT directory a symlink tree that is the union of all the DIRECTORIES." @@ -88,12 +132,28 @@ the DIRECTORIES." (((? string?) leaves ...) leaves))) + (define (leaf=? a b) + (equal? (basename a) (basename b))) + + (define (resolve-collision leaves) + ;; LEAVES all have the same basename, so choose one of them. + (format (current-error-port) "warning: collision encountered: ~{~a ~}~%" + leaves) + + ;; TODO: Implement smarter strategies. + (format (current-error-port) "warning: arbitrarily choosing ~a~%" + (car leaves)) + (car leaves)) + (setvbuf (current-output-port) _IOLBF) (setvbuf (current-error-port) _IOLBF) (mkdir output) - (let loop ((tree (tree-union (append-map (compose tree-leaves file-tree) - directories))) + (let loop ((tree (delete-duplicate-leaves + (tree-union (append-map (compose tree-leaves file-tree) + directories)) + leaf=? + resolve-collision)) (dir '())) (match tree ((? string?) diff --git a/guix/derivations.scm b/guix/derivations.scm index 7b131955b0..ce8858a2fa 100644 --- a/guix/derivations.scm +++ b/guix/derivations.scm @@ -112,28 +112,48 @@ download with a fixed hash (aka. `fetchurl')." read-derivation)) inputs))))) -(define (derivation-prerequisites-to-build store drv) - "Return the list of derivation-inputs required to build DRV and not already -available in STORE, recursively." +(define* (derivation-prerequisites-to-build store drv + #:key (outputs + (map + car + (derivation-outputs drv)))) + "Return the list of derivation-inputs required to build the OUTPUTS of +DRV and not already available in STORE, recursively." + (define built? + (cut valid-path? store <>)) + (define input-built? (match-lambda (($ <derivation-input> path sub-drvs) (let ((out (map (cut derivation-path->output-path path <>) sub-drvs))) - (any (cut valid-path? store <>) out))))) + (any built? out))))) - (let loop ((drv drv) - (result '())) - (let ((inputs (remove (lambda (i) - (or (member i result) ; XXX: quadratic - (input-built? i))) - (derivation-inputs drv)))) - (fold loop - (append inputs result) - (map (lambda (i) - (call-with-input-file (derivation-input-path i) - read-derivation)) - inputs))))) + (define (derivation-built? drv sub-drvs) + (match drv + (($ <derivation> outputs) + (let ((paths (map (lambda (sub-drv) + (derivation-output-path + (assoc-ref outputs sub-drv))) + sub-drvs))) + (every built? paths))))) + + (let loop ((drv drv) + (sub-drvs outputs) + (result '())) + (if (derivation-built? drv sub-drvs) + result + (let ((inputs (remove (lambda (i) + (or (member i result) ; XXX: quadratic + (input-built? i))) + (derivation-inputs drv)))) + (fold loop + (append inputs result) + (map (lambda (i) + (call-with-input-file (derivation-input-path i) + read-derivation)) + inputs) + (map derivation-input-sub-derivations inputs)))))) (define (read-derivation drv-port) "Read the derivation from DRV-PORT and return the corresponding diff --git a/guix/gnu-maintenance.scm b/guix/gnu-maintenance.scm index 87ef427481..c934694147 100644 --- a/guix/gnu-maintenance.scm +++ b/guix/gnu-maintenance.scm @@ -1,6 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2012 Nikita Karetnikov <nikita@karetnikov.org> -;;; Copyright © 2012 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2010, 2011, 2012, 2013 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -22,10 +22,28 @@ #:use-module (web client) #:use-module (web response) #:use-module (ice-9 regex) + #:use-module (ice-9 match) #:use-module (srfi srfi-1) #:use-module (srfi srfi-11) #:use-module (srfi srfi-26) - #:export (official-gnu-packages)) + #:use-module (system foreign) + #:use-module (guix ftp-client) + #:export (official-gnu-packages + releases + latest-release + gnu-package-name->name+version)) + +;;; Commentary: +;;; +;;; Code for dealing with the maintenance of GNU packages, such as +;;; auto-updates. +;;; +;;; Code: + + +;;; +;;; List of GNU packages. +;;; (define (http-fetch uri) "Return a string containing the textual data at URI, a string." @@ -55,3 +73,119 @@ (and=> (regexp-exec %package-line-rx line) (cut match:substring <> 1))) lst))) + +;;; +;;; Latest release. +;;; + +(define (ftp-server/directory project) + "Return the FTP server and directory where PROJECT's tarball are +stored." + (define quirks + '(("commoncpp2" "ftp.gnu.org" "/gnu/commoncpp") + ("ucommon" "ftp.gnu.org" "/gnu/commoncpp") + ("libzrtpcpp" "ftp.gnu.org" "/gnu/ccrtp") + ("libosip2" "ftp.gnu.org" "/gnu/osip") + ("libgcrypt" "ftp.gnupg.org" "/gcrypt/libgcrypt") + ("libgpg-error" "ftp.gnupg.org" "/gcrypt/libgpg-error") + ("libassuan" "ftp.gnupg.org" "/gcrypt/libassuan") + ("gnupg" "ftp.gnupg.org" "/gcrypt/gnupg") + ("freefont-ttf" "ftp.gnu.org" "/gnu/freefont") + ("gnu-ghostscript" "ftp.gnu.org" "/gnu/ghostscript") + ("mit-scheme" "ftp.gnu.org" "/gnu/mit-scheme/stable.pkg") + ("icecat" "ftp.gnu.org" "/gnu/gnuzilla") + ("source-highlight" "ftp.gnu.org" "/gnu/src-highlite") + ("TeXmacs" "ftp.texmacs.org" "/TeXmacs/targz"))) + + (match (assoc project quirks) + ((_ server directory) + (values server directory)) + (_ + (values "ftp.gnu.org" (string-append "/gnu/" project))))) + +(define (releases project) + "Return the list of releases of PROJECT as a list of release name/directory +pairs. Example: (\"mit-scheme-9.0.1\" . \"/gnu/mit-scheme/stable.pkg/9.0.1\"). " + ;; TODO: Parse something like fencepost.gnu.org:/gd/gnuorg/packages-ftp. + (define release-rx + (make-regexp (string-append "^" project + "-([0-9]|[^-])*(-src)?\\.tar\\."))) + + (define alpha-rx + (make-regexp "^.*-.*[0-9](-|~)?(alpha|beta|rc|cvs|svn|git)-?[0-9\\.]*\\.tar\\.")) + + (define (sans-extension tarball) + (let ((end (string-contains tarball ".tar"))) + (substring tarball 0 end))) + + (let-values (((server directory) (ftp-server/directory project))) + (define conn (ftp-open server)) + + (let loop ((directories (list directory)) + (result '())) + (if (null? directories) + (begin + (ftp-close conn) + result) + (let* ((directory (car directories)) + (files (ftp-list conn directory)) + (subdirs (filter-map (lambda (file) + (match file + ((name 'directory . _) name) + (_ #f))) + files))) + (loop (append (map (cut string-append directory "/" <>) + subdirs) + (cdr directories)) + (append + ;; Filter out signatures, deltas, and files which + ;; are potentially not releases of PROJECT--e.g., + ;; in /gnu/guile, filter out guile-oops and + ;; guile-www; in mit-scheme, filter out binaries. + (filter-map (lambda (file) + (match file + ((file 'file . _) + (and (not (string-suffix? ".sig" file)) + (regexp-exec release-rx file) + (not (regexp-exec alpha-rx file)) + (let ((s (sans-extension file))) + (and (regexp-exec + %package-name-rx s) + (cons s directory))))) + (_ #f))) + files) + result))))))) + +(define version-string>? + (let ((strverscmp + (let ((sym (or (dynamic-func "strverscmp" (dynamic-link)) + (error "could not find `strverscmp' (from GNU libc)")))) + (pointer->procedure int sym (list '* '*))))) + (lambda (a b) + "Return #t when B denotes a newer version than A." + (> (strverscmp (string->pointer a) (string->pointer b)) 0)))) + +(define (latest-release project) + "Return (\"FOO-X.Y\" . \"/bar/foo\") or #f." + (let ((releases (releases project))) + (and (not (null? releases)) + (fold (lambda (release latest) + (if (version-string>? (car release) (car latest)) + release + latest)) + '("" . "") + releases)))) + +(define %package-name-rx + ;; Regexp for a package name, e.g., "foo-X.Y". Since TeXmacs uses + ;; "TeXmacs-X.Y-src", the `-src' suffix is allowed. + (make-regexp "^(.*)-(([0-9]|\\.)+)(-src)?")) + +(define (gnu-package-name->name+version name+version) + "Return the package name and version number extracted from NAME+VERSION." + (let ((match (regexp-exec %package-name-rx name+version))) + (if (not match) + (values name+version #f) + (values (match:substring match 1) (match:substring match 2))))) + +;;; gnu-maintenance.scm ends here diff --git a/guix/snix.scm b/guix/snix.scm index c90893bdfe..977898989b 100644 --- a/guix/snix.scm +++ b/guix/snix.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2010, 2011, 2012 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2010, 2011, 2012, 2013 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -366,15 +366,18 @@ location of DERIVATION." attribute-value) (#f '()) - ((('derivation _ _ (attributes ...)) ...) - (map (lambda (attrs) - (let* ((full-name (attribute-value - (find-attribute-by-name "name" attrs))) - (name (package-name->name+version full-name))) - (list name - (list 'unquote - (string->symbol name))))) - attributes)))) + ((inputs ...) + ;; Inputs can be either derivations or the null value. + (filter-map (match-lambda + (('derivation _ _ (attributes ...)) + (let* ((full-name + (attribute-value + (find-attribute-by-name "name" attributes))) + (name (package-name->name+version full-name))) + (list name + (list 'unquote (string->symbol name))))) + ('null #f)) + inputs)))) (define (maybe-inputs guix-name inputs) (match inputs @@ -390,6 +393,16 @@ location of DERIVATION." `(string-append ,@items)) (x x))) + (define (license-variable license) + ;; Return the name of the (guix licenses) variable for LICENSE. + (match license + ("GPLv2+" 'gpl2+) + ("GPLv3+" 'gpl3+) + ("LGPLv2+" 'lgpl2.1+) + ("LGPLv2.1+" 'lgpl2.1+) + ("LGPLv3+" 'lgpl3+) + (_ license))) + (let* ((source (find-attribute-by-name "src" attributes)) (urls (source-urls source)) (sha256 (source-sha256 source)) @@ -423,7 +436,7 @@ location of DERIVATION." ,(and=> (find-attribute-by-name "longDescription" meta) attribute-value)) (license ,(and=> (find-attribute-by-name "license" meta) - attribute-value))) + (compose license-variable attribute-value)))) loc)))))) (define (nixpkgs->guix-package nixpkgs attribute) diff --git a/nix/nix-daemon/guix-daemon.cc b/nix/nix-daemon/guix-daemon.cc index 7e266111a0..604a26f0b1 100644 --- a/nix/nix-daemon/guix-daemon.cc +++ b/nix/nix-daemon/guix-daemon.cc @@ -69,7 +69,7 @@ static const struct argp_option options[] = { { "system", GUIX_OPT_SYSTEM, "SYSTEM", 0, "Assume SYSTEM as the current system type" }, - { "build-cores", 'C', "N", 0, + { "cores", 'c', "N", 0, "Use N CPU cores to build each derivation; 0 means as many as available" }, { "max-jobs", 'M', "N", 0, "Allow at most N build jobs" }, @@ -141,7 +141,7 @@ parse_opt (int key, char *arg, struct argp_state *state) case GUIX_OPT_DEBUG: verbosity = lvlDebug; break; - case 'C': + case 'c': settings.buildCores = atoi (arg); break; case 'M': @@ -193,8 +193,8 @@ main (int argc, char *argv[]) argp_parse (&argp, argc, argv, 0, 0, 0); if (geteuid () == 0 && settings.buildUsersGroup.empty ()) - fprintf (stderr, "warning: running as root is highly recommended, " - "unless `--build-users-group' is used\n"); + fprintf (stderr, "warning: daemon is running as root, so " + "using `--build-users-group' is highly recommended\n"); #ifdef HAVE_CHROOT if (settings.useChroot) diff --git a/tests/derivations.scm b/tests/derivations.scm index 692b2aea8d..166a917490 100644 --- a/tests/derivations.scm +++ b/tests/derivations.scm @@ -360,6 +360,44 @@ ;; built. (null? (derivation-prerequisites-to-build %store drv)))) +(test-assert "derivation-prerequisites-to-build when outputs already present" + (let*-values (((builder) + '(begin (mkdir %output) #t)) + ((input-drv-path input-drv) + (build-expression->derivation %store "input" + (%current-system) + builder '())) + ((input-path) + (derivation-output-path + (assoc-ref (derivation-outputs input-drv) + "out"))) + ((drv-path drv) + (build-expression->derivation %store "something" + (%current-system) + builder + `(("i" ,input-drv-path)))) + ((output) + (derivation-output-path + (assoc-ref (derivation-outputs drv) "out")))) + ;; Make sure these things are not already built. + (when (valid-path? %store input-path) + (delete-paths %store (list input-path))) + (when (valid-path? %store output) + (delete-paths %store (list output))) + + (and (equal? (map derivation-input-path + (derivation-prerequisites-to-build %store drv)) + (list input-drv-path)) + + ;; Build DRV and delete its input. + (build-derivations %store (list drv-path)) + (delete-paths %store (list input-path)) + (not (valid-path? %store input-path)) + + ;; Now INPUT-PATH is missing, yet it shouldn't be listed as a + ;; prerequisite to build because DRV itself is already built. + (null? (derivation-prerequisites-to-build %store drv))))) + (test-assert "build-expression->derivation with expression returning #f" (let* ((builder '(begin (mkdir %output) diff --git a/tests/guix-package.sh b/tests/guix-package.sh index 81b7f05634..bd2c816b9a 100644 --- a/tests/guix-package.sh +++ b/tests/guix-package.sh @@ -1,5 +1,5 @@ # GNU Guix --- Functional package management for GNU -# Copyright © 2012 Ludovic Courtès <ludo@gnu.org> +# Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org> # # This file is part of GNU Guix. # @@ -27,13 +27,13 @@ rm -f "$profile" trap 'rm "$profile" "$profile-"[0-9]*' EXIT -guix-package -b -p "$profile" \ +guix-package --bootstrap -p "$profile" \ -i `guix-build -e '(@@ (distro packages base) %bootstrap-guile)'` test -L "$profile" && test -L "$profile-1-link" test -f "$profile/bin/guile" # Installing the same package a second time does nothing. -guix-package -b -p "$profile" \ +guix-package --bootstrap -p "$profile" \ -i `guix-build -e '(@@ (distro packages base) %bootstrap-guile)'` test -L "$profile" && test -L "$profile-1-link" ! test -f "$profile-2-link" @@ -42,7 +42,7 @@ test -f "$profile/bin/guile" # Check whether we have network access. if guile -c '(getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)' 2> /dev/null then - guix-package -b -p "$profile" \ + guix-package --bootstrap -p "$profile" \ -i `guix-build -e '(@@ (distro packages base) gnu-make-boot0)'` test -L "$profile-2-link" test -f "$profile/bin/make" && test -f "$profile/bin/guile" @@ -64,13 +64,13 @@ then test "`guix-package -p "$profile" -I 'g.*e' | cut -f1`" = "guile-bootstrap" # Remove a package. - guix-package -b -p "$profile" -r "guile-bootstrap" + guix-package --bootstrap -p "$profile" -r "guile-bootstrap" test -L "$profile-3-link" test -f "$profile/bin/make" && ! test -f "$profile/bin/guile" fi # Make sure the `:' syntax works. -guix-package -b -i "libsigsegv:lib" -n +guix-package --bootstrap -i "libsigsegv:lib" -n # Check whether `--list-available' returns something sensible. guix-package -A 'gui.*e' | grep guile diff --git a/tests/snix.scm b/tests/snix.scm index 7623d0cd8f..89582f2408 100644 --- a/tests/snix.scm +++ b/tests/snix.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2012 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -61,7 +61,7 @@ ('home-page (? string?)) ('synopsis (? string?)) ('description (? string?)) - ('license (? string?))) + ('license (? symbol?))) (and (member '("libffi" ,libffi) inputs) (member '("gmp" ,gmp) pinputs) #t)) diff --git a/tests/union.scm b/tests/union.scm index 58c0a301b2..5bbf992a59 100644 --- a/tests/union.scm +++ b/tests/union.scm @@ -65,6 +65,25 @@ (bin make) (share (doc (make README)))))) +(test-equal "delete-duplicate-leaves, default" + '(bin make touch ls) + (delete-duplicate-leaves '(bin ls make touch ls))) + +(test-equal "delete-duplicate-leaves, file names" + '("doc" ("info" + "/binutils/ld.info" + "/gcc/gcc.info" + "/binutils/standards.info")) + (let ((leaf=? (lambda (a b) + (string=? (basename a) (basename b))))) + (delete-duplicate-leaves '("doc" + ("info" + "/binutils/ld.info" + "/binutils/standards.info" + "/gcc/gcc.info" + "/gcc/standards.info")) + leaf=?))) + (test-skip (if (and %store (false-if-exception (getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV))) |