1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2013 Mark H Weaver <mhw@netris.org>
4 ;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
6 ;;; This file is part of GNU Guix.
8 ;;; GNU Guix is free software; you can redistribute it and/or modify it
9 ;;; under the terms of the GNU General Public License as published by
10 ;;; the Free Software Foundation; either version 3 of the License, or (at
11 ;;; your option) any later version.
13 ;;; GNU Guix is distributed in the hope that it will be useful, but
14 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;;; GNU General Public License for more details.
18 ;;; You should have received a copy of the GNU General Public License
19 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
21 (define-module (gnu packages)
22 #:use-module (guix packages)
23 #:use-module (guix ui)
24 #:use-module (guix utils)
25 #:use-module (ice-9 ftw)
26 #:use-module (ice-9 vlist)
27 #:use-module (ice-9 match)
28 #:use-module (srfi srfi-1)
29 #:use-module (srfi srfi-26)
30 #:use-module (srfi srfi-39)
31 #:export (search-patch
32 search-bootstrap-binary
34 %bootstrap-binaries-path
39 find-best-packages-by-name
40 find-newest-available-packages
42 package-direct-dependents
43 package-transitive-dependents
44 package-covering-dependents))
48 ;;; General utilities for the software distribution---i.e., the modules under
49 ;;; (gnu packages ...).
53 (define _ (cut gettext <> "guix"))
55 ;; By default, we store patches and bootstrap binaries alongside Guile
56 ;; modules. This is so that these extra files can be found without
57 ;; requiring a special setup, such as a specific installation directory
58 ;; and an extra environment variable. One advantage of this setup is
59 ;; that everything just works in an auto-compilation setting.
63 (map (cut string-append <> "/gnu/packages/patches")
66 (define %bootstrap-binaries-path
68 (map (cut string-append <> "/gnu/packages/bootstrap")
71 (define (search-patch file-name)
72 "Search the patch FILE-NAME."
73 (search-path (%patch-path) file-name))
75 (define (search-bootstrap-binary file-name system)
76 "Search the bootstrap binary FILE-NAME for SYSTEM."
77 (search-path (%bootstrap-binaries-path)
78 (string-append system "/" file-name)))
80 (define %distro-module-directory
81 ;; Absolute path of the (gnu packages ...) module root.
82 (string-append (dirname (search-path %load-path "gnu/packages.scm"))
85 (define (package-files)
86 "Return the list of files that implement distro modules."
89 (dirname (dirname (search-path %load-path "gnu/packages.scm")))))
91 (file-system-fold (const #t) ; enter?
92 (lambda (path stat result) ; leaf
93 (if (string-suffix? ".scm" path)
94 (cons (substring path prefix-len) result)
96 (lambda (path stat result) ; down
98 (lambda (path stat result) ; up
101 (lambda (path stat errno result)
102 (warning (_ "cannot access `~a': ~a~%")
103 path (strerror errno))
106 %distro-module-directory
109 (define (package-modules)
110 "Return the list of modules that provide packages for the distribution."
112 (char-set-complement (char-set #\/)))
114 (filter-map (lambda (path)
115 (let ((name (map string->symbol
116 (string-tokenize (string-drop-right path 4)
118 (false-if-exception (resolve-interface name))))
121 (define (fold-packages proc init)
122 "Call (PROC PACKAGE RESULT) for each available package, using INIT as
123 the initial value of RESULT. It is guaranteed to never traverse the
125 (identity ; discard second return value
126 (fold2 (lambda (module result seen)
127 (fold2 (lambda (var result seen)
128 (if (and (package? var)
129 (not (vhash-assq var seen)))
130 (values (proc var result)
131 (vhash-consq var #t seen))
132 (values result seen)))
135 (module-map (lambda (sym var)
136 (false-if-exception (variable-ref var)))
142 (define* (find-packages-by-name name #:optional version)
143 "Return the list of packages with the given NAME. If VERSION is not #f,
144 then only return packages whose version is equal to VERSION."
145 (define right-package?
148 (and (string=? (package-name p) name)
149 (string=? (package-version p) version)))
151 (string=? (package-name p) name))))
153 (fold-packages (lambda (package result)
154 (if (right-package? package)
155 (cons package result)
159 (define find-newest-available-packages
162 "Return a vhash keyed by package names, and with
163 associated values of the form
165 (newest-version newest-package ...)
167 where the preferred package is listed first."
169 ;; FIXME: Currently, the preferred package is whichever one
170 ;; was found last by 'fold-packages'. Find a better solution.
171 (fold-packages (lambda (p r)
172 (let ((name (package-name p))
173 (version (package-version p)))
174 (match (vhash-assoc name r)
175 ((_ newest-so-far . pkgs)
176 (case (version-compare version newest-so-far)
177 ((>) (vhash-cons name `(,version ,p) r))
178 ((=) (vhash-cons name `(,version ,p ,@pkgs) r))
180 (#f (vhash-cons name `(,version ,p) r)))))
183 (define (find-best-packages-by-name name version)
184 "If version is #f, return the list of packages named NAME with the highest
185 version numbers; otherwise, return the list of packages named NAME and at
188 (find-packages-by-name name version)
189 (match (vhash-assoc name (find-newest-available-packages))
190 ((_ version pkgs ...) pkgs)
194 (define* (vhash-refq vhash key #:optional (dflt #f))
195 "Look up KEY in the vhash VHASH, and return the value (if any) associated
196 with it. If KEY is not found, return DFLT (or `#f' if no DFLT argument is
197 supplied). Uses `eq?' for equality testing."
198 (or (and=> (vhash-assq key vhash) cdr)
201 (define package-dependencies
204 "Return a vhash keyed by package, and with associated values that are a
205 list of packages that depend on that package."
207 (lambda (package dag)
210 ;; Insert a graph edge from each of package's inputs to package.
212 (cons package (vhash-refq d in '()))
215 (match (package-direct-inputs package)
216 (((labels packages . _) ...)
220 (define (package-direct-dependents packages)
221 "Return a list of packages from the distribution that directly depend on the
222 packages in PACKAGES."
226 (vhash-refq (package-dependencies) p '()))
229 (define (package-transitive-dependents packages)
230 "Return the transitive dependent packages of the distribution packages in
231 PACKAGES---i.e. the dependents of those packages, plus their dependents,
233 (let ((dependency-dag (package-dependencies)))
236 (lambda (node) (vhash-refq dependency-dag node))
237 ;; Start with the dependents to avoid including PACKAGES in the result.
238 (package-direct-dependents packages))))
240 (define (package-covering-dependents packages)
241 "Return a minimal list of packages from the distribution whose dependencies
242 include all of PACKAGES and all packages that depend on PACKAGES."
243 (let ((dependency-dag (package-dependencies)))
246 (lambda (node) (vhash-refq dependency-dag node))
247 ;; Start with the dependents to avoid including PACKAGES in the result.
248 (package-direct-dependents packages))))