aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/guix.texi27
-rw-r--r--gnu/packages/cdrom.scm44
-rw-r--r--gnu/packages/gtk.scm4
-rw-r--r--gnu/packages/linux-initrd.scm6
-rw-r--r--gnu/packages/linux.scm80
-rw-r--r--gnu/packages/system.scm56
-rw-r--r--gnu/packages/xorg.scm20
-rw-r--r--gnu/system/dmd.scm38
-rw-r--r--gnu/system/shadow.scm94
-rw-r--r--gnu/system/vm.scm81
-rw-r--r--guix/build-system/trivial.scm10
-rw-r--r--guix/scripts/package.scm287
-rw-r--r--scripts/guix.in2
-rw-r--r--tests/guix-package.sh20
-rw-r--r--tests/packages.scm15
15 files changed, 640 insertions, 144 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index 442cef26da..94658f2b21 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -711,9 +711,28 @@ second one.
@item @emph{Durations}. You can also get the last @emph{N}@tie{}days, weeks,
or months by passing an integer along with the first letter of the
-duration, e.g., @code{--list-generations=20d}.
+duration. For example, @code{--list-generations=20d} lists generations
+that are up to 20 days old.
@end itemize
+@item --delete-generations[=@var{pattern}]
+@itemx -d [@var{pattern}]
+When @var{pattern} is omitted, delete all generations except the current
+one.
+
+This command accepts the same patterns as @option{--list-generations}.
+When @var{pattern} is specified, delete the matching generations. When
+@var{pattern} specifies a duration, generations @emph{older} than the
+specified duration match. For instance, @code{--delete-generations=1m}
+deletes generations that are more than one month old.
+
+If the current generation matches, it is deleted atomically---i.e., by
+switching to the previous available generation. Note that the zeroth
+generation is never deleted.
+
+Note that deleting generations prevents roll-back to them.
+Consequently, this command must be used with care.
+
@end table
@node Packages with Multiple Outputs
@@ -781,6 +800,12 @@ deleted. The set of garbage collector roots includes default user
profiles, and may be augmented with @command{guix build --root}, for
example (@pxref{Invoking guix build}).
+Prior to running @code{guix gc --collect-garbage} to make space, it is
+often useful to remove old generations from user profiles; that way, old
+package builds referenced by those generations can be reclaimed. This
+is achieved by running @code{guix package --delete-generations}
+(@pxref{Invoking guix package}).
+
The @command{guix gc} command has three modes of operation: it can be
used to garbage-collect any dead files (the default), to delete specific
files (the @code{--delete} option), or to print garbage-collector
diff --git a/gnu/packages/cdrom.scm b/gnu/packages/cdrom.scm
index f881e7ab3a..b5b14c718e 100644
--- a/gnu/packages/cdrom.scm
+++ b/gnu/packages/cdrom.scm
@@ -20,15 +20,18 @@
(define-module (gnu packages cdrom)
#:use-module (guix download)
#:use-module (guix packages)
- #:use-module ((guix licenses) #:select (lgpl2.1+ gpl2 gpl3+))
+ #:use-module ((guix licenses) #:select (lgpl2.1+ gpl2 gpl2+ gpl3+))
#:use-module (guix build-system gnu)
#:use-module (gnu packages)
#:use-module (gnu packages acl)
#:use-module (gnu packages compression)
+ #:use-module ((gnu packages gettext) #:renamer (symbol-prefix-proc 'gnu:))
+ #:use-module (gnu packages gtk)
#:use-module (gnu packages readline)
#:use-module (gnu packages ncurses)
#:use-module (gnu packages help2man)
- #:use-module (gnu packages pkg-config))
+ #:use-module (gnu packages pkg-config)
+ #:use-module (gnu packages which))
(define-public libcddb
(package
@@ -142,3 +145,40 @@ target drive is CDDA capable. In addition to simple reading, cdparanoia adds
extra-robust data verification, synchronization, error handling and scratch
reconstruction capability.")
(license gpl2))) ; libraries under lgpl2.1
+
+(define-public dvdisaster
+ (package
+ (name "dvdisaster")
+ (version "0.72.4")
+ (source (origin
+ (method url-fetch)
+ (uri (string-append "http://dvdisaster.net/downloads/dvdisaster-"
+ version ".tar.bz2"))
+ (sha256
+ (base32
+ "0pm039a78h7m9vvjmmjfkl05ii6qdmfhvbypxjbc7j5w82y66is4"))))
+ (build-system gnu-build-system)
+ (inputs
+ `(("gettext" ,gnu:gettext)
+ ("gtk+" ,gtk+)
+ ("pkg-config" ,pkg-config)
+ ("which" ,which)))
+ (arguments
+ `(#:tests? #f)) ; no check target
+ (home-page "http://dvdisaster.net/en/index.html")
+ (synopsis "error correcting codes for optical media images")
+ (description "Optical media (CD,DVD,BD) keep their data only for a
+finite time (typically for many years). After that time, data loss develops
+slowly with read errors growing from the outer media region towards the
+inside.
+
+Dvdisaster stores data on CD/DVD/BD (supported media) in a way that it is
+fully recoverable even after some read errors have developed. This enables
+you to rescue the complete data to a new medium.
+
+Data loss is prevented by using error correcting codes. Error correction
+data is either added to the medium or kept in separate error correction
+files. Dvdisaster works at the image level so that the recovery does not
+depend on the file system of the medium. The maximum error correction
+capacity is user-selectable.")
+ (license gpl2+)))
diff --git a/gnu/packages/gtk.scm b/gnu/packages/gtk.scm
index e72f7c5acc..013d29379b 100644
--- a/gnu/packages/gtk.scm
+++ b/gnu/packages/gtk.scm
@@ -110,14 +110,14 @@ affine transformation (scale, rotation, shear, etc.)")
(define-public harfbuzz
(package
(name "harfbuzz")
- (version "0.9.20")
+ (version "0.9.21")
(source (origin
(method url-fetch)
(uri (string-append "http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-"
version ".tar.bz2"))
(sha256
(base32
- "0rxwvd8j4vcadlhx4a7la33clzggxziblx1k43ccbw5w7yh4yf43"))))
+ "1s6sffgf6ndy12fyln2bdnkn3cb1qfkch0rakdgkgwlq7n46zlx0"))))
(build-system gnu-build-system)
(inputs
`(("cairo" ,cairo)
diff --git a/gnu/packages/linux-initrd.scm b/gnu/packages/linux-initrd.scm
index b62843aadd..ed30fa56b1 100644
--- a/gnu/packages/linux-initrd.scm
+++ b/gnu/packages/linux-initrd.scm
@@ -363,8 +363,7 @@ the Linux kernel.")
(make-essential-device-nodes)
;; Prepare the real root file system under /root.
- (unless (file-exists? "/root")
- (mkdir "/root"))
+ (mkdir-p "/root")
(if root
;; Assume ROOT has a usable /dev tree.
(mount root "/root" "ext3")
@@ -374,6 +373,9 @@ the Linux kernel.")
(mount-essential-file-systems #:root "/root")
+ (mkdir-p "/root/tmp")
+ (mount "none" "/root/tmp" "tmpfs")
+
;; XXX: We don't copy our fellow Guile modules to /root (see
;; 'qemu-initrd'), so if TO-LOAD tries to load a module (which can
;; happen if it throws, to display the exception!), then we're
diff --git a/gnu/packages/linux.scm b/gnu/packages/linux.scm
index 38bff72933..06b0b6da99 100644
--- a/gnu/packages/linux.scm
+++ b/gnu/packages/linux.scm
@@ -30,6 +30,8 @@
#:use-module (gnu packages perl)
#:use-module (gnu packages pkg-config)
#:use-module (gnu packages algebra)
+ #:use-module ((gnu packages gettext)
+ #:renamer (symbol-prefix-proc 'g:))
#:use-module (guix packages)
#:use-module (guix download)
#:use-module (guix build-system gnu))
@@ -566,3 +568,81 @@ controls IPv4 and IPv6 configuration and tc stands for traffic control. Both
tools print detailed usage messages and are accompanied by a set of
manpages.")
(license gpl2+)))
+
+(define-public net-tools
+ ;; XXX: This package is basically unmaintained, but it provides a few
+ ;; commands not yet provided by Inetutils, such as 'route', so we have to
+ ;; live with it.
+ (package
+ (name "net-tools")
+ (version "1.60")
+ (home-page "http://www.tazenda.demon.co.uk/phil/net-tools/")
+ (source (origin
+ (method url-fetch)
+ (uri (string-append home-page "/" name "-"
+ version ".tar.bz2"))
+ (sha256
+ (base32
+ "0yvxrzk0mzmspr7sa34hm1anw6sif39gyn85w4c5ywfn8inxvr3s"))))
+ (build-system gnu-build-system)
+ (arguments
+ '(#:phases (alist-replace
+ 'patch
+ (lambda* (#:key inputs #:allow-other-keys)
+ (define (apply-patch file)
+ (zero? (system* "patch" "-p1" "--batch"
+ "--input" file)))
+
+ (let ((patch.gz (assoc-ref inputs "patch")))
+ (format #t "applying Debian patch set '~a'...~%"
+ patch.gz)
+ (system (string-append "gunzip < " patch.gz " > the-patch"))
+ (pk 'here)
+ (and (apply-patch "the-patch")
+ (for-each apply-patch
+ (find-files "debian/patches"
+ "\\.patch")))))
+ (alist-replace
+ 'configure
+ (lambda* (#:key outputs #:allow-other-keys)
+ (let ((out (assoc-ref outputs "out")))
+ (mkdir-p (string-append out "/bin"))
+ (mkdir-p (string-append out "/sbin"))
+
+ ;; Pretend we have everything...
+ (system "yes | make config")
+
+ ;; ... except we don't have libdnet, so remove that
+ ;; definition.
+ (substitute* '("config.make" "config.h")
+ (("^.*HAVE_AFDECnet.*$") ""))))
+ %standard-phases))
+
+ ;; Binaries that depend on libnet-tools.a don't declare that
+ ;; dependency, making it parallel-unsafe.
+ #:parallel-build? #f
+
+ #:tests? #f ; no test suite
+ #:make-flags (list "CC=gcc"
+ (string-append "BASEDIR="
+ (assoc-ref %outputs "out")))))
+
+ ;; Use the big Debian patch set (the thing does not even compile out of
+ ;; the box.)
+ (inputs `(("patch" ,(origin
+ (method url-fetch)
+ (uri
+ "http://ftp.de.debian.org/debian/pool/main/n/net-tools/net-tools_1.60-24.2.diff.gz")
+ (sha256
+ (base32
+ "0p93lsqx23v5fv4hpbrydmfvw1ha2rgqpn2zqbs2jhxkzhjc030p"))))))
+ (native-inputs `(("gettext" ,g:gettext)))
+
+ (synopsis "Tools for controlling the network subsystem in Linux")
+ (description
+ "This package includes the important tools for controlling the network
+subsystem of the Linux kernel. This includes arp, hostname, ifconfig,
+netstat, rarp and route. Additionally, this package contains utilities
+relating to particular network hardware types (plipconfig, slattach) and
+advanced aspects of IP configuration (iptunnel, ipmaddr).")
+ (license gpl2+)))
diff --git a/gnu/packages/system.scm b/gnu/packages/system.scm
index 9af0365812..3524544746 100644
--- a/gnu/packages/system.scm
+++ b/gnu/packages/system.scm
@@ -23,10 +23,15 @@
#:use-module (guix download)
#:use-module (guix build-system cmake)
#:use-module (guix build-system gnu)
+ #:use-module (guix build-system trivial)
#:use-module (gnu packages)
#:use-module (gnu packages ncurses)
#:use-module (gnu packages linux)
#:use-module (gnu packages guile)
+ #:use-module ((gnu packages base)
+ #:select (tar))
+ #:use-module ((gnu packages compression)
+ #:select (gzip))
#:use-module (gnu packages pkg-config))
(define-public dmd
@@ -35,11 +40,8 @@
(version "-0.4")
(source (origin
(method url-fetch)
-
- ;; XXX: Temporary location until dmd gets back home.
- (uri (string-append
- "http://www.fdn.fr/~lcourtes/software/guix/dmd-"
- version ".tar.gz"))
+ (uri (string-append "ftp://alpha.gnu.org/gnu/dmd/dmd-"
+ version ".tar.gz"))
(sha256
(base32
"094ja3xvk9ljghhxmy39if67cfjd1hy6m4svnp399n0wpxvaryvy"))))
@@ -268,3 +270,47 @@ login, passwd, su, groupadd, and useradd.")
asks for a login name and then transfers over to 'login'. It is extended to
allow automatic login and starting any app.")
(license gpl2+)))
+
+(define-public net-base
+ (package
+ (name "net-base")
+ (version "5.1")
+ (source (origin
+ (method url-fetch)
+ (uri (string-append
+ "http://ftp.de.debian.org/debian/pool/main/n/netbase/netbase_"
+ version ".tar.gz"))
+ (sha256
+ (base32
+ "17l8xk2x632id5f9x9v5fs9wqc650hldd2lf3dh90r1zisj1ya8d"))))
+ (build-system trivial-build-system)
+ (arguments
+ `(#:modules ((guix build utils))
+ #:builder (begin
+ (use-modules (guix build utils)
+ (srfi srfi-26))
+
+ (let* ((source (assoc-ref %build-inputs "source"))
+ (tar (assoc-ref %build-inputs "tar"))
+ (gzip (assoc-ref %build-inputs "gzip"))
+ (output (assoc-ref %outputs "out"))
+ (etc (string-append output "/etc")))
+ (setenv "PATH" (string-append gzip "/bin"))
+ (system* (string-append tar "/bin/tar") "xvf"
+ source)
+ (chdir ,(string-append "netbase-" version))
+ (mkdir-p etc)
+ (for-each copy-file
+ '("etc-services" "etc-protocols" "etc-rpc")
+ (map (cut string-append etc "/" <>)
+ '("services" "protocols" "rpc")))
+ #t))))
+ (native-inputs `(("tar" ,tar)
+ ("gzip" ,gzip)))
+ (synopsis "IANA protocol, port, and RPC number assignments")
+ (description
+ "This package provides the /etc/services, /etc/protocols, and /etc/rpc
+files, which contain information about the IANA-assigned port, protocol, and
+ONC RPC numbers")
+ (home-page "http://packages.debian.org/sid/netbase")
+ (license gpl2)))
diff --git a/gnu/packages/xorg.scm b/gnu/packages/xorg.scm
index 613e2c5f0e..df535c1ced 100644
--- a/gnu/packages/xorg.scm
+++ b/gnu/packages/xorg.scm
@@ -2096,7 +2096,6 @@ tracking.")
(license license:x11)))
-;; FIXME: Tries to install file joystick-properties.h into ...--xorg-server-1.12.2/include/xorg
(define-public xf86-input-joystick
(package
(name "xf86-input-joystick")
@@ -2114,6 +2113,11 @@ tracking.")
(build-system gnu-build-system)
(inputs `(("pkg-config" ,pkg-config)
("xorg-server" ,xorg-server)))
+ (arguments
+ `(#:configure-flags
+ (list (string-append "--with-sdkdir="
+ (assoc-ref %outputs "out")
+ "/include/xorg"))))
(home-page "http://www.x.org/wiki/")
(synopsis "xorg implementation of the X Window System")
(description "X.org provides an implementation of the X Window System")
@@ -2186,13 +2190,20 @@ tracking.")
("mtdev" ,mtdev)
("pkg-config" ,pkg-config)
("xorg-server" ,xorg-server)))
+ (arguments
+ `(#:configure-flags
+ (list (string-append "--with-sdkdir="
+ (assoc-ref %outputs "out")
+ "/include/xorg")
+ (string-append "--with-xorg-conf-dir="
+ (assoc-ref %outputs "out")
+ "/share/X11/xorg.conf.d"))))
(home-page "http://www.x.org/wiki/")
(synopsis "xorg implementation of the X Window System")
(description "X.org provides an implementation of the X Window System")
(license license:x11)))
-;; FIXME: Installation tries to create ...-xorg-server-1.12.2/share/X11/xorg.conf.d
(define-public xf86-input-vmmouse
(package
(name "xf86-input-vmmouse")
@@ -2210,6 +2221,11 @@ tracking.")
(build-system gnu-build-system)
(inputs `(("pkg-config" ,pkg-config)
("xorg-server" ,xorg-server)))
+ (arguments
+ `(#:configure-flags
+ (list(string-append "--with-xorg-conf-dir="
+ (assoc-ref %outputs "out")
+ "/share/X11/xorg.conf.d"))))
(home-page "http://www.x.org/wiki/")
(synopsis "xorg implementation of the X Window System")
(description "X.org provides an implementation of the X Window System")
diff --git a/gnu/system/dmd.scm b/gnu/system/dmd.scm
index b248d9f0c5..4d3b4b31f0 100644
--- a/gnu/system/dmd.scm
+++ b/gnu/system/dmd.scm
@@ -27,6 +27,8 @@
#:select (mingetty inetutils))
#:use-module ((gnu packages package-management)
#:select (guix))
+ #:use-module ((gnu packages linux)
+ #:select (net-tools))
#:use-module (ice-9 match)
#:use-module (srfi srfi-1)
#:export (service?
@@ -144,31 +146,51 @@
(inputs `(("inetutils" ,inetutils)
("syslog.conf" ,syslog.conf))))))
-(define* (guix-service store #:key (guix guix))
+(define* (guix-service store #:key (guix guix) (builder-group "guixbuild"))
"Return a service that runs the build daemon from GUIX."
(let* ((drv (package-derivation store guix))
(daemon (string-append (derivation->output-path drv)
"/bin/guix-daemon")))
(service
(provision '(guix-daemon))
- (start `(make-forkexec-constructor ,daemon))
+ (start `(make-forkexec-constructor ,daemon
+ "--build-users-group"
+ ,builder-group))
(inputs `(("guix" ,guix))))))
(define* (static-networking-service store interface ip
- #:key (inetutils inetutils))
- "Return a service that starts INTERFACE with address IP."
+ #:key
+ gateway
+ (inetutils inetutils)
+ (net-tools net-tools))
+ "Return a service that starts INTERFACE with address IP. If GATEWAY is
+true, it must be a string specifying the default network gateway."
;; TODO: Eventually we should do this using Guile's networking procedures,
;; like 'configure-qemu-networking' does, but the patch that does this is
;; not yet in stock Guile.
(let ((ifconfig (string-append (package-output store inetutils)
- "/bin/ifconfig")))
+ "/bin/ifconfig"))
+ (route (string-append (package-output store net-tools)
+ "/sbin/route")))
(service
(provision '(networking))
- (start `(make-forkexec-constructor ,ifconfig ,interface ,ip "up"))
- (stop `(make-forkexec-constructor ,ifconfig ,interface "down"))
+ (start `(lambda _
+ (and (zero? (system* ,ifconfig ,interface ,ip "up"))
+ ,(if gateway
+ `(begin
+ (sleep 3) ; XXX
+ (zero? (system* ,route "add" "-net" "default"
+ "gw" ,gateway)))
+ #t))))
+ (stop `(lambda _
+ (system* ,ifconfig ,interface "down")
+ (system* ,route "del" "-net" "default")))
(respawn? #f)
- (inputs `(("inetutils" ,inetutils))))))
+ (inputs `(("inetutils" ,inetutils)
+ ,@(if gateway
+ `(("net-tools" ,net-tools))
+ '()))))))
(define (dmd-configuration-file store services)
diff --git a/gnu/system/shadow.scm b/gnu/system/shadow.scm
index 71f8e0d771..4f59b2b325 100644
--- a/gnu/system/shadow.scm
+++ b/gnu/system/shadow.scm
@@ -18,8 +18,34 @@
(define-module (gnu system shadow)
#:use-module (guix store)
+ #:use-module (guix records)
+ #:use-module (guix packages)
+ #:use-module ((gnu packages system)
+ #:select (shadow))
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
#:use-module (ice-9 match)
- #:export (passwd-file))
+ #:use-module (ice-9 format)
+ #:export (user-account
+ user-account?
+ user-account-name
+ user-account-pass
+ user-account-uid
+ user-account-gid
+ user-account-comment
+ user-account-home-directory
+ user-account-shell
+
+ user-group
+ user-group?
+ user-group-name
+ user-group-password
+ user-group-id
+ user-group-members
+
+ passwd-file
+ group-file
+ guix-build-accounts))
;;; Commentary:
;;;
@@ -27,16 +53,53 @@
;;;
;;; Code:
+(define-record-type* <user-account>
+ user-account make-user-account
+ user-account?
+ (name user-account-name)
+ (password user-account-pass (default ""))
+ (uid user-account-uid)
+ (gid user-account-gid)
+ (comment user-account-comment (default ""))
+ (home-directory user-account-home-directory)
+ (shell user-account-shell (default "/bin/sh")))
+
+(define-record-type* <user-group>
+ user-group make-user-group
+ user-group?
+ (name user-group-name)
+ (password user-group-password (default #f))
+ (id user-group-id)
+ (members user-group-members (default '())))
+
+(define (group-file store groups)
+ "Return a /etc/group file for GROUPS, a list of <user-group> objects."
+ (define contents
+ (let loop ((groups groups)
+ (result '()))
+ (match groups
+ ((($ <user-group> name _ gid (users ...)) rest ...)
+ ;; XXX: Ignore the group password.
+ (loop rest
+ (cons (string-append name "::" (number->string gid)
+ ":" (string-join users ","))
+ result)))
+ (()
+ (string-join (reverse result) "\n" 'suffix)))))
+
+ (add-text-to-store store "group" contents))
+
(define* (passwd-file store accounts #:key shadow?)
- "Return a password file for ACCOUNTS, a list of vectors as returned by
-'getpwnam'. If SHADOW? is true, then it is a /etc/shadow file, otherwise it
-is a /etc/passwd file."
+ "Return a password file for ACCOUNTS, a list of <user-account> objects. If
+SHADOW? is true, then it is a /etc/shadow file, otherwise it is a /etc/passwd
+file."
;; XXX: The resulting file is world-readable, so beware when SHADOW? is #t!
(define contents
(let loop ((accounts accounts)
(result '()))
(match accounts
- ((#(name pass uid gid comment home-dir shell) rest ...)
+ ((($ <user-account> name pass uid gid comment home-dir shell)
+ rest ...)
(loop rest
(cons (if shadow?
(string-append name
@@ -54,4 +117,25 @@ is a /etc/passwd file."
(add-text-to-store store (if shadow? "shadow" "passwd")
contents '()))
+(define* (guix-build-accounts store count #:key
+ (first-uid 30001)
+ (gid 30000)
+ (shadow shadow))
+ "Return a list of COUNT user accounts for Guix build users, with UIDs
+starting at FIRST-UID, and under GID."
+ (let* ((gid* gid)
+ (no-login (string-append (package-output store shadow) "/sbin/nologin")))
+ (unfold (cut > <> count)
+ (lambda (n)
+ (user-account
+ (name (format #f "guixbuilder~2,'0d" n))
+ (password "!")
+ (uid (+ first-uid n -1))
+ (gid gid*)
+ (comment (format #f "Guix Build User ~2d" n))
+ (home-directory "/var/empty")
+ (shell no-login)))
+ 1+
+ 1)))
+
;;; shadow.scm ends here
diff --git a/gnu/system/vm.scm b/gnu/system/vm.scm
index 0ed805510a..917fa3ecb1 100644
--- a/gnu/system/vm.scm
+++ b/gnu/system/vm.scm
@@ -30,6 +30,7 @@
#:use-module (gnu packages bash)
#:use-module (gnu packages qemu)
#:use-module (gnu packages parted)
+ #:use-module (gnu packages zile)
#:use-module (gnu packages grub)
#:use-module (gnu packages linux)
#:use-module (gnu packages linux-initrd)
@@ -295,7 +296,7 @@ such as /etc files."
(begin
(display "creating ext3 partition...\n")
(and (zero? (system* mkfs "-F" "/dev/vda1"))
- (begin
+ (let ((store (string-append "/fs" ,%store-directory)))
(display "mounting partition...\n")
(mkdir "/fs")
(mount "/dev/vda1" "/fs" "ext3")
@@ -303,7 +304,8 @@ such as /etc files."
(symlink grub.cfg "/fs/boot/grub/grub.cfg")
;; Populate the image's store.
- (mkdir-p (string-append "/fs" ,%store-directory))
+ (mkdir-p store)
+ (chmod store #o1775)
(for-each (lambda (thing)
(copy-recursively thing
(string-append "/fs"
@@ -337,6 +339,12 @@ such as /etc files."
(loop rest
(cons `(mkdir-p ,(string-append "/fs" name))
statements)))
+ ((('directory name uid gid) rest ...)
+ (let ((dir (string-append "/fs" name)))
+ (loop rest
+ (cons* `(chown ,dir ,uid ,gid)
+ `(mkdir-p ,dir)
+ statements))))
(((new '-> old) rest ...)
(loop rest
(cons `(symlink ,old
@@ -459,13 +467,26 @@ Happy birthday, GNU! http://www.gnu.org/gnu30
(nscd-service store)
;; QEMU networking settings.
- (static-networking-service store "eth0" "10.0.2.10")))
+ (static-networking-service store "eth0" "10.0.2.10"
+ #:gateway "10.0.2.2")))
+
+ (define build-user-gid 30000)
+
+ (define build-accounts
+ (guix-build-accounts store 10 #:gid build-user-gid))
(define resolv.conf
;; Name resolution for default QEMU settings.
(add-text-to-store store "resolv.conf"
"nameserver 10.0.2.3\n"))
+ (define etc-services
+ (string-append (package-output store net-base) "/etc/services"))
+ (define etc-protocols
+ (string-append (package-output store net-base) "/etc/protocols"))
+ (define etc-rpc
+ (string-append (package-output store net-base) "/etc/rpc"))
+
(parameterize ((%guile-for-build (package-derivation store guile-final)))
(let* ((bash-drv (package-derivation store bash))
(bash-file (string-append (derivation->output-path bash-drv)
@@ -474,12 +495,36 @@ Happy birthday, GNU! http://www.gnu.org/gnu30
(dmd-file (string-append (derivation->output-path dmd-drv)
"/bin/dmd"))
(dmd-conf (dmd-configuration-file store %dmd-services))
- (accounts (list (vector "root" "" 0 0 "System administrator"
- "/" bash-file)))
+ (accounts (cons* (user-account
+ (name "root")
+ (password "")
+ (uid 0) (gid 0)
+ (comment "System administrator")
+ (home-directory "/")
+ (shell bash-file))
+ (user-account
+ (name "guest")
+ (password "")
+ (uid 1000) (gid 100)
+ (comment "Guest of GNU")
+ (home-directory "/home/guest")
+ (shell bash-file))
+ build-accounts))
(passwd (passwd-file store accounts))
(shadow (passwd-file store accounts #:shadow? #t))
- (group (add-text-to-store store "group"
- "root:x:0:\n"))
+ (group (group-file store
+ (list (user-group
+ (name "root")
+ (id 0))
+ (user-group
+ (name "users")
+ (id 100)
+ (members '("guest")))
+ (user-group
+ (name "guixbuild")
+ (id build-user-gid)
+ (members (map user-account-name
+ build-accounts))))))
(pam.d-drv (pam-services->directory store %pam-services))
(pam.d (derivation->output-path pam.d-drv))
@@ -490,6 +535,9 @@ Happy birthday, GNU! http://www.gnu.org/gnu30
("gcc" ,gcc-final)
("libc" ,glibc-final)
("inetutils" ,inetutils)
+ ("procps" ,procps)
+ ("psmisc" ,psmisc)
+ ("zile" ,zile)
("guix" ,guix-0.4)))
;; TODO: Replace with a real profile with a manifest.
@@ -514,21 +562,31 @@ This image features the GNU Guix package manager, which was used to
build it (http://www.gnu.org/software/guix/). The init system is
GNU dmd (http://www.gnu.org/software/dmd/).
-You can log in as 'root' with no password.
+You can log in as 'guest' or 'root' with no password.
"))
- (populate `((directory "/etc")
+ (populate `((directory "/nix/store" 0 ,build-user-gid)
+ (directory "/etc")
(directory "/var/log") ; for dmd
(directory "/var/run/nscd")
("/etc/shadow" -> ,shadow)
("/etc/passwd" -> ,passwd)
+ ("/etc/group" -> ,group)
("/etc/login.defs" -> "/dev/null")
("/etc/pam.d" -> ,pam.d)
("/etc/resolv.conf" -> ,resolv.conf)
("/etc/profile" -> ,bashrc)
("/etc/issue" -> ,issue)
+ ("/etc/services" -> ,etc-services)
+ ("/etc/protocols" -> ,etc-protocols)
+ ("/etc/rpc" -> ,etc-rpc)
(directory "/var/nix/gcroots")
- ("/var/nix/gcroots/default-profile" -> ,profile)))
+ ("/var/nix/gcroots/default-profile" -> ,profile)
+ (directory "/tmp")
+ (directory "/var/nix/profiles/per-user/root" 0 0)
+ (directory "/var/nix/profiles/per-user/guest"
+ 1000 100)
+ (directory "/home/guest" 1000 100)))
(out (derivation->output-path
(package-derivation store mingetty)))
(boot (add-text-to-store store "boot"
@@ -549,7 +607,7 @@ You can log in as 'root' with no password.
(qemu-image store
#:grub-configuration grub.cfg
#:populate populate
- #:disk-image-size (* 500 (expt 2 20))
+ #:disk-image-size (* 550 (expt 2 20))
#:initialize-store? #t
#:inputs-to-copy `(("boot" ,boot)
("linux" ,linux-libre)
@@ -567,6 +625,7 @@ You can log in as 'root' with no password.
("etc-bashrc" ,bashrc)
("etc-issue" ,issue)
("etc-motd" ,motd)
+ ("net-base" ,net-base)
,@(append-map service-inputs
%dmd-services))))))
diff --git a/guix/build-system/trivial.scm b/guix/build-system/trivial.scm
index 3c5031c4bd..f91997d1e9 100644
--- a/guix/build-system/trivial.scm
+++ b/guix/build-system/trivial.scm
@@ -42,7 +42,10 @@
search-paths)
"Run build expression BUILDER, an expression, for SYSTEM. SOURCE is
ignored."
- (build-expression->derivation store name system builder inputs
+ (build-expression->derivation store name system builder
+ (if source
+ `(("source" ,source) ,@inputs)
+ inputs)
#:outputs outputs
#:modules modules
#:guile-for-build
@@ -54,7 +57,10 @@ ignored."
search-paths native-search-paths)
"Like `trivial-build', but in a cross-compilation context."
(build-expression->derivation store name system builder
- (append native-inputs inputs)
+ (let ((inputs (append native-inputs inputs)))
+ (if source
+ `(("source" ,source) ,@inputs)
+ inputs))
#:outputs outputs
#:modules modules
#:guile-for-build
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index 66505f172f..5c7c165cbb 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -214,6 +214,25 @@ all of PACKAGES, a list of name/version/output/path/deps tuples."
(compose string->number (cut match:substring <> 1)))
0))
+(define (link-to-empty-profile generation)
+ "Link GENERATION, a string, to the empty profile."
+ (let* ((drv (profile-derivation (%store) '()))
+ (prof (derivation->output-path drv "out")))
+ (when (not (build-derivations (%store) (list drv)))
+ (leave (_ "failed to build the empty profile~%")))
+
+ (switch-symlinks generation prof)))
+
+(define (switch-to-previous-generation profile)
+ "Atomically switch PROFILE to the previous generation."
+ (let* ((number (generation-number profile))
+ (previous-number (previous-generation-number profile number))
+ (previous-generation (format #f "~a-~a-link"
+ profile previous-number)))
+ (format #t (_ "switching from generation ~a to ~a~%")
+ number previous-number)
+ (switch-symlinks profile previous-generation)))
+
(define (roll-back profile)
"Roll back to the previous generation of PROFILE."
(let* ((number (generation-number profile))
@@ -221,38 +240,30 @@ all of PACKAGES, a list of name/version/output/path/deps tuples."
(previous-generation (format #f "~a-~a-link"
profile previous-number))
(manifest (string-append previous-generation "/manifest")))
-
- (define (switch-link)
- ;; Atomically switch PROFILE to the previous generation.
- (format #t (_ "switching from generation ~a to ~a~%")
- number previous-number)
- (switch-symlinks profile previous-generation))
-
- (cond ((not (file-exists? profile)) ; invalid profile
- (leave (_ "profile `~a' does not exist~%")
+ (cond ((not (file-exists? profile)) ; invalid profile
+ (leave (_ "profile '~a' does not exist~%")
profile))
- ((zero? number) ; empty profile
+ ((zero? number) ; empty profile
(format (current-error-port)
(_ "nothing to do: already at the empty profile~%")))
- ((or (zero? previous-number) ; going to emptiness
+ ((or (zero? previous-number) ; going to emptiness
(not (file-exists? previous-generation)))
- (let* ((drv (profile-derivation (%store) '()))
- (prof (derivation->output-path drv "out")))
- (when (not (build-derivations (%store) (list drv)))
- (leave (_ "failed to build the empty profile~%")))
-
- (switch-symlinks previous-generation prof)
- (switch-link)))
- (else (switch-link))))) ; anything else
+ (link-to-empty-profile previous-generation)
+ (switch-to-previous-generation profile))
+ (else
+ (switch-to-previous-generation profile))))) ; anything else
(define (generation-time profile number)
"Return the creation time of a generation in the UTC format."
(make-time time-utc 0
(stat:ctime (stat (format #f "~a-~a-link" profile number)))))
-(define* (matching-generations str #:optional (profile %current-profile))
+(define* (matching-generations str #:optional (profile %current-profile)
+ #:key (duration-relation <=))
"Return the list of available generations matching a pattern in STR. See
-'string->generations' and 'string->duration' for the list of valid patterns."
+'string->generations' and 'string->duration' for the list of valid patterns.
+When STR is a duration pattern, return all the generations whose ctime has
+DURATION-RELATION with the current time."
(define (valid-generations lst)
(define (valid-generation? n)
(any (cut = n <>) (generation-numbers profile)))
@@ -301,7 +312,7 @@ all of PACKAGES, a list of name/version/output/path/deps tuples."
(subtract-duration (time-at-midnight (current-time))
duration))))
(delete #f (map (lambda (x)
- (and (<= s (cdr x))
+ (and (duration-relation s (cdr x))
(first x)))
generation-ctime-alist))))))
@@ -511,6 +522,9 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n"))
(display (_ "
-l, --list-generations[=PATTERN]
list generations matching PATTERN"))
+ (display (_ "
+ -d, --delete-generations[=PATTERN]
+ delete generations matching PATTERN"))
(newline)
(display (_ "
-p, --profile=PROFILE use PROFILE instead of the user's default profile"))
@@ -574,6 +588,10 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n"))
(lambda (opt name arg result)
(cons `(query list-generations ,(or arg ""))
result)))
+ (option '(#\d "delete-generations") #f #t
+ (lambda (opt name arg result)
+ (alist-cons 'delete-generations (or arg "")
+ result)))
(option '("search-paths") #f #f
(lambda (opt name arg result)
(cons `(query search-paths) result)))
@@ -824,85 +842,150 @@ more information.~%"))
install))))
(_ #f)))
+ (define current-generation-number
+ (generation-number profile))
+
+ (define (display-and-delete number)
+ (let ((generation (format #f "~a-~a-link" profile number)))
+ (unless (zero? number)
+ (format #t (_ "deleting ~a~%") generation)
+ (delete-file generation))))
+
+ (define (delete-generation number)
+ (let* ((previous-number (previous-generation-number profile number))
+ (previous-generation (format #f "~a-~a-link"
+ profile previous-number)))
+ (cond ((zero? number)) ; do not delete generation 0
+ ((and (= number current-generation-number)
+ (not (file-exists? previous-generation)))
+ (link-to-empty-profile previous-generation)
+ (switch-to-previous-generation profile)
+ (display-and-delete number))
+ ((= number current-generation-number)
+ (roll-back profile)
+ (display-and-delete number))
+ (else
+ (display-and-delete number)))))
+
;; First roll back if asked to.
- (if (and (assoc-ref opts 'roll-back?) (not dry-run?))
- (begin
- (roll-back profile)
- (process-actions (alist-delete 'roll-back? opts)))
- (let* ((installed (manifest-packages (profile-manifest profile)))
- (upgrade-regexps (filter-map (match-lambda
- (('upgrade . regexp)
- (make-regexp (or regexp "")))
- (_ #f))
- opts))
- (upgrade (if (null? upgrade-regexps)
- '()
- (let ((newest (find-newest-available-packages)))
- (filter-map (match-lambda
- ((name version output path _)
- (and (any (cut regexp-exec <> name)
- upgrade-regexps)
- (upgradeable? name version path)
- (find-package name
- (or output "out"))))
- (_ #f))
- installed))))
- (install (append
- upgrade
- (filter-map (match-lambda
- (('install . (? package? p))
- (package->tuple p))
- (('install . (? store-path?))
- #f)
- (('install . package)
- (find-package package))
- (_ #f))
- opts)))
- (drv (filter-map (match-lambda
- ((name version sub-drv
- (? package? package)
- (deps ...))
- (check-package-freshness package)
- (package-derivation (%store) package))
- (_ #f))
- install))
- (install* (append
- (filter-map (match-lambda
- (('install . (? package? p))
- #f)
- (('install . (? store-path? path))
- (let-values (((name version)
- (package-name->name+version
- (store-path-package-name
- path))))
- `(,name ,version #f ,path ())))
- (_ #f))
- opts)
- (map (lambda (tuple drv)
- (match tuple
- ((name version sub-drv _ (deps ...))
- (let ((output-path
- (derivation->output-path
- drv sub-drv)))
- `(,name ,version ,sub-drv ,output-path
- ,(canonicalize-deps deps))))))
- install drv)))
- (remove (filter-map (match-lambda
- (('remove . package)
- package)
- (_ #f))
- opts))
- (remove* (filter-map (cut assoc <> installed) remove))
- (packages (append install*
- (fold (lambda (package result)
- (match package
- ((name _ out _ ...)
- (filter (negate
- (cut same-package? <>
- name out))
- result))))
- (fold alist-delete installed remove)
- install*))))
+ (cond ((and (assoc-ref opts 'roll-back?) (not dry-run?))
+ (begin
+ (roll-back profile)
+ (process-actions (alist-delete 'roll-back? opts))))
+ ((and (assoc-ref opts 'delete-generations)
+ (not dry-run?))
+ (filter-map
+ (match-lambda
+ (('delete-generations . pattern)
+ (cond ((not (file-exists? profile)) ; XXX: race condition
+ (leave (_ "profile '~a' does not exist~%")
+ profile))
+ ((string-null? pattern)
+ (let ((numbers (generation-numbers profile)))
+ (if (equal? numbers '(0))
+ (exit 0)
+ (for-each display-and-delete
+ (delete current-generation-number
+ numbers)))))
+ ;; Do not delete the zeroth generation.
+ ((equal? 0 (string->number pattern))
+ (exit 0))
+
+ ;; If PATTERN is a duration, match generations that are
+ ;; older than the specified duration.
+ ((matching-generations pattern profile
+ #:duration-relation >)
+ =>
+ (lambda (numbers)
+ (if (null-list? numbers)
+ (exit 1)
+ (for-each delete-generation numbers))))
+ (else
+ (leave (_ "invalid syntax: ~a~%")
+ pattern)))
+
+ (process-actions
+ (alist-delete 'delete-generations opts)))
+ (_ #f))
+ opts))
+ (else
+ (let* ((installed (manifest-packages (profile-manifest profile)))
+ (upgrade-regexps (filter-map (match-lambda
+ (('upgrade . regexp)
+ (make-regexp (or regexp "")))
+ (_ #f))
+ opts))
+ (upgrade (if (null? upgrade-regexps)
+ '()
+ (let ((newest (find-newest-available-packages)))
+ (filter-map
+ (match-lambda
+ ((name version output path _)
+ (and (any (cut regexp-exec <> name)
+ upgrade-regexps)
+ (upgradeable? name version path)
+ (find-package name
+ (or output "out"))))
+ (_ #f))
+ installed))))
+ (install (append
+ upgrade
+ (filter-map (match-lambda
+ (('install . (? package? p))
+ (package->tuple p))
+ (('install . (? store-path?))
+ #f)
+ (('install . package)
+ (find-package package))
+ (_ #f))
+ opts)))
+ (drv (filter-map (match-lambda
+ ((name version sub-drv
+ (? package? package)
+ (deps ...))
+ (check-package-freshness package)
+ (package-derivation (%store) package))
+ (_ #f))
+ install))
+ (install*
+ (append
+ (filter-map (match-lambda
+ (('install . (? package? p))
+ #f)
+ (('install . (? store-path? path))
+ (let-values (((name version)
+ (package-name->name+version
+ (store-path-package-name
+ path))))
+ `(,name ,version #f ,path ())))
+ (_ #f))
+ opts)
+ (map (lambda (tuple drv)
+ (match tuple
+ ((name version sub-drv _ (deps ...))
+ (let ((output-path
+ (derivation->output-path
+ drv sub-drv)))
+ `(,name ,version ,sub-drv ,output-path
+ ,(canonicalize-deps deps))))))
+ install drv)))
+ (remove (filter-map (match-lambda
+ (('remove . package)
+ package)
+ (_ #f))
+ opts))
+ (remove* (filter-map (cut assoc <> installed) remove))
+ (packages
+ (append install*
+ (fold (lambda (package result)
+ (match package
+ ((name _ out _ ...)
+ (filter (negate
+ (cut same-package? <>
+ name out))
+ result))))
+ (fold alist-delete installed remove)
+ install*))))
(when (equal? profile %current-profile)
(ensure-default-profile))
@@ -946,7 +1029,7 @@ more information.~%"))
count)
count)
(display-search-paths packages
- profile))))))))))
+ profile)))))))))))
(define (process-query opts)
;; Process any query specified by OPTS. Return #t when a query was
@@ -983,7 +1066,7 @@ more information.~%"))
((string-null? pattern)
(let ((numbers (generation-numbers profile)))
(if (equal? numbers '(0))
- (exit 1)
+ (exit 0)
(for-each list-generation numbers))))
((matching-generations pattern profile)
=>
diff --git a/scripts/guix.in b/scripts/guix.in
index 4015560cd5..c99e866361 100644
--- a/scripts/guix.in
+++ b/scripts/guix.in
@@ -1,4 +1,4 @@
-#!@GUILE@ -s
+#!@GUILE@ --no-auto-compile
-*- scheme -*-
!#
;;; GNU Guix --- Functional package management for GNU
diff --git a/tests/guix-package.sh b/tests/guix-package.sh
index 5f97aff026..9116f352c9 100644
--- a/tests/guix-package.sh
+++ b/tests/guix-package.sh
@@ -142,6 +142,17 @@ then
# Make sure LIBRARY_PATH gets listed by `--search-paths'.
guix package --bootstrap -p "$profile" -i guile-bootstrap -i gcc-bootstrap
guix package --search-paths -p "$profile" | grep LIBRARY_PATH
+
+ # Delete the third generation and check that it was actually deleted.
+ guix package -p "$profile" --delete-generations=3
+ test -z "`guix package -p "$profile" -l 3`"
+
+ # Exit with 1 when a generation does not exist.
+ if guix package -p "$profile" --delete-generations=42;
+ then false; else true; fi
+
+ # Exit with 0 when trying to delete the zeroth generation.
+ guix package -p "$profile" --delete-generations=0
fi
# Make sure the `:' syntax works.
@@ -155,7 +166,14 @@ if guix package --bootstrap -i "guile-bootstrap:does-not-exist" -p "$profile";
then false; else true; fi
# Check whether `--list-available' returns something sensible.
-guix package -A 'gui.*e' | grep guile
+guix package -p "$profile" -A 'gui.*e' | grep guile
+
+# There's no generation older than 12 months, so the following command should
+# have no effect.
+generation="`readlink_base "$profile"`"
+if guix package -p "$profile" --delete-generations=12m;
+then false; else true; fi
+test "`readlink_base "$profile"`" = "$generation"
#
# Try with the default profile.
diff --git a/tests/packages.scm b/tests/packages.scm
index 706739fb70..e0cf4ee001 100644
--- a/tests/packages.scm
+++ b/tests/packages.scm
@@ -167,6 +167,21 @@
(equal? (call-with-input-file p get-bytevector-all)
(call-with-input-file i get-bytevector-all))))))
+(test-assert "trivial with source"
+ (let* ((i (search-path %load-path "ice-9/boot-9.scm"))
+ (p (package (inherit (dummy-package "trivial-with-source"))
+ (build-system trivial-build-system)
+ (source i)
+ (arguments
+ `(#:guile ,%bootstrap-guile
+ #:builder (copy-file (assoc-ref %build-inputs "source")
+ %output)))))
+ (d (package-derivation %store p)))
+ (and (build-derivations %store (list d))
+ (let ((p (derivation->output-path d)))
+ (equal? (call-with-input-file p get-bytevector-all)
+ (call-with-input-file i get-bytevector-all))))))
+
(test-assert "trivial with system-dependent input"
(let* ((p (package (inherit (dummy-package "trivial-system-dependent-input"))
(build-system trivial-build-system)