summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/guix.texi6
-rw-r--r--guix/scripts/build.scm33
-rw-r--r--guix/ui.scm31
-rw-r--r--tests/guix-build.sh8
4 files changed, 50 insertions, 28 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index cfa5aac326..847c73ab8c 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -1483,12 +1483,16 @@ The @var{options} may be zero or more of the following:
 
 @item --expression=@var{expr}
 @itemx -e @var{expr}
-Build the package @var{expr} evaluates to.
+Build the package or derivation @var{expr} evaluates to.
 
 For example, @var{expr} may be @code{(@@ (gnu packages guile)
 guile-1.8)}, which unambiguously designates this specific variant of
 version 1.8 of Guile.
 
+Alternately, @var{expr} may refer to a zero-argument monadic procedure
+(@pxref{The Store Monad}).  The procedure must return a derivation as a
+monadic value, which is then passed through @code{run-with-store}.
+
 @item --source
 @itemx -S
 Build the packages' source derivations, rather than the packages
diff --git a/guix/scripts/build.scm b/guix/scripts/build.scm
index f63736c09c..dd9a9b8127 100644
--- a/guix/scripts/build.scm
+++ b/guix/scripts/build.scm
@@ -23,6 +23,7 @@
   #:use-module (guix derivations)
   #:use-module (guix packages)
   #:use-module (guix utils)
+  #:use-module (guix monads)
   #:use-module (ice-9 format)
   #:use-module (ice-9 match)
   #:use-module (ice-9 vlist)
@@ -38,19 +39,23 @@
 (define %store
   (make-parameter #f))
 
-(define (derivations-from-package-expressions str package-derivation
-                                              system source?)
+(define (derivation-from-expression str package-derivation
+                                    system source?)
   "Read/eval STR and return the corresponding derivation path for SYSTEM.
-When SOURCE? is true, return the derivations of the package sources;
-otherwise, use PACKAGE-DERIVATION to compute the derivation of a package."
-  (let ((p (read/eval-package-expression str)))
-    (if source?
-        (let ((source (package-source p)))
-          (if source
-              (package-source-derivation (%store) source)
-              (leave (_ "package `~a' has no source~%")
-                     (package-name p))))
-        (package-derivation (%store) p system))))
+When SOURCE? is true and STR evaluates to a package, return the derivation of
+the package source; otherwise, use PACKAGE-DERIVATION to compute the
+derivation of a package."
+  (match (read/eval str)
+    ((? package? p)
+     (if source?
+         (let ((source (package-source p)))
+           (if source
+               (package-source-derivation (%store) source)
+               (leave (_ "package `~a' has no source~%")
+                      (package-name p))))
+         (package-derivation (%store) p system)))
+    ((? procedure? proc)
+     (run-with-store (%store) (proc) #:system system))))
 
 
 ;;;
@@ -68,7 +73,7 @@ otherwise, use PACKAGE-DERIVATION to compute the derivation of a package."
   (display (_ "Usage: guix build [OPTION]... PACKAGE-OR-DERIVATION...
 Build the given PACKAGE-OR-DERIVATION and return their output paths.\n"))
   (display (_ "
-  -e, --expression=EXPR  build the package EXPR evaluates to"))
+  -e, --expression=EXPR  build the package or derivation EXPR evaluates to"))
   (display (_ "
   -S, --source           build the packages' source derivations"))
   (display (_ "
@@ -255,7 +260,7 @@ Build the given PACKAGE-OR-DERIVATION and return their output paths.\n"))
                  (sys  (assoc-ref opts 'system))
                  (drv  (filter-map (match-lambda
                                     (('expression . str)
-                                     (derivations-from-package-expressions
+                                     (derivation-from-expression
                                       str package->derivation sys src?))
                                     (('argument . (? derivation-path? drv))
                                      (call-with-input-file drv read-derivation))
diff --git a/guix/ui.scm b/guix/ui.scm
index 8a28574c3c..f15419f7a8 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -45,6 +45,7 @@
             show-what-to-build
             call-with-error-handling
             with-error-handling
+            read/eval
             read/eval-package-expression
             location->string
             switch-symlinks
@@ -193,25 +194,29 @@ General help using GNU software: <http://www.gnu.org/gethelp/>"))
         (leave (_ "~a~%")
                (strerror (system-error-errno args)))))))
 
-(define (read/eval-package-expression str)
-  "Read and evaluate STR and return the package it refers to, or exit an
-error."
+(define (read/eval str)
+  "Read and evaluate STR, raising an error if something goes wrong."
   (let ((exp (catch #t
                (lambda ()
                  (call-with-input-string str read))
                (lambda args
                  (leave (_ "failed to read expression ~s: ~s~%")
                         str args)))))
-    (let ((p (catch #t
-               (lambda ()
-                 (eval exp the-scm-module))
-               (lambda args
-                 (leave (_ "failed to evaluate expression `~a': ~s~%")
-                        exp args)))))
-      (if (package? p)
-          p
-          (leave (_ "expression `~s' does not evaluate to a package~%")
-                 exp)))))
+    (catch #t
+      (lambda ()
+        (eval exp the-scm-module))
+      (lambda args
+        (leave (_ "failed to evaluate expression `~a': ~s~%")
+               exp args)))))
+
+(define (read/eval-package-expression str)
+  "Read and evaluate STR and return the package it refers to, or exit an
+error."
+  (match (read/eval str)
+    ((? package? p) p)
+    (_
+     (leave (_ "expression ~s does not evaluate to a package~%")
+            str))))
 
 (define* (show-what-to-build store drv
                              #:key dry-run? (use-substitutes? #t))
diff --git a/tests/guix-build.sh b/tests/guix-build.sh
index e228b38616..391e7b9da3 100644
--- a/tests/guix-build.sh
+++ b/tests/guix-build.sh
@@ -72,3 +72,11 @@ if guix build -n time-3.2;	# FAIL, version not found
 then false; else true; fi
 if guix build -n something-that-will-never-exist; # FAIL
 then false; else true; fi
+
+# Invoking a monadic procedure.
+guix build -e "(begin
+                 (use-modules (guix monads) (guix utils))
+                 (lambda ()
+                   (derivation-expression \"test\" (%current-system)
+                                          '(mkdir %output) '())))" \
+   --dry-run