diff options
| -rw-r--r-- | .dir-locals.el | 1 | ||||
| -rw-r--r-- | doc/guix.texi | 10 | ||||
| -rw-r--r-- | guix/build/profiles.scm | 67 | ||||
| -rw-r--r-- | guix/profiles.scm | 21 | ||||
| -rw-r--r-- | tests/profiles.scm | 26 |
5 files changed, 118 insertions, 7 deletions
diff --git a/.dir-locals.el b/.dir-locals.el index 7aef8536255..eb3da94da4a 100644 --- a/.dir-locals.el +++ b/.dir-locals.el | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | ((indent-tabs-mode . nil) | 14 | ((indent-tabs-mode . nil) |
| 15 | (eval . (put 'eval-when 'scheme-indent-function 1)) | 15 | (eval . (put 'eval-when 'scheme-indent-function 1)) |
| 16 | (eval . (put 'test-assert 'scheme-indent-function 1)) | 16 | (eval . (put 'test-assert 'scheme-indent-function 1)) |
| 17 | (eval . (put 'test-assertm 'scheme-indent-function 1)) | ||
| 17 | (eval . (put 'test-equal 'scheme-indent-function 1)) | 18 | (eval . (put 'test-equal 'scheme-indent-function 1)) |
| 18 | (eval . (put 'test-eq 'scheme-indent-function 1)) | 19 | (eval . (put 'test-eq 'scheme-indent-function 1)) |
| 19 | (eval . (put 'call-with-input-string 'scheme-indent-function 1)) | 20 | (eval . (put 'call-with-input-string 'scheme-indent-function 1)) |
diff --git a/doc/guix.texi b/doc/guix.texi index 8241cb07bfd..1b1690a8e3f 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -950,6 +950,16 @@ created in @file{$HOME/.guix-profile}. This symlink always points to the | |||
| 950 | current generation of the user's default profile. Thus, users can add | 950 | current generation of the user's default profile. Thus, users can add |
| 951 | @file{$HOME/.guix-profile/bin} to their @code{PATH} environment | 951 | @file{$HOME/.guix-profile/bin} to their @code{PATH} environment |
| 952 | variable, and so on. | 952 | variable, and so on. |
| 953 | @cindex search paths | ||
| 954 | If you are not using the Guix System Distribution, consider adding the | ||
| 955 | following lines to your @file{~/.bash_profile} (@pxref{Bash Startup | ||
| 956 | Files,,, bash, The GNU Bash Reference Manual}) so that newly-spawned | ||
| 957 | shells get all the right environment variable definitions: | ||
| 958 | |||
| 959 | @example | ||
| 960 | GUIX_PROFILE="$HOME/.guix-profile" \ | ||
| 961 | source "$HOME/.guix-profile/etc/profile" | ||
| 962 | @end example | ||
| 953 | 963 | ||
| 954 | In a multi-user setup, user profiles are stored in a place registered as | 964 | In a multi-user setup, user profiles are stored in a place registered as |
| 955 | a @dfn{garbage-collector root}, which @file{$HOME/.guix-profile} points | 965 | a @dfn{garbage-collector root}, which @file{$HOME/.guix-profile} points |
diff --git a/guix/build/profiles.scm b/guix/build/profiles.scm index 1c5b54e40b8..eda54cb37a0 100644 --- a/guix/build/profiles.scm +++ b/guix/build/profiles.scm | |||
| @@ -18,6 +18,10 @@ | |||
| 18 | 18 | ||
| 19 | (define-module (guix build profiles) | 19 | (define-module (guix build profiles) |
| 20 | #:use-module (guix build union) | 20 | #:use-module (guix build union) |
| 21 | #:use-module (guix build utils) | ||
| 22 | #:use-module (guix search-paths) | ||
| 23 | #:use-module (srfi srfi-26) | ||
| 24 | #:use-module (ice-9 match) | ||
| 21 | #:use-module (ice-9 pretty-print) | 25 | #:use-module (ice-9 pretty-print) |
| 22 | #:export (build-profile)) | 26 | #:export (build-profile)) |
| 23 | 27 | ||
| @@ -28,14 +32,71 @@ | |||
| 28 | ;;; | 32 | ;;; |
| 29 | ;;; Code: | 33 | ;;; Code: |
| 30 | 34 | ||
| 35 | (define (abstract-profile profile) | ||
| 36 | "Return a procedure that replaces PROFILE in VALUE with a reference to the | ||
| 37 | 'GUIX_PROFILE' environment variable. This allows users to specify what the | ||
| 38 | user-friendly name of the profile is, for instance ~/.guix-profile rather than | ||
| 39 | /gnu/store/...-profile." | ||
| 40 | (let ((replacement (string-append "${GUIX_PROFILE:-" profile "}"))) | ||
| 41 | (match-lambda | ||
| 42 | ((search-path . value) | ||
| 43 | (let* ((separator (search-path-specification-separator search-path)) | ||
| 44 | (items (string-tokenize* value separator)) | ||
| 45 | (crop (cute string-drop <> (string-length profile)))) | ||
| 46 | (cons search-path | ||
| 47 | (string-join (map (lambda (str) | ||
| 48 | (string-append replacement (crop str))) | ||
| 49 | items) | ||
| 50 | separator))))))) | ||
| 51 | |||
| 52 | (define (write-environment-variable-definition port) | ||
| 53 | "Write the given environment variable definition to PORT." | ||
| 54 | (match-lambda | ||
| 55 | ((search-path . value) | ||
| 56 | (display (search-path-definition search-path value #:kind 'prefix) | ||
| 57 | port) | ||
| 58 | (newline port)))) | ||
| 59 | |||
| 31 | (define* (build-profile output inputs | 60 | (define* (build-profile output inputs |
| 32 | #:key manifest) | 61 | #:key manifest search-paths) |
| 33 | "Build a user profile from INPUTS in directory OUTPUT. Write MANIFEST, an | 62 | "Build a user profile from INPUTS in directory OUTPUT. Write MANIFEST, an |
| 34 | sexp, to OUTPUT/manifest." | 63 | sexp, to OUTPUT/manifest. Create OUTPUT/etc/profile with Bash definitions for |
| 64 | all the variables listed in SEARCH-PATHS." | ||
| 65 | ;; Make the symlinks. | ||
| 35 | (union-build output inputs | 66 | (union-build output inputs |
| 36 | #:log-port (%make-void-port "w")) | 67 | #:log-port (%make-void-port "w")) |
| 68 | |||
| 69 | ;; Store meta-data. | ||
| 37 | (call-with-output-file (string-append output "/manifest") | 70 | (call-with-output-file (string-append output "/manifest") |
| 38 | (lambda (p) | 71 | (lambda (p) |
| 39 | (pretty-print manifest p)))) | 72 | (pretty-print manifest p))) |
| 73 | |||
| 74 | ;; Add a ready-to-use Bash profile. | ||
| 75 | (mkdir-p (string-append output "/etc")) | ||
| 76 | (call-with-output-file (string-append output "/etc/profile") | ||
| 77 | (lambda (port) | ||
| 78 | ;; The use of $GUIX_PROFILE described below is not great. Another | ||
| 79 | ;; option would have been to use "$1" and have users run: | ||
| 80 | ;; | ||
| 81 | ;; source ~/.guix-profile/etc/profile ~/.guix-profile | ||
| 82 | ;; | ||
| 83 | ;; However, when 'source' is used with no arguments, $1 refers to the | ||
| 84 | ;; first positional parameter of the calling scripts, so we can rely on | ||
| 85 | ;; it. | ||
| 86 | (display "\ | ||
| 87 | # Source this file to define all the relevant environment variables in Bash | ||
| 88 | # for this profile. You may want to define the 'GUIX_PROFILE' environment | ||
| 89 | # variable to point to the \"visible\" name of the profile, like this: | ||
| 90 | # | ||
| 91 | # GUIX_PROFILE=/path/to/profile | ||
| 92 | # source /path/to/profile/etc/profile | ||
| 93 | # | ||
| 94 | # When GUIX_PROFILE is undefined, the various environment variables refer | ||
| 95 | # to this specific profile generation. | ||
| 96 | \n" port) | ||
| 97 | (let ((variables (evaluate-search-paths (cons $PATH search-paths) | ||
| 98 | (list output)))) | ||
| 99 | (for-each (write-environment-variable-definition port) | ||
| 100 | (map (abstract-profile output) variables)))))) | ||
| 40 | 101 | ||
| 41 | ;;; profile.scm ends here | 102 | ;;; profile.scm ends here |
diff --git a/guix/profiles.scm b/guix/profiles.scm index afc22e118d4..11d9bf0cd9b 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm | |||
| @@ -598,17 +598,30 @@ the monadic procedures listed in HOOKS--such as an Info 'dir' file, etc." | |||
| 598 | 598 | ||
| 599 | (define builder | 599 | (define builder |
| 600 | #~(begin | 600 | #~(begin |
| 601 | (use-modules (guix build profiles)) | 601 | (use-modules (guix build profiles) |
| 602 | (guix search-paths)) | ||
| 602 | 603 | ||
| 603 | (setvbuf (current-output-port) _IOLBF) | 604 | (setvbuf (current-output-port) _IOLBF) |
| 604 | (setvbuf (current-error-port) _IOLBF) | 605 | (setvbuf (current-error-port) _IOLBF) |
| 605 | 606 | ||
| 607 | (define search-paths | ||
| 608 | ;; Search paths of MANIFEST's packages, converted back to their | ||
| 609 | ;; record form. | ||
| 610 | (map sexp->search-path-specification | ||
| 611 | '#$(map search-path-specification->sexp | ||
| 612 | (append-map manifest-entry-search-paths | ||
| 613 | (manifest-entries manifest))))) | ||
| 614 | |||
| 606 | (build-profile #$output '#$inputs | 615 | (build-profile #$output '#$inputs |
| 607 | #:manifest '#$(manifest->gexp manifest)))) | 616 | #:manifest '#$(manifest->gexp manifest) |
| 617 | #:search-paths search-paths))) | ||
| 608 | 618 | ||
| 609 | (gexp->derivation "profile" builder | 619 | (gexp->derivation "profile" builder |
| 610 | #:modules '((guix build union) | 620 | #:modules '((guix build profiles) |
| 611 | (guix build profiles)) | 621 | (guix build union) |
| 622 | (guix build utils) | ||
| 623 | (guix search-paths) | ||
| 624 | (guix records)) | ||
| 612 | #:local-build? #t))) | 625 | #:local-build? #t))) |
| 613 | 626 | ||
| 614 | (define (profile-regexp profile) | 627 | (define (profile-regexp profile) |
diff --git a/tests/profiles.scm b/tests/profiles.scm index 890f09a751c..a39717191dc 100644 --- a/tests/profiles.scm +++ b/tests/profiles.scm | |||
| @@ -29,6 +29,8 @@ | |||
| 29 | #:use-module ((gnu packages guile) #:prefix packages:) | 29 | #:use-module ((gnu packages guile) #:prefix packages:) |
| 30 | #:use-module (ice-9 match) | 30 | #:use-module (ice-9 match) |
| 31 | #:use-module (ice-9 regex) | 31 | #:use-module (ice-9 regex) |
| 32 | #:use-module (ice-9 popen) | ||
| 33 | #:use-module (rnrs io ports) | ||
| 32 | #:use-module (srfi srfi-11) | 34 | #:use-module (srfi srfi-11) |
| 33 | #:use-module (srfi srfi-64)) | 35 | #:use-module (srfi srfi-64)) |
| 34 | 36 | ||
| @@ -220,6 +222,30 @@ | |||
| 220 | (manifest-entry-search-paths entry) | 222 | (manifest-entry-search-paths entry) |
| 221 | (package-native-search-paths | 223 | (package-native-search-paths |
| 222 | packages:guile-2.0))))))))) | 224 | packages:guile-2.0))))))))) |
| 225 | |||
| 226 | (test-assertm "etc/profile" | ||
| 227 | ;; Make sure we get an 'etc/profile' file that at least defines $PATH. | ||
| 228 | (mlet* %store-monad | ||
| 229 | ((guile -> (package | ||
| 230 | (inherit %bootstrap-guile) | ||
| 231 | (native-search-paths | ||
| 232 | (package-native-search-paths packages:guile-2.0)))) | ||
| 233 | (entry -> (package->manifest-entry guile)) | ||
| 234 | (drv (profile-derivation (manifest (list entry)) | ||
| 235 | #:hooks '())) | ||
| 236 | (profile -> (derivation->output-path drv))) | ||
| 237 | (mbegin %store-monad | ||
| 238 | (built-derivations (list drv)) | ||
| 239 | (let* ((pipe (open-input-pipe | ||
| 240 | (string-append "source " | ||
| 241 | profile "/etc/profile; " | ||
| 242 | "unset GUIX_PROFILE; set"))) | ||
| 243 | (env (get-string-all pipe))) | ||
| 244 | (return | ||
| 245 | (and (zero? (close-pipe pipe)) | ||
| 246 | (string-contains env | ||
| 247 | (string-append "PATH=" profile "/bin")))))))) | ||
| 248 | |||
| 223 | (test-end "profiles") | 249 | (test-end "profiles") |
| 224 | 250 | ||
| 225 | 251 | ||
