packages: Have `package-derivation' return a <derivation> as a second value.

* guix/packages.scm (cache): Change the `drv' argument to `thunk'.
  Memoize all the return values of THUNK.
  (cached-derivation): Remove.
  (cached): New macro.
  (package-derivation): Use `cached' instead of `(or (cached-derivation) …)'.
* doc/guix.texi (Defining Packages): Update accordingly.
This commit is contained in:
Ludovic Courtès 2013-01-20 22:17:58 +01:00
parent 079fca3be8
commit e509d1527d
3 changed files with 56 additions and 45 deletions

View File

@ -765,9 +765,8 @@ The build actions it prescribes may then be realized by using the
@code{build-derivations} procedure (@pxref{The Store}). @code{build-derivations} procedure (@pxref{The Store}).
@deffn {Scheme Procedure} package-derivation @var{store} @var{package} [@var{system}] @deffn {Scheme Procedure} package-derivation @var{store} @var{package} [@var{system}]
Return the derivation of @var{package} for @var{system}. The result is Return the derivation path and corresponding @code{<derivation>} object
the file name of the derivation---i.e., a @code{.drv} file under of @var{package} for @var{system} (@pxref{Derivations}).
@code{/nix/store}.
@var{package} must be a valid @code{<package>} object, and @var{system} @var{package} must be a valid @code{<package>} object, and @var{system}
must be a string denoting the target system type---e.g., must be a string denoting the target system type---e.g.,

View File

@ -217,25 +217,34 @@ recursively."
;; Package to derivation-path mapping. ;; Package to derivation-path mapping.
(make-weak-key-hash-table 100)) (make-weak-key-hash-table 100))
(define (cache package system drv) (define (cache package system thunk)
"Memoize DRV as the derivation of PACKAGE on SYSTEM." "Memoize the return values of THUNK as the derivation of PACKAGE on
SYSTEM."
(let ((vals (call-with-values thunk list)))
;; Use `hashq-set!' instead of `hash-set!' because `hash' returns the
;; same value for all structs (as of Guile 2.0.6), and because pointer
;; equality is sufficient in practice.
(hashq-set! %derivation-cache package `((,system ,@vals)))
(apply values vals)))
;; Use `hashq-set!' instead of `hash-set!' because `hash' returns the (define-syntax-rule (cached package system body ...)
;; same value for all structs (as of Guile 2.0.6), and because pointer "Memoize the result of BODY for the arguments PACKAGE and SYSTEM.
;; equality is sufficient in practice. Return the cached result when available."
(hashq-set! %derivation-cache package `((,system . ,drv))) (let ((thunk (lambda () body ...)))
drv) (match (hashq-ref %derivation-cache package)
((alist (... ...))
(define (cached-derivation package system) (match (assoc-ref alist system)
"Return the cached derivation path of PACKAGE for SYSTEM, or #f." ((vals (... ...))
(match (hashq-ref %derivation-cache package) (apply values vals))
((alist ...) (#f
(assoc-ref alist system)) (cache package system thunk))))
(#f #f))) (#f
(cache package system thunk)))))
(define* (package-derivation store package (define* (package-derivation store package
#:optional (system (%current-system))) #:optional (system (%current-system)))
"Return the derivation of PACKAGE for SYSTEM." "Return the derivation path and corresponding <derivation> object of
PACKAGE for SYSTEM."
(define (intern file) (define (intern file)
;; Add FILE to the store. Set the `recursive?' bit to #t, so that ;; Add FILE to the store. Set the `recursive?' bit to #t, so that
;; file permissions are preserved. ;; file permissions are preserved.
@ -281,32 +290,28 @@ recursively."
(package package) (package package)
(input x))))))) (input x)))))))
(or (cached-derivation package system) ;; Compute the derivation and cache the result. Caching is important
;; because some derivations, such as the implicit inputs of the GNU build
;; system, will be queried many, many times in a row.
(cached package system
(match package
(($ <package> name version source (= build-system-builder builder)
args inputs propagated-inputs native-inputs self-native-input?
outputs)
;; TODO: For `search-paths', add a builder prologue that calls
;; `set-path-environment-variable'.
(let ((inputs (map expand-input
(package-transitive-inputs package))))
;; Compute the derivation and cache the result. Caching is (apply builder
;; important because some derivations, such as the implicit inputs store (package-full-name package)
;; of the GNU build system, will be queried many, many times in a (and source
;; row. (package-source-derivation store source system))
(cache inputs
package system #:outputs outputs #:system system
(match package (if (procedure? args)
(($ <package> name version source (= build-system-builder builder) (args system)
args inputs propagated-inputs native-inputs self-native-input? args)))))))
outputs)
;; TODO: For `search-paths', add a builder prologue that calls
;; `set-path-environment-variable'.
(let ((inputs (map expand-input
(package-transitive-inputs package))))
(apply builder
store (package-full-name package)
(and source
(package-source-derivation store source system))
inputs
#:outputs outputs #:system system
(if (procedure? args)
(args system)
args))))))))
(define* (package-cross-derivation store package) (define* (package-cross-derivation store package)
;; TODO ;; TODO

View File

@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2012 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -27,6 +27,7 @@
#:use-module (gnu packages) #:use-module (gnu packages)
#:use-module (gnu packages base) #:use-module (gnu packages base)
#:use-module (gnu packages bootstrap) #:use-module (gnu packages bootstrap)
#:use-module (srfi srfi-11)
#:use-module (srfi srfi-26) #:use-module (srfi srfi-26)
#:use-module (srfi srfi-64) #:use-module (srfi srfi-64)
#:use-module (rnrs io ports) #:use-module (rnrs io ports)
@ -70,7 +71,13 @@
("d" ,d) ("d/x" "something.drv")) ("d" ,d) ("d/x" "something.drv"))
(pk 'x (package-transitive-inputs e)))))) (pk 'x (package-transitive-inputs e))))))
(test-skip (if (not %store) 2 0)) (test-skip (if (not %store) 3 0))
(test-assert "return values"
(let-values (((drv-path drv)
(package-derivation %store (dummy-package "p"))))
(and (derivation-path? drv-path)
(derivation? drv))))
(test-assert "trivial" (test-assert "trivial"
(let* ((p (package (inherit (dummy-package "trivial")) (let* ((p (package (inherit (dummy-package "trivial"))