diff options
| author | David Elsing <david.elsing@posteo.net> | 2025-03-04 20:33:08 +0000 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2025-03-05 00:28:49 +0100 |
| commit | 30e51cb6b42e86f9f94d6380f69a1020ee99ff39 (patch) | |
| tree | 6bcf2847774381f7c3a102c1a0ae143ee97d9879 | |
| parent | 749eb1a2dd9fdf63a71f223b3f6756d9cb5940e6 (diff) | |
gexp: ‘with-parameters’ properly handles ‘%graft?’.
Fixes <https://issues.guix.gnu.org/75879>.
* .dir-locals.el (scheme-mode): Remove mparameterize indentation rules.
Add state-parameterize and store-parameterize indentation rules.
* etc/manifests/system-tests.scm (test-for-current-guix): Replace
mparameterize with store-parameterize.
* etc/manifests/time-travel.scm (guix-instance-compiler): Likewise.
* gnu/tests.scm (compile-system-test): Likewise.
* guix/gexp.scm (compile-parameterized): Use state-call-with-parameters.
* guix/monads.scm (mparameterize): Remove macro.
(state-call-with-parameters): New procedure.
(state-parameterize): New macro.
* guix/store.scm (store-parameterize): New macro.
* tests/gexp.scm ("with-parameters for %graft?"): New test.
* tests/monads.scm ("mparameterize"): Remove test.
("state-parameterize"): New test.
Co-authored-by: Ludovic Courtès <ludo@gnu.org>
Change-Id: I0c74066ca3f37072815b073fb3039925488a9645
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
| -rw-r--r-- | .dir-locals.el | 3 | ||||
| -rw-r--r-- | etc/manifests/system-tests.scm | 2 | ||||
| -rw-r--r-- | etc/manifests/time-travel.scm | 8 | ||||
| -rw-r--r-- | gnu/tests.scm | 8 | ||||
| -rw-r--r-- | guix/gexp.scm | 42 | ||||
| -rw-r--r-- | guix/monads.scm | 68 | ||||
| -rw-r--r-- | guix/store.scm | 2 | ||||
| -rw-r--r-- | tests/gexp.scm | 20 | ||||
| -rw-r--r-- | tests/monads.scm | 20 |
9 files changed, 114 insertions, 59 deletions
diff --git a/.dir-locals.el b/.dir-locals.el index d629b51c8a1..76c9e12992a 100644 --- a/.dir-locals.el +++ b/.dir-locals.el | |||
| @@ -138,7 +138,8 @@ | |||
| 138 | (eval . (put 'munless 'scheme-indent-function 1)) | 138 | (eval . (put 'munless 'scheme-indent-function 1)) |
| 139 | (eval . (put 'mlet* 'scheme-indent-function 2)) | 139 | (eval . (put 'mlet* 'scheme-indent-function 2)) |
| 140 | (eval . (put 'mlet 'scheme-indent-function 2)) | 140 | (eval . (put 'mlet 'scheme-indent-function 2)) |
| 141 | (eval . (put 'mparameterize 'scheme-indent-function 2)) | 141 | (eval . (put 'state-parameterize 'scheme-indent-function 2)) |
| 142 | (eval . (put 'store-parameterize 'scheme-indent-function 2)) | ||
| 142 | (eval . (put 'run-with-store 'scheme-indent-function 1)) | 143 | (eval . (put 'run-with-store 'scheme-indent-function 1)) |
| 143 | (eval . (put 'run-with-state 'scheme-indent-function 1)) | 144 | (eval . (put 'run-with-state 'scheme-indent-function 1)) |
| 144 | (eval . (put 'wrap-program 'scheme-indent-function 1)) | 145 | (eval . (put 'wrap-program 'scheme-indent-function 1)) |
diff --git a/etc/manifests/system-tests.scm b/etc/manifests/system-tests.scm index 4e16c53dcfc..430f5075207 100644 --- a/etc/manifests/system-tests.scm +++ b/etc/manifests/system-tests.scm | |||
| @@ -53,7 +53,7 @@ instance." | |||
| 53 | (map (lambda (test) | 53 | (map (lambda (test) |
| 54 | (system-test | 54 | (system-test |
| 55 | (inherit test) | 55 | (inherit test) |
| 56 | (value (mparameterize %store-monad ((current-guix-package guix)) | 56 | (value (store-parameterize ((current-guix-package guix)) |
| 57 | (system-test-value test))))) | 57 | (system-test-value test))))) |
| 58 | (match (getenv "TESTS") | 58 | (match (getenv "TESTS") |
| 59 | (#f | 59 | (#f |
diff --git a/etc/manifests/time-travel.scm b/etc/manifests/time-travel.scm index 039ca89889d..5256d2195c2 100644 --- a/etc/manifests/time-travel.scm +++ b/etc/manifests/time-travel.scm | |||
| @@ -22,7 +22,7 @@ | |||
| 22 | (use-modules (srfi srfi-9) (ice-9 match) | 22 | (use-modules (srfi srfi-9) (ice-9 match) |
| 23 | (guix channels) (guix gexp) | 23 | (guix channels) (guix gexp) |
| 24 | ((guix store) #:select (%store-monad)) | 24 | ((guix store) #:select (%store-monad)) |
| 25 | ((guix monads) #:select (mparameterize return)) | 25 | ((guix monads) #:select (store-parameterize return)) |
| 26 | ((guix git) #:select (%repository-cache-directory)) | 26 | ((guix git) #:select (%repository-cache-directory)) |
| 27 | ((guix build utils) #:select (mkdir-p))) | 27 | ((guix build utils) #:select (mkdir-p))) |
| 28 | 28 | ||
| @@ -40,9 +40,9 @@ | |||
| 40 | ;; When this manifest is evaluated by Cuirass, make sure it does not | 40 | ;; When this manifest is evaluated by Cuirass, make sure it does not |
| 41 | ;; fiddle with the cached checkout that Cuirass is also using since | 41 | ;; fiddle with the cached checkout that Cuirass is also using since |
| 42 | ;; concurrent accesses are unsafe. | 42 | ;; concurrent accesses are unsafe. |
| 43 | (mparameterize %store-monad ((%repository-cache-directory | 43 | (store-parameterize ((%repository-cache-directory |
| 44 | (string-append (%repository-cache-directory) | 44 | (string-append (%repository-cache-directory) |
| 45 | "/time-travel/" system))) | 45 | "/time-travel/" system))) |
| 46 | (return (mkdir-p (%repository-cache-directory))) | 46 | (return (mkdir-p (%repository-cache-directory))) |
| 47 | (latest-channel-derivation channels))))) | 47 | (latest-channel-derivation channels))))) |
| 48 | 48 | ||
diff --git a/gnu/tests.scm b/gnu/tests.scm index 2a9e51511f0..1e3dbf09445 100644 --- a/gnu/tests.scm +++ b/gnu/tests.scm | |||
| @@ -34,7 +34,7 @@ | |||
| 34 | #:use-module (gnu services shepherd) | 34 | #:use-module (gnu services shepherd) |
| 35 | #:use-module (guix discovery) | 35 | #:use-module (guix discovery) |
| 36 | #:use-module (guix monads) | 36 | #:use-module (guix monads) |
| 37 | #:use-module ((guix store) #:select (%store-monad)) | 37 | #:use-module ((guix store) #:select (%store-monad store-parameterize)) |
| 38 | #:use-module ((guix utils) | 38 | #:use-module ((guix utils) |
| 39 | #:select (%current-system %current-target-system)) | 39 | #:select (%current-system %current-target-system)) |
| 40 | #:use-module (srfi srfi-1) | 40 | #:use-module (srfi srfi-1) |
| @@ -289,9 +289,9 @@ the system under test." | |||
| 289 | (define-gexp-compiler (compile-system-test (test <system-test>) | 289 | (define-gexp-compiler (compile-system-test (test <system-test>) |
| 290 | system target) | 290 | system target) |
| 291 | "Compile TEST to a derivation." | 291 | "Compile TEST to a derivation." |
| 292 | (mparameterize %store-monad ((%current-system system) | 292 | (store-parameterize ((%current-system system) |
| 293 | (%current-target-system target)) | 293 | (%current-target-system target)) |
| 294 | (system-test-value test))) | 294 | (system-test-value test))) |
| 295 | 295 | ||
| 296 | (define (test-modules) | 296 | (define (test-modules) |
| 297 | "Return the list of modules that define system tests." | 297 | "Return the list of modules that define system tests." |
diff --git a/guix/gexp.scm b/guix/gexp.scm index ad51bc55b78..9ce6810172b 100644 --- a/guix/gexp.scm +++ b/guix/gexp.scm | |||
| @@ -733,26 +733,28 @@ x86_64-linux when COREUTILS is lowered." | |||
| 733 | (lambda (parameterized system target) | 733 | (lambda (parameterized system target) |
| 734 | (match (parameterized-bindings parameterized) | 734 | (match (parameterized-bindings parameterized) |
| 735 | (((parameters values) ...) | 735 | (((parameters values) ...) |
| 736 | (let ((fluids (map parameter-fluid parameters)) | 736 | (let ((thunk (parameterized-thunk parameterized)) |
| 737 | (thunk (parameterized-thunk parameterized))) | 737 | (values (map (lambda (thunk) (thunk)) values))) |
| 738 | ;; Install the PARAMETERS for the dynamic extent of THUNK. | 738 | ;; Install the PARAMETERS for the store monad. |
| 739 | (with-fluids* fluids | 739 | (state-with-parameters parameters values |
| 740 | (map (lambda (thunk) (thunk)) values) | 740 | ;; Install the PARAMETERS for the dynamic extent of THUNK. |
| 741 | (lambda () | 741 | ;; Special-case '%current-system' and '%current-target-system' to |
| 742 | ;; Special-case '%current-system' and '%current-target-system' to | 742 | ;; make sure we get the desired effect. |
| 743 | ;; make sure we get the desired effect. | 743 | (with-fluids* (map parameter-fluid parameters) |
| 744 | (let ((system (if (memq %current-system parameters) | 744 | values |
| 745 | (%current-system) | 745 | (lambda () |
| 746 | system)) | 746 | (let ((system (if (memq %current-system parameters) |
| 747 | (target (if (memq %current-target-system parameters) | 747 | (%current-system) |
| 748 | (%current-target-system) | 748 | system)) |
| 749 | target))) | 749 | (target (if (memq %current-target-system parameters) |
| 750 | (match (thunk) | 750 | (%current-target-system) |
| 751 | ((? struct? obj) | 751 | target))) |
| 752 | (lower-object obj system #:target target)) | 752 | (match (thunk) |
| 753 | (obj ;store item | 753 | ((? struct? obj) |
| 754 | (with-monad %store-monad | 754 | (lower-object obj system #:target target)) |
| 755 | (return obj))))))))))) | 755 | (obj ;store item |
| 756 | (with-monad %store-monad | ||
| 757 | (return obj)))))))))))) | ||
| 756 | 758 | ||
| 757 | expander => (lambda (parameterized lowered output) | 759 | expander => (lambda (parameterized lowered output) |
| 758 | (match (parameterized-bindings parameterized) | 760 | (match (parameterized-bindings parameterized) |
diff --git a/guix/monads.scm b/guix/monads.scm index 0bd8ac9315d..e1b056dc95f 100644 --- a/guix/monads.scm +++ b/guix/monads.scm | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2013, 2014, 2015, 2017, 2022 Ludovic Courtès <ludo@gnu.org> | 2 | ;;; Copyright © 2013-2015, 2017, 2022, 2025 Ludovic Courtès <ludo@gnu.org> |
| 3 | ;;; Copyright © 2025 David Elsing <david.elsing@posteo.net> | ||
| 3 | ;;; | 4 | ;;; |
| 4 | ;;; This file is part of GNU Guix. | 5 | ;;; This file is part of GNU Guix. |
| 5 | ;;; | 6 | ;;; |
| @@ -19,6 +20,7 @@ | |||
| 19 | (define-module (guix monads) | 20 | (define-module (guix monads) |
| 20 | #:use-module ((system syntax) | 21 | #:use-module ((system syntax) |
| 21 | #:select (syntax-local-binding)) | 22 | #:select (syntax-local-binding)) |
| 23 | #:autoload (guix deprecation) (warn-about-deprecation) | ||
| 22 | #:use-module (ice-9 match) | 24 | #:use-module (ice-9 match) |
| 23 | #:use-module (srfi srfi-1) | 25 | #:use-module (srfi srfi-1) |
| 24 | #:use-module (srfi srfi-9) | 26 | #:use-module (srfi srfi-9) |
| @@ -40,7 +42,6 @@ | |||
| 40 | mbegin | 42 | mbegin |
| 41 | mwhen | 43 | mwhen |
| 42 | munless | 44 | munless |
| 43 | mparameterize | ||
| 44 | lift0 lift1 lift2 lift3 lift4 lift5 lift6 lift7 lift | 45 | lift0 lift1 lift2 lift3 lift4 lift5 lift6 lift7 lift |
| 45 | listm | 46 | listm |
| 46 | foldm | 47 | foldm |
| @@ -58,7 +59,9 @@ | |||
| 58 | set-current-state | 59 | set-current-state |
| 59 | state-push | 60 | state-push |
| 60 | state-pop | 61 | state-pop |
| 61 | run-with-state)) | 62 | run-with-state |
| 63 | state-parameterize | ||
| 64 | mparameterize)) | ||
| 62 | 65 | ||
| 63 | ;;; Commentary: | 66 | ;;; Commentary: |
| 64 | ;;; | 67 | ;;; |
| @@ -399,21 +402,6 @@ expression." | |||
| 399 | (mbegin %current-monad | 402 | (mbegin %current-monad |
| 400 | mexp0 mexp* ...))))) | 403 | mexp0 mexp* ...))))) |
| 401 | 404 | ||
| 402 | (define-syntax mparameterize | ||
| 403 | (syntax-rules () | ||
| 404 | "This form implements dynamic scoping, similar to 'parameterize', but in a | ||
| 405 | monadic context." | ||
| 406 | ((_ monad ((parameter value) rest ...) body ...) | ||
| 407 | (let ((old-value (parameter))) | ||
| 408 | (mbegin monad | ||
| 409 | ;; XXX: Non-local exits are not correctly handled. | ||
| 410 | (return (parameter value)) | ||
| 411 | (mlet monad ((result (mparameterize monad (rest ...) body ...))) | ||
| 412 | (parameter old-value) | ||
| 413 | (return result))))) | ||
| 414 | ((_ monad () body ...) | ||
| 415 | (mbegin monad body ...)))) | ||
| 416 | |||
| 417 | (define-syntax define-lift | 405 | (define-syntax define-lift |
| 418 | (syntax-rules () | 406 | (syntax-rules () |
| 419 | ((_ liftn (args ...)) | 407 | ((_ liftn (args ...)) |
| @@ -600,4 +588,48 @@ the previous state as a monadic value." | |||
| 600 | (lambda (state) | 588 | (lambda (state) |
| 601 | (values state (cons value state)))) | 589 | (values state (cons value state)))) |
| 602 | 590 | ||
| 591 | (define-public (state-with-parameters parameters parameter-values mval) | ||
| 592 | "Set PARAMETERS to PARAMETER-VALUES for the dynamic extent of MVAL, a value | ||
| 593 | in the state monad." | ||
| 594 | (define (set-value parameter value) | ||
| 595 | (parameter value)) | ||
| 596 | |||
| 597 | (lambda (state) | ||
| 598 | ;; XXX: 'with-fluids*' does not work with prompts, therefore the parameters | ||
| 599 | ;; are set globally. This leaves the parameters changed upon a non-local | ||
| 600 | ;; exit and restores them only after running MVAL to completion. See | ||
| 601 | ;; <https://issues.guix.gnu.org/76485>. | ||
| 602 | (let ((old-values (map set-value parameters parameter-values))) | ||
| 603 | (call-with-values | ||
| 604 | (lambda () | ||
| 605 | (mval state)) | ||
| 606 | (lambda (value state) | ||
| 607 | (map set-value parameters old-values) | ||
| 608 | (values value state)))))) | ||
| 609 | |||
| 610 | (define-syntax state-parameterize | ||
| 611 | (syntax-rules () | ||
| 612 | "This form implements dynamic scoping, similar to 'parameterize', but also | ||
| 613 | in the monadic context of the state monad." | ||
| 614 | ((_ ((param value) ...) body ...) | ||
| 615 | (let ((parameters (list param ...)) | ||
| 616 | (values (list value ...))) | ||
| 617 | (state-with-parameters parameters values | ||
| 618 | ;; Install the parameters also for the evaluation of body ... | ||
| 619 | (with-fluids* (map parameter-fluid parameters) | ||
| 620 | values | ||
| 621 | (lambda () | ||
| 622 | (mbegin %state-monad body ...)))))))) | ||
| 623 | |||
| 624 | (define-syntax mparameterize ;can be removed after 2026-03-05 | ||
| 625 | (lambda (s) | ||
| 626 | "This is the old form for 'state-parameterize', which pretended to work | ||
| 627 | with any monad but was in fact specialized for '%state-monad'." | ||
| 628 | (syntax-case s () | ||
| 629 | ((_ monad bindings body ...) | ||
| 630 | (begin | ||
| 631 | (warn-about-deprecation 'mparameterize (current-source-location) | ||
| 632 | #:replacement 'state-parameterize) | ||
| 633 | #'(state-parameterize bindings body ...)))))) | ||
| 634 | |||
| 603 | ;;; monads.scm end here | 635 | ;;; monads.scm end here |
diff --git a/guix/store.scm b/guix/store.scm index cf5848e580b..bae8e7762b0 100644 --- a/guix/store.scm +++ b/guix/store.scm | |||
| @@ -178,6 +178,7 @@ | |||
| 178 | store-lift | 178 | store-lift |
| 179 | store-lower | 179 | store-lower |
| 180 | run-with-store | 180 | run-with-store |
| 181 | store-parameterize | ||
| 181 | %guile-for-build | 182 | %guile-for-build |
| 182 | current-system | 183 | current-system |
| 183 | set-current-system | 184 | set-current-system |
| @@ -1919,6 +1920,7 @@ This is a mutating version that should be avoided. Prefer the functional | |||
| 1919 | (define-alias %store-monad %state-monad) | 1920 | (define-alias %store-monad %state-monad) |
| 1920 | (define-alias store-return state-return) | 1921 | (define-alias store-return state-return) |
| 1921 | (define-alias store-bind state-bind) | 1922 | (define-alias store-bind state-bind) |
| 1923 | (define-alias store-parameterize state-parameterize) | ||
| 1922 | 1924 | ||
| 1923 | ;; Instantiate templates for %STORE-MONAD since it's syntactically different | 1925 | ;; Instantiate templates for %STORE-MONAD since it's syntactically different |
| 1924 | ;; from %STATE-MONAD. | 1926 | ;; from %STATE-MONAD. |
diff --git a/tests/gexp.scm b/tests/gexp.scm index e870f6cb1b9..2376c70d1ba 100644 --- a/tests/gexp.scm +++ b/tests/gexp.scm | |||
| @@ -451,6 +451,26 @@ | |||
| 451 | (return (string=? (derivation-file-name drv) | 451 | (return (string=? (derivation-file-name drv) |
| 452 | (derivation-file-name result))))) | 452 | (derivation-file-name result))))) |
| 453 | 453 | ||
| 454 | (test-assertm "with-parameters for %graft?" | ||
| 455 | (mlet* %store-monad ((replacement -> (package | ||
| 456 | (inherit %bootstrap-guile) | ||
| 457 | (name (string-upcase | ||
| 458 | (package-name | ||
| 459 | %bootstrap-guile))))) | ||
| 460 | (guile -> (package | ||
| 461 | (inherit %bootstrap-guile) | ||
| 462 | (replacement replacement))) | ||
| 463 | (drv0 (package->derivation %bootstrap-guile)) | ||
| 464 | (drv1 (package->derivation replacement)) | ||
| 465 | (obj0 -> (with-parameters ((%graft? #f)) | ||
| 466 | guile)) | ||
| 467 | (obj1 -> (with-parameters ((%graft? #t)) | ||
| 468 | guile)) | ||
| 469 | (result0 (lower-object obj0)) | ||
| 470 | (result1 (lower-object obj1))) | ||
| 471 | (return (and (eq? drv0 result0) | ||
| 472 | (eq? drv1 result1))))) | ||
| 473 | |||
| 454 | (test-assert "with-parameters + file-append" | 474 | (test-assert "with-parameters + file-append" |
| 455 | (let* ((system (match (%current-system) | 475 | (let* ((system (match (%current-system) |
| 456 | ("aarch64-linux" "x86_64-linux") | 476 | ("aarch64-linux" "x86_64-linux") |
diff --git a/tests/monads.scm b/tests/monads.scm index 7f255f02bf5..c05d13776a5 100644 --- a/tests/monads.scm +++ b/tests/monads.scm | |||
| @@ -136,18 +136,16 @@ | |||
| 136 | %monads | 136 | %monads |
| 137 | %monad-run)) | 137 | %monad-run)) |
| 138 | 138 | ||
| 139 | (test-assert "mparameterize" | 139 | (test-assert "state-parameterize" |
| 140 | (let ((parameter (make-parameter 'outside))) | 140 | (let ((parameter (make-parameter 'outside))) |
| 141 | (every (lambda (monad run) | 141 | (equal? |
| 142 | (equal? | 142 | (run-with-state |
| 143 | (run (mlet monad ((outer (return (parameter))) | 143 | (mlet %state-monad ((outer (return (parameter))) |
| 144 | (inner | 144 | (inner |
| 145 | (mparameterize monad ((parameter 'inside)) | 145 | (state-parameterize ((parameter 'inside)) |
| 146 | (return (parameter))))) | 146 | (return (parameter))))) |
| 147 | (return (list outer inner (parameter))))) | 147 | (return (list outer inner (parameter))))) |
| 148 | '(outside inside outside))) | 148 | '(outside inside outside)))) |
| 149 | %monads | ||
| 150 | %monad-run))) | ||
| 151 | 149 | ||
| 152 | (test-assert "mlet* + text-file + package-file" | 150 | (test-assert "mlet* + text-file + package-file" |
| 153 | (run-with-store %store | 151 | (run-with-store %store |
