summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/guix.texi17
-rw-r--r--guix/scripts/package.scm33
-rw-r--r--tests/guix-package.sh20
3 files changed, 53 insertions, 17 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index f155fbe818..a07bf824d6 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -10,7 +10,7 @@
 @include version.texi
 
 @copying
-Copyright @copyright{} 2012, 2013, 2014, 2015 Ludovic Courtès@*
+Copyright @copyright{} 2012, 2013, 2014, 2015, 2016 Ludovic Courtès@*
 Copyright @copyright{} 2013, 2014 Andreas Enge@*
 Copyright @copyright{} 2013 Nikita Karetnikov@*
 Copyright @copyright{} 2015 Mathieu Lirzin@*
@@ -1462,6 +1462,21 @@ name: gmp
 @dots{}
 @end example
 
+It is also possible to refine search results using several @code{-s}
+flags.  For example, the following command returns a list of board
+games:
+
+@example
+$ guix package -s '\<board\>' -s game | recsel -p name
+name: gnubg
+@dots{}
+@end example
+
+If we were to omit @code{-s game}, we would also get software packages
+that deal with printed circuit boards; removing the angle brackets
+around @code{board} would further add packages that have to do with
+keyboards.
+
 @item --show=@var{package}
 Show details about @var{package}, taken from the list of available packages, in
 @code{recutils} format (@pxref{Top, GNU recutils databases,, recutils, GNU
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index d0b5abd0e2..02eb600c43 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.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 © 2013 Nikita Karetnikov <nikita@karetnikov.org>
 ;;; Copyright © 2013, 2015 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2014 Alex Kost <alezost@gmail.com>
@@ -230,21 +230,24 @@ specified in MANIFEST, a manifest object."
 ;;; Package specifications.
 ;;;
 
-(define (find-packages-by-description rx)
-  "Return the list of packages whose name, synopsis, or description matches
-RX."
+(define (find-packages-by-description regexps)
+  "Return the list of packages whose name matches one of REGEXPS, or whose
+synopsis or description matches all of REGEXPS."
   (define version<? (negate version>=?))
 
+  (define (matches-all? str)
+    (every (cut regexp-exec <> str) regexps))
+
+  (define (matches-one? str)
+    (find (cut regexp-exec <> str) regexps))
+
   (sort
    (fold-packages (lambda (package result)
-                    (define matches?
-                      (cut regexp-exec rx <>))
-
-                    (if (or (matches? (package-name package))
+                    (if (or (matches-one? (package-name package))
                             (and=> (package-synopsis package)
-                                   (compose matches? P_))
+                                   (compose matches-all? P_))
                             (and=> (package-description package)
-                                   (compose matches? P_)))
+                                   (compose matches-all? P_)))
                         (cons package result)
                         result))
                   '())
@@ -696,11 +699,15 @@ processed, #f otherwise."
                                       (package-name p2))))))
          #t))
 
-      (('search regexp)
-       (let ((regexp (make-regexp* regexp regexp/icase)))
+      (('search _)
+       (let* ((patterns (filter-map (match-lambda
+                                      (('query 'search rx) rx)
+                                      (_                   #f))
+                                    opts))
+              (regexps  (map (cut make-regexp* <> regexp/icase) patterns)))
          (leave-on-EPIPE
           (for-each (cute package->recutils <> (current-output-port))
-                    (find-packages-by-description regexp)))
+                    (find-packages-by-description regexps)))
          #t))
 
       (('show requested-name)
diff --git a/tests/guix-package.sh b/tests/guix-package.sh
index 5e6ff8b012..cf1a185590 100644
--- a/tests/guix-package.sh
+++ b/tests/guix-package.sh
@@ -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 © 2013 Nikita Karetnikov <nikita@karetnikov.org>
 #
 # This file is part of GNU Guix.
@@ -30,9 +30,10 @@ readlink_base ()
 
 module_dir="t-guix-package-$$"
 profile="t-profile-$$"
-rm -f "$profile"
+tmpfile="t-guix-package-file-$$"
+rm -f "$profile" "$tmpfile"
 
-trap 'rm -f "$profile" "$profile-"[0-9]* ; rm -rf "$module_dir" t-home-'"$$" EXIT
+trap 'rm -f "$profile" "$profile-"[0-9]* "$tmpfile"; rm -rf "$module_dir" t-home-'"$$" EXIT
 
 # Use `-e' with a non-package expression.
 if guix package --bootstrap -e +;
@@ -96,6 +97,19 @@ test "`guix package -s "An example GNU package" | grep ^name:`" = \
     "name: hello"
 test -z "`guix package -s "n0t4r341p4ck4g3"`"
 
+# Search with one and then two regexps.
+# First we get printed circuit boards *and* board games.
+guix package -s '\<board\>' > "$tmpfile"
+grep '^name: pcb' "$tmpfile"
+grep '^name: gnubg' "$tmpfile"
+
+# Second we get only board games.
+guix package -s '\<board\>' -s game > "$tmpfile"
+grep -v '^name: pcb' "$tmpfile" > /dev/null
+grep '^name: gnubg' "$tmpfile"
+
+rm -f "$tmpfile"
+
 # Make sure `--search' can display all the packages.
 guix package --search="" > /dev/null