summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/guix.texi14
-rw-r--r--guix-package.in44
-rw-r--r--tests/guix-package.sh19
3 files changed, 63 insertions, 14 deletions
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"