diff options
| author | Tomas Volf <~@wolfsden.cz> | 2026-05-14 21:26:16 +0200 |
|---|---|---|
| committer | Maxim Cournoyer <maxim@guixotic.coop> | 2026-06-15 10:48:17 +0900 |
| commit | d11615f609d2cd58fb1305205a4fa975dc8e4657 (patch) | |
| tree | 7f282d90f61523ff71c5d342aaa53ed7dd98b5bb | |
| parent | 2c646830c1de33fba8e761b86a173041150a030c (diff) | |
environment: Allow setting environment variables with -E.
* guix/scripts/environment.scm (show-environment-options-help) [-E]: Document
the change.
* guix/scripts/environment.scm (%options) [-E]: If arg contains =, split it
and store under 'extra-env.
* guix/scripts/environment.scm (launch-environment, launch-environment/fork)
(launch-environment/container): Take and use `environment-variables' keyword argument.
* guix/scripts/environment.scm (guix-environment*): Process 'environment-variables opts.
* guix/profiles.scm (load-profile): Add `environment-variables' keyword argument.
* doc/guix.texi (Invoking guix shell): Document the change.
* tests/guix-environment.sh (GUIX_TEST_ZZZ): Test it.
Change-Id: Ib1db19ef73dda8f561b05731079a96eda076e365
Signed-off-by: Maxim Cournoyer <maxim@guixotic.coop>
Modified-by: Maxim Cournoyer <maxim@guixotic.coop>
| -rw-r--r-- | doc/guix.texi | 17 | ||||
| -rw-r--r-- | guix/profiles.scm | 8 | ||||
| -rw-r--r-- | guix/scripts/environment.scm | 54 | ||||
| -rw-r--r-- | tests/guix-environment.sh | 5 |
4 files changed, 63 insertions, 21 deletions
diff --git a/doc/guix.texi b/doc/guix.texi index c624c497d2a..05eac9bda96 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -6803,20 +6803,26 @@ creating an environment in which search paths only contain package inputs. | |||
| 6803 | 6803 | ||
| 6804 | @item --preserve=@var{regexp} | 6804 | @item --preserve=@var{regexp} |
| 6805 | @itemx -E @var{regexp} | 6805 | @itemx -E @var{regexp} |
| 6806 | @itemx -E @var{var}=@var{value} | ||
| 6806 | When used alongside @option{--pure}, preserve the environment variables | 6807 | When used alongside @option{--pure}, preserve the environment variables |
| 6807 | matching @var{regexp}---in other words, put them on a ``white list'' of | 6808 | matching @var{regexp}---in other words, put them on a ``white list'' of |
| 6808 | environment variables that must be preserved. This option can be repeated | 6809 | environment variables that must be preserved. This option can be |
| 6809 | several times. | 6810 | repeated several times. |
| 6811 | |||
| 6812 | When @var{regexp} contains a variable assignment (with a @samp{=} | ||
| 6813 | character), the @var{var} environment variable is directly set to the | ||
| 6814 | @var{value} in the environment. This is used in the example below to | ||
| 6815 | set the number of threads OpenMPI should use: | ||
| 6810 | 6816 | ||
| 6811 | @example | 6817 | @example |
| 6812 | guix shell --pure --preserve=^SLURM openmpi @dots{} \ | 6818 | guix shell --pure --preserve=^SLURM -E OMP_NUM_THREADS=16 openmpi @dots{} \ |
| 6813 | -- mpirun @dots{} | 6819 | -- mpirun @dots{} |
| 6814 | @end example | 6820 | @end example |
| 6815 | 6821 | ||
| 6816 | This example runs @command{mpirun} in a context where the only environment | 6822 | This example runs @command{mpirun} in a context where the only environment |
| 6817 | variables defined are @env{PATH}, environment variables whose name starts | 6823 | variables defined are @env{PATH}, environment variables whose name starts |
| 6818 | with @samp{SLURM}, as well as the usual ``precious'' variables (@env{HOME}, | 6824 | with @samp{SLURM}, variable @env{TERM} set to @samp{no=color}, as well as |
| 6819 | @env{USER}, etc.). | 6825 | the usual ``precious'' variables (@env{HOME}, @env{USER}, etc.). |
| 6820 | 6826 | ||
| 6821 | @item --search-paths | 6827 | @item --search-paths |
| 6822 | Display the environment variable definitions that make up the | 6828 | Display the environment variable definitions that make up the |
| @@ -7319,6 +7325,7 @@ creating an environment in which search paths only contain package inputs. | |||
| 7319 | 7325 | ||
| 7320 | @item --preserve=@var{regexp} | 7326 | @item --preserve=@var{regexp} |
| 7321 | @itemx -E @var{regexp} | 7327 | @itemx -E @var{regexp} |
| 7328 | @itemx -E @var{var}=@var{value} | ||
| 7322 | When used alongside @option{--pure}, preserve the environment variables | 7329 | When used alongside @option{--pure}, preserve the environment variables |
| 7323 | matching @var{regexp}---in other words, put them on a ``white list'' of | 7330 | matching @var{regexp}---in other words, put them on a ``white list'' of |
| 7324 | environment variables that must be preserved. This option can be repeated | 7331 | environment variables that must be preserved. This option can be repeated |
diff --git a/guix/profiles.scm b/guix/profiles.scm index b39116bc0bf..aced7bd25cb 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm | |||
| @@ -2171,14 +2171,20 @@ WHITE-LIST-REGEXPS and those listed in WHITE-LIST." | |||
| 2171 | (define* (load-profile profile | 2171 | (define* (load-profile profile |
| 2172 | #:optional (manifest (profile-manifest profile)) | 2172 | #:optional (manifest (profile-manifest profile)) |
| 2173 | #:key pure? (white-list-regexps '()) | 2173 | #:key pure? (white-list-regexps '()) |
| 2174 | (environment-variables '()) | ||
| 2174 | (white-list %precious-variables)) | 2175 | (white-list %precious-variables)) |
| 2175 | "Set the environment variables specified by MANIFEST for PROFILE. When | 2176 | "Set the environment variables specified by MANIFEST for PROFILE. When |
| 2176 | PURE? is #t, unset the variables in the current environment except those that | 2177 | PURE? is #t, unset the variables in the current environment except those that |
| 2177 | match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST. | 2178 | match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST. |
| 2178 | Otherwise, augment existing environment variables with additional search | 2179 | Otherwise, augment existing environment variables with additional search |
| 2179 | paths." | 2180 | paths. Environment variables in ENVIRONMENT-VARIABLES, a list of pairs, are |
| 2181 | @emph{set} in the environment." | ||
| 2180 | (when pure? | 2182 | (when pure? |
| 2181 | (purify-environment white-list white-list-regexps)) | 2183 | (purify-environment white-list white-list-regexps)) |
| 2184 | (map (match-lambda | ||
| 2185 | ((name . value) | ||
| 2186 | (setenv name value))) | ||
| 2187 | environment-variables) | ||
| 2182 | (for-each (match-lambda | 2188 | (for-each (match-lambda |
| 2183 | ((($ <search-path-specification> variable _ separator) . value) | 2189 | ((($ <search-path-specification> variable _ separator) . value) |
| 2184 | (let ((current (getenv variable))) | 2190 | (let ((current (getenv variable))) |
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index dc7f3b9b280..bd7d4ca6ed4 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm | |||
| @@ -100,7 +100,9 @@ shell'." | |||
| 100 | (display (G_ " | 100 | (display (G_ " |
| 101 | --pure unset existing environment variables")) | 101 | --pure unset existing environment variables")) |
| 102 | (display (G_ " | 102 | (display (G_ " |
| 103 | -E, --preserve=REGEXP preserve environment variables that match REGEXP")) | 103 | -E, --preserve=REGEXP |
| 104 | -E VAR=VALUE preserve environment variables that match REGEXP; | ||
| 105 | if REGEXP contains `=', set VAR to VALUE instead")) | ||
| 104 | (display (G_ " | 106 | (display (G_ " |
| 105 | --search-paths display needed environment variable definitions")) | 107 | --search-paths display needed environment variable definitions")) |
| 106 | (display (G_ " | 108 | (display (G_ " |
| @@ -212,9 +214,15 @@ COMMAND or an interactive shell in that environment.\n")) | |||
| 212 | (alist-cons 'pure #t result))) | 214 | (alist-cons 'pure #t result))) |
| 213 | (option '(#\E "preserve") #t #f | 215 | (option '(#\E "preserve") #t #f |
| 214 | (lambda (opt name arg result) | 216 | (lambda (opt name arg result) |
| 215 | (alist-cons 'inherit-regexp | 217 | (let ((=-index (string-index arg #\=))) |
| 216 | (make-regexp* arg) | 218 | (if =-index |
| 217 | result))) | 219 | (alist-cons 'environment-variables |
| 220 | (cons (substring arg 0 =-index) | ||
| 221 | (substring arg (1+ =-index))) | ||
| 222 | result) | ||
| 223 | (alist-cons 'inherit-regexp | ||
| 224 | (make-regexp* arg) | ||
| 225 | result))))) | ||
| 218 | (option '("inherit") #t #f ;deprecated | 226 | (option '("inherit") #t #f ;deprecated |
| 219 | (lambda (opt name arg result) | 227 | (lambda (opt name arg result) |
| 220 | (warning (G_ "'--inherit' is deprecated, \ | 228 | (warning (G_ "'--inherit' is deprecated, \ |
| @@ -513,19 +521,23 @@ and suitable for 'exit'." | |||
| 513 | 521 | ||
| 514 | (define* (launch-environment command profile manifest | 522 | (define* (launch-environment command profile manifest |
| 515 | #:key pure? (white-list '()) | 523 | #:key pure? (white-list '()) |
| 524 | (environment-variables '()) | ||
| 516 | emulate-fhs?) | 525 | emulate-fhs?) |
| 517 | "Load the environment of PROFILE, which corresponds to MANIFEST, and execute | 526 | "Load the environment of PROFILE, which corresponds to MANIFEST, and execute |
| 518 | COMMAND. When PURE?, pre-existing environment variables are cleared before | 527 | COMMAND. When PURE?, pre-existing environment variables are cleared before |
| 519 | setting the new ones, except those matching the regexps in WHITE-LIST. When | 528 | setting the new ones, except those matching the regexps in WHITE-LIST. |
| 520 | EMULATE-FHS?, first set up an FHS environment with $PATH and generate the LD | 529 | Variables in ENVIRONMENT-VARIABLES (a list of pairs) are set in the |
| 521 | cache." | 530 | environment. When EMULATE-FHS?, first set up an FHS environment with $PATH |
| 531 | and generate the LD cache." | ||
| 522 | ;; Properly handle SIGINT, so pressing C-c in an interactive terminal | 532 | ;; Properly handle SIGINT, so pressing C-c in an interactive terminal |
| 523 | ;; application works. | 533 | ;; application works. |
| 524 | (sigaction SIGINT SIG_DFL) | 534 | (sigaction SIGINT SIG_DFL) |
| 525 | ;; Restore original action for SIGPIPE. | 535 | ;; Restore original action for SIGPIPE. |
| 526 | (sigaction SIGPIPE SIG_DFL) | 536 | (sigaction SIGPIPE SIG_DFL) |
| 527 | (load-profile profile manifest | 537 | (load-profile profile manifest |
| 528 | #:pure? pure? #:white-list-regexps white-list) | 538 | #:pure? pure? |
| 539 | #:white-list-regexps white-list | ||
| 540 | #:environment-variables environment-variables) | ||
| 529 | 541 | ||
| 530 | ;; Give users a way to know that they're in 'guix environment', so they can | 542 | ;; Give users a way to know that they're in 'guix environment', so they can |
| 531 | ;; adjust 'PS1' accordingly, for instance. Set it to PROFILE so users can | 543 | ;; adjust 'PS1' accordingly, for instance. Set it to PROFILE so users can |
| @@ -734,15 +746,19 @@ command name." | |||
| 734 | closest)))))))) | 746 | closest)))))))) |
| 735 | 747 | ||
| 736 | (define* (launch-environment/fork command profile manifest | 748 | (define* (launch-environment/fork command profile manifest |
| 737 | #:key pure? (white-list '())) | 749 | #:key |
| 750 | pure? (white-list '()) | ||
| 751 | (environment-variables '())) | ||
| 738 | "Run COMMAND in a new process with an environment containing PROFILE, with | 752 | "Run COMMAND in a new process with an environment containing PROFILE, with |
| 739 | the search paths specified by MANIFEST. When PURE?, pre-existing environment | 753 | the search paths specified by MANIFEST. When PURE?, pre-existing environment |
| 740 | variables are cleared before setting the new ones, except those matching the | 754 | variables are cleared before setting the new ones, except those matching the |
| 741 | regexps in WHITE-LIST." | 755 | regexps in WHITE-LIST. Variables in ENVIRONMENT-VARIABLES (a list of pairs) |
| 756 | are set in the environment." | ||
| 742 | (match (primitive-fork) | 757 | (match (primitive-fork) |
| 743 | (0 (launch-environment command profile manifest | 758 | (0 (launch-environment command profile manifest |
| 744 | #:pure? pure? | 759 | #:pure? pure? |
| 745 | #:white-list white-list)) | 760 | #:white-list white-list |
| 761 | #:environment-variables environment-variables)) | ||
| 746 | (pid (match (waitpid pid) | 762 | (pid (match (waitpid pid) |
| 747 | ((_ . status) | 763 | ((_ . status) |
| 748 | status))))) | 764 | status))))) |
| @@ -752,7 +768,8 @@ regexps in WHITE-LIST." | |||
| 752 | map-cwd? cwd emulate-fhs? nesting? | 768 | map-cwd? cwd emulate-fhs? nesting? |
| 753 | writable-root? | 769 | writable-root? |
| 754 | (setup-hook #f) | 770 | (setup-hook #f) |
| 755 | (symlinks '()) (white-list '())) | 771 | (symlinks '()) (white-list '()) |
| 772 | (environment-variables '())) | ||
| 756 | "Run COMMAND within a container that features the software in PROFILE. | 773 | "Run COMMAND within a container that features the software in PROFILE. |
| 757 | Environment variables are set according to the search paths of MANIFEST. The | 774 | Environment variables are set according to the search paths of MANIFEST. The |
| 758 | global shell is BASH, a file name for a GNU Bash binary in the store. When | 775 | global shell is BASH, a file name for a GNU Bash binary in the store. When |
| @@ -777,7 +794,10 @@ SYMLINKS must be a list of (SOURCE -> TARGET) tuples denoting symlinks to be | |||
| 777 | added to the container. | 794 | added to the container. |
| 778 | 795 | ||
| 779 | Preserve environment variables whose name matches the one of the regexps in | 796 | Preserve environment variables whose name matches the one of the regexps in |
| 780 | WHILE-LIST." | 797 | WHILE-LIST. |
| 798 | |||
| 799 | Variables in ENVIRONMENT-VARIABLES (a list of pairs) are set in the | ||
| 800 | environment." | ||
| 781 | (define (optional-mapping->fs mapping) | 801 | (define (optional-mapping->fs mapping) |
| 782 | (and (file-exists? (file-system-mapping-source mapping)) | 802 | (and (file-exists? (file-system-mapping-source mapping)) |
| 783 | (file-system-mapping->bind-mount mapping))) | 803 | (file-system-mapping->bind-mount mapping))) |
| @@ -977,6 +997,7 @@ WHILE-LIST." | |||
| 977 | (string-append home-dir "/.guix-profile") | 997 | (string-append home-dir "/.guix-profile") |
| 978 | profile) | 998 | profile) |
| 979 | manifest #:pure? #f | 999 | manifest #:pure? #f |
| 1000 | #:environment-variables environment-variables | ||
| 980 | #:emulate-fhs? emulate-fhs?))) | 1001 | #:emulate-fhs? emulate-fhs?))) |
| 981 | #:populate-file-system | 1002 | #:populate-file-system |
| 982 | (lambda () | 1003 | (lambda () |
| @@ -1171,7 +1192,8 @@ command-line option processing with 'parse-command-line'." | |||
| 1171 | '("/bin/sh") | 1192 | '("/bin/sh") |
| 1172 | (list %default-shell)))) | 1193 | (list %default-shell)))) |
| 1173 | (mappings (pick-all opts 'file-system-mapping)) | 1194 | (mappings (pick-all opts 'file-system-mapping)) |
| 1174 | (white-list (pick-all opts 'inherit-regexp))) | 1195 | (white-list (pick-all opts 'inherit-regexp)) |
| 1196 | (environment-variables (pick-all opts 'environment-variables))) | ||
| 1175 | 1197 | ||
| 1176 | (define store-needed? | 1198 | (define store-needed? |
| 1177 | ;; Whether connecting to the daemon is needed. | 1199 | ;; Whether connecting to the daemon is needed. |
| @@ -1291,6 +1313,8 @@ when using '--container'; doing nothing~%")) | |||
| 1291 | #:profile profile | 1313 | #:profile profile |
| 1292 | #:manifest manifest | 1314 | #:manifest manifest |
| 1293 | #:white-list white-list | 1315 | #:white-list white-list |
| 1316 | #:environment-variables | ||
| 1317 | environment-variables | ||
| 1294 | #:link-profile? link-prof? | 1318 | #:link-profile? link-prof? |
| 1295 | #:network? network? | 1319 | #:network? network? |
| 1296 | #:map-cwd? (not no-cwd?) | 1320 | #:map-cwd? (not no-cwd?) |
| @@ -1308,6 +1332,8 @@ when using '--container'; doing nothing~%")) | |||
| 1308 | (exit/status | 1332 | (exit/status |
| 1309 | (launch-environment/fork command profile manifest | 1333 | (launch-environment/fork command profile manifest |
| 1310 | #:white-list white-list | 1334 | #:white-list white-list |
| 1335 | #:environment-variables | ||
| 1336 | environment-variables | ||
| 1311 | #:pure? pure?))))))))))))) | 1337 | #:pure? pure?))))))))))))) |
| 1312 | 1338 | ||
| 1313 | ;;; Local Variables: | 1339 | ;;; Local Variables: |
diff --git a/tests/guix-environment.sh b/tests/guix-environment.sh index 56cb289f2ff..450f0265221 100644 --- a/tests/guix-environment.sh +++ b/tests/guix-environment.sh | |||
| @@ -49,18 +49,21 @@ test -x `sed -r 's/^export PATH="(.*)"/\1/' "$tmpdir/a"`/guile | |||
| 49 | 49 | ||
| 50 | cmp "$tmpdir/a" "$tmpdir/b" | 50 | cmp "$tmpdir/a" "$tmpdir/b" |
| 51 | 51 | ||
| 52 | # Check '--preserve'. | 52 | # Check '--preserve', as well as its -E VAR=VALUE special case. |
| 53 | GUIX_TEST_ABC=1 | 53 | GUIX_TEST_ABC=1 |
| 54 | GUIX_TEST_DEF=2 | 54 | GUIX_TEST_DEF=2 |
| 55 | GUIX_TEST_XYZ=3 | 55 | GUIX_TEST_XYZ=3 |
| 56 | GUIX_TEST_ZZZ=4 | ||
| 56 | export GUIX_TEST_ABC GUIX_TEST_DEF GUIX_TEST_XYZ | 57 | export GUIX_TEST_ABC GUIX_TEST_DEF GUIX_TEST_XYZ |
| 57 | guix environment --bootstrap --ad-hoc guile-bootstrap --pure \ | 58 | guix environment --bootstrap --ad-hoc guile-bootstrap --pure \ |
| 58 | --preserve='^GUIX_TEST_A' --preserve='^GUIX_TEST_D' \ | 59 | --preserve='^GUIX_TEST_A' --preserve='^GUIX_TEST_D' \ |
| 60 | --preserve='^GUIX_TEST_Z' -E 'GUIX_TEST_ZZZ=overridden' \ | ||
| 59 | -- "$SHELL" -c set > "$tmpdir/a" | 61 | -- "$SHELL" -c set > "$tmpdir/a" |
| 60 | grep '^PATH=' "$tmpdir/a" | 62 | grep '^PATH=' "$tmpdir/a" |
| 61 | grep '^GUIX_TEST_ABC=1' "$tmpdir/a" | 63 | grep '^GUIX_TEST_ABC=1' "$tmpdir/a" |
| 62 | grep '^GUIX_TEST_DEF=2' "$tmpdir/a" | 64 | grep '^GUIX_TEST_DEF=2' "$tmpdir/a" |
| 63 | grep '^GUIX_TEST_XYZ=3' "$tmpdir/a" && false | 65 | grep '^GUIX_TEST_XYZ=3' "$tmpdir/a" && false |
| 66 | grep '^GUIX_TEST_ZZZ=overridden' "$tmpdir/a" | ||
| 64 | 67 | ||
| 65 | # Make sure the exit value is preserved. | 68 | # Make sure the exit value is preserved. |
| 66 | if guix environment --bootstrap --ad-hoc guile-bootstrap --pure \ | 69 | if guix environment --bootstrap --ad-hoc guile-bootstrap --pure \ |
