publish: Move 'query-path-info' call where it belongs.
[jackhill/guix/guix.git] / gnu / packages.scm
CommitLineData
233e7676 1;;; GNU Guix --- Functional package management for GNU
ee06af5b 2;;; Copyright © 2012, 2013, 2014, 2015 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>
6b1891b0 5;;;
233e7676 6;;; This file is part of GNU Guix.
6b1891b0 7;;;
233e7676 8;;; GNU Guix is free software; you can redistribute it and/or modify it
6b1891b0
LC
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.
12;;;
233e7676 13;;; GNU Guix is distributed in the hope that it will be useful, but
6b1891b0
LC
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.
17;;;
18;;; You should have received a copy of the GNU General Public License
233e7676 19;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
6b1891b0 20
59a43334 21(define-module (gnu packages)
6b1891b0 22 #:use-module (guix packages)
98eb8cbe 23 #:use-module (guix ui)
800cdeef 24 #:use-module (guix utils)
4ea44419
AK
25 #:use-module ((guix ftp-client) #:select (ftp-open))
26 #:use-module (guix gnu-maintenance)
861be0cc 27 #:use-module (guix upstream)
6b1891b0 28 #:use-module (ice-9 ftw)
c2868b1e 29 #:use-module (ice-9 vlist)
dc5669cd 30 #:use-module (ice-9 match)
6b1891b0 31 #:use-module (srfi srfi-1)
5e3b388b 32 #:use-module (srfi srfi-11)
6b1891b0 33 #:use-module (srfi srfi-26)
dbab5150
LC
34 #:use-module (srfi srfi-34)
35 #:use-module (srfi srfi-35)
800cdeef
LC
36 #:use-module (srfi srfi-39)
37 #:export (search-patch
ac5aa288 38 search-bootstrap-binary
0492f4a2 39 %patch-path
0b3651bc 40 %bootstrap-binaries-path
c107b541 41 %package-module-path
7d193ec3 42
ba326ce4 43 fold-packages
7d193ec3 44
dc5669cd 45 find-packages-by-name
3f26bfc1 46 find-best-packages-by-name
7d193ec3
EB
47 find-newest-available-packages
48
5e3b388b
CR
49 check-package-freshness
50
84189ebc
LC
51 specification->package
52 specification->package+output))
6b1891b0
LC
53
54;;; Commentary:
55;;;
56;;; General utilities for the software distribution---i.e., the modules under
59a43334 57;;; (gnu packages ...).
6b1891b0
LC
58;;;
59;;; Code:
60
0b3651bc
LC
61;; By default, we store patches and bootstrap binaries alongside Guile
62;; modules. This is so that these extra files can be found without
63;; requiring a special setup, such as a specific installation directory
64;; and an extra environment variable. One advantage of this setup is
65;; that everything just works in an auto-compilation setting.
a9f60c42 66
a9f60c42 67(define %bootstrap-binaries-path
ac5aa288 68 (make-parameter
1ffa7090 69 (map (cut string-append <> "/gnu/packages/bootstrap")
0b3651bc 70 %load-path)))
ac5aa288 71
800cdeef 72(define (search-patch file-name)
dbab5150
LC
73 "Search the patch FILE-NAME. Raise an error if not found."
74 (or (search-path (%patch-path) file-name)
75 (raise (condition
76 (&message (message (format #f (_ "~a: patch not found")
77 file-name)))))))
800cdeef 78
ac5aa288 79(define (search-bootstrap-binary file-name system)
dfba5489
LC
80 "Search the bootstrap binary FILE-NAME for SYSTEM. Raise an error if not
81found."
82 (or (search-path (%bootstrap-binaries-path)
83 (string-append system "/" file-name))
84 (raise (condition
85 (&message
86 (message
87 (format #f (_ "could not find bootstrap binary '~a' \
88for system '~a'")
89 file-name system)))))))
ac5aa288 90
84836a57
LC
91(define %distro-root-directory
92 ;; Absolute file name of the module hierarchy.
93 (dirname (search-path %load-path "guix.scm")))
6b1891b0 94
c107b541
LC
95(define %package-module-path
96 ;; Search path for package modules. Each item must be either a directory
97 ;; name or a pair whose car is a directory and whose cdr is a sub-directory
98 ;; to narrow the search.
8689901f
LC
99 (let* ((not-colon (char-set-complement (char-set #\:)))
100 (environment (string-tokenize (or (getenv "GUIX_PACKAGE_PATH") "")
101 not-colon)))
102 ;; Automatically add items from $GUIX_PACKAGE_PATH to Guile's search path.
103 (for-each (lambda (directory)
104 (set! %load-path (cons directory %load-path))
105 (set! %load-compiled-path
106 (cons directory %load-compiled-path)))
107 environment)
108
109 (make-parameter
110 (append environment `((,%distro-root-directory . "gnu/packages"))))))
c107b541 111
ee06af5b
LC
112(define %patch-path
113 ;; Define it after '%package-module-path' so that '%load-path' contains user
114 ;; directories, allowing patches in $GUIX_PACKAGE_PATH to be found.
115 (make-parameter
116 (map (lambda (directory)
117 (if (string=? directory %distro-root-directory)
118 (string-append directory "/gnu/packages/patches")
119 directory))
120 %load-path)))
121
84836a57 122(define* (scheme-files directory)
d95523fb
LC
123 "Return the list of Scheme files found under DIRECTORY, recursively. The
124returned list is sorted in alphabetical order."
125
126 ;; Sort entries so that 'fold-packages' works in a deterministic fashion
127 ;; regardless of details of the underlying file system.
128 (sort (file-system-fold (const #t) ; enter?
129 (lambda (path stat result) ; leaf
130 (if (string-suffix? ".scm" path)
131 (cons path result)
132 result))
133 (lambda (path stat result) ; down
134 result)
135 (lambda (path stat result) ; up
136 result)
137 (const #f) ; skip
138 (lambda (path stat errno result)
139 (warning (_ "cannot access `~a': ~a~%")
140 path (strerror errno))
141 result)
142 '()
143 directory
144 stat)
145 string<?))
6b1891b0 146
c107b541
LC
147(define file-name->module-name
148 (let ((not-slash (char-set-complement (char-set #\/))))
149 (lambda (file)
150 "Return the module name (a list of symbols) corresponding to FILE."
151 (map string->symbol
152 (string-tokenize (string-drop-right file 4) not-slash)))))
84836a57
LC
153
154(define* (package-modules directory #:optional sub-directory)
155 "Return the list of modules that provide packages for the distribution.
156Optionally, narrow the search to SUB-DIRECTORY."
157 (define prefix-len
158 (string-length directory))
159
160 (filter-map (lambda (file)
4ae7559f
LC
161 (let* ((file (substring file prefix-len))
162 (module (file-name->module-name file)))
163 (catch #t
164 (lambda ()
165 (resolve-interface module))
166 (lambda args
167 ;; Report the error, but keep going.
168 (warn-about-load-error module args)
169 #f))))
84836a57
LC
170 (scheme-files (if sub-directory
171 (string-append directory "/" sub-directory)
172 directory))))
6b1891b0 173
c107b541
LC
174(define* (all-package-modules #:optional (path (%package-module-path)))
175 "Return the list of package modules found in PATH, a list of directories to
176search."
177 (fold-right (lambda (spec result)
178 (match spec
179 ((? string? directory)
180 (append (package-modules directory) result))
181 ((directory . sub-directory)
182 (append (package-modules directory sub-directory)
183 result))))
184 '()
185 path))
186
ba326ce4
LC
187(define (fold-packages proc init)
188 "Call (PROC PACKAGE RESULT) for each available package, using INIT as
c2868b1e
MW
189the initial value of RESULT. It is guaranteed to never traverse the
190same package twice."
191 (identity ; discard second return value
192 (fold2 (lambda (module result seen)
193 (fold2 (lambda (var result seen)
194 (if (and (package? var)
195 (not (vhash-assq var seen)))
196 (values (proc var result)
197 (vhash-consq var #t seen))
198 (values result seen)))
199 result
200 seen
201 (module-map (lambda (sym var)
202 (false-if-exception (variable-ref var)))
203 module)))
204 init
205 vlist-null
c107b541 206 (all-package-modules))))
ba326ce4 207
9ffc1c00
LC
208(define find-packages-by-name
209 (let ((packages (delay
210 (fold-packages (lambda (p r)
211 (vhash-cons (package-name p) p r))
724311a2
LC
212 vlist-null)))
213 (version>? (lambda (p1 p2)
214 (version>? (package-version p1) (package-version p2)))))
9ffc1c00
LC
215 (lambda* (name #:optional version)
216 "Return the list of packages with the given NAME. If VERSION is not #f,
724311a2
LC
217then only return packages whose version is prefixed by VERSION, sorted in
218decreasing version order."
219 (let ((matching (sort (vhash-fold* cons '() name (force packages))
220 version>?)))
9ffc1c00
LC
221 (if version
222 (filter (lambda (package)
724311a2 223 (string-prefix? version (package-version package)))
9ffc1c00
LC
224 matching)
225 matching)))))
dc5669cd 226
3f26bfc1
LC
227(define find-newest-available-packages
228 (memoize
229 (lambda ()
230 "Return a vhash keyed by package names, and with
dc5669cd
MW
231associated values of the form
232
233 (newest-version newest-package ...)
234
235where the preferred package is listed first."
236
3f26bfc1
LC
237 ;; FIXME: Currently, the preferred package is whichever one
238 ;; was found last by 'fold-packages'. Find a better solution.
239 (fold-packages (lambda (p r)
240 (let ((name (package-name p))
241 (version (package-version p)))
242 (match (vhash-assoc name r)
243 ((_ newest-so-far . pkgs)
244 (case (version-compare version newest-so-far)
245 ((>) (vhash-cons name `(,version ,p) r))
246 ((=) (vhash-cons name `(,version ,p ,@pkgs) r))
247 ((<) r)))
248 (#f (vhash-cons name `(,version ,p) r)))))
249 vlist-null))))
250
251(define (find-best-packages-by-name name version)
252 "If version is #f, return the list of packages named NAME with the highest
253version numbers; otherwise, return the list of packages named NAME and at
254VERSION."
255 (if version
256 (find-packages-by-name name version)
257 (match (vhash-assoc name (find-newest-available-packages))
258 ((_ version pkgs ...) pkgs)
259 (#f '()))))
7d193ec3
EB
260
261\f
4ea44419
AK
262(define %sigint-prompt
263 ;; The prompt to jump to upon SIGINT.
264 (make-prompt-tag "interruptible"))
265
266(define (call-with-sigint-handler thunk handler)
267 "Call THUNK and return its value. Upon SIGINT, call HANDLER with the signal
268number in the context of the continuation of the call to this function, and
269return its return value."
270 (call-with-prompt %sigint-prompt
271 (lambda ()
272 (sigaction SIGINT
273 (lambda (signum)
274 (sigaction SIGINT SIG_DFL)
275 (abort-to-prompt %sigint-prompt signum)))
276 (dynamic-wind
277 (const #t)
278 thunk
279 (cut sigaction SIGINT SIG_DFL)))
280 (lambda (k signum)
281 (handler signum))))
282
283(define-syntax-rule (waiting exp fmt rest ...)
284 "Display the given message while EXP is being evaluated."
285 (let* ((message (format #f fmt rest ...))
286 (blank (make-string (string-length message) #\space)))
287 (display message (current-error-port))
288 (force-output (current-error-port))
289 (call-with-sigint-handler
290 (lambda ()
291 (dynamic-wind
292 (const #f)
293 (lambda () exp)
294 (lambda ()
295 ;; Clear the line.
296 (display #\cr (current-error-port))
297 (display blank (current-error-port))
298 (display #\cr (current-error-port))
299 (force-output (current-error-port)))))
300 (lambda (signum)
301 (format (current-error-port) " interrupted by signal ~a~%" SIGINT)
302 #f))))
303
304(define ftp-open*
305 ;; Memoizing version of `ftp-open'. The goal is to avoid initiating a new
306 ;; FTP connection for each package, esp. since most of them are to the same
307 ;; server. This has a noticeable impact when doing "guix upgrade -u".
308 (memoize ftp-open))
309
310(define (check-package-freshness package)
311 "Check whether PACKAGE has a newer version available upstream, and report
312it."
313 ;; TODO: Automatically inject the upstream version when desired.
314
315 (catch #t
316 (lambda ()
317 (when (false-if-exception (gnu-package? package))
318 (let ((name (package-name package))
319 (full-name (package-full-name package)))
861be0cc
LC
320 ;; XXX: This could work with non-GNU packages as well. However,
321 ;; GNU's FTP-based updater would be too slow if it weren't memoized,
322 ;; and the generic interface in (guix upstream) doesn't support
323 ;; that.
4ea44419
AK
324 (match (waiting (latest-release name
325 #:ftp-open ftp-open*
326 #:ftp-close (const #f))
327 (_ "looking for the latest release of GNU ~a...") name)
861be0cc 328 ((? upstream-source? source)
501d7647 329 (let ((latest-version
861be0cc
LC
330 (string-append (upstream-source-package source) "-"
331 (upstream-source-version source))))
501d7647
LC
332 (when (version>? latest-version full-name)
333 (format (current-error-port)
334 (_ "~a: note: using ~a \
4ea44419 335but ~a is available upstream~%")
501d7647
LC
336 (location->string (package-location package))
337 full-name latest-version))))
4ea44419
AK
338 (_ #t)))))
339 (lambda (key . args)
340 ;; Silently ignore networking errors rather than preventing
341 ;; installation.
342 (case key
343 ((getaddrinfo-error ftp-error) #f)
344 (else (apply throw key args))))))
5e3b388b
CR
345
346(define (specification->package spec)
347 "Return a package matching SPEC. SPEC may be a package name, or a package
348name followed by a hyphen and a version number. If the version number is not
349present, return the preferred newest version."
350 (let-values (((name version)
351 (package-name->name+version spec)))
352 (match (find-best-packages-by-name name version)
353 ((p) ; one match
354 p)
355 ((p x ...) ; several matches
356 (warning (_ "ambiguous package specification `~a'~%") spec)
357 (warning (_ "choosing ~a from ~a~%")
358 (package-full-name p)
359 (location->string (package-location p)))
360 p)
361 (_ ; no matches
362 (if version
363 (leave (_ "~A: package not found for version ~a~%")
364 name version)
365 (leave (_ "~A: unknown package~%") name))))))
84189ebc
LC
366
367(define* (specification->package+output spec #:optional (output "out"))
368 "Return the package and output specified by SPEC, or #f and #f; SPEC may
369optionally contain a version number and an output name, as in these examples:
370
371 guile
372 guile-2.0.9
373 guile:debug
374 guile-2.0.9:debug
375
376If SPEC does not specify a version number, return the preferred newest
377version; if SPEC does not specify an output, return OUTPUT."
378 (define (ensure-output p sub-drv)
379 (if (member sub-drv (package-outputs p))
380 sub-drv
381 (leave (_ "package `~a' lacks output `~a'~%")
382 (package-full-name p)
383 sub-drv)))
384
385 (let-values (((name version sub-drv)
386 (package-specification->name+version+output spec output)))
387 (match (find-best-packages-by-name name version)
388 ((p)
389 (values p (ensure-output p sub-drv)))
390 ((p p* ...)
391 (warning (_ "ambiguous package specification `~a'~%")
392 spec)
393 (warning (_ "choosing ~a from ~a~%")
394 (package-full-name p)
395 (location->string (package-location p)))
396 (values p (ensure-output p sub-drv)))
397 (()
398 (leave (_ "~a: package not found~%") spec)))))