guix-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Add guix search command


From: Andy Wingo
Subject: Add guix search command
Date: Wed, 05 Aug 2015 13:36:06 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux)

Here's an implementation of a guix search command.  By default it gives
similar output as compared to "apt-cache search", just printing the
package name and synopsis; you can make it print recutils-style info
instead.  You can also limit search to installed packages, though that
predicate is really "available packages for which there is also a
manifest entry in a profile that has the same name".

WDYT?

Andy

>From 9c99457bbcdf209a80bd280563e660010be160ed Mon Sep 17 00:00:00 2001
From: Andy Wingo <address@hidden>
Date: Wed, 5 Aug 2015 13:03:43 +0200
Subject: [PATCH] Add guix search command

* Makefile.am: Add search.scm.
* doc.am: Add search command.
* doc/guix.texi (Invoking guix search): New section.
* NEWS: Update.
* guix/scripts/search.scm: New file.
---
 Makefile.am             |   1 +
 NEWS                    |   2 +-
 doc.am                  |   1 +
 doc/guix.texi           |  48 ++++++++++
 guix/scripts/search.scm | 239 ++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 290 insertions(+), 1 deletion(-)
 create mode 100644 guix/scripts/search.scm

diff --git a/Makefile.am b/Makefile.am
index 47fa243..5a2a82e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -109,6 +109,7 @@ MODULES =                                   \
   guix/scripts/gc.scm                          \
   guix/scripts/hash.scm                                \
   guix/scripts/pull.scm                                \
+  guix/scripts/search.scm                      \
   guix/scripts/substitute.scm                  \
   guix/scripts/authenticate.scm                        \
   guix/scripts/refresh.scm                     \
diff --git a/NEWS b/NEWS
index c72c86a..7421738 100644
--- a/NEWS
+++ b/NEWS
@@ -14,7 +14,7 @@ Please send Guix bug reports to address@hidden
 
 ** Package management
 
-*** New ‘guix edit’, ‘guix size’, and ‘guix install’ commands
+*** New ‘guix edit’, ‘guix size’, ‘guix install’, and ‘guix search’ commands
 *** New ‘--manifest’ option for ‘guix package’, for declarative profiles
 *** Similarly, new ‘M-x guix-apply-manifest’ for the Emacs UI
 *** Emacs support now includes completion for ‘guix’ commands in shell-mode
diff --git a/doc.am b/doc.am
index 7f21ec3..7db1117 100644
--- a/doc.am
+++ b/doc.am
@@ -113,6 +113,7 @@ SUBCOMMANDS :=                                      \
   publish                                      \
   pull                                         \
   refresh                                      \
+  search                                       \
   size                                         \
   system
 
diff --git a/doc/guix.texi b/doc/guix.texi
index 2b09a30..425975e 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -132,6 +132,7 @@ Utilities
 * Invoking guix import::        Importing package definitions.
 * Invoking guix refresh::       Updating package definitions.
 * Invoking guix lint::          Finding errors in package definitions.
+* Invoking guix search::        Searching for packages.
 * Invoking guix size::          Profiling disk usage.
 * Invoking guix environment::   Setting up development environments.
 * Invoking guix publish::       Sharing substitutes.
@@ -1388,6 +1389,9 @@ List the available packages whose name, synopsis, or 
description matches
 @code{recutils} format (@pxref{Top, GNU recutils databases,, recutils,
 GNU recutils manual}).
 
+There is also a @command{guix search} command implementing similar
+functionality.  @xref{Invoking guix search}, for more.
+
 This allows specific fields to be extracted using the @command{recsel}
 command, for instance:
 
@@ -3472,6 +3476,7 @@ programming interface of Guix in a convenient way.
 * Invoking guix import::        Importing package definitions.
 * Invoking guix refresh::       Updating package definitions.
 * Invoking guix lint::          Finding errors in package definitions.
+* Invoking guix search::        Searching for packages.
 * Invoking guix size::          Profiling disk usage.
 * Invoking guix environment::   Setting up development environments.
 * Invoking guix publish::       Sharing substitutes.
@@ -4214,6 +4219,49 @@ and exit.
 
 @end table
 
address@hidden Invoking guix search
address@hidden Invoking @command{guix search}
+
+The @command{guix search} command is a simple interface to query what
+packages are installed and available, optionally filtering by name, with
+some control over how the results are printed.  The general syntax is:
+
address@hidden
+guix search @var{options} @address@hidden
address@hidden example
+
+Invoking @command{guix search} will find all packages matching the
+specified @var{pattern} regular expressions, or all packages if no
address@hidden argument is given.  By default, the results will be
+printed on one line apiece, with each line indicating the package name
+and its synopsis.
+
+The available options are:
+
address@hidden @code
+
address@hidden --installed
address@hidden -I
+Only search for available packages that are also installed.
+
address@hidden --available
address@hidden -A
+Search all available packages.
+
address@hidden address@hidden
address@hidden -p @var{profile}
+Use @var{profile} instead of the user's default profile when searching
+for installed packages.
+
address@hidden --short
+Show output in @address@hidden: @var{synopsis}} format.  This is the
+default.
+
address@hidden --recutils
+Show output in @code{recutils} format (@pxref{Top, GNU recutils
+databases,, recutils, GNU recutils manual}).
address@hidden table
+
 @node Invoking guix size
 @section Invoking @command{guix size}
 
diff --git a/guix/scripts/search.scm b/guix/scripts/search.scm
new file mode 100644
index 0000000..3fe2576
--- /dev/null
+++ b/guix/scripts/search.scm
@@ -0,0 +1,239 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <address@hidden>
+;;; Copyright © 2013 Nikita Karetnikov <address@hidden>
+;;; Copyright © 2013, 2015 Mark H Weaver <address@hidden>
+;;; Copyright © 2014 Alex Kost <address@hidden>
+;;; Copyright © 2015 Andy Wingo <address@hidden>
+;;;
+;;; 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 scripts search)
+  #:use-module (guix ui)
+  #:use-module (guix store)
+  #:use-module (guix derivations)
+  #:use-module (guix packages)
+  #:use-module (guix profiles)
+  #:use-module (guix search-paths)
+  #:use-module (guix monads)
+  #:use-module (guix utils)
+  #:use-module (guix config)
+  #:use-module ((guix build utils)
+                #:select (directory-exists? mkdir-p search-path-as-list))
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 regex)
+  #:use-module (ice-9 vlist)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-19)
+  #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-34)
+  #:use-module (srfi srfi-35)
+  #:use-module (srfi srfi-37)
+  #:use-module (gnu packages)
+  #:use-module (gnu packages base)
+  #:use-module (gnu packages guile)
+  #:use-module ((gnu packages bootstrap) #:select (%bootstrap-guile))
+  #:export (guix-search))
+
+(define %store
+  (make-parameter #f))
+
+
+;;;
+;;; Profiles.
+;;;
+
+(define %user-profile-directory
+  (and=> (getenv "HOME")
+         (cut string-append <> "/.guix-profile")))
+
+(define %profile-directory
+  (string-append %state-directory "/profiles/"
+                 (or (and=> (or (getenv "USER")
+                                (getenv "LOGNAME"))
+                            (cut string-append "per-user/" <>))
+                     "default")))
+
+(define %current-profile
+  ;; Call it `guix-profile', not `profile', to allow Guix profiles to
+  ;; coexist with Nix profiles.
+  (string-append %profile-directory "/guix-profile"))
+
+
+;;;
+;;; Package specifications.
+;;;
+
+(define (package<? p1 p2)
+  (define version<? (negate version>=?))
+
+  (lambda (p1 p2)
+    (case (string-compare (package-name p1) (package-name p2)
+                          (const '<) (const '=) (const '>))
+      ((=)  (version<? (package-version p1) (package-version p2)))
+      ((<)  #t)
+      (else #f))))
+
+(define* (filter-packages matches? #:key profile)
+  (define manifest
+    (if profile (profile-manifest profile) #f))
+
+  (define (visit package tail)
+    (if (and (matches? package)
+             (or (not manifest)
+                 (let ((pattern (manifest-pattern
+                                  (name (package-name package)))))
+                   (manifest-installed? manifest pattern))))
+        (cons package tail)
+        tail))
+   
+  (sort (fold-packages visit '()) package<?))
+
+(define* (find-packages patterns #:key profile
+                        (search-in-synopsis? #t)
+                        (search-in-description? #t))
+  (define filter-installed?)
+
+  (define matches?
+    (match patterns
+      (() (lambda (_) #t))
+      (_
+       (let ((regexps (map (cut make-regexp <> regexp/icase)
+                           patterns)))
+         (lambda (str)
+           (or-map (cut regexp-exec <> str) regexps))))))
+
+  (define (package-matches? package)
+    (or (matches? (package-name package))
+        (and search-in-description?
+             (and=> (package-synopsis package)
+                    (compose matches? P_)))
+        (and search-in-synopsis?
+             (and=> (package-description package)
+                    (compose matches? P_)))))
+
+  (filter-packages package-matches? #:profile profile))
+
+
+;;;
+;;; Pretty-printing.
+;;;
+
+(define (show-packages packages pretty)
+  (leave-on-EPIPE
+   (match pretty
+     ('short
+      (for-each (lambda (package)
+                  (format #t "~a ~24t~a"
+                          (package-name package)
+                          (P_ (package-synopsis package)))
+                  (newline))
+                packages))
+     ('recutils
+      (for-each (cute package->recutils <> (current-output-port))
+                packages)))))
+
+
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  ;; Alist of default option values.
+  `((profile . ,%current-profile)
+    (max-silent-time . 3600)
+    (verbosity . 0)
+    (pretty . short)
+    (substitutes? . #t)))
+
+(define (show-help)
+  (display (_ "Usage: guix search [OPTION]... [REGEXP]
+Search for packages matching REGEXP.\n"))
+  (display (_ "
+  -p, --profile=PROFILE  use PROFILE instead of the user's default profile"))
+  (newline)
+  (display (_ "
+  -I, --installed
+                         only search installed packages"))
+  (display (_ "
+  -A, --available
+                         search all available packages"))
+  (newline)
+  (display (_ "
+  --short
+                         show output in NAME: SYNOPSIS format (default)"))
+  (display (_ "
+  --recutils
+                         show output in recutils format"))
+  (newline)
+  (display (_ "
+  -h, --help             display this help and exit"))
+  (display (_ "
+  -V, --version          display version information and exit"))
+  (newline)
+  (show-bug-report-information))
+
+(define %options
+  ;; Specification of the command-line options.
+  (list (option '(#\h "help") #f #f
+                (lambda args
+                  (show-help)
+                  (exit 0)))
+        (option '(#\V "version") #f #f
+                (lambda args
+                  (show-version-and-exit "guix package")))
+        (option '(#\p "profile") #t #f
+                (lambda (opt name arg result)
+                  (alist-cons 'profile arg
+                              (alist-delete 'profile result))))
+        (option '(#\I "installed") #f #f
+                (lambda (opt name arg result)
+                  (alist-cons 'only-installed? #t result)))
+        (option '(#\A "available") #f #f
+                (lambda (opt name arg result)
+                  (alist-cons 'only-installed? #f result)))
+        (option '("short") #f #f
+                (lambda (opt name arg result)
+                  (alist-cons 'pretty 'short result)))
+        (option '("recutils") #f #f
+                (lambda (opt name arg result)
+                  (alist-cons 'pretty 'recutils result)))))
+
+
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-search . args)
+  (define (handle-argument arg result)
+    ;; Process non-option argument ARG by calling back ARG-HANDLER.
+    (alist-cons 'search arg result))
+
+  (let ((opts (parse-command-line args %options (list %default-options)
+                                  #:argument-handler handle-argument)))
+    (with-error-handling
+      (let* ((patterns (fold (lambda (opt patterns)
+                               (match opt
+                                 (('search . pattern) (cons pattern patterns))
+                                 (_ patterns)))
+                             '() opts))
+             (only-installed? (assoc-ref opts 'only-installed?))
+             (profile (and only-installed? (assoc-ref opts 'profile)))
+             (pretty (assoc-ref opts 'pretty))
+             (packages (find-packages patterns #:profile profile)))
+        (leave-on-EPIPE
+         (show-packages packages pretty))))))
-- 
2.4.3


reply via email to

[Prev in Thread] Current Thread [Next in Thread]