Archived
1
0
Fork 0

packages: 'package-mapping' can recurse on implicit inputs.

* guix/packages.scm (build-system-with-package-mapping): New procedure.
(package-mapping): Add #:deep? and honor it.
* tests/packages.scm ("package-mapping"): Compare the direct inputs of
the bag of P0 and that of P1.
("package-mapping, deep"): New test.
This commit is contained in:
Ludovic Courtès 2020-09-21 17:44:29 +02:00
parent f458cfbcc5
commit ff39361c80
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
3 changed files with 88 additions and 18 deletions

View file

@ -6296,10 +6296,11 @@ A more generic procedure to rewrite a package dependency graph is
@code{package-mapping}: it supports arbitrary changes to nodes in the @code{package-mapping}: it supports arbitrary changes to nodes in the
graph. graph.
@deffn {Scheme Procedure} package-mapping @var{proc} [@var{cut?}] @deffn {Scheme Procedure} package-mapping @var{proc} [@var{cut?}] [#:deep? #f]
Return a procedure that, given a package, applies @var{proc} to all the packages Return a procedure that, given a package, applies @var{proc} to all the packages
depended on and returns the resulting package. The procedure stops recursion depended on and returns the resulting package. The procedure stops recursion
when @var{cut?} returns true for a given package. when @var{cut?} returns true for a given package. When @var{deep?} is true, @var{proc} is
applied to implicit inputs as well.
@end deffn @end deffn
@menu @menu

View file

@ -968,10 +968,31 @@ packages they depend on, recursively."
(vhash-consq package #t visited) (vhash-consq package #t visited)
(fold set-insert closure dependencies)))))))) (fold set-insert closure dependencies))))))))
(define* (package-mapping proc #:optional (cut? (const #f))) (define (build-system-with-package-mapping bs rewrite)
"Return a variant of BS, a build system, that rewrites a bag's inputs by
passing them through REWRITE, a procedure that takes an input tuplet and
returns a \"rewritten\" input tuplet."
(define lower
(build-system-lower bs))
(define (lower* . args)
(let ((lowered (apply lower args)))
(bag
(inherit lowered)
(build-inputs (map rewrite (bag-build-inputs lowered)))
(host-inputs (map rewrite (bag-host-inputs lowered)))
(target-inputs (map rewrite (bag-target-inputs lowered))))))
(build-system
(inherit bs)
(lower lower*)))
(define* (package-mapping proc #:optional (cut? (const #f))
#:key deep?)
"Return a procedure that, given a package, applies PROC to all the packages "Return a procedure that, given a package, applies PROC to all the packages
depended on and returns the resulting package. The procedure stops recursion depended on and returns the resulting package. The procedure stops recursion
when CUT? returns true for a given package." when CUT? returns true for a given package. When DEEP? is true, PROC is
applied to implicit inputs as well."
(define (rewrite input) (define (rewrite input)
(match input (match input
((label (? package? package) outputs ...) ((label (? package? package) outputs ...)
@ -980,21 +1001,35 @@ when CUT? returns true for a given package."
(_ (_
input))) input)))
(define mapping-property
;; Property indicating whether the package has already been processed.
(gensym " package-mapping-done"))
(define replace (define replace
(mlambdaq (p) (mlambdaq (p)
;; If P is the result of a previous call, return it.
(if (assq-ref (package-properties p) mapping-property)
p
;; Return a variant of P with PROC applied to P and its explicit ;; Return a variant of P with PROC applied to P and its explicit
;; dependencies, recursively. Memoize the transformations. Failing to ;; dependencies, recursively. Memoize the transformations. Failing
;; do that, we would build a huge object graph with lots of duplicates, ;; to do that, we would build a huge object graph with lots of
;; which in turns prevents us from benefiting from memoization in ;; duplicates, which in turns prevents us from benefiting from
;; 'package-derivation'. ;; memoization in 'package-derivation'.
(let ((p (proc p))) (let ((p (proc p)))
(package (package
(inherit p) (inherit p)
(location (package-location p)) (location (package-location p))
(build-system (if deep?
(build-system-with-package-mapping
(package-build-system p) rewrite)
(package-build-system p)))
(inputs (map rewrite (package-inputs p))) (inputs (map rewrite (package-inputs p)))
(native-inputs (map rewrite (package-native-inputs p))) (native-inputs (map rewrite (package-native-inputs p)))
(propagated-inputs (map rewrite (package-propagated-inputs p))) (propagated-inputs (map rewrite (package-propagated-inputs p)))
(replacement (and=> (package-replacement p) proc)))))) (replacement (and=> (package-replacement p) proc))
(properties `((,mapping-property . #t)
,@(package-properties p))))))))
replace) replace)

View file

@ -1172,15 +1172,24 @@
(let* ((dep (dummy-package "chbouib" (let* ((dep (dummy-package "chbouib"
(native-inputs `(("x" ,grep))))) (native-inputs `(("x" ,grep)))))
(p0 (dummy-package "example" (p0 (dummy-package "example"
(source 77)
(inputs `(("foo" ,coreutils) (inputs `(("foo" ,coreutils)
("bar" ,grep) ("bar" ,grep)
("baz" ,dep))))) ("baz" ,dep)))))
(transform (lambda (p) (transform (lambda (p)
(package (inherit p) (source 42)))) (package (inherit p) (source 42))))
(rewrite (package-mapping transform)) (rewrite (package-mapping transform))
(p1 (rewrite p0))) (p1 (rewrite p0))
(bag0 (package->bag p0))
(bag1 (package->bag p1)))
(and (eq? p1 (rewrite p0)) (and (eq? p1 (rewrite p0))
(eqv? 42 (package-source p1)) (eqv? 42 (package-source p1))
;; Implicit inputs should be left unchanged (skip "source", "foo",
;; "bar", and "baz" in this comparison).
(equal? (drop (bag-direct-inputs bag0) 4)
(drop (bag-direct-inputs bag1) 4))
(match (package-inputs p1) (match (package-inputs p1)
((("foo" dep1) ("bar" dep2) ("baz" dep3)) ((("foo" dep1) ("bar" dep2) ("baz" dep3))
(and (eq? dep1 (rewrite coreutils)) ;memoization (and (eq? dep1 (rewrite coreutils)) ;memoization
@ -1194,6 +1203,31 @@
(and (eq? dep (rewrite grep)) (and (eq? dep (rewrite grep))
(package-source dep)))))))))) (package-source dep))))))))))
(test-equal "package-mapping, deep"
'(42)
(let* ((p0 (dummy-package "example"
(inputs `(("foo" ,coreutils)
("bar" ,grep)))))
(transform (lambda (p)
(package (inherit p) (source 42))))
(rewrite (package-mapping transform #:deep? #t))
(p1 (rewrite p0))
(bag (package->bag p1)))
(and (eq? p1 (rewrite p0))
(match (bag-direct-inputs bag)
((("source" 42) ("foo" dep1) ("bar" dep2) rest ..1)
(and (eq? dep1 (rewrite coreutils)) ;memoization
(eq? dep2 (rewrite grep))
(= 42 (package-source dep1))
(= 42 (package-source dep2))
;; Check that implicit inputs of P0 also got rewritten.
(delete-duplicates
(map (match-lambda
((_ package . _)
(package-source package)))
rest))))))))
(test-assert "package-input-rewriting" (test-assert "package-input-rewriting"
(let* ((dep (dummy-package "chbouib" (let* ((dep (dummy-package "chbouib"
(native-inputs `(("x" ,grep))))) (native-inputs `(("x" ,grep)))))