aboutsummaryrefslogtreecommitdiff
path: root/guix
diff options
context:
space:
mode:
authorLeo Famulari <leo@famulari.name>2016-05-13 02:03:22 -0400
committerLeo Famulari <leo@famulari.name>2016-05-13 02:08:11 -0400
commiteb74eb4199db3faac654114257996f244ec308f5 (patch)
tree9504ae968710941557be6d1edd244618eeb14448 /guix
parentf10e7ef475da430afa46e0b062010952ed886694 (diff)
parente9017c98d61f305b624bacaa30e8891ec0100980 (diff)
downloadgnu-guix-eb74eb4199db3faac654114257996f244ec308f5.tar
gnu-guix-eb74eb4199db3faac654114257996f244ec308f5.tar.gz
Merge branch 'master' into core-updates
Diffstat (limited to 'guix')
-rw-r--r--guix/build-system/gnu.scm1
-rw-r--r--guix/build-system/python.scm1
-rw-r--r--guix/build/syscalls.scm92
-rw-r--r--guix/combinators.scm116
-rw-r--r--guix/derivations.scm1
-rw-r--r--guix/gnu-maintenance.scm3
-rw-r--r--guix/import/elpa.scm4
-rw-r--r--guix/nar.scm4
-rw-r--r--guix/profiles.scm143
-rw-r--r--guix/scripts/archive.scm1
-rw-r--r--guix/scripts/build.scm1
-rw-r--r--guix/scripts/environment.scm10
-rw-r--r--guix/scripts/graph.scm2
-rw-r--r--guix/scripts/lint.scm1
-rw-r--r--guix/scripts/size.scm2
-rwxr-xr-xguix/scripts/substitute.scm1
-rw-r--r--guix/scripts/system.scm142
-rw-r--r--guix/serialization.scm4
-rw-r--r--guix/store.scm1
-rw-r--r--guix/ui.scm1
-rw-r--r--guix/utils.scm192
21 files changed, 434 insertions, 289 deletions
diff --git a/guix/build-system/gnu.scm b/guix/build-system/gnu.scm
index a7d1952b57..f6df183da4 100644
--- a/guix/build-system/gnu.scm
+++ b/guix/build-system/gnu.scm
@@ -19,6 +19,7 @@
(define-module (guix build-system gnu)
#:use-module (guix store)
#:use-module (guix utils)
+ #:use-module (guix combinators)
#:use-module (guix derivations)
#:use-module (guix search-paths)
#:use-module (guix build-system)
diff --git a/guix/build-system/python.scm b/guix/build-system/python.scm
index 326e6fd429..c3d6c62404 100644
--- a/guix/build-system/python.scm
+++ b/guix/build-system/python.scm
@@ -21,6 +21,7 @@
(define-module (guix build-system python)
#:use-module (guix store)
#:use-module (guix utils)
+ #:use-module (guix combinators)
#:use-module (guix packages)
#:use-module (guix derivations)
#:use-module (guix search-paths)
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index 4e543d70d8..48ff227e10 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -65,6 +65,7 @@
processes
mkdtemp!
pivot-root
+ fcntl-flock
CLONE_CHILD_CLEARTID
CLONE_CHILD_SETTID
@@ -110,9 +111,7 @@
termios-input-speed
termios-output-speed
local-flags
- TCSANOW
- TCSADRAIN
- TCSAFLUSH
+ tcsetattr-action
tcgetattr
tcsetattr
@@ -641,6 +640,81 @@ system to PUT-OLD."
;;;
+;;; Advisory file locking.
+;;;
+
+(define-c-struct %struct-flock ;<fcntl.h>
+ sizeof-flock
+ list
+ read-flock
+ write-flock!
+ (type short)
+ (whence short)
+ (start size_t)
+ (length size_t)
+ (pid int))
+
+(define F_SETLKW
+ ;; On Linux-based systems, this is usually 7, but not always
+ ;; (exceptions include SPARC.) On GNU/Hurd, it's 9.
+ (cond ((string-contains %host-type "sparc") 9) ; sparc-*-linux-gnu
+ ((string-contains %host-type "linux") 7) ; *-linux-gnu
+ (else 9))) ; *-gnu*
+
+(define F_SETLK
+ ;; Likewise: GNU/Hurd and SPARC use 8, while the others typically use 6.
+ (cond ((string-contains %host-type "sparc") 8) ; sparc-*-linux-gnu
+ ((string-contains %host-type "linux") 6) ; *-linux-gnu
+ (else 8))) ; *-gnu*
+
+(define F_xxLCK
+ ;; The F_RDLCK, F_WRLCK, and F_UNLCK constants.
+ (cond ((string-contains %host-type "sparc") #(1 2 3)) ; sparc-*-linux-gnu
+ ((string-contains %host-type "hppa") #(1 2 3)) ; hppa-*-linux-gnu
+ ((string-contains %host-type "linux") #(0 1 2)) ; *-linux-gnu
+ (else #(1 2 3)))) ; *-gnu*
+
+(define fcntl-flock
+ (let ((proc (syscall->procedure int "fcntl" `(,int ,int *))))
+ (lambda* (fd-or-port operation #:key (wait? #t))
+ "Perform locking OPERATION on the file beneath FD-OR-PORT. OPERATION
+must be a symbol, one of 'read-lock, 'write-lock, or 'unlock. When WAIT? is
+true, block until the lock is acquired; otherwise, thrown an 'flock-error'
+exception if it's already taken."
+ (define (operation->int op)
+ (case op
+ ((read-lock) (vector-ref F_xxLCK 0))
+ ((write-lock) (vector-ref F_xxLCK 1))
+ ((unlock) (vector-ref F_xxLCK 2))
+ (else (error "invalid fcntl-flock operation" op))))
+
+ (define fd
+ (if (port? fd-or-port)
+ (fileno fd-or-port)
+ fd-or-port))
+
+ (define bv
+ (make-bytevector sizeof-flock))
+
+ (write-flock! bv 0
+ (operation->int operation) SEEK_SET
+ 0 0 ;whole file
+ 0)
+
+ ;; XXX: 'fcntl' is a vararg function, but here we happily use the
+ ;; standard ABI; crossing fingers.
+ (let ((ret (proc fd
+ (if wait?
+ F_SETLKW ; lock & wait
+ F_SETLK) ; non-blocking attempt
+ (bytevector->pointer bv)))
+ (err (errno)))
+ (unless (zero? ret)
+ ;; Presumably we got EAGAIN or so.
+ (throw 'flock-error err))))))
+
+
+;;;
;;; Network interfaces.
;;;
@@ -1059,9 +1133,11 @@ given an integer, returns the list of names of the constants that are or'd."
(define EXTPROC #o0200000))
;; "Actions" values for 'tcsetattr'.
-(define TCSANOW 0)
-(define TCSADRAIN 1)
-(define TCSAFLUSH 2)
+(define-bits tcsetattr-action
+ %unused-tcsetattr-action->symbols
+ (define TCSANOW 0)
+ (define TCSADRAIN 1)
+ (define TCSAFLUSH 2))
(define-record-type <termios>
(termios input-flags output-flags control-flags local-flags
@@ -1107,8 +1183,8 @@ given an integer, returns the list of names of the constants that are or'd."
(define tcsetattr
(let ((proc (syscall->procedure int "tcsetattr" (list int int '*))))
(lambda (fd actions termios)
- "Use TERMIOS for the tty at FD. ACTIONS is one of 'TCSANOW',
-'TCSADRAIN', or 'TCSAFLUSH'; see tcsetattr(3) for details."
+ "Use TERMIOS for the tty at FD. ACTIONS is one of of the values
+produced by 'tcsetattr-action'; see tcsetattr(3) for details."
(define bv
(make-bytevector sizeof-termios))
diff --git a/guix/combinators.scm b/guix/combinators.scm
new file mode 100644
index 0000000000..9e4689ba9c
--- /dev/null
+++ b/guix/combinators.scm
@@ -0,0 +1,116 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.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 (guix combinators)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 vlist)
+ #:export (memoize
+ fold2
+ fold-tree
+ fold-tree-leaves
+ compile-time-value))
+
+;;; Commentary:
+;;;
+;;; This module provides useful combinators that complement SRFI-1 and
+;;; friends.
+;;;
+;;; Code:
+
+(define (memoize proc)
+ "Return a memoizing version of PROC."
+ (let ((cache (make-hash-table)))
+ (lambda args
+ (let ((results (hash-ref cache args)))
+ (if results
+ (apply values results)
+ (let ((results (call-with-values (lambda ()
+ (apply proc args))
+ list)))
+ (hash-set! cache args results)
+ (apply values results)))))))
+
+(define fold2
+ (case-lambda
+ ((proc seed1 seed2 lst)
+ "Like `fold', but with a single list and two seeds."
+ (let loop ((result1 seed1)
+ (result2 seed2)
+ (lst lst))
+ (if (null? lst)
+ (values result1 result2)
+ (call-with-values
+ (lambda () (proc (car lst) result1 result2))
+ (lambda (result1 result2)
+ (loop result1 result2 (cdr lst)))))))
+ ((proc seed1 seed2 lst1 lst2)
+ "Like `fold', but with a two lists and two seeds."
+ (let loop ((result1 seed1)
+ (result2 seed2)
+ (lst1 lst1)
+ (lst2 lst2))
+ (if (or (null? lst1) (null? lst2))
+ (values result1 result2)
+ (call-with-values
+ (lambda () (proc (car lst1) (car lst2) result1 result2))
+ (lambda (result1 result2)
+ (fold2 proc result1 result2 (cdr lst1) (cdr lst2)))))))))
+
+(define (fold-tree proc init children roots)
+ "Call (PROC NODE RESULT) for each node in the tree that is reachable from
+ROOTS, using INIT as the initial value of RESULT. The order in which nodes
+are traversed is not specified, however, each node is visited only once, based
+on an eq? check. Children of a node to be visited are generated by
+calling (CHILDREN NODE), the result of which should be a list of nodes that
+are connected to NODE in the tree, or '() or #f if NODE is a leaf node."
+ (let loop ((result init)
+ (seen vlist-null)
+ (lst roots))
+ (match lst
+ (() result)
+ ((head . tail)
+ (if (not (vhash-assq head seen))
+ (loop (proc head result)
+ (vhash-consq head #t seen)
+ (match (children head)
+ ((or () #f) tail)
+ (children (append tail children))))
+ (loop result seen tail))))))
+
+(define (fold-tree-leaves proc init children roots)
+ "Like fold-tree, but call (PROC NODE RESULT) only for leaf nodes."
+ (fold-tree
+ (lambda (node result)
+ (match (children node)
+ ((or () #f) (proc node result))
+ (else result)))
+ init children roots))
+
+(define-syntax compile-time-value ;not quite at home
+ (syntax-rules ()
+ "Evaluate the given expression at compile time. The expression must
+evaluate to a simple datum."
+ ((_ exp)
+ (let-syntax ((v (lambda (s)
+ (let ((val exp))
+ (syntax-case s ()
+ (_ #`'#,(datum->syntax s val)))))))
+ v))))
+
+;;; combinators.scm ends here
diff --git a/guix/derivations.scm b/guix/derivations.scm
index 2d8584e72d..d4f697477b 100644
--- a/guix/derivations.scm
+++ b/guix/derivations.scm
@@ -30,6 +30,7 @@
#:use-module (ice-9 vlist)
#:use-module (guix store)
#:use-module (guix utils)
+ #:use-module (guix combinators)
#:use-module (guix monads)
#:use-module (guix hash)
#:use-module (guix base32)
diff --git a/guix/gnu-maintenance.scm b/guix/gnu-maintenance.scm
index 8021d99c8b..adb62aa68c 100644
--- a/guix/gnu-maintenance.scm
+++ b/guix/gnu-maintenance.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2010, 2011, 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2012, 2013 Nikita Karetnikov <nikita@karetnikov.org>
;;;
;;; This file is part of GNU Guix.
@@ -30,6 +30,7 @@
#:use-module (guix http-client)
#:use-module (guix ftp-client)
#:use-module (guix utils)
+ #:use-module (guix combinators)
#:use-module (guix records)
#:use-module (guix upstream)
#:use-module (guix packages)
diff --git a/guix/import/elpa.scm b/guix/import/elpa.scm
index ccc4063a53..320a09e8c6 100644
--- a/guix/import/elpa.scm
+++ b/guix/import/elpa.scm
@@ -35,8 +35,8 @@
#:use-module (guix base32)
#:use-module (guix upstream)
#:use-module (guix packages)
- #:use-module ((guix utils) #:select (call-with-temporary-output-file
- memoize))
+ #:use-module ((guix combinators) #:select (memoize))
+ #:use-module ((guix utils) #:select (call-with-temporary-output-file))
#:export (elpa->guix-package
%elpa-updater))
diff --git a/guix/nar.scm b/guix/nar.scm
index 43e5210752..739d3d3a57 100644
--- a/guix/nar.scm
+++ b/guix/nar.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2014 Mark H Weaver <mhw@netris.org>
;;;
;;; This file is part of GNU Guix.
@@ -18,8 +18,8 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (guix nar)
- #:use-module (guix utils)
#:use-module (guix serialization)
+ #:use-module (guix build syscalls)
#:use-module ((guix build utils)
#:select (delete-file-recursively with-directory-excursion))
#:use-module (guix store)
diff --git a/guix/profiles.scm b/guix/profiles.scm
index a3277cef71..8355af7a48 100644
--- a/guix/profiles.scm
+++ b/guix/profiles.scm
@@ -445,6 +445,40 @@ replace it."
(cons (gexp-input thing output) deps)))
(manifest-entries manifest)))
+(define (manifest-lookup-package manifest name)
+ "Return as a monadic value the first package or store path referenced by
+MANIFEST that named NAME, or #f if not found."
+ ;; Return as a monadic value the package or store path referenced by the
+ ;; manifest ENTRY, or #f if not referenced.
+ (define (entry-lookup-package entry)
+ (define (find-among-inputs inputs)
+ (find (lambda (input)
+ (and (package? input)
+ (equal? name (package-name input))))
+ inputs))
+ (define (find-among-store-items items)
+ (find (lambda (item)
+ (equal? name (package-name->name+version
+ (store-path-package-name item))))
+ items))
+
+ ;; TODO: Factorize.
+ (define references*
+ (store-lift references))
+
+ (with-monad %store-monad
+ (match (manifest-entry-item entry)
+ ((? package? package)
+ (match (package-transitive-inputs package)
+ (((labels inputs . _) ...)
+ (return (find-among-inputs inputs)))))
+ ((? string? item)
+ (mlet %store-monad ((refs (references* item)))
+ (return (find-among-store-items refs)))))))
+
+ (anym %store-monad
+ entry-lookup-package (manifest-entries manifest)))
+
(define (info-dir-file manifest)
"Return a derivation that builds the 'dir' file for all the entries of
MANIFEST."
@@ -608,41 +642,7 @@ MANIFEST. Single-file bundles are required by programs such as Git and Lynx."
(define (gtk-icon-themes manifest)
"Return a derivation that unions all icon themes from manifest entries and
creates the GTK+ 'icon-theme.cache' file for each theme."
- ;; Return as a monadic value the GTK+ package or store path referenced by the
- ;; manifest ENTRY, or #f if not referenced.
- (define (entry-lookup-gtk+ entry)
- (define (find-among-inputs inputs)
- (find (lambda (input)
- (and (package? input)
- (string=? "gtk+" (package-name input))))
- inputs))
-
- (define (find-among-store-items items)
- (find (lambda (item)
- (equal? "gtk+"
- (package-name->name+version
- (store-path-package-name item))))
- items))
-
- ;; TODO: Factorize.
- (define references*
- (store-lift references))
-
- (with-monad %store-monad
- (match (manifest-entry-item entry)
- ((? package? package)
- (match (package-transitive-inputs package)
- (((labels inputs . _) ...)
- (return (find-among-inputs inputs)))))
- ((? string? item)
- (mlet %store-monad ((refs (references* item)))
- (return (find-among-store-items refs)))))))
-
- (define (manifest-lookup-gtk+ manifest)
- (anym %store-monad
- entry-lookup-gtk+ (manifest-entries manifest)))
-
- (mlet %store-monad ((gtk+ (manifest-lookup-gtk+ manifest)))
+ (mlet %store-monad ((gtk+ (manifest-lookup-package manifest "gtk+")))
(define build
#~(begin
(use-modules (guix build utils)
@@ -686,13 +686,84 @@ creates the GTK+ 'icon-theme.cache' file for each theme."
#:substitutable? #f)
(return #f))))
+(define (xdg-desktop-database manifest)
+ "Return a derivation that builds the @file{mimeinfo.cache} database from
+desktop files. It's used to query what applications can handle a given
+MIME type."
+ (mlet %store-monad ((desktop-file-utils
+ (manifest-lookup-package
+ manifest "desktop-file-utils")))
+ (define build
+ #~(begin
+ (use-modules (srfi srfi-26)
+ (guix build utils)
+ (guix build union))
+ (let* ((destdir (string-append #$output "/share/applications"))
+ (appdirs (filter file-exists?
+ (map (cut string-append <>
+ "/share/applications")
+ '#$(manifest-inputs manifest))))
+ (update-desktop-database (string-append
+ #+desktop-file-utils
+ "/bin/update-desktop-database")))
+ (mkdir-p (string-append #$output "/share"))
+ (union-build destdir appdirs
+ #:log-port (%make-void-port "w"))
+ (zero? (system* update-desktop-database destdir)))))
+
+ ;; Don't run the hook when 'desktop-file-utils' is not referenced.
+ (if desktop-file-utils
+ (gexp->derivation "xdg-desktop-database" build
+ #:modules '((guix build utils)
+ (guix build union))
+ #:local-build? #t
+ #:substitutable? #f)
+ (return #f))))
+
+(define (xdg-mime-database manifest)
+ "Return a derivation that builds the @file{mime.cache} database from manifest
+entries. It's used to query the MIME type of a given file."
+ (mlet %store-monad ((shared-mime-info
+ (manifest-lookup-package
+ manifest "shared-mime-info")))
+ (define build
+ #~(begin
+ (use-modules (srfi srfi-26)
+ (guix build utils)
+ (guix build union))
+ (let* ((datadir (string-append #$output "/share"))
+ (destdir (string-append datadir "/mime"))
+ (mimedirs (filter file-exists?
+ (map (cut string-append <>
+ "/share/mime")
+ '#$(manifest-inputs manifest))))
+ (update-mime-database (string-append
+ #+shared-mime-info
+ "/bin/update-mime-database")))
+ (mkdir-p datadir)
+ (union-build destdir mimedirs
+ #:log-port (%make-void-port "w"))
+ (setenv "XDG_DATA_HOME" datadir)
+ (zero? (system* update-mime-database destdir)))))
+
+ ;; Don't run the hook when 'shared-mime-info' is referenced.
+ (if shared-mime-info
+ (gexp->derivation "xdg-mime-database" build
+ #:modules '((guix build utils)
+ (guix build union))
+ #:local-build? #t
+ #:substitutable? #f)
+ (return #f))))
+
(define %default-profile-hooks
;; This is the list of derivation-returning procedures that are called by
;; default when making a non-empty profile.
(list info-dir-file
ghc-package-cache-file
ca-certificate-bundle
- gtk-icon-themes))
+ gtk-icon-themes
+ xdg-desktop-database
+ xdg-mime-database))
(define* (profile-derivation manifest
#:key
diff --git a/guix/scripts/archive.scm b/guix/scripts/archive.scm
index 3fb210ee91..e06c38aaab 100644
--- a/guix/scripts/archive.scm
+++ b/guix/scripts/archive.scm
@@ -19,6 +19,7 @@
(define-module (guix scripts archive)
#:use-module (guix config)
#:use-module (guix utils)
+ #:use-module (guix combinators)
#:use-module ((guix build utils) #:select (mkdir-p))
#:use-module ((guix serialization) #:select (restore-file))
#:use-module (guix store)
diff --git a/guix/scripts/build.scm b/guix/scripts/build.scm
index 9a6b427fc5..320ec39be2 100644
--- a/guix/scripts/build.scm
+++ b/guix/scripts/build.scm
@@ -24,6 +24,7 @@
#:use-module (guix derivations)
#:use-module (guix packages)
#:use-module (guix grafts)
+ #:use-module (guix combinators)
;; Use the procedure that destructures "NAME-VERSION" forms.
#:use-module ((guix utils) #:hide (package-name->name+version))
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm
index d4c09ef54c..9ba487d1eb 100644
--- a/guix/scripts/environment.scm
+++ b/guix/scripts/environment.scm
@@ -25,7 +25,6 @@
#:use-module (guix packages)
#:use-module (guix profiles)
#:use-module (guix search-paths)
- #:use-module (guix utils)
#:use-module (guix build utils)
#:use-module (guix monads)
#:use-module ((guix gexp) #:select (lower-inputs))
@@ -499,12 +498,13 @@ Otherwise, return the derivation for the Bash package."
;; The '--' token is used to separate the command to run from the rest of
;; the operands.
- (let-values (((args command) (split args "--")))
+ (let-values (((args command) (break (cut string=? "--" <>) args)))
(let ((opts (parse-command-line args %options (list %default-options)
#:argument-handler handle-argument)))
- (if (null? command)
- opts
- (alist-cons 'exec command opts)))))
+ (match command
+ (() opts)
+ (("--") opts)
+ (("--" command ...) (alist-cons 'exec command opts))))))
(define (assert-container-features)
"Check if containers can be created and exit with an informative error
diff --git a/guix/scripts/graph.scm b/guix/scripts/graph.scm
index b0d7c08582..ba63780e2b 100644
--- a/guix/scripts/graph.scm
+++ b/guix/scripts/graph.scm
@@ -21,7 +21,7 @@
#:use-module (guix graph)
#:use-module (guix grafts)
#:use-module (guix scripts)
- #:use-module (guix utils)
+ #:use-module (guix combinators)
#:use-module (guix packages)
#:use-module (guix monads)
#:use-module (guix store)
diff --git a/guix/scripts/lint.scm b/guix/scripts/lint.scm
index c581586ac3..06001d3eae 100644
--- a/guix/scripts/lint.scm
+++ b/guix/scripts/lint.scm
@@ -31,6 +31,7 @@
#:use-module (guix records)
#:use-module (guix ui)
#:use-module (guix utils)
+ #:use-module (guix combinators)
#:use-module (guix scripts)
#:use-module (guix gnu-maintenance)
#:use-module (guix monads)
diff --git a/guix/scripts/size.scm b/guix/scripts/size.scm
index 8f0cb7decd..be1e8ca087 100644
--- a/guix/scripts/size.scm
+++ b/guix/scripts/size.scm
@@ -21,7 +21,7 @@
#:use-module (guix scripts)
#:use-module (guix store)
#:use-module (guix monads)
- #:use-module (guix utils)
+ #:use-module (guix combinators)
#:use-module (guix grafts)
#:use-module (guix packages)
#:use-module (guix derivations)
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index 1cfab81dbd..d46d610347 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -21,6 +21,7 @@
#:use-module (guix ui)
#:use-module ((guix store) #:hide (close-connection))
#:use-module (guix utils)
+ #:use-module (guix combinators)
#:use-module (guix config)
#:use-module (guix records)
#:use-module (guix serialization)
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index e5d754a6fa..dd1e534c9b 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -236,6 +236,72 @@ BODY..., and restore them."
(with-monad %store-monad
(return #f)))))
+(define-syntax-rule (with-shepherd-error-handling body ...)
+ (warn-on-system-error
+ (guard (c ((shepherd-error? c)
+ (report-shepherd-error c)))
+ body ...)))
+
+(define (report-shepherd-error error)
+ "Report ERROR, a '&shepherd-error' error condition object."
+ (cond ((service-not-found-error? error)
+ (report-error (_ "service '~a' could not be found~%")
+ (service-not-found-error-service error)))
+ ((action-not-found-error? error)
+ (report-error (_ "service '~a' does not have an action '~a'~%")
+ (action-not-found-error-service error)
+ (action-not-found-error-action error)))
+ ((action-exception-error? error)
+ (report-error (_ "exception caught while executing '~a' \
+on service '~a':~%")
+ (action-exception-error-action error)
+ (action-exception-error-service error))
+ (print-exception (current-error-port) #f
+ (action-exception-error-key error)
+ (action-exception-error-arguments error)))
+ ((unknown-shepherd-error? error)
+ (report-error (_ "something went wrong: ~s~%")
+ (unknown-shepherd-error-sexp error)))
+ ((shepherd-error? error)
+ (report-error (_ "shepherd error~%")))
+ ((not error) ;not an error
+ #t)))
+
+(define (call-with-service-upgrade-info new-services mproc)
+ "Call MPROC, a monadic procedure in %STORE-MONAD, passing it the list of
+names of services to load (upgrade), and the list of names of services to
+unload."
+ (define (essential? service)
+ (memq service '(root shepherd)))
+
+ (define new-service-names
+ (map (compose first shepherd-service-provision)
+ new-services))
+
+ (let-values (((running stopped) (current-services)))
+ (if (and running stopped)
+ (let* ((to-load
+ ;; Only load services that are either new or currently stopped.
+ (remove (lambda (service)
+ (memq (first (shepherd-service-provision service))
+ running))
+ new-services))
+ (to-unload
+ ;; Unload services that are (1) no longer required, or (2) are
+ ;; in TO-LOAD.
+ (remove essential?
+ (append (remove (lambda (service)
+ (memq service new-service-names))
+ (append running stopped))
+ (filter (lambda (service)
+ (memq service stopped))
+ (map shepherd-service-canonical-name
+ to-load))))))
+ (mproc to-load to-unload))
+ (with-monad %store-monad
+ (warning (_ "failed to obtain list of shepherd services~%"))
+ (return #f)))))
+
(define (upgrade-shepherd-services os)
"Upgrade the Shepherd (PID 1) by unloading obsolete services and loading new
services specified in OS and not currently running.
@@ -243,59 +309,35 @@ services specified in OS and not currently running.
This is currently very conservative in that it does not stop or unload any
running service. Unloading or stopping the wrong service ('udev', say) could
bring the system down."
- (define (essential? service)
- (memq service '(root shepherd)))
-
(define new-services
(service-parameters
(fold-services (operating-system-services os)
#:target-type shepherd-root-service-type)))
- (define new-service-names
- (map (compose first shepherd-service-provision)
- new-services))
-
- ;; Arrange to simply emit a warning if we cannot connect to the shepherd.
- (warn-on-system-error
- (let-values (((running stopped) (current-services)))
- (define to-load
- ;; Only load services that are either new or currently stopped.
- (remove (lambda (service)
- (memq (first (shepherd-service-provision service))
- running))
- new-services))
- (define to-unload
- ;; Unload services that are (1) no longer required, or (2) are in
- ;; TO-LOAD.
- (remove essential?
- (append (remove (lambda (service)
- (memq service new-service-names))
- (append running stopped))
- (filter (lambda (service)
- (memq service stopped))
- (map shepherd-service-canonical-name
- to-load)))))
-
- (for-each (lambda (unload)
- (info (_ "unloading service '~a'...~%") unload)
- (unload-service unload))
- to-unload)
-
- (with-monad %store-monad
- (munless (null? to-load)
- (let ((to-load-names (map shepherd-service-canonical-name to-load))
- (to-start (filter shepherd-service-auto-start? to-load)))
- (info (_ "loading new services:~{ ~a~}...~%") to-load-names)
- (mlet %store-monad ((files (mapm %store-monad shepherd-service-file
- to-load)))
- ;; Here we assume that FILES are exactly those that were computed
- ;; as part of the derivation that built OS, which is normally the
- ;; case.
- (load-services (map derivation->output-path files))
-
- (for-each start-service
- (map shepherd-service-canonical-name to-start))
- (return #t))))))))
+ ;; Arrange to simply emit a warning if the service upgrade fails.
+ (with-shepherd-error-handling
+ (call-with-service-upgrade-info new-services
+ (lambda (to-load to-unload)
+ (for-each (lambda (unload)
+ (info (_ "unloading service '~a'...~%") unload)
+ (unload-service unload))
+ to-unload)
+
+ (with-monad %store-monad
+ (munless (null? to-load)
+ (let ((to-load-names (map shepherd-service-canonical-name to-load))
+ (to-start (filter shepherd-service-auto-start? to-load)))
+ (info (_ "loading new services:~{ ~a~}...~%") to-load-names)
+ (mlet %store-monad ((files (mapm %store-monad shepherd-service-file
+ to-load)))
+ ;; Here we assume that FILES are exactly those that were computed
+ ;; as part of the derivation that built OS, which is normally the
+ ;; case.
+ (load-services (map derivation->output-path files))
+
+ (for-each start-service
+ (map shepherd-service-canonical-name to-start))
+ (return #t)))))))))
(define* (switch-to-system os
#:optional (profile %system-profile))
@@ -839,4 +881,8 @@ argument list and OPTS is the option alist."
(parameterize ((%graft? (assoc-ref opts 'graft?)))
(process-command command args opts)))))
+;;; Local Variables:
+;;; eval: (put 'call-with-service-upgrade-info 'scheme-indent-function 1)
+;;; End:
+
;;; system.scm ends here
diff --git a/guix/serialization.scm b/guix/serialization.scm
index 7a3defc03d..286b4cbf30 100644
--- a/guix/serialization.scm
+++ b/guix/serialization.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -17,7 +17,7 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (guix serialization)
- #:use-module (guix utils)
+ #:use-module (guix combinators)
#:use-module (rnrs bytevectors)
#:use-module (rnrs io ports)
#:use-module (srfi srfi-1)
diff --git a/guix/store.scm b/guix/store.scm
index 8d1099dab2..f352a99cbd 100644
--- a/guix/store.scm
+++ b/guix/store.scm
@@ -19,6 +19,7 @@
(define-module (guix store)
#:use-module (guix utils)
#:use-module (guix config)
+ #:use-module (guix combinators)
#:use-module (guix serialization)
#:use-module (guix monads)
#:autoload (guix base32) (bytevector->base32-string)
diff --git a/guix/ui.scm b/guix/ui.scm
index 04ac43723e..8310974ac7 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -30,6 +30,7 @@
#:use-module (guix packages)
#:use-module (guix profiles)
#:use-module (guix derivations)
+ #:use-module (guix combinators)
#:use-module (guix build-system)
#:use-module (guix serialization)
#:use-module ((guix build utils) #:select (mkdir-p))
diff --git a/guix/utils.scm b/guix/utils.scm
index 6c01edde21..c77da5d846 100644
--- a/guix/utils.scm
+++ b/guix/utils.scm
@@ -32,8 +32,9 @@
#:use-module (rnrs bytevectors)
#:use-module (rnrs io ports)
#:use-module ((rnrs bytevectors) #:select (bytevector-u8-set!))
+ #:use-module (guix combinators)
#:use-module ((guix build utils) #:select (dump-port))
- #:use-module ((guix build syscalls) #:select (errno mkdtemp!))
+ #:use-module ((guix build syscalls) #:select (mkdtemp!))
#:use-module (ice-9 vlist)
#:use-module (ice-9 format)
#:autoload (ice-9 popen) (open-pipe*)
@@ -43,12 +44,10 @@
#:use-module (ice-9 format)
#:use-module ((ice-9 iconv) #:select (bytevector->string))
#:use-module (system foreign)
+ #:re-export (memoize) ; for backwards compatibility
#:export (bytevector->base16-string
base16-string->bytevector
- compile-time-value
- fcntl-flock
- memoize
strip-keyword-arguments
default-keyword-arguments
substitute-keyword-arguments
@@ -82,10 +81,6 @@
call-with-temporary-output-file
call-with-temporary-directory
with-atomic-file-output
- fold2
- fold-tree
- fold-tree-leaves
- split
cache-directory
readlink*
edit-expression
@@ -100,22 +95,6 @@
;;;
-;;; Compile-time computations.
-;;;
-
-(define-syntax compile-time-value
- (syntax-rules ()
- "Evaluate the given expression at compile time. The expression must
-evaluate to a simple datum."
- ((_ exp)
- (let-syntax ((v (lambda (s)
- (let ((val exp))
- (syntax-case s ()
- (_ #`'#,(datum->syntax s val)))))))
- v))))
-
-
-;;;
;;; Base 16.
;;;
@@ -361,94 +340,9 @@ This procedure returns #t on success."
;;;
-;;; Advisory file locking.
-;;;
-
-(define %struct-flock
- ;; 'struct flock' from <fcntl.h>.
- (list short ; l_type
- short ; l_whence
- size_t ; l_start
- size_t ; l_len
- int)) ; l_pid
-
-(define F_SETLKW
- ;; On Linux-based systems, this is usually 7, but not always
- ;; (exceptions include SPARC.) On GNU/Hurd, it's 9.
- (compile-time-value
- (cond ((string-contains %host-type "sparc") 9) ; sparc-*-linux-gnu
- ((string-contains %host-type "linux") 7) ; *-linux-gnu
- (else 9)))) ; *-gnu*
-
-(define F_SETLK
- ;; Likewise: GNU/Hurd and SPARC use 8, while the others typically use 6.
- (compile-time-value
- (cond ((string-contains %host-type "sparc") 8) ; sparc-*-linux-gnu
- ((string-contains %host-type "linux") 6) ; *-linux-gnu
- (else 8)))) ; *-gnu*
-
-(define F_xxLCK
- ;; The F_RDLCK, F_WRLCK, and F_UNLCK constants.
- (compile-time-value
- (cond ((string-contains %host-type "sparc") #(1 2 3)) ; sparc-*-linux-gnu
- ((string-contains %host-type "hppa") #(1 2 3)) ; hppa-*-linux-gnu
- ((string-contains %host-type "linux") #(0 1 2)) ; *-linux-gnu
- (else #(1 2 3))))) ; *-gnu*
-
-(define fcntl-flock
- (let* ((ptr (dynamic-func "fcntl" (dynamic-link)))
- (proc (pointer->procedure int ptr `(,int ,int *))))
- (lambda* (fd-or-port operation #:key (wait? #t))
- "Perform locking OPERATION on the file beneath FD-OR-PORT. OPERATION
-must be a symbol, one of 'read-lock, 'write-lock, or 'unlock. When WAIT? is
-true, block until the lock is acquired; otherwise, thrown an 'flock-error'
-exception if it's already taken."
- (define (operation->int op)
- (case op
- ((read-lock) (vector-ref F_xxLCK 0))
- ((write-lock) (vector-ref F_xxLCK 1))
- ((unlock) (vector-ref F_xxLCK 2))
- (else (error "invalid fcntl-flock operation" op))))
-
- (define fd
- (if (port? fd-or-port)
- (fileno fd-or-port)
- fd-or-port))
-
- ;; XXX: 'fcntl' is a vararg function, but here we happily use the
- ;; standard ABI; crossing fingers.
- (let ((err (proc fd
- (if wait?
- F_SETLKW ; lock & wait
- F_SETLK) ; non-blocking attempt
- (make-c-struct %struct-flock
- (list (operation->int operation)
- SEEK_SET
- 0 0 ; whole file
- 0)))))
- (or (zero? err)
-
- ;; Presumably we got EAGAIN or so.
- (throw 'flock-error (errno)))))))
-
-
-;;;
-;;; Miscellaneous.
+;;; Keyword arguments.
;;;
-(define (memoize proc)
- "Return a memoizing version of PROC."
- (let ((cache (make-hash-table)))
- (lambda args
- (let ((results (hash-ref cache args)))
- (if results
- (apply values results)
- (let ((results (call-with-values (lambda ()
- (apply proc args))
- list)))
- (hash-set! cache args results)
- (apply values results)))))))
-
(define (strip-keyword-arguments keywords args)
"Remove all of the keyword arguments listed in KEYWORDS from ARGS."
(let loop ((args args)
@@ -534,6 +428,11 @@ For instance:
(#f
(loop rest kw/values (cons* value kw result))))))))
+
+;;;
+;;; System strings.
+;;;
+
(define* (nix-system->gnu-triplet
#:optional (system (%current-system)) (vendor "unknown"))
"Return a guess of the GNU triplet corresponding to Nix system
@@ -732,79 +631,6 @@ output port, and PROC's result is returned."
(lambda (key . args)
(false-if-exception (delete-file template))))))
-(define fold2
- (case-lambda
- ((proc seed1 seed2 lst)
- "Like `fold', but with a single list and two seeds."
- (let loop ((result1 seed1)
- (result2 seed2)
- (lst lst))
- (if (null? lst)
- (values result1 result2)
- (call-with-values
- (lambda () (proc (car lst) result1 result2))
- (lambda (result1 result2)
- (loop result1 result2 (cdr lst)))))))
- ((proc seed1 seed2 lst1 lst2)
- "Like `fold', but with a two lists and two seeds."
- (let loop ((result1 seed1)
- (result2 seed2)
- (lst1 lst1)
- (lst2 lst2))
- (if (or (null? lst1) (null? lst2))
- (values result1 result2)
- (call-with-values
- (lambda () (proc (car lst1) (car lst2) result1 result2))
- (lambda (result1 result2)
- (fold2 proc result1 result2 (cdr lst1) (cdr lst2)))))))))
-
-(define (fold-tree proc init children roots)
- "Call (PROC NODE RESULT) for each node in the tree that is reachable from
-ROOTS, using INIT as the initial value of RESULT. The order in which nodes
-are traversed is not specified, however, each node is visited only once, based
-on an eq? check. Children of a node to be visited are generated by
-calling (CHILDREN NODE), the result of which should be a list of nodes that
-are connected to NODE in the tree, or '() or #f if NODE is a leaf node."
- (let loop ((result init)
- (seen vlist-null)
- (lst roots))
- (match lst
- (() result)
- ((head . tail)
- (if (not (vhash-assq head seen))
- (loop (proc head result)
- (vhash-consq head #t seen)
- (match (children head)
- ((or () #f) tail)
- (children (append tail children))))
- (loop result seen tail))))))
-
-(define (fold-tree-leaves proc init children roots)
- "Like fold-tree, but call (PROC NODE RESULT) only for leaf nodes."
- (fold-tree
- (lambda (node result)
- (match (children node)
- ((or () #f) (proc node result))
- (else result)))
- init children roots))
-
-(define (split lst e)
- "Return two values, a list containing the elements of the list LST that
-appear before the first occurence of the object E and a list containing the
-elements after E."
- (define (same? x)
- (equal? e x))
-
- (let loop ((rest lst)
- (acc '()))
- (match rest
- (()
- (values lst '()))
- (((? same?) . tail)
- (values (reverse acc) tail))
- ((head . tail)
- (loop tail (cons head acc))))))
-
(define (cache-directory)
"Return the cache directory for Guix, by default ~/.cache/guix."
(or (getenv "XDG_CONFIG_HOME")