diff options
| author | Ricardo Wurmus <rekado@elephly.net> | 2019-02-06 13:03:26 +0100 |
|---|---|---|
| committer | Ricardo Wurmus <rekado@elephly.net> | 2019-02-06 13:03:26 +0100 |
| commit | ba88eea2b3a8a33ecd7fc0ec64e3917c6c2fe21d (patch) | |
| tree | 75c68e44d3d76440f416552711b1a47ec83e411e /gnu/packages.scm | |
| parent | f380f9d55e6757c242acf6c71c4a3ccfcdb066b2 (diff) | |
| parent | 4aeb7f34c948f32363f2ae29c6942c6328df758c (diff) | |
Merge branch 'master' into core-updates
Diffstat (limited to 'gnu/packages.scm')
| -rw-r--r-- | gnu/packages.scm | 259 |
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 | ||
| 152 | authoritative when entries have been added via GUIX_PACKAGE_PATH or '-L' | ||
| 153 | flags." | ||
| 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, | ||
| 192 | PROC is called along these lines: | ||
| 193 | |||
| 194 | (PROC NAME VERSION RESULT | ||
| 195 | #:outputs OUTPUTS | ||
| 196 | #:location LOCATION | ||
| 197 | …) | ||
| 198 | |||
| 199 | PROC can use #:allow-other-keys to ignore the bits it's not interested in. | ||
| 200 | When a package cache is available, this procedure does not actually load any | ||
| 201 | package 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 | ||
| 257 | package 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 | 299 | order." |
| 213 | associated 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) | |
| 217 | where 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) | 308 | then only return packages whose version is prefixed by VERSION, sorted in |
| 222 | (let ((name (package-name p)) | 309 | decreasing 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 | ||
| 330 | matching 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 | |||
| 236 | VERSION." | 356 | VERSION." |
| 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 | |||
| 372 | The primary purpose of the cache is to speed up package lookup by name such | ||
| 373 | that we don't have to traverse and load all the package modules, thereby also | ||
| 374 | reducing 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 | ||
| 474 | specification 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 |
| 299 | optionally contain a version number and an output name, as in these examples: | 498 | optionally contain a version number and an output name, as in these examples: |
