summaryrefslogtreecommitdiff
path: root/gnu/packages.scm
diff options
context:
space:
mode:
authorRicardo Wurmus <rekado@elephly.net>2019-02-06 13:03:26 +0100
committerRicardo Wurmus <rekado@elephly.net>2019-02-06 13:03:26 +0100
commitba88eea2b3a8a33ecd7fc0ec64e3917c6c2fe21d (patch)
tree75c68e44d3d76440f416552711b1a47ec83e411e /gnu/packages.scm
parentf380f9d55e6757c242acf6c71c4a3ccfcdb066b2 (diff)
parent4aeb7f34c948f32363f2ae29c6942c6328df758c (diff)
Merge branch 'master' into core-updates
Diffstat (limited to 'gnu/packages.scm')
-rw-r--r--gnu/packages.scm259
1 files changed, 229 insertions, 30 deletions
diff --git a/gnu/packages.scm b/gnu/packages.scm
index 333b18f9f0b..9cd57fc7046 100644
--- a/gnu/packages.scm
+++ b/gnu/packages.scm
@@ -1,5 +1,5 @@
1;;; GNU Guix --- Functional package management for GNU 1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org> 2;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
3;;; Copyright © 2013 Mark H Weaver <mhw@netris.org> 3;;; Copyright © 2013 Mark H Weaver <mhw@netris.org>
4;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org> 4;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
5;;; Copyright © 2016, 2017 Alex Kost <alezost@gmail.com> 5;;; Copyright © 2016, 2017 Alex Kost <alezost@gmail.com>
@@ -28,11 +28,14 @@
28 #:use-module (guix memoization) 28 #:use-module (guix memoization)
29 #:use-module ((guix build utils) 29 #:use-module ((guix build utils)
30 #:select ((package-name->name+version 30 #:select ((package-name->name+version
31 . hyphen-separated-name->name+version))) 31 . hyphen-separated-name->name+version)
32 mkdir-p))
32 #:autoload (guix profiles) (packages->manifest) 33 #:autoload (guix profiles) (packages->manifest)
33 #:use-module (guix describe) 34 #:use-module (guix describe)
34 #:use-module (ice-9 vlist) 35 #:use-module (ice-9 vlist)
35 #:use-module (ice-9 match) 36 #:use-module (ice-9 match)
37 #:autoload (ice-9 binary-ports) (put-bytevector)
38 #:autoload (system base compile) (compile)
36 #:use-module (srfi srfi-1) 39 #:use-module (srfi srfi-1)
37 #:use-module (srfi srfi-11) 40 #:use-module (srfi srfi-11)
38 #:use-module (srfi srfi-26) 41 #:use-module (srfi srfi-26)
@@ -50,14 +53,18 @@
50 %default-package-module-path 53 %default-package-module-path
51 54
52 fold-packages 55 fold-packages
56 fold-available-packages
53 57
54 find-packages-by-name 58 find-packages-by-name
59 find-package-locations
55 find-best-packages-by-name 60 find-best-packages-by-name
56 find-newest-available-packages
57 61
58 specification->package 62 specification->package
59 specification->package+output 63 specification->package+output
60 specifications->manifest)) 64 specification->location
65 specifications->manifest
66
67 generate-package-cache))
61 68
62;;; Commentary: 69;;; Commentary:
63;;; 70;;;
@@ -140,6 +147,14 @@ for system '~a'")
140 ;; Default search path for package modules. 147 ;; Default search path for package modules.
141 `((,%distro-root-directory . "gnu/packages"))) 148 `((,%distro-root-directory . "gnu/packages")))
142 149
150(define (cache-is-authoritative?)
151 "Return true if the pre-computed package cache is authoritative. It is not
152authoritative when entries have been added via GUIX_PACKAGE_PATH or '-L'
153flags."
154 (equal? (%package-module-path)
155 (append %default-package-module-path
156 (package-path-entries))))
157
143(define %package-module-path 158(define %package-module-path
144 ;; Search path for package modules. Each item must be either a directory 159 ;; Search path for package modules. Each item must be either a directory
145 ;; name or a pair whose car is a directory and whose cdr is a sub-directory 160 ;; name or a pair whose car is a directory and whose cdr is a sub-directory
@@ -172,6 +187,50 @@ for system '~a'")
172 directory)) 187 directory))
173 %load-path))) 188 %load-path)))
174 189
190(define (fold-available-packages proc init)
191 "Fold PROC over the list of available packages. For each available package,
192PROC is called along these lines:
193
194 (PROC NAME VERSION RESULT
195 #:outputs OUTPUTS
196 #:location LOCATION
197 …)
198
199PROC can use #:allow-other-keys to ignore the bits it's not interested in.
200When a package cache is available, this procedure does not actually load any
201package module."
202 (define cache
203 (load-package-cache (current-profile)))
204
205 (if (and cache (cache-is-authoritative?))
206 (vhash-fold (lambda (name vector result)
207 (match vector
208 (#(name version module symbol outputs
209 supported? deprecated?
210 file line column)
211 (proc name version result
212 #:outputs outputs
213 #:location (and file
214 (location file line column))
215 #:supported? supported?
216 #:deprecated? deprecated?))))
217 init
218 cache)
219 (fold-packages (lambda (package result)
220 (proc (package-name package)
221 (package-version package)
222 result
223 #:outputs (package-outputs package)
224 #:location (package-location package)
225 #:supported?
226 (->bool
227 (member (%current-system)
228 (package-supported-systems package)))
229 #:deprecated?
230 (->bool
231 (package-superseded package))))
232 init)))
233
175(define* (fold-packages proc init 234(define* (fold-packages proc init
176 #:optional 235 #:optional
177 (modules (all-modules (%package-module-path) 236 (modules (all-modules (%package-module-path)
@@ -188,7 +247,35 @@ is guaranteed to never traverse the same package twice."
188 init 247 init
189 modules)) 248 modules))
190 249
191(define find-packages-by-name 250(define %package-cache-file
251 ;; Location of the package cache.
252 "/lib/guix/package.cache")
253
254(define load-package-cache
255 (mlambda (profile)
256 "Attempt to load the package cache. On success return a vhash keyed by
257package names. Return #f on failure."
258 (match profile
259 (#f #f)
260 (profile
261 (catch 'system-error
262 (lambda ()
263 (define lst
264 (load-compiled (string-append profile %package-cache-file)))
265 (fold (lambda (item vhash)
266 (match item
267 (#(name version module symbol outputs
268 supported? deprecated?
269 file line column)
270 (vhash-cons name item vhash))))
271 vlist-null
272 lst))
273 (lambda args
274 (if (= ENOENT (system-error-errno args))
275 #f
276 (apply throw args))))))))
277
278(define find-packages-by-name/direct ;bypass the cache
192 (let ((packages (delay 279 (let ((packages (delay
193 (fold-packages (lambda (p r) 280 (fold-packages (lambda (p r)
194 (vhash-cons (package-name p) p r)) 281 (vhash-cons (package-name p) p r))
@@ -207,28 +294,61 @@ decreasing version order."
207 matching) 294 matching)
208 matching))))) 295 matching)))))
209 296
210(define find-newest-available-packages 297(define (cache-lookup cache name)
211 (mlambda () 298 "Lookup package NAME in CACHE. Return a list sorted in increasing version
212 "Return a vhash keyed by package names, and with 299order."
213associated values of the form 300 (define (package-version<? v1 v2)
214 301 (version>? (vector-ref v2 1) (vector-ref v1 1)))
215 (newest-version newest-package ...) 302
216 303 (sort (vhash-fold* cons '() name cache)
217where the preferred package is listed first." 304 package-version<?))
218 305
219 ;; FIXME: Currently, the preferred package is whichever one 306(define* (find-packages-by-name name #:optional version)
220 ;; was found last by 'fold-packages'. Find a better solution. 307 "Return the list of packages with the given NAME. If VERSION is not #f,
221 (fold-packages (lambda (p r) 308then only return packages whose version is prefixed by VERSION, sorted in
222 (let ((name (package-name p)) 309decreasing version order."
223 (version (package-version p))) 310 (define cache
224 (match (vhash-assoc name r) 311 (load-package-cache (current-profile)))
225 ((_ newest-so-far . pkgs) 312
226 (case (version-compare version newest-so-far) 313 (if (and (cache-is-authoritative?) cache)
227 ((>) (vhash-cons name `(,version ,p) r)) 314 (match (cache-lookup cache name)
228 ((=) (vhash-cons name `(,version ,p ,@pkgs) r)) 315 (#f #f)
229 ((<) r))) 316 ((#(_ versions modules symbols _ _ _ _ _ _) ...)
230 (#f (vhash-cons name `(,version ,p) r))))) 317 (fold (lambda (version* module symbol result)
231 vlist-null))) 318 (if (or (not version)
319 (version-prefix? version version*))
320 (cons (module-ref (resolve-interface module)
321 symbol)
322 result)
323 result))
324 '()
325 versions modules symbols)))
326 (find-packages-by-name/direct name version)))
327
328(define* (find-package-locations name #:optional version)
329 "Return a list of version/location pairs corresponding to each package
330matching NAME and VERSION."
331 (define cache
332 (load-package-cache (current-profile)))
333
334 (if (and cache (cache-is-authoritative?))
335 (match (cache-lookup cache name)
336 (#f '())
337 ((#(name versions modules symbols outputs
338 supported? deprecated?
339 files lines columns) ...)
340 (fold (lambda (version* file line column result)
341 (if (and file
342 (or (not version)
343 (version-prefix? version version*)))
344 (alist-cons version* (location file line column)
345 result)
346 result))
347 '()
348 versions files lines columns)))
349 (map (lambda (package)
350 (cons (package-version package) (package-location package)))
351 (find-packages-by-name/direct name version))))
232 352
233(define (find-best-packages-by-name name version) 353(define (find-best-packages-by-name name version)
234 "If version is #f, return the list of packages named NAME with the highest 354 "If version is #f, return the list of packages named NAME with the highest
@@ -236,9 +356,64 @@ version numbers; otherwise, return the list of packages named NAME and at
236VERSION." 356VERSION."
237 (if version 357 (if version
238 (find-packages-by-name name version) 358 (find-packages-by-name name version)
239 (match (vhash-assoc name (find-newest-available-packages)) 359 (match (find-packages-by-name name)
240 ((_ version pkgs ...) pkgs) 360 (()
241 (#f '())))) 361 '())
362 ((matches ...)
363 ;; Return the subset of MATCHES with the higher version number.
364 (let ((highest (package-version (first matches))))
365 (take-while (lambda (p)
366 (string=? (package-version p) highest))
367 matches))))))
368
369(define (generate-package-cache directory)
370 "Generate under DIRECTORY a cache of all the available packages.
371
372The primary purpose of the cache is to speed up package lookup by name such
373that we don't have to traverse and load all the package modules, thereby also
374reducing the memory footprint."
375 (define cache-file
376 (string-append directory %package-cache-file))
377
378 (define (expand-cache module symbol variable result)
379 (match (false-if-exception (variable-ref variable))
380 ((? package? package)
381 (if (hidden-package? package)
382 result
383 (cons `#(,(package-name package)
384 ,(package-version package)
385 ,(module-name module)
386 ,symbol
387 ,(package-outputs package)
388 ,(->bool (member (%current-system)
389 (package-supported-systems package)))
390 ,(->bool (package-superseded package))
391 ,@(let ((loc (package-location package)))
392 (if loc
393 `(,(location-file loc)
394 ,(location-line loc)
395 ,(location-column loc))
396 '(#f #f #f))))
397 result)))
398 (_
399 result)))
400
401 (define exp
402 (fold-module-public-variables* expand-cache '()
403 (all-modules (%package-module-path)
404 #:warn
405 warn-about-load-error)))
406
407 (mkdir-p (dirname cache-file))
408 (call-with-output-file cache-file
409 (lambda (port)
410 ;; Store the cache as a '.go' file. This makes loading fast and reduces
411 ;; heap usage since some of the static data is directly mmapped.
412 (put-bytevector port
413 (compile `'(,@exp)
414 #:to 'bytecode
415 #:opts '(#:to-file? #t)))))
416 cache-file)
242 417
243 418
244(define %sigint-prompt 419(define %sigint-prompt
@@ -294,6 +469,30 @@ present, return the preferred newest version."
294 (let-values (((name version) (package-name->name+version spec))) 469 (let-values (((name version) (package-name->name+version spec)))
295 (%find-package spec name version))) 470 (%find-package spec name version)))
296 471
472(define (specification->location spec)
473 "Return the location of the highest-numbered package matching SPEC, a
474specification such as \"guile@2\" or \"emacs\"."
475 (let-values (((name version) (package-name->name+version spec)))
476 (match (find-package-locations name version)
477 (()
478 (if version
479 (leave (G_ "~A: package not found for version ~a~%") name version)
480 (leave (G_ "~A: unknown package~%") name)))
481 (lst
482 (let* ((highest (match lst (((version . _) _ ...) version)))
483 (locations (take-while (match-lambda
484 ((version . location)
485 (string=? version highest)))
486 lst)))
487 (match locations
488 (((version . location) . rest)
489 (unless (null? rest)
490 (warning (G_ "ambiguous package specification `~a'~%") spec)
491 (warning (G_ "choosing ~a@~a from ~a~%")
492 name version
493 (location->string location)))
494 location)))))))
495
297(define* (specification->package+output spec #:optional (output "out")) 496(define* (specification->package+output spec #:optional (output "out"))
298 "Return the package and output specified by SPEC, or #f and #f; SPEC may 497 "Return the package and output specified by SPEC, or #f and #f; SPEC may
299optionally contain a version number and an output name, as in these examples: 498optionally contain a version number and an output name, as in these examples: