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