packages: Mark the 'patches' field as delayed.
[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)
6b1891b0 27 #:use-module (ice-9 ftw)
c2868b1e 28 #:use-module (ice-9 vlist)
dc5669cd 29 #:use-module (ice-9 match)
6b1891b0 30 #:use-module (srfi srfi-1)
5e3b388b 31 #:use-module (srfi srfi-11)
6b1891b0 32 #:use-module (srfi srfi-26)
800cdeef
LC
33 #:use-module (srfi srfi-39)
34 #:export (search-patch
ac5aa288 35 search-bootstrap-binary
800cdeef 36 %patch-directory
0b3651bc 37 %bootstrap-binaries-path
c107b541 38 %package-module-path
7d193ec3 39
ba326ce4 40 fold-packages
7d193ec3 41
dc5669cd 42 find-packages-by-name
3f26bfc1 43 find-best-packages-by-name
7d193ec3
EB
44 find-newest-available-packages
45
46 package-direct-dependents
47 package-transitive-dependents
4ea44419
AK
48 package-covering-dependents
49
5e3b388b
CR
50 check-package-freshness
51
52 specification->package))
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
LC
72(define (search-patch file-name)
73 "Search the patch FILE-NAME."
128663e4 74 (search-path (%patch-path) file-name))
800cdeef 75
ac5aa288
LC
76(define (search-bootstrap-binary file-name system)
77 "Search the bootstrap binary FILE-NAME for SYSTEM."
128663e4
LC
78 (search-path (%bootstrap-binaries-path)
79 (string-append system "/" file-name)))
ac5aa288 80
84836a57
LC
81(define %distro-root-directory
82 ;; Absolute file name of the module hierarchy.
83 (dirname (search-path %load-path "guix.scm")))
6b1891b0 84
c107b541
LC
85(define %package-module-path
86 ;; Search path for package modules. Each item must be either a directory
87 ;; name or a pair whose car is a directory and whose cdr is a sub-directory
88 ;; to narrow the search.
8689901f
LC
89 (let* ((not-colon (char-set-complement (char-set #\:)))
90 (environment (string-tokenize (or (getenv "GUIX_PACKAGE_PATH") "")
91 not-colon)))
92 ;; Automatically add items from $GUIX_PACKAGE_PATH to Guile's search path.
93 (for-each (lambda (directory)
94 (set! %load-path (cons directory %load-path))
95 (set! %load-compiled-path
96 (cons directory %load-compiled-path)))
97 environment)
98
99 (make-parameter
100 (append environment `((,%distro-root-directory . "gnu/packages"))))))
c107b541 101
ee06af5b
LC
102(define %patch-path
103 ;; Define it after '%package-module-path' so that '%load-path' contains user
104 ;; directories, allowing patches in $GUIX_PACKAGE_PATH to be found.
105 (make-parameter
106 (map (lambda (directory)
107 (if (string=? directory %distro-root-directory)
108 (string-append directory "/gnu/packages/patches")
109 directory))
110 %load-path)))
111
84836a57 112(define* (scheme-files directory)
d95523fb
LC
113 "Return the list of Scheme files found under DIRECTORY, recursively. The
114returned list is sorted in alphabetical order."
115
116 ;; Sort entries so that 'fold-packages' works in a deterministic fashion
117 ;; regardless of details of the underlying file system.
118 (sort (file-system-fold (const #t) ; enter?
119 (lambda (path stat result) ; leaf
120 (if (string-suffix? ".scm" path)
121 (cons path result)
122 result))
123 (lambda (path stat result) ; down
124 result)
125 (lambda (path stat result) ; up
126 result)
127 (const #f) ; skip
128 (lambda (path stat errno result)
129 (warning (_ "cannot access `~a': ~a~%")
130 path (strerror errno))
131 result)
132 '()
133 directory
134 stat)
135 string<?))
6b1891b0 136
c107b541
LC
137(define file-name->module-name
138 (let ((not-slash (char-set-complement (char-set #\/))))
139 (lambda (file)
140 "Return the module name (a list of symbols) corresponding to FILE."
141 (map string->symbol
142 (string-tokenize (string-drop-right file 4) not-slash)))))
84836a57
LC
143
144(define* (package-modules directory #:optional sub-directory)
145 "Return the list of modules that provide packages for the distribution.
146Optionally, narrow the search to SUB-DIRECTORY."
147 (define prefix-len
148 (string-length directory))
149
150 (filter-map (lambda (file)
151 (let ((file (substring file prefix-len)))
152 (false-if-exception
153 (resolve-interface (file-name->module-name file)))))
154 (scheme-files (if sub-directory
155 (string-append directory "/" sub-directory)
156 directory))))
6b1891b0 157
c107b541
LC
158(define* (all-package-modules #:optional (path (%package-module-path)))
159 "Return the list of package modules found in PATH, a list of directories to
160search."
161 (fold-right (lambda (spec result)
162 (match spec
163 ((? string? directory)
164 (append (package-modules directory) result))
165 ((directory . sub-directory)
166 (append (package-modules directory sub-directory)
167 result))))
168 '()
169 path))
170
ba326ce4
LC
171(define (fold-packages proc init)
172 "Call (PROC PACKAGE RESULT) for each available package, using INIT as
c2868b1e
MW
173the initial value of RESULT. It is guaranteed to never traverse the
174same package twice."
175 (identity ; discard second return value
176 (fold2 (lambda (module result seen)
177 (fold2 (lambda (var result seen)
178 (if (and (package? var)
179 (not (vhash-assq var seen)))
180 (values (proc var result)
181 (vhash-consq var #t seen))
182 (values result seen)))
183 result
184 seen
185 (module-map (lambda (sym var)
186 (false-if-exception (variable-ref var)))
187 module)))
188 init
189 vlist-null
c107b541 190 (all-package-modules))))
ba326ce4 191
9ffc1c00
LC
192(define find-packages-by-name
193 (let ((packages (delay
194 (fold-packages (lambda (p r)
195 (vhash-cons (package-name p) p r))
196 vlist-null))))
197 (lambda* (name #:optional version)
198 "Return the list of packages with the given NAME. If VERSION is not #f,
6b1891b0 199then only return packages whose version is equal to VERSION."
9ffc1c00
LC
200 (let ((matching (vhash-fold* cons '() name (force packages))))
201 (if version
202 (filter (lambda (package)
203 (string=? (package-version package) version))
204 matching)
205 matching)))))
dc5669cd 206
3f26bfc1
LC
207(define find-newest-available-packages
208 (memoize
209 (lambda ()
210 "Return a vhash keyed by package names, and with
dc5669cd
MW
211associated values of the form
212
213 (newest-version newest-package ...)
214
215where the preferred package is listed first."
216
3f26bfc1
LC
217 ;; FIXME: Currently, the preferred package is whichever one
218 ;; was found last by 'fold-packages'. Find a better solution.
219 (fold-packages (lambda (p r)
220 (let ((name (package-name p))
221 (version (package-version p)))
222 (match (vhash-assoc name r)
223 ((_ newest-so-far . pkgs)
224 (case (version-compare version newest-so-far)
225 ((>) (vhash-cons name `(,version ,p) r))
226 ((=) (vhash-cons name `(,version ,p ,@pkgs) r))
227 ((<) r)))
228 (#f (vhash-cons name `(,version ,p) r)))))
229 vlist-null))))
230
231(define (find-best-packages-by-name name version)
232 "If version is #f, return the list of packages named NAME with the highest
233version numbers; otherwise, return the list of packages named NAME and at
234VERSION."
235 (if version
236 (find-packages-by-name name version)
237 (match (vhash-assoc name (find-newest-available-packages))
238 ((_ version pkgs ...) pkgs)
239 (#f '()))))
7d193ec3
EB
240
241\f
242(define* (vhash-refq vhash key #:optional (dflt #f))
243 "Look up KEY in the vhash VHASH, and return the value (if any) associated
244with it. If KEY is not found, return DFLT (or `#f' if no DFLT argument is
245supplied). Uses `eq?' for equality testing."
246 (or (and=> (vhash-assq key vhash) cdr)
247 dflt))
248
249(define package-dependencies
250 (memoize
251 (lambda ()
252 "Return a vhash keyed by package, and with associated values that are a
253list of packages that depend on that package."
254 (fold-packages
255 (lambda (package dag)
256 (fold
257 (lambda (in d)
258 ;; Insert a graph edge from each of package's inputs to package.
259 (vhash-consq in
260 (cons package (vhash-refq d in '()))
261 (vhash-delq in d)))
262 dag
263 (match (package-direct-inputs package)
264 (((labels packages . _) ...)
265 packages) )))
266 vlist-null))))
267
268(define (package-direct-dependents packages)
269 "Return a list of packages from the distribution that directly depend on the
270packages in PACKAGES."
271 (delete-duplicates
272 (concatenate
273 (map (lambda (p)
274 (vhash-refq (package-dependencies) p '()))
275 packages))))
276
277(define (package-transitive-dependents packages)
278 "Return the transitive dependent packages of the distribution packages in
279PACKAGES---i.e. the dependents of those packages, plus their dependents,
280recursively."
281 (let ((dependency-dag (package-dependencies)))
282 (fold-tree
283 cons '()
284 (lambda (node) (vhash-refq dependency-dag node))
285 ;; Start with the dependents to avoid including PACKAGES in the result.
286 (package-direct-dependents packages))))
287
288(define (package-covering-dependents packages)
289 "Return a minimal list of packages from the distribution whose dependencies
290include all of PACKAGES and all packages that depend on PACKAGES."
291 (let ((dependency-dag (package-dependencies)))
292 (fold-tree-leaves
293 cons '()
294 (lambda (node) (vhash-refq dependency-dag node))
295 ;; Start with the dependents to avoid including PACKAGES in the result.
296 (package-direct-dependents packages))))
4ea44419
AK
297
298\f
299(define %sigint-prompt
300 ;; The prompt to jump to upon SIGINT.
301 (make-prompt-tag "interruptible"))
302
303(define (call-with-sigint-handler thunk handler)
304 "Call THUNK and return its value. Upon SIGINT, call HANDLER with the signal
305number in the context of the continuation of the call to this function, and
306return its return value."
307 (call-with-prompt %sigint-prompt
308 (lambda ()
309 (sigaction SIGINT
310 (lambda (signum)
311 (sigaction SIGINT SIG_DFL)
312 (abort-to-prompt %sigint-prompt signum)))
313 (dynamic-wind
314 (const #t)
315 thunk
316 (cut sigaction SIGINT SIG_DFL)))
317 (lambda (k signum)
318 (handler signum))))
319
320(define-syntax-rule (waiting exp fmt rest ...)
321 "Display the given message while EXP is being evaluated."
322 (let* ((message (format #f fmt rest ...))
323 (blank (make-string (string-length message) #\space)))
324 (display message (current-error-port))
325 (force-output (current-error-port))
326 (call-with-sigint-handler
327 (lambda ()
328 (dynamic-wind
329 (const #f)
330 (lambda () exp)
331 (lambda ()
332 ;; Clear the line.
333 (display #\cr (current-error-port))
334 (display blank (current-error-port))
335 (display #\cr (current-error-port))
336 (force-output (current-error-port)))))
337 (lambda (signum)
338 (format (current-error-port) " interrupted by signal ~a~%" SIGINT)
339 #f))))
340
341(define ftp-open*
342 ;; Memoizing version of `ftp-open'. The goal is to avoid initiating a new
343 ;; FTP connection for each package, esp. since most of them are to the same
344 ;; server. This has a noticeable impact when doing "guix upgrade -u".
345 (memoize ftp-open))
346
347(define (check-package-freshness package)
348 "Check whether PACKAGE has a newer version available upstream, and report
349it."
350 ;; TODO: Automatically inject the upstream version when desired.
351
352 (catch #t
353 (lambda ()
354 (when (false-if-exception (gnu-package? package))
355 (let ((name (package-name package))
356 (full-name (package-full-name package)))
357 (match (waiting (latest-release name
358 #:ftp-open ftp-open*
359 #:ftp-close (const #f))
360 (_ "looking for the latest release of GNU ~a...") name)
501d7647
LC
361 ((? gnu-release? release)
362 (let ((latest-version
363 (string-append (gnu-release-package release) "-"
364 (gnu-release-version release))))
365 (when (version>? latest-version full-name)
366 (format (current-error-port)
367 (_ "~a: note: using ~a \
4ea44419 368but ~a is available upstream~%")
501d7647
LC
369 (location->string (package-location package))
370 full-name latest-version))))
4ea44419
AK
371 (_ #t)))))
372 (lambda (key . args)
373 ;; Silently ignore networking errors rather than preventing
374 ;; installation.
375 (case key
376 ((getaddrinfo-error ftp-error) #f)
377 (else (apply throw key args))))))
5e3b388b
CR
378
379(define (specification->package spec)
380 "Return a package matching SPEC. SPEC may be a package name, or a package
381name followed by a hyphen and a version number. If the version number is not
382present, return the preferred newest version."
383 (let-values (((name version)
384 (package-name->name+version spec)))
385 (match (find-best-packages-by-name name version)
386 ((p) ; one match
387 p)
388 ((p x ...) ; several matches
389 (warning (_ "ambiguous package specification `~a'~%") spec)
390 (warning (_ "choosing ~a from ~a~%")
391 (package-full-name p)
392 (location->string (package-location p)))
393 p)
394 (_ ; no matches
395 (if version
396 (leave (_ "~A: package not found for version ~a~%")
397 name version)
398 (leave (_ "~A: unknown package~%") name))))))