summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/guix.texi18
-rw-r--r--guix/scripts/graph.scm21
-rw-r--r--tests/graph.scm14
3 files changed, 52 insertions, 1 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index 3a9ebe8a63..adc7fefcae 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -5445,6 +5445,10 @@ end, display the fraction of packages covered by all these updaters.
 List top-level dependent packages that would need to be rebuilt as a
 result of upgrading one or more packages.
 
+@xref{Invoking guix graph, the @code{reverse-package} type of
+@command{guix graph}}, for information on how to visualize the list of
+dependents of a package.
+
 @end table
 
 Be aware that the @code{--list-dependent} option only
@@ -5746,6 +5750,20 @@ This is the default type used in the example above.  It shows the DAG of
 package objects, excluding implicit dependencies.  It is concise, but
 filters out many details.
 
+@item reverse-package
+This shows the @emph{reverse} DAG of packages.  For example:
+
+@example
+guix graph --type=reverse-package ocaml
+@end example
+
+... yields the graph of packages that depend on OCaml.
+
+Note that for core packages this can yield huge graphs.  If all you want
+is to know the number of packages that depend on a given package, use
+@command{guix refresh --list-dependent} (@pxref{Invoking guix refresh,
+@option{--list-dependent}}).
+
 @item bag-emerged
 This is the package DAG, @emph{including} implicit inputs.
 
diff --git a/guix/scripts/graph.scm b/guix/scripts/graph.scm
index d96df5fbaf..79ce503a2e 100644
--- a/guix/scripts/graph.scm
+++ b/guix/scripts/graph.scm
@@ -37,6 +37,7 @@
   #:use-module (srfi srfi-37)
   #:use-module (ice-9 match)
   #:export (%package-node-type
+            %reverse-package-node-type
             %bag-node-type
             %bag-with-origins-node-type
             %bag-emerged-node-type
@@ -103,6 +104,25 @@ name."
 
 
 ;;;
+;;; Reverse package DAG.
+;;;
+
+(define %reverse-package-node-type
+  ;; For this node type we first need to compute the list of packages and the
+  ;; list of back-edges.  Since we want to do it only once, we use the
+  ;; promises below.
+  (let* ((packages   (delay (fold-packages cons '())))
+         (back-edges (delay (run-with-store #f    ;store not actually needed
+                              (node-back-edges %package-node-type
+                                               (force packages))))))
+    (node-type
+     (inherit %package-node-type)
+     (name "reverse-package")
+     (description "the reverse DAG of packages")
+     (edges (lift1 (force back-edges) %store-monad)))))
+
+
+;;;
 ;;; Package DAG using bags.
 ;;;
 
@@ -323,6 +343,7 @@ substitutes."
 (define %node-types
   ;; List of all the node types.
   (list %package-node-type
+        %reverse-package-node-type
         %bag-node-type
         %bag-with-origins-node-type
         %bag-emerged-node-type
diff --git a/tests/graph.scm b/tests/graph.scm
index bc4d62fe50..6431c482f7 100644
--- a/tests/graph.scm
+++ b/tests/graph.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015, 2016 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -32,6 +32,7 @@
   #:use-module (gnu packages)
   #:use-module (gnu packages base)
   #:use-module (gnu packages guile)
+  #:use-module (gnu packages libunistring)
   #:use-module (gnu packages bootstrap)
   #:use-module (ice-9 match)
   #:use-module (srfi srfi-1)
@@ -92,6 +93,17 @@ edges."
                           (list p3 p3 p2)
                           (list p2 p1 p1))))))))
 
+(test-assert "reverse package DAG"
+  (let-values (((backend nodes+edges) (make-recording-backend)))
+    (run-with-store %store
+      (export-graph (list libunistring) 'port
+                    #:node-type %reverse-package-node-type
+                    #:backend backend))
+    ;; We should see nothing more than these 3 packages.
+    (let-values (((nodes edges) (nodes+edges)))
+      (and (member (package->tuple guile-2.0) nodes)
+           (->bool (member (edge->tuple libunistring guile-2.0) edges))))))
+
 (test-assert "bag-emerged DAG"
   (let-values (((backend nodes+edges) (make-recording-backend)))
     (let* ((o        (dummy-origin (method (lambda _