summary refs log tree commit diff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2017-06-28 21:57:16 +0200
committerLudovic Courtès <ludo@gnu.org>2021-03-30 22:48:43 +0200
commit9e5812ac59b01ff011ec0c5b0f437dfe85d6fcc7 (patch)
tree890de746df1cb8896304b15bfeb4bfbc5373d687
parent37c32caf2cd21c8b7ca764c262efc7be49f26c86 (diff)
downloadguix-9e5812ac59b01ff011ec0c5b0f437dfe85d6fcc7.tar.gz
packages: Core procedures are written in monadic style.
This plays better with the functional object cache, which is no longer
lost across calls to procedures created by 'store-lift'.

* guix/packages.scm (input-graft, input-cross-graft): Remove 'store'
parameter.  Return a monadic procedure.
(bag-grafts): Remove 'store' parameter and turn into a monadic
procedure.
(graft-derivation*): New procedure.
(cached): Remove clause to match syntax without (=> CACHE).
(package-grafts): Define using 'store-lower'.
(package-grafts*): New procedure, from former 'package-grafts'.  Remove
'store' parameter and turn into a monadic procedure.
(package->derivation): Rewrite using 'mcached' and a monadic variant of
the former 'package-derivation' procedure.
(package->cross-derivation): Likewise.
(package-derivation, package-cross-derivation): Rewrite in terms of
'store-lower'.
(%graft-cache): Remove.
-rw-r--r--guix/packages.scm254
1 files changed, 136 insertions, 118 deletions
diff --git a/guix/packages.scm b/guix/packages.scm
index 1b2728f033..36e55c0a42 100644
--- a/guix/packages.scm
+++ b/guix/packages.scm
@@ -1199,9 +1199,7 @@ Return the cached result when available."
             (#f (cache! cache package key thunk))
             (value value)))
          (#f
-          (cache! cache package key thunk)))))
-    ((_ package system body ...)
-     (cached (=> %derivation-cache) package system body ...))))
+          (cache! cache package key thunk)))))))
 
 (define* (expand-input package input #:key native?)
   "Expand INPUT, an input tuple, to a name/<gexp-input> tuple.  PACKAGE is
@@ -1277,45 +1275,51 @@ and return it."
                                  (&package-error
                                   (package package))))))))))))
 
-(define %graft-cache
-  ;; 'eq?' cache mapping package objects to a graft corresponding to their
-  ;; replacement package.
-  (make-weak-key-hash-table 200))
+(define (input-graft system)
+  "Return a monadic procedure that, given a package with a graft, returns a
+graft, and #f otherwise."
+  (with-monad %store-monad
+    (match-lambda*
+      (((? package? package) output)
+       (let ((replacement (package-replacement package)))
+         (if replacement
+             ;; XXX: We should use a separate cache instead of abusing the
+             ;; object cache.
+             (mcached (mlet %store-monad ((orig (package->derivation package system
+                                                                     #:graft? #f))
+                                          (new  (package->derivation replacement system
+                                                                     #:graft? #t)))
+                        (return (graft
+                                  (origin orig)
+                                  (origin-output output)
+                                  (replacement new)
+                                  (replacement-output output))))
+                      package 'graft output system)
+             (return #f))))
+      (_
+       (return #f)))))
 
-(define (input-graft store system)
-  "Return a procedure that, given a package with a replacement and an output name,
-returns a graft, and #f otherwise."
-  (match-lambda*
-    (((? package? package) output)
-     (let ((replacement (package-replacement package)))
-       (and replacement
-            (cached (=> %graft-cache) package (cons output system)
-                    (let ((orig (package-derivation store package system
-                                                    #:graft? #f))
-                          (new  (package-derivation store replacement system
-                                                    #:graft? #t)))
-                      (graft
-                        (origin orig)
-                        (origin-output output)
-                        (replacement new)
-                        (replacement-output output)))))))))
-
-(define (input-cross-graft store target system)
+(define (input-cross-graft target system)
   "Same as 'input-graft', but for cross-compilation inputs."
-  (match-lambda*
-    (((? package? package) output)
-     (let ((replacement (package-replacement package)))
-       (and replacement
-            (let ((orig (package-cross-derivation store package target system
-                                                  #:graft? #f))
-                  (new  (package-cross-derivation store replacement
-                                                  target system
-                                                  #:graft? #t)))
-              (graft
-                (origin orig)
-                (origin-output output)
-                (replacement new)
-                (replacement-output output))))))))
+  (with-monad %store-monad
+    (match-lambda*
+      (((? package? package) output)
+       (let ((replacement (package-replacement package)))
+         (if replacement
+             (mlet %store-monad ((orig (package->cross-derivation package
+                                                                  target system
+                                                                  #:graft? #f))
+                                 (new  (package->cross-derivation replacement
+                                                                  target system
+                                                                  #:graft? #t)))
+               (return (graft
+                         (origin orig)
+                         (origin-output output)
+                         (replacement new)
+                         (replacement-output output))))
+             (return #f))))
+      (_
+       (return #f)))))
 
 (define* (fold-bag-dependencies proc seed bag
                                 #:key (native? #t))
@@ -1350,7 +1354,7 @@ dependencies; otherwise, restrict to target dependencies."
       ((head . tail)
        (loop tail result visited)))))
 
-(define* (bag-grafts store bag)
+(define* (bag-grafts bag)
   "Return the list of grafts potentially applicable to BAG.  Potentially
 applicable grafts are collected by looking at direct or indirect dependencies
 of BAG that have a 'replacement'.  Whether a graft is actually applicable
@@ -1359,46 +1363,55 @@ to (see 'graft-derivation'.)"
   (define system (bag-system bag))
   (define target (bag-target bag))
 
-  (define native-grafts
-    (let ((->graft (input-graft store system)))
-      (parameterize ((%current-system system)
-                     (%current-target-system #f))
-        (fold-bag-dependencies (lambda (package output grafts)
-                                 (match (->graft package output)
-                                   (#f    grafts)
-                                   (graft (cons graft grafts))))
-                               '()
-                               bag))))
-
-  (define target-grafts
-    (if target
-        (let ((->graft (input-cross-graft store target system)))
+  (mlet %store-monad
+      ((native-grafts
+        (let ((->graft (input-graft system)))
           (parameterize ((%current-system system)
-                         (%current-target-system target))
+                         (%current-target-system #f))
             (fold-bag-dependencies (lambda (package output grafts)
-                                     (match (->graft package output)
-                                       (#f    grafts)
-                                       (graft (cons graft grafts))))
-                                   '()
-                                   bag
-                                   #:native? #f)))
-        '()))
-
-  ;; We can end up with several identical grafts if we stumble upon packages
-  ;; that are not 'eq?' but map to the same derivation (this can happen when
-  ;; using things like 'package-with-explicit-inputs'.)  Hence the
-  ;; 'delete-duplicates' call.
-  (delete-duplicates
-   (append native-grafts target-grafts)))
-
-(define* (package-grafts store package
-                         #:optional (system (%current-system))
-                         #:key target)
+                                     (mlet %store-monad ((grafts grafts))
+                                       (>>= (->graft package output)
+                                            (match-lambda
+                                              (#f    (return grafts))
+                                              (graft (return (cons graft grafts)))))))
+                                   (return '())
+                                   bag))))
+
+       (target-grafts
+        (if target
+            (let ((->graft (input-cross-graft target system)))
+              (parameterize ((%current-system system)
+                             (%current-target-system target))
+                (fold-bag-dependencies
+                 (lambda (package output grafts)
+                   (mlet %store-monad ((grafts grafts))
+                     (>>= (->graft package output)
+                          (match-lambda
+                            (#f    (return grafts))
+                            (graft (return (cons graft grafts)))))))
+                 (return '())
+                 bag
+                 #:native? #f)))
+            (return '()))))
+
+    ;; We can end up with several identical grafts if we stumble upon packages
+    ;; that are not 'eq?' but map to the same derivation (this can happen when
+    ;; using things like 'package-with-explicit-inputs'.)  Hence the
+    ;; 'delete-duplicates' call.
+    (return (delete-duplicates
+             (append native-grafts target-grafts)))))
+
+(define* (package-grafts* package
+                          #:optional (system (%current-system))
+                          #:key target)
   "Return the list of grafts applicable to PACKAGE as built for SYSTEM and
 TARGET."
   (let* ((package (or (package-replacement package) package))
          (bag     (package->bag package system target)))
-    (bag-grafts store bag)))
+    (bag-grafts bag)))
+
+(define package-grafts
+  (store-lower package-grafts*))
 
 (define-inlinable (derivation=? drv1 drv2)
   "Return true if DRV1 and DRV2 are equal."
@@ -1438,7 +1451,6 @@ error reporting."
         ;; It's possible that INPUTS contains packages that are not 'eq?' but
         ;; that lead to the same derivation.  Delete those duplicates to avoid
         ;; issues down the road, such as duplicate entries in '%build-inputs'.
-        ;; TODO: Change to monadic style.
         (apply (bag-build bag) (bag-name bag)
                (delete-duplicates input-drvs input=?)
                #:search-paths paths
@@ -1488,51 +1500,57 @@ This is an internal procedure."
 (define bag->derivation*
   (store-lower bag->derivation))
 
-(define* (package-derivation store package
-                             #:optional (system (%current-system))
-                             #:key (graft? (%graft?)))
+(define graft-derivation*
+  (store-lift graft-derivation))
+
+(define* (package->derivation package
+                              #:optional (system (%current-system))
+                              #:key (graft? (%graft?)))
   "Return the <derivation> object of PACKAGE for 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 (cons system graft?)
-          (let* ((bag (package->bag package system #f #:graft? graft?))
-                 (drv (bag->derivation* store bag package)))
-            (if graft?
-                (match (bag-grafts store bag)
-                  (()
-                   drv)
-                  (grafts
-                   (let ((guile (package-derivation store (guile-for-grafts)
-                                                    system #:graft? #f)))
-                     ;; TODO: As an optimization, we can simply graft the tip
-                     ;; of the derivation graph since 'graft-derivation'
-                     ;; recurses anyway.
-                     (graft-derivation store drv grafts
-                                       #:system system
-                                       #:guile guile))))
-                drv))))
-
-(define* (package-cross-derivation store package target
-                                   #:optional (system (%current-system))
-                                   #:key (graft? (%graft?)))
+  (mcached (mlet* %store-monad ((bag -> (package->bag package system #f
+                                                      #:graft? graft?))
+                                (drv (bag->derivation bag package)))
+             (if graft?
+                 (>>= (bag-grafts bag)
+                      (match-lambda
+                        (()
+                         (return drv))
+                        (grafts
+                         (mlet %store-monad ((guile (package->derivation
+                                                     (default-guile)
+                                                     system #:graft? #f)))
+                           (graft-derivation* drv grafts
+                                              #:system system
+                                              #:guile guile)))))
+                 (return drv)))
+           package system #f graft?))
+
+(define* (package->cross-derivation package target
+                                    #:optional (system (%current-system))
+                                    #:key (graft? (%graft?)))
   "Cross-build PACKAGE for TARGET (a GNU triplet) from host SYSTEM (a Guix
 system identifying string)."
-  (cached package (list system target graft?)
-          (let* ((bag (package->bag package system target #:graft? graft?))
-                 (drv (bag->derivation* store bag package)))
-            (if graft?
-                (match (bag-grafts store bag)
-                  (()
-                   drv)
-                  (grafts
-                   (graft-derivation store drv grafts
-                                     #:system system
-                                     #:guile
-                                     (package-derivation store (guile-for-grafts)
-                                                         system #:graft? #f))))
-                drv))))
+  (mcached (mlet* %store-monad ((bag -> (package->bag package system target
+                                                      #:graft? graft?))
+                                (drv (bag->derivation bag package)))
+             (if graft?
+                 (>>= (bag-grafts bag)
+                      (match-lambda
+                        (()
+                         (return drv))
+                        (grafts
+                         (mlet %store-monad ((guile (package->derivation
+                                                     (default-guile)
+                                                     system #:graft? #f)))
+                           (graft-derivation* drv grafts
+                                              #:system system
+                                              #:guile guile)))))
+                 (return drv)))
+           package system target graft?))
 
 (define* (package-output store package
                          #:optional (output "out") (system (%current-system)))
@@ -1580,11 +1598,11 @@ unless you know what you are doing."
                   out)
               store))))
 
-(define package->derivation
-  (store-lift package-derivation))
+(define package-derivation
+  (store-lower package->derivation))
 
-(define package->cross-derivation
-  (store-lift package-cross-derivation))
+(define package-cross-derivation
+  (store-lower package->cross-derivation))
 
 (define-gexp-compiler (package-compiler (package <package>) system target)
   ;; Compile PACKAGE to a derivation for SYSTEM, optionally cross-compiled for