packages: Add 'search-auxiliary-file'.
[jackhill/guix/guix.git] / gnu / packages.scm
CommitLineData
233e7676 1;;; GNU Guix --- Functional package management for GNU
f9704f17 2;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
c2868b1e 3;;; Copyright © 2013 Mark H Weaver <mhw@netris.org>
7d193ec3 4;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
96eaa55f 5;;; Copyright © 2016, 2017 Alex Kost <alezost@gmail.com>
fad155d4 6;;; Copyright © 2016 Mathieu Lirzin <mthl@gnu.org>
6b1891b0 7;;;
233e7676 8;;; This file is part of GNU Guix.
6b1891b0 9;;;
233e7676 10;;; GNU Guix is free software; you can redistribute it and/or modify it
6b1891b0
LC
11;;; under the terms of the GNU General Public License as published by
12;;; the Free Software Foundation; either version 3 of the License, or (at
13;;; your option) any later version.
14;;;
233e7676 15;;; GNU Guix is distributed in the hope that it will be useful, but
6b1891b0
LC
16;;; WITHOUT ANY WARRANTY; without even the implied warranty of
17;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;;; GNU General Public License for more details.
19;;;
20;;; You should have received a copy of the GNU General Public License
233e7676 21;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
6b1891b0 22
59a43334 23(define-module (gnu packages)
6b1891b0 24 #:use-module (guix packages)
98eb8cbe 25 #:use-module (guix ui)
800cdeef 26 #:use-module (guix utils)
f9704f17 27 #:use-module (guix memoization)
958dd3ce 28 #:use-module (guix combinators)
95cd4971
LC
29 #:use-module ((guix build utils)
30 #:select ((package-name->name+version
31 . hyphen-separated-name->name+version)))
6b1891b0 32 #:use-module (ice-9 ftw)
c2868b1e 33 #:use-module (ice-9 vlist)
dc5669cd 34 #:use-module (ice-9 match)
6b1891b0 35 #:use-module (srfi srfi-1)
5e3b388b 36 #:use-module (srfi srfi-11)
6b1891b0 37 #:use-module (srfi srfi-26)
dbab5150
LC
38 #:use-module (srfi srfi-34)
39 #:use-module (srfi srfi-35)
800cdeef
LC
40 #:use-module (srfi srfi-39)
41 #:export (search-patch
25897079 42 search-patches
96eaa55f 43 search-auxiliary-file
ac5aa288 44 search-bootstrap-binary
0492f4a2 45 %patch-path
96eaa55f 46 %auxiliary-files-path
0b3651bc 47 %bootstrap-binaries-path
c107b541 48 %package-module-path
7d193ec3 49
ba326ce4 50 fold-packages
2a6ba870 51 scheme-modules ;XXX: for lack of a better place
7d193ec3 52
dc5669cd 53 find-packages-by-name
3f26bfc1 54 find-best-packages-by-name
7d193ec3
EB
55 find-newest-available-packages
56
84189ebc
LC
57 specification->package
58 specification->package+output))
6b1891b0
LC
59
60;;; Commentary:
61;;;
62;;; General utilities for the software distribution---i.e., the modules under
59a43334 63;;; (gnu packages ...).
6b1891b0
LC
64;;;
65;;; Code:
66
96eaa55f
AK
67;; By default, we store patches, auxiliary files and bootstrap binaries
68;; alongside Guile modules. This is so that these extra files can be
69;; found without requiring a special setup, such as a specific
70;; installation directory and an extra environment variable. One
71;; advantage of this setup is that everything just works in an
72;; auto-compilation setting.
a9f60c42 73
a9f60c42 74(define %bootstrap-binaries-path
ac5aa288 75 (make-parameter
1ffa7090 76 (map (cut string-append <> "/gnu/packages/bootstrap")
0b3651bc 77 %load-path)))
ac5aa288 78
96eaa55f
AK
79(define %auxiliary-files-path
80 (make-parameter
81 (map (cut string-append <> "/gnu/packages/aux-files")
82 %load-path)))
83
84(define (search-auxiliary-file file-name)
85 "Search the auxiliary FILE-NAME. Return #f if not found."
86 (search-path (%auxiliary-files-path) file-name))
87
800cdeef 88(define (search-patch file-name)
dbab5150
LC
89 "Search the patch FILE-NAME. Raise an error if not found."
90 (or (search-path (%patch-path) file-name)
91 (raise (condition
92 (&message (message (format #f (_ "~a: patch not found")
93 file-name)))))))
800cdeef 94
25897079
AK
95(define-syntax-rule (search-patches file-name ...)
96 "Return the list of absolute file names corresponding to each
97FILE-NAME found in %PATCH-PATH."
98 (list (search-patch file-name) ...))
99
ac5aa288 100(define (search-bootstrap-binary file-name system)
dfba5489
LC
101 "Search the bootstrap binary FILE-NAME for SYSTEM. Raise an error if not
102found."
103 (or (search-path (%bootstrap-binaries-path)
104 (string-append system "/" file-name))
105 (raise (condition
106 (&message
107 (message
108 (format #f (_ "could not find bootstrap binary '~a' \
109for system '~a'")
110 file-name system)))))))
ac5aa288 111
84836a57
LC
112(define %distro-root-directory
113 ;; Absolute file name of the module hierarchy.
114 (dirname (search-path %load-path "guix.scm")))
6b1891b0 115
c107b541
LC
116(define %package-module-path
117 ;; Search path for package modules. Each item must be either a directory
118 ;; name or a pair whose car is a directory and whose cdr is a sub-directory
119 ;; to narrow the search.
8689901f
LC
120 (let* ((not-colon (char-set-complement (char-set #\:)))
121 (environment (string-tokenize (or (getenv "GUIX_PACKAGE_PATH") "")
122 not-colon)))
123 ;; Automatically add items from $GUIX_PACKAGE_PATH to Guile's search path.
124 (for-each (lambda (directory)
125 (set! %load-path (cons directory %load-path))
126 (set! %load-compiled-path
127 (cons directory %load-compiled-path)))
128 environment)
129
130 (make-parameter
131 (append environment `((,%distro-root-directory . "gnu/packages"))))))
c107b541 132
ee06af5b
LC
133(define %patch-path
134 ;; Define it after '%package-module-path' so that '%load-path' contains user
135 ;; directories, allowing patches in $GUIX_PACKAGE_PATH to be found.
136 (make-parameter
137 (map (lambda (directory)
138 (if (string=? directory %distro-root-directory)
139 (string-append directory "/gnu/packages/patches")
140 directory))
141 %load-path)))
142
84836a57 143(define* (scheme-files directory)
d95523fb
LC
144 "Return the list of Scheme files found under DIRECTORY, recursively. The
145returned list is sorted in alphabetical order."
146
147 ;; Sort entries so that 'fold-packages' works in a deterministic fashion
148 ;; regardless of details of the underlying file system.
149 (sort (file-system-fold (const #t) ; enter?
150 (lambda (path stat result) ; leaf
151 (if (string-suffix? ".scm" path)
152 (cons path result)
153 result))
154 (lambda (path stat result) ; down
155 result)
156 (lambda (path stat result) ; up
157 result)
158 (const #f) ; skip
159 (lambda (path stat errno result)
160 (warning (_ "cannot access `~a': ~a~%")
161 path (strerror errno))
162 result)
163 '()
164 directory
165 stat)
166 string<?))
6b1891b0 167
c107b541
LC
168(define file-name->module-name
169 (let ((not-slash (char-set-complement (char-set #\/))))
170 (lambda (file)
171 "Return the module name (a list of symbols) corresponding to FILE."
172 (map string->symbol
173 (string-tokenize (string-drop-right file 4) not-slash)))))
84836a57 174
2a6ba870
LC
175(define* (scheme-modules directory #:optional sub-directory)
176 "Return the list of Scheme modules available under DIRECTORY.
84836a57
LC
177Optionally, narrow the search to SUB-DIRECTORY."
178 (define prefix-len
179 (string-length directory))
180
181 (filter-map (lambda (file)
4ae7559f
LC
182 (let* ((file (substring file prefix-len))
183 (module (file-name->module-name file)))
184 (catch #t
185 (lambda ()
186 (resolve-interface module))
187 (lambda args
188 ;; Report the error, but keep going.
189 (warn-about-load-error module args)
190 #f))))
84836a57
LC
191 (scheme-files (if sub-directory
192 (string-append directory "/" sub-directory)
193 directory))))
6b1891b0 194
c107b541
LC
195(define* (all-package-modules #:optional (path (%package-module-path)))
196 "Return the list of package modules found in PATH, a list of directories to
197search."
198 (fold-right (lambda (spec result)
199 (match spec
200 ((? string? directory)
2a6ba870 201 (append (scheme-modules directory) result))
c107b541 202 ((directory . sub-directory)
2a6ba870 203 (append (scheme-modules directory sub-directory)
c107b541
LC
204 result))))
205 '()
206 path))
207
ba326ce4
LC
208(define (fold-packages proc init)
209 "Call (PROC PACKAGE RESULT) for each available package, using INIT as
c2868b1e
MW
210the initial value of RESULT. It is guaranteed to never traverse the
211same package twice."
212 (identity ; discard second return value
213 (fold2 (lambda (module result seen)
214 (fold2 (lambda (var result seen)
215 (if (and (package? var)
6980511b
LC
216 (not (vhash-assq var seen))
217 (not (hidden-package? var)))
c2868b1e
MW
218 (values (proc var result)
219 (vhash-consq var #t seen))
220 (values result seen)))
221 result
222 seen
223 (module-map (lambda (sym var)
224 (false-if-exception (variable-ref var)))
225 module)))
226 init
227 vlist-null
c107b541 228 (all-package-modules))))
ba326ce4 229
9ffc1c00
LC
230(define find-packages-by-name
231 (let ((packages (delay
232 (fold-packages (lambda (p r)
233 (vhash-cons (package-name p) p r))
724311a2
LC
234 vlist-null)))
235 (version>? (lambda (p1 p2)
236 (version>? (package-version p1) (package-version p2)))))
9ffc1c00
LC
237 (lambda* (name #:optional version)
238 "Return the list of packages with the given NAME. If VERSION is not #f,
724311a2
LC
239then only return packages whose version is prefixed by VERSION, sorted in
240decreasing version order."
241 (let ((matching (sort (vhash-fold* cons '() name (force packages))
242 version>?)))
9ffc1c00
LC
243 (if version
244 (filter (lambda (package)
724311a2 245 (string-prefix? version (package-version package)))
9ffc1c00
LC
246 matching)
247 matching)))))
dc5669cd 248
3f26bfc1 249(define find-newest-available-packages
55b2d921
LC
250 (mlambda ()
251 "Return a vhash keyed by package names, and with
dc5669cd
MW
252associated values of the form
253
254 (newest-version newest-package ...)
255
256where the preferred package is listed first."
257
55b2d921
LC
258 ;; FIXME: Currently, the preferred package is whichever one
259 ;; was found last by 'fold-packages'. Find a better solution.
260 (fold-packages (lambda (p r)
261 (let ((name (package-name p))
262 (version (package-version p)))
263 (match (vhash-assoc name r)
264 ((_ newest-so-far . pkgs)
265 (case (version-compare version newest-so-far)
266 ((>) (vhash-cons name `(,version ,p) r))
267 ((=) (vhash-cons name `(,version ,p ,@pkgs) r))
268 ((<) r)))
269 (#f (vhash-cons name `(,version ,p) r)))))
270 vlist-null)))
3f26bfc1
LC
271
272(define (find-best-packages-by-name name version)
273 "If version is #f, return the list of packages named NAME with the highest
274version numbers; otherwise, return the list of packages named NAME and at
275VERSION."
276 (if version
277 (find-packages-by-name name version)
278 (match (vhash-assoc name (find-newest-available-packages))
279 ((_ version pkgs ...) pkgs)
280 (#f '()))))
7d193ec3
EB
281
282\f
4ea44419
AK
283(define %sigint-prompt
284 ;; The prompt to jump to upon SIGINT.
285 (make-prompt-tag "interruptible"))
286
287(define (call-with-sigint-handler thunk handler)
288 "Call THUNK and return its value. Upon SIGINT, call HANDLER with the signal
289number in the context of the continuation of the call to this function, and
290return its return value."
291 (call-with-prompt %sigint-prompt
292 (lambda ()
293 (sigaction SIGINT
294 (lambda (signum)
295 (sigaction SIGINT SIG_DFL)
296 (abort-to-prompt %sigint-prompt signum)))
297 (dynamic-wind
298 (const #t)
299 thunk
300 (cut sigaction SIGINT SIG_DFL)))
301 (lambda (k signum)
302 (handler signum))))
303
fad155d4
ML
304\f
305;;;
306;;; Package specification.
307;;;
308
1b846da8 309(define* (%find-package spec name version #:key fallback?)
fad155d4
ML
310 (match (find-best-packages-by-name name version)
311 ((pkg . pkg*)
312 (unless (null? pkg*)
313 (warning (_ "ambiguous package specification `~a'~%") spec)
314 (warning (_ "choosing ~a from ~a~%")
315 (package-full-name pkg)
316 (location->string (package-location pkg))))
1b846da8 317 (when fallback?
7befee30
LC
318 (warning (_ "deprecated NAME-VERSION syntax; \
319use NAME@VERSION instead~%")))
01afdab8
LC
320
321 (match (package-superseded pkg)
322 ((? package? new)
323 (info (_ "package '~a' has been superseded by '~a'~%")
324 (package-name pkg) (package-name new))
325 new)
326 (#f
327 pkg)))
e465d9e1 328 (x
fad155d4
ML
329 (if version
330 (leave (_ "~A: package not found for version ~a~%") name version)
efb107e0 331 (if (not fallback?)
1b846da8
ML
332 ;; XXX: Fallback to the older specification style with an hyphen
333 ;; between NAME and VERSION, for backward compatibility.
95cd4971
LC
334 (call-with-values
335 (lambda ()
336 (hyphen-separated-name->name+version name))
337 (cut %find-package spec <> <> #:fallback? #t))
efb107e0
LC
338
339 ;; The fallback case didn't find anything either, so bail out.
1b846da8 340 (leave (_ "~A: unknown package~%") name))))))
fad155d4 341
5e3b388b
CR
342(define (specification->package spec)
343 "Return a package matching SPEC. SPEC may be a package name, or a package
1b846da8 344name followed by an at-sign and a version number. If the version number is not
5e3b388b 345present, return the preferred newest version."
fad155d4
ML
346 (let-values (((name version) (package-name->name+version spec)))
347 (%find-package spec name version)))
84189ebc
LC
348
349(define* (specification->package+output spec #:optional (output "out"))
350 "Return the package and output specified by SPEC, or #f and #f; SPEC may
351optionally contain a version number and an output name, as in these examples:
352
353 guile
1b846da8 354 guile@2.0.9
84189ebc 355 guile:debug
1b846da8 356 guile@2.0.9:debug
84189ebc
LC
357
358If SPEC does not specify a version number, return the preferred newest
359version; if SPEC does not specify an output, return OUTPUT."
84189ebc
LC
360 (let-values (((name version sub-drv)
361 (package-specification->name+version+output spec output)))
fad155d4
ML
362 (match (%find-package spec name version)
363 (#f
364 (values #f #f))
365 (package
366 (if (member sub-drv (package-outputs package))
367 (values package sub-drv)
368 (leave (_ "package `~a' lacks output `~a'~%")
369 (package-full-name package)
370 sub-drv))))))