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 ;; By default, we store patches and bootstrap binaries alongside Guile
54 ;; modules. This is so that these extra files can be found without
55 ;; requiring a special setup, such as a specific installation directory
56 ;; and an extra environment variable. One advantage of this setup is
57 ;; that everything just works in an auto-compilation setting.
61 (map (cut string-append <> "/gnu/packages/patches")
64 (define %bootstrap-binaries-path
66 (map (cut string-append <> "/gnu/packages/bootstrap")
69 (define (search-patch file-name)
70 "Search the patch FILE-NAME."
71 (search-path (%patch-path) file-name))
73 (define (search-bootstrap-binary file-name system)
74 "Search the bootstrap binary FILE-NAME for SYSTEM."
75 (search-path (%bootstrap-binaries-path)
76 (string-append system "/" file-name)))
78 (define %distro-module-directory
79 ;; Absolute path of the (gnu packages ...) module root.
80 (string-append (dirname (search-path %load-path "gnu/packages.scm"))
83 (define (package-files)
84 "Return the list of files that implement distro modules."
87 (dirname (dirname (search-path %load-path "gnu/packages.scm")))))
89 (file-system-fold (const #t) ; enter?
90 (lambda (path stat result) ; leaf
91 (if (string-suffix? ".scm" path)
92 (cons (substring path prefix-len) result)
94 (lambda (path stat result) ; down
96 (lambda (path stat result) ; up
99 (lambda (path stat errno result)
100 (warning (_ "cannot access `~a': ~a~%")
101 path (strerror errno))
104 %distro-module-directory
107 (define (package-modules)
108 "Return the list of modules that provide packages for the distribution."
110 (char-set-complement (char-set #\/)))
112 (filter-map (lambda (path)
113 (let ((name (map string->symbol
114 (string-tokenize (string-drop-right path 4)
116 (false-if-exception (resolve-interface name))))
119 (define (fold-packages proc init)
120 "Call (PROC PACKAGE RESULT) for each available package, using INIT as
121 the initial value of RESULT. It is guaranteed to never traverse the
123 (identity ; discard second return value
124 (fold2 (lambda (module result seen)
125 (fold2 (lambda (var result seen)
126 (if (and (package? var)
127 (not (vhash-assq var seen)))
128 (values (proc var result)
129 (vhash-consq var #t seen))
130 (values result seen)))
133 (module-map (lambda (sym var)
134 (false-if-exception (variable-ref var)))
140 (define* (find-packages-by-name name #:optional version)
141 "Return the list of packages with the given NAME. If VERSION is not #f,
142 then only return packages whose version is equal to VERSION."
143 (define right-package?
146 (and (string=? (package-name p) name)
147 (string=? (package-version p) version)))
149 (string=? (package-name p) name))))
151 (fold-packages (lambda (package result)
152 (if (right-package? package)
153 (cons package result)
157 (define find-newest-available-packages
160 "Return a vhash keyed by package names, and with
161 associated values of the form
163 (newest-version newest-package ...)
165 where the preferred package is listed first."
167 ;; FIXME: Currently, the preferred package is whichever one
168 ;; was found last by 'fold-packages'. Find a better solution.
169 (fold-packages (lambda (p r)
170 (let ((name (package-name p))
171 (version (package-version p)))
172 (match (vhash-assoc name r)
173 ((_ newest-so-far . pkgs)
174 (case (version-compare version newest-so-far)
175 ((>) (vhash-cons name `(,version ,p) r))
176 ((=) (vhash-cons name `(,version ,p ,@pkgs) r))
178 (#f (vhash-cons name `(,version ,p) r)))))
181 (define (find-best-packages-by-name name version)
182 "If version is #f, return the list of packages named NAME with the highest
183 version numbers; otherwise, return the list of packages named NAME and at
186 (find-packages-by-name name version)
187 (match (vhash-assoc name (find-newest-available-packages))
188 ((_ version pkgs ...) pkgs)
192 (define* (vhash-refq vhash key #:optional (dflt #f))
193 "Look up KEY in the vhash VHASH, and return the value (if any) associated
194 with it. If KEY is not found, return DFLT (or `#f' if no DFLT argument is
195 supplied). Uses `eq?' for equality testing."
196 (or (and=> (vhash-assq key vhash) cdr)
199 (define package-dependencies
202 "Return a vhash keyed by package, and with associated values that are a
203 list of packages that depend on that package."
205 (lambda (package dag)
208 ;; Insert a graph edge from each of package's inputs to package.
210 (cons package (vhash-refq d in '()))
213 (match (package-direct-inputs package)
214 (((labels packages . _) ...)
218 (define (package-direct-dependents packages)
219 "Return a list of packages from the distribution that directly depend on the
220 packages in PACKAGES."
224 (vhash-refq (package-dependencies) p '()))
227 (define (package-transitive-dependents packages)
228 "Return the transitive dependent packages of the distribution packages in
229 PACKAGES---i.e. the dependents of those packages, plus their dependents,
231 (let ((dependency-dag (package-dependencies)))
234 (lambda (node) (vhash-refq dependency-dag node))
235 ;; Start with the dependents to avoid including PACKAGES in the result.
236 (package-direct-dependents packages))))
238 (define (package-covering-dependents packages)
239 "Return a minimal list of packages from the distribution whose dependencies
240 include all of PACKAGES and all packages that depend on PACKAGES."
241 (let ((dependency-dag (package-dependencies)))
244 (lambda (node) (vhash-refq dependency-dag node))
245 ;; Start with the dependents to avoid including PACKAGES in the result.
246 (package-direct-dependents packages))))