diff options
| -rw-r--r-- | guix/profiles.scm | 41 | ||||
| -rw-r--r-- | guix/scripts/environment.scm | 51 | ||||
| -rw-r--r-- | tests/profiles.scm | 27 |
3 files changed, 76 insertions, 43 deletions
diff --git a/guix/profiles.scm b/guix/profiles.scm index 8cbffa4d2bf..09b2d1525ab 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | ;;; Copyright © 2019 Kyle Meyer <kyle@kyleam.com> | 11 | ;;; Copyright © 2019 Kyle Meyer <kyle@kyleam.com> |
| 12 | ;;; Copyright © 2019 Mathieu Othacehe <m.othacehe@gmail.com> | 12 | ;;; Copyright © 2019 Mathieu Othacehe <m.othacehe@gmail.com> |
| 13 | ;;; Copyright © 2020 Danny Milosavljevic <dannym@scratchpost.org> | 13 | ;;; Copyright © 2020 Danny Milosavljevic <dannym@scratchpost.org> |
| 14 | ;;; Copyright © 2014 David Thompson <davet@gnu.org> | ||
| 14 | ;;; | 15 | ;;; |
| 15 | ;;; This file is part of GNU Guix. | 16 | ;;; This file is part of GNU Guix. |
| 16 | ;;; | 17 | ;;; |
| @@ -54,6 +55,7 @@ | |||
| 54 | #:use-module (srfi srfi-26) | 55 | #:use-module (srfi srfi-26) |
| 55 | #:use-module (srfi srfi-34) | 56 | #:use-module (srfi srfi-34) |
| 56 | #:use-module (srfi srfi-35) | 57 | #:use-module (srfi srfi-35) |
| 58 | #:autoload (srfi srfi-98) (get-environment-variables) | ||
| 57 | #:export (&profile-error | 59 | #:export (&profile-error |
| 58 | profile-error? | 60 | profile-error? |
| 59 | profile-error-profile | 61 | profile-error-profile |
| @@ -127,6 +129,7 @@ | |||
| 127 | %default-profile-hooks | 129 | %default-profile-hooks |
| 128 | profile-derivation | 130 | profile-derivation |
| 129 | profile-search-paths | 131 | profile-search-paths |
| 132 | load-profile | ||
| 130 | 133 | ||
| 131 | profile | 134 | profile |
| 132 | profile? | 135 | profile? |
| @@ -1916,6 +1919,44 @@ already effective." | |||
| 1916 | (evaluate-search-paths (manifest-search-paths manifest) | 1919 | (evaluate-search-paths (manifest-search-paths manifest) |
| 1917 | (list profile) getenv)) | 1920 | (list profile) getenv)) |
| 1918 | 1921 | ||
| 1922 | (define %precious-variables | ||
| 1923 | ;; Environment variables in the default 'load-profile' white list. | ||
| 1924 | '("HOME" "USER" "LOGNAME" "DISPLAY" "TERM" "TZ" "PAGER")) | ||
| 1925 | |||
| 1926 | (define (purify-environment white-list white-list-regexps) | ||
| 1927 | "Unset all environment variables except those that match the regexps in | ||
| 1928 | WHITE-LIST-REGEXPS and those listed in WHITE-LIST." | ||
| 1929 | (for-each unsetenv | ||
| 1930 | (remove (lambda (variable) | ||
| 1931 | (or (member variable white-list) | ||
| 1932 | (find (cut regexp-exec <> variable) | ||
| 1933 | white-list-regexps))) | ||
| 1934 | (match (get-environment-variables) | ||
| 1935 | (((names . _) ...) | ||
| 1936 | names))))) | ||
| 1937 | |||
| 1938 | (define* (load-profile profile | ||
| 1939 | #:optional (manifest (profile-manifest profile)) | ||
| 1940 | #:key pure? (white-list-regexps '()) | ||
| 1941 | (white-list %precious-variables)) | ||
| 1942 | "Set the environment variables specified by MANIFEST for PROFILE. When | ||
| 1943 | PURE? is #t, unset the variables in the current environment except those that | ||
| 1944 | match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST. | ||
| 1945 | Otherwise, augment existing environment variables with additional search | ||
| 1946 | paths." | ||
| 1947 | (when pure? | ||
| 1948 | (purify-environment white-list white-list-regexps)) | ||
| 1949 | (for-each (match-lambda | ||
| 1950 | ((($ <search-path-specification> variable _ separator) . value) | ||
| 1951 | (let ((current (getenv variable))) | ||
| 1952 | (setenv variable | ||
| 1953 | (if (and current (not pure?)) | ||
| 1954 | (if separator | ||
| 1955 | (string-append value separator current) | ||
| 1956 | value) | ||
| 1957 | value))))) | ||
| 1958 | (profile-search-paths profile manifest))) | ||
| 1959 | |||
| 1919 | (define (profile-regexp profile) | 1960 | (define (profile-regexp profile) |
| 1920 | "Return a regular expression that matches PROFILE's name and number." | 1961 | "Return a regular expression that matches PROFILE's name and number." |
| 1921 | (make-regexp (string-append "^" (regexp-quote (basename profile)) | 1962 | (make-regexp (string-append "^" (regexp-quote (basename profile)) |
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index 5ceb86f7a9a..6958bd6238b 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm | |||
| @@ -52,50 +52,9 @@ | |||
| 52 | #:export (assert-container-features | 52 | #:export (assert-container-features |
| 53 | guix-environment)) | 53 | guix-environment)) |
| 54 | 54 | ||
| 55 | ;; Protect some env vars from purification. Borrowed from nix-shell. | ||
| 56 | (define %precious-variables | ||
| 57 | '("HOME" "USER" "LOGNAME" "DISPLAY" "TERM" "TZ" "PAGER")) | ||
| 58 | |||
| 59 | (define %default-shell | 55 | (define %default-shell |
| 60 | (or (getenv "SHELL") "/bin/sh")) | 56 | (or (getenv "SHELL") "/bin/sh")) |
| 61 | 57 | ||
| 62 | (define (purify-environment white-list) | ||
| 63 | "Unset all environment variables except those that match the regexps in | ||
| 64 | WHITE-LIST and those listed in %PRECIOUS-VARIABLES. A small number of | ||
| 65 | variables such as 'HOME' and 'USER' are left untouched." | ||
| 66 | (for-each unsetenv | ||
| 67 | (remove (lambda (variable) | ||
| 68 | (or (member variable %precious-variables) | ||
| 69 | (find (cut regexp-exec <> variable) | ||
| 70 | white-list))) | ||
| 71 | (match (get-environment-variables) | ||
| 72 | (((names . _) ...) | ||
| 73 | names))))) | ||
| 74 | |||
| 75 | (define* (create-environment profile manifest | ||
| 76 | #:key pure? (white-list '())) | ||
| 77 | "Set the environment variables specified by MANIFEST for PROFILE. When | ||
| 78 | PURE? is #t, unset the variables in the current environment except those that | ||
| 79 | match the regexps in WHITE-LIST. Otherwise, augment existing environment | ||
| 80 | variables with additional search paths." | ||
| 81 | (when pure? | ||
| 82 | (purify-environment white-list)) | ||
| 83 | (for-each (match-lambda | ||
| 84 | ((($ <search-path-specification> variable _ separator) . value) | ||
| 85 | (let ((current (getenv variable))) | ||
| 86 | (setenv variable | ||
| 87 | (if (and current (not pure?)) | ||
| 88 | (if separator | ||
| 89 | (string-append value separator current) | ||
| 90 | value) | ||
| 91 | value))))) | ||
| 92 | (profile-search-paths profile manifest)) | ||
| 93 | |||
| 94 | ;; Give users a way to know that they're in 'guix environment', so they can | ||
| 95 | ;; adjust 'PS1' accordingly, for instance. Set it to PROFILE so users can | ||
| 96 | ;; conveniently access its contents. | ||
| 97 | (setenv "GUIX_ENVIRONMENT" profile)) | ||
| 98 | |||
| 99 | (define* (show-search-paths profile manifest #:key pure?) | 58 | (define* (show-search-paths profile manifest #:key pure?) |
| 100 | "Display the search paths of MANIFEST applied to PROFILE. When PURE? is #t, | 59 | "Display the search paths of MANIFEST applied to PROFILE. When PURE? is #t, |
| 101 | do not augment existing environment variables with additional search paths." | 60 | do not augment existing environment variables with additional search paths." |
| @@ -425,8 +384,14 @@ regexps in WHITE-LIST." | |||
| 425 | ;; Properly handle SIGINT, so pressing C-c in an interactive terminal | 384 | ;; Properly handle SIGINT, so pressing C-c in an interactive terminal |
| 426 | ;; application works. | 385 | ;; application works. |
| 427 | (sigaction SIGINT SIG_DFL) | 386 | (sigaction SIGINT SIG_DFL) |
| 428 | (create-environment profile manifest | 387 | (load-profile profile manifest |
| 429 | #:pure? pure? #:white-list white-list) | 388 | #:pure? pure? #:white-list-regexps white-list) |
| 389 | |||
| 390 | ;; Give users a way to know that they're in 'guix environment', so they can | ||
| 391 | ;; adjust 'PS1' accordingly, for instance. Set it to PROFILE so users can | ||
| 392 | ;; conveniently access its contents. | ||
| 393 | (setenv "GUIX_ENVIRONMENT" profile) | ||
| 394 | |||
| 430 | (match command | 395 | (match command |
| 431 | ((program . args) | 396 | ((program . args) |
| 432 | (apply execlp program program args)))) | 397 | (apply execlp program program args)))) |
diff --git a/tests/profiles.scm b/tests/profiles.scm index ce77711d63c..1a06ff88f34 100644 --- a/tests/profiles.scm +++ b/tests/profiles.scm | |||
| @@ -279,6 +279,33 @@ | |||
| 279 | (string=? (dirname (readlink bindir)) | 279 | (string=? (dirname (readlink bindir)) |
| 280 | (derivation->output-path guile)))))) | 280 | (derivation->output-path guile)))))) |
| 281 | 281 | ||
| 282 | (test-assertm "load-profile" | ||
| 283 | (mlet* %store-monad | ||
| 284 | ((entry -> (package->manifest-entry %bootstrap-guile)) | ||
| 285 | (guile (package->derivation %bootstrap-guile)) | ||
| 286 | (drv (profile-derivation (manifest (list entry)) | ||
| 287 | #:hooks '() | ||
| 288 | #:locales? #f)) | ||
| 289 | (profile -> (derivation->output-path drv)) | ||
| 290 | (bindir -> (string-append profile "/bin")) | ||
| 291 | (_ (built-derivations (list drv)))) | ||
| 292 | (define-syntax-rule (with-environment-excursion exp ...) | ||
| 293 | (let ((env (environ))) | ||
| 294 | (dynamic-wind | ||
| 295 | (const #t) | ||
| 296 | (lambda () exp ...) | ||
| 297 | (lambda () (environ env))))) | ||
| 298 | |||
| 299 | (return (and (with-environment-excursion | ||
| 300 | (load-profile profile) | ||
| 301 | (and (string-prefix? (string-append bindir ":") | ||
| 302 | (getenv "PATH")) | ||
| 303 | (getenv "GUILE_LOAD_PATH"))) | ||
| 304 | (with-environment-excursion | ||
| 305 | (load-profile profile #:pure? #t #:white-list '()) | ||
| 306 | (equal? (list (string-append "PATH=" bindir)) | ||
| 307 | (environ))))))) | ||
| 308 | |||
| 282 | (test-assertm "<profile>" | 309 | (test-assertm "<profile>" |
| 283 | (mlet* %store-monad | 310 | (mlet* %store-monad |
| 284 | ((entry -> (package->manifest-entry %bootstrap-guile)) | 311 | ((entry -> (package->manifest-entry %bootstrap-guile)) |
