diff --git a/doc/guix.texi b/doc/guix.texi index 3b850d91b4..7de7f4f0c2 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -444,11 +444,23 @@ previous generations of the profile remain available, should the user want to roll back. For each user, a symlink to the user's default profile is automatically -created in @file{$HOME/.guix-profile}. This symlink always point to the +created in @file{$HOME/.guix-profile}. This symlink always points to the current generation of the user's default profile. Thus, users can add @file{$HOME/.guix-profile/bin} to their @code{PATH} environment variable, and so on. +In a multi-user setup, user profiles must be stored in a place +registered as a @dfn{garbage-collector root}, which +@file{$HOME/.guix-profile} points to (@pxref{Invoking guix-gc}). That +directory is normally +@code{@var{localstatedir}/profiles/per-user/@var{user}}, where +@var{localstatedir} is the value passed to @code{configure} as +@code{--localstatedir}, and @var{user} is the user name. It must be +created by @code{root}, with @var{user} as the owner. When it does not +exist, @command{guix-package} emits an error about it. + +The @var{options} can be among the following: + @table @code @item --install=@var{package} diff --git a/guix-package.in b/guix-package.in index 3b8615cb72..3e98239e28 100644 --- a/guix-package.in +++ b/guix-package.in @@ -36,6 +36,7 @@ exec ${GUILE-@GUILE@} -L "@guilemoduledir@" -l "$0" \ #:use-module (guix packages) #:use-module (guix utils) #:use-module (guix config) + #:use-module ((guix build utils) #:select (directory-exists? mkdir-p)) #:use-module (ice-9 ftw) #:use-module (ice-9 format) #:use-module (ice-9 match) @@ -63,7 +64,7 @@ exec ${GUILE-@GUILE@} -L "@guilemoduledir@" -l "$0" \ (cut string-append <> "/.guix-profile"))) (define %profile-directory - (string-append %state-directory "/profiles/" + (string-append (or (getenv "NIX_STATE_DIR") %state-directory) "/profiles/" (or (and=> (getenv "USER") (cut string-append "per-user/" <>)) "default"))) @@ -330,6 +331,34 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (() (leave (_ "~a: package not found~%") request))))) + (define (ensure-default-profile) + ;; Ensure the default profile symlink and directory exist. + + ;; Create ~/.guix-profile if it doesn't exist yet. + (when (and %user-environment-directory + %current-profile + (not (false-if-exception + (lstat %user-environment-directory)))) + (symlink %current-profile %user-environment-directory)) + + ;; Attempt to create /…/profiles/per-user/$USER if needed. + (unless (directory-exists? %profile-directory) + (catch 'system-error + (lambda () + (mkdir-p %profile-directory)) + (lambda args + ;; Often, we cannot create %PROFILE-DIRECTORY because its + ;; parent directory is root-owned and we're running + ;; unprivileged. + (format (current-error-port) + (_ "error: while creating directory `~a': ~a~%") + %profile-directory + (strerror (system-error-errno args))) + (format (current-error-port) + (_ "Please create the `~a' directory, with you as the owner.~%") + %profile-directory) + (exit 1))))) + (define (process-actions opts) ;; Process any install/remove/upgrade action from OPTS. (let* ((dry-run? (assoc-ref opts 'dry-run?)) @@ -355,7 +384,7 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (package-name->name+version (store-path-package-name path)))) - `(,name ,version #f ,path))) + `(,name ,version #f ,path))) (_ #f)) opts) (map (lambda (tuple drv) @@ -382,6 +411,9 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) remove) install*)))) + (when (equal? (assoc-ref opts 'profile) %current-profile) + (ensure-default-profile)) + (show-what-to-build drv dry-run?) (or dry-run? @@ -458,14 +490,6 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (setvbuf (current-error-port) _IOLBF) (let ((opts (parse-options))) - - ;; Create ~/.guix-profile if it doesn't exist yet. - (when (and %user-environment-directory - %current-profile - (not (false-if-exception - (lstat %user-environment-directory)))) - (symlink %current-profile %user-environment-directory)) - (with-error-handling (or (process-query opts) (parameterize ((%guile-for-build diff --git a/tests/guix-package.sh b/tests/guix-package.sh index 6c8258032b..e5b8db7088 100644 --- a/tests/guix-package.sh +++ b/tests/guix-package.sh @@ -25,10 +25,11 @@ guix-package --version profile="t-profile-$$" rm -f "$profile" -trap 'rm "$profile" "$profile-"[0-9]*' EXIT +trap 'rm "$profile" "$profile-"[0-9]* ; rm -rf t-home-'"$$" EXIT -guix-package --bootstrap -p "$profile" \ - -i `guix-build -e '(@@ (distro packages base) %bootstrap-guile)'` +boot_guile="`guix-build -e '(@ (distro packages bootstrap) %bootstrap-guile)'`" + +guix-package --bootstrap -p "$profile" -i "$boot_guile" test -L "$profile" && test -L "$profile-1-link" test -f "$profile/bin/guile" @@ -75,3 +76,15 @@ guix-package --bootstrap -i "binutils:lib" -p "$profile" -n # Check whether `--list-available' returns something sensible. guix-package -A 'gui.*e' | grep guile +# Try with the default profile. + +XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}" +export XDG_CACHE_HOME +HOME="t-home-$$" +export HOME + +mkdir -p "$HOME" + +guix-package --bootstrap -i "$boot_guile" +test -L "$HOME/.guix-profile" +test -f "$HOME/.guix-profile/bin/guile"