mirror of
https://https.git.savannah.gnu.org/git/guix.git/
synced 2025-07-10 16:50:43 +02:00
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>
This commit is contained in:
parent
749eb1a2dd
commit
30e51cb6b4
9 changed files with 114 additions and 59 deletions
|
@ -138,7 +138,8 @@
|
||||||
(eval . (put 'munless 'scheme-indent-function 1))
|
(eval . (put 'munless 'scheme-indent-function 1))
|
||||||
(eval . (put 'mlet* 'scheme-indent-function 2))
|
(eval . (put 'mlet* 'scheme-indent-function 2))
|
||||||
(eval . (put 'mlet 'scheme-indent-function 2))
|
(eval . (put 'mlet 'scheme-indent-function 2))
|
||||||
(eval . (put 'mparameterize 'scheme-indent-function 2))
|
(eval . (put 'state-parameterize 'scheme-indent-function 2))
|
||||||
|
(eval . (put 'store-parameterize 'scheme-indent-function 2))
|
||||||
(eval . (put 'run-with-store 'scheme-indent-function 1))
|
(eval . (put 'run-with-store 'scheme-indent-function 1))
|
||||||
(eval . (put 'run-with-state 'scheme-indent-function 1))
|
(eval . (put 'run-with-state 'scheme-indent-function 1))
|
||||||
(eval . (put 'wrap-program 'scheme-indent-function 1))
|
(eval . (put 'wrap-program 'scheme-indent-function 1))
|
||||||
|
|
|
@ -53,7 +53,7 @@ instance."
|
||||||
(map (lambda (test)
|
(map (lambda (test)
|
||||||
(system-test
|
(system-test
|
||||||
(inherit test)
|
(inherit test)
|
||||||
(value (mparameterize %store-monad ((current-guix-package guix))
|
(value (store-parameterize ((current-guix-package guix))
|
||||||
(system-test-value test)))))
|
(system-test-value test)))))
|
||||||
(match (getenv "TESTS")
|
(match (getenv "TESTS")
|
||||||
(#f
|
(#f
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
(use-modules (srfi srfi-9) (ice-9 match)
|
(use-modules (srfi srfi-9) (ice-9 match)
|
||||||
(guix channels) (guix gexp)
|
(guix channels) (guix gexp)
|
||||||
((guix store) #:select (%store-monad))
|
((guix store) #:select (%store-monad))
|
||||||
((guix monads) #:select (mparameterize return))
|
((guix monads) #:select (store-parameterize return))
|
||||||
((guix git) #:select (%repository-cache-directory))
|
((guix git) #:select (%repository-cache-directory))
|
||||||
((guix build utils) #:select (mkdir-p)))
|
((guix build utils) #:select (mkdir-p)))
|
||||||
|
|
||||||
|
@ -40,9 +40,9 @@
|
||||||
;; When this manifest is evaluated by Cuirass, make sure it does not
|
;; When this manifest is evaluated by Cuirass, make sure it does not
|
||||||
;; fiddle with the cached checkout that Cuirass is also using since
|
;; fiddle with the cached checkout that Cuirass is also using since
|
||||||
;; concurrent accesses are unsafe.
|
;; concurrent accesses are unsafe.
|
||||||
(mparameterize %store-monad ((%repository-cache-directory
|
(store-parameterize ((%repository-cache-directory
|
||||||
(string-append (%repository-cache-directory)
|
(string-append (%repository-cache-directory)
|
||||||
"/time-travel/" system)))
|
"/time-travel/" system)))
|
||||||
(return (mkdir-p (%repository-cache-directory)))
|
(return (mkdir-p (%repository-cache-directory)))
|
||||||
(latest-channel-derivation channels)))))
|
(latest-channel-derivation channels)))))
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
#:use-module (gnu services shepherd)
|
#:use-module (gnu services shepherd)
|
||||||
#:use-module (guix discovery)
|
#:use-module (guix discovery)
|
||||||
#:use-module (guix monads)
|
#:use-module (guix monads)
|
||||||
#:use-module ((guix store) #:select (%store-monad))
|
#:use-module ((guix store) #:select (%store-monad store-parameterize))
|
||||||
#:use-module ((guix utils)
|
#:use-module ((guix utils)
|
||||||
#:select (%current-system %current-target-system))
|
#:select (%current-system %current-target-system))
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
|
@ -289,9 +289,9 @@ the system under test."
|
||||||
(define-gexp-compiler (compile-system-test (test <system-test>)
|
(define-gexp-compiler (compile-system-test (test <system-test>)
|
||||||
system target)
|
system target)
|
||||||
"Compile TEST to a derivation."
|
"Compile TEST to a derivation."
|
||||||
(mparameterize %store-monad ((%current-system system)
|
(store-parameterize ((%current-system system)
|
||||||
(%current-target-system target))
|
(%current-target-system target))
|
||||||
(system-test-value test)))
|
(system-test-value test)))
|
||||||
|
|
||||||
(define (test-modules)
|
(define (test-modules)
|
||||||
"Return the list of modules that define system tests."
|
"Return the list of modules that define system tests."
|
||||||
|
|
|
@ -733,26 +733,28 @@ x86_64-linux when COREUTILS is lowered."
|
||||||
(lambda (parameterized system target)
|
(lambda (parameterized system target)
|
||||||
(match (parameterized-bindings parameterized)
|
(match (parameterized-bindings parameterized)
|
||||||
(((parameters values) ...)
|
(((parameters values) ...)
|
||||||
(let ((fluids (map parameter-fluid parameters))
|
(let ((thunk (parameterized-thunk parameterized))
|
||||||
(thunk (parameterized-thunk parameterized)))
|
(values (map (lambda (thunk) (thunk)) values)))
|
||||||
;; Install the PARAMETERS for the dynamic extent of THUNK.
|
;; Install the PARAMETERS for the store monad.
|
||||||
(with-fluids* fluids
|
(state-with-parameters parameters values
|
||||||
(map (lambda (thunk) (thunk)) values)
|
;; Install the PARAMETERS for the dynamic extent of THUNK.
|
||||||
(lambda ()
|
;; Special-case '%current-system' and '%current-target-system' to
|
||||||
;; Special-case '%current-system' and '%current-target-system' to
|
;; make sure we get the desired effect.
|
||||||
;; make sure we get the desired effect.
|
(with-fluids* (map parameter-fluid parameters)
|
||||||
(let ((system (if (memq %current-system parameters)
|
values
|
||||||
(%current-system)
|
(lambda ()
|
||||||
system))
|
(let ((system (if (memq %current-system parameters)
|
||||||
(target (if (memq %current-target-system parameters)
|
(%current-system)
|
||||||
(%current-target-system)
|
system))
|
||||||
target)))
|
(target (if (memq %current-target-system parameters)
|
||||||
(match (thunk)
|
(%current-target-system)
|
||||||
((? struct? obj)
|
target)))
|
||||||
(lower-object obj system #:target target))
|
(match (thunk)
|
||||||
(obj ;store item
|
((? struct? obj)
|
||||||
(with-monad %store-monad
|
(lower-object obj system #:target target))
|
||||||
(return obj)))))))))))
|
(obj ;store item
|
||||||
|
(with-monad %store-monad
|
||||||
|
(return obj))))))))))))
|
||||||
|
|
||||||
expander => (lambda (parameterized lowered output)
|
expander => (lambda (parameterized lowered output)
|
||||||
(match (parameterized-bindings parameterized)
|
(match (parameterized-bindings parameterized)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
;;; GNU Guix --- Functional package management for GNU
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
;;; Copyright © 2013, 2014, 2015, 2017, 2022 Ludovic Courtès <ludo@gnu.org>
|
;;; Copyright © 2013-2015, 2017, 2022, 2025 Ludovic Courtès <ludo@gnu.org>
|
||||||
|
;;; Copyright © 2025 David Elsing <david.elsing@posteo.net>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -19,6 +20,7 @@
|
||||||
(define-module (guix monads)
|
(define-module (guix monads)
|
||||||
#:use-module ((system syntax)
|
#:use-module ((system syntax)
|
||||||
#:select (syntax-local-binding))
|
#:select (syntax-local-binding))
|
||||||
|
#:autoload (guix deprecation) (warn-about-deprecation)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
#:use-module (srfi srfi-9)
|
#:use-module (srfi srfi-9)
|
||||||
|
@ -40,7 +42,6 @@
|
||||||
mbegin
|
mbegin
|
||||||
mwhen
|
mwhen
|
||||||
munless
|
munless
|
||||||
mparameterize
|
|
||||||
lift0 lift1 lift2 lift3 lift4 lift5 lift6 lift7 lift
|
lift0 lift1 lift2 lift3 lift4 lift5 lift6 lift7 lift
|
||||||
listm
|
listm
|
||||||
foldm
|
foldm
|
||||||
|
@ -58,7 +59,9 @@
|
||||||
set-current-state
|
set-current-state
|
||||||
state-push
|
state-push
|
||||||
state-pop
|
state-pop
|
||||||
run-with-state))
|
run-with-state
|
||||||
|
state-parameterize
|
||||||
|
mparameterize))
|
||||||
|
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
;;;
|
;;;
|
||||||
|
@ -399,21 +402,6 @@ expression."
|
||||||
(mbegin %current-monad
|
(mbegin %current-monad
|
||||||
mexp0 mexp* ...)))))
|
mexp0 mexp* ...)))))
|
||||||
|
|
||||||
(define-syntax mparameterize
|
|
||||||
(syntax-rules ()
|
|
||||||
"This form implements dynamic scoping, similar to 'parameterize', but in a
|
|
||||||
monadic context."
|
|
||||||
((_ monad ((parameter value) rest ...) body ...)
|
|
||||||
(let ((old-value (parameter)))
|
|
||||||
(mbegin monad
|
|
||||||
;; XXX: Non-local exits are not correctly handled.
|
|
||||||
(return (parameter value))
|
|
||||||
(mlet monad ((result (mparameterize monad (rest ...) body ...)))
|
|
||||||
(parameter old-value)
|
|
||||||
(return result)))))
|
|
||||||
((_ monad () body ...)
|
|
||||||
(mbegin monad body ...))))
|
|
||||||
|
|
||||||
(define-syntax define-lift
|
(define-syntax define-lift
|
||||||
(syntax-rules ()
|
(syntax-rules ()
|
||||||
((_ liftn (args ...))
|
((_ liftn (args ...))
|
||||||
|
@ -600,4 +588,48 @@ the previous state as a monadic value."
|
||||||
(lambda (state)
|
(lambda (state)
|
||||||
(values state (cons value state))))
|
(values state (cons value state))))
|
||||||
|
|
||||||
|
(define-public (state-with-parameters parameters parameter-values mval)
|
||||||
|
"Set PARAMETERS to PARAMETER-VALUES for the dynamic extent of MVAL, a value
|
||||||
|
in the state monad."
|
||||||
|
(define (set-value parameter value)
|
||||||
|
(parameter value))
|
||||||
|
|
||||||
|
(lambda (state)
|
||||||
|
;; XXX: 'with-fluids*' does not work with prompts, therefore the parameters
|
||||||
|
;; are set globally. This leaves the parameters changed upon a non-local
|
||||||
|
;; exit and restores them only after running MVAL to completion. See
|
||||||
|
;; <https://issues.guix.gnu.org/76485>.
|
||||||
|
(let ((old-values (map set-value parameters parameter-values)))
|
||||||
|
(call-with-values
|
||||||
|
(lambda ()
|
||||||
|
(mval state))
|
||||||
|
(lambda (value state)
|
||||||
|
(map set-value parameters old-values)
|
||||||
|
(values value state))))))
|
||||||
|
|
||||||
|
(define-syntax state-parameterize
|
||||||
|
(syntax-rules ()
|
||||||
|
"This form implements dynamic scoping, similar to 'parameterize', but also
|
||||||
|
in the monadic context of the state monad."
|
||||||
|
((_ ((param value) ...) body ...)
|
||||||
|
(let ((parameters (list param ...))
|
||||||
|
(values (list value ...)))
|
||||||
|
(state-with-parameters parameters values
|
||||||
|
;; Install the parameters also for the evaluation of body ...
|
||||||
|
(with-fluids* (map parameter-fluid parameters)
|
||||||
|
values
|
||||||
|
(lambda ()
|
||||||
|
(mbegin %state-monad body ...))))))))
|
||||||
|
|
||||||
|
(define-syntax mparameterize ;can be removed after 2026-03-05
|
||||||
|
(lambda (s)
|
||||||
|
"This is the old form for 'state-parameterize', which pretended to work
|
||||||
|
with any monad but was in fact specialized for '%state-monad'."
|
||||||
|
(syntax-case s ()
|
||||||
|
((_ monad bindings body ...)
|
||||||
|
(begin
|
||||||
|
(warn-about-deprecation 'mparameterize (current-source-location)
|
||||||
|
#:replacement 'state-parameterize)
|
||||||
|
#'(state-parameterize bindings body ...))))))
|
||||||
|
|
||||||
;;; monads.scm end here
|
;;; monads.scm end here
|
||||||
|
|
|
@ -178,6 +178,7 @@
|
||||||
store-lift
|
store-lift
|
||||||
store-lower
|
store-lower
|
||||||
run-with-store
|
run-with-store
|
||||||
|
store-parameterize
|
||||||
%guile-for-build
|
%guile-for-build
|
||||||
current-system
|
current-system
|
||||||
set-current-system
|
set-current-system
|
||||||
|
@ -1919,6 +1920,7 @@ This is a mutating version that should be avoided. Prefer the functional
|
||||||
(define-alias %store-monad %state-monad)
|
(define-alias %store-monad %state-monad)
|
||||||
(define-alias store-return state-return)
|
(define-alias store-return state-return)
|
||||||
(define-alias store-bind state-bind)
|
(define-alias store-bind state-bind)
|
||||||
|
(define-alias store-parameterize state-parameterize)
|
||||||
|
|
||||||
;; Instantiate templates for %STORE-MONAD since it's syntactically different
|
;; Instantiate templates for %STORE-MONAD since it's syntactically different
|
||||||
;; from %STATE-MONAD.
|
;; from %STATE-MONAD.
|
||||||
|
|
|
@ -451,6 +451,26 @@
|
||||||
(return (string=? (derivation-file-name drv)
|
(return (string=? (derivation-file-name drv)
|
||||||
(derivation-file-name result)))))
|
(derivation-file-name result)))))
|
||||||
|
|
||||||
|
(test-assertm "with-parameters for %graft?"
|
||||||
|
(mlet* %store-monad ((replacement -> (package
|
||||||
|
(inherit %bootstrap-guile)
|
||||||
|
(name (string-upcase
|
||||||
|
(package-name
|
||||||
|
%bootstrap-guile)))))
|
||||||
|
(guile -> (package
|
||||||
|
(inherit %bootstrap-guile)
|
||||||
|
(replacement replacement)))
|
||||||
|
(drv0 (package->derivation %bootstrap-guile))
|
||||||
|
(drv1 (package->derivation replacement))
|
||||||
|
(obj0 -> (with-parameters ((%graft? #f))
|
||||||
|
guile))
|
||||||
|
(obj1 -> (with-parameters ((%graft? #t))
|
||||||
|
guile))
|
||||||
|
(result0 (lower-object obj0))
|
||||||
|
(result1 (lower-object obj1)))
|
||||||
|
(return (and (eq? drv0 result0)
|
||||||
|
(eq? drv1 result1)))))
|
||||||
|
|
||||||
(test-assert "with-parameters + file-append"
|
(test-assert "with-parameters + file-append"
|
||||||
(let* ((system (match (%current-system)
|
(let* ((system (match (%current-system)
|
||||||
("aarch64-linux" "x86_64-linux")
|
("aarch64-linux" "x86_64-linux")
|
||||||
|
|
|
@ -136,18 +136,16 @@
|
||||||
%monads
|
%monads
|
||||||
%monad-run))
|
%monad-run))
|
||||||
|
|
||||||
(test-assert "mparameterize"
|
(test-assert "state-parameterize"
|
||||||
(let ((parameter (make-parameter 'outside)))
|
(let ((parameter (make-parameter 'outside)))
|
||||||
(every (lambda (monad run)
|
(equal?
|
||||||
(equal?
|
(run-with-state
|
||||||
(run (mlet monad ((outer (return (parameter)))
|
(mlet %state-monad ((outer (return (parameter)))
|
||||||
(inner
|
(inner
|
||||||
(mparameterize monad ((parameter 'inside))
|
(state-parameterize ((parameter 'inside))
|
||||||
(return (parameter)))))
|
(return (parameter)))))
|
||||||
(return (list outer inner (parameter)))))
|
(return (list outer inner (parameter)))))
|
||||||
'(outside inside outside)))
|
'(outside inside outside))))
|
||||||
%monads
|
|
||||||
%monad-run)))
|
|
||||||
|
|
||||||
(test-assert "mlet* + text-file + package-file"
|
(test-assert "mlet* + text-file + package-file"
|
||||||
(run-with-store %store
|
(run-with-store %store
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue