profiles: Generate an 'etc/profile' file.
Suggested by 宋文武 <iyzsong@gmail.com> in <http://bugs.gnu.org/20255>. * guix/build/profiles.scm (abstract-profile, write-environment-variable-definition): New procedures. (build-profile): Add #:search-paths parameter. Create OUTPUT/etc/profile. * guix/profiles.scm (profile-derivation)[builder]: Add 'search-paths' variable and pass it to 'build-profile'. Adjust #:modules argument. * tests/profiles.scm ("etc/profile"): New test. * doc/guix.texi (Invoking guix package): Mention etc/profile.master
parent
611adb1ee5
commit
d664f1b431
|
@ -14,6 +14,7 @@
|
|||
((indent-tabs-mode . nil)
|
||||
(eval . (put 'eval-when 'scheme-indent-function 1))
|
||||
(eval . (put 'test-assert 'scheme-indent-function 1))
|
||||
(eval . (put 'test-assertm 'scheme-indent-function 1))
|
||||
(eval . (put 'test-equal 'scheme-indent-function 1))
|
||||
(eval . (put 'test-eq 'scheme-indent-function 1))
|
||||
(eval . (put 'call-with-input-string 'scheme-indent-function 1))
|
||||
|
|
|
@ -950,6 +950,16 @@ 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.
|
||||
@cindex search paths
|
||||
If you are not using the Guix System Distribution, consider adding the
|
||||
following lines to your @file{~/.bash_profile} (@pxref{Bash Startup
|
||||
Files,,, bash, The GNU Bash Reference Manual}) so that newly-spawned
|
||||
shells get all the right environment variable definitions:
|
||||
|
||||
@example
|
||||
GUIX_PROFILE="$HOME/.guix-profile" \
|
||||
source "$HOME/.guix-profile/etc/profile"
|
||||
@end example
|
||||
|
||||
In a multi-user setup, user profiles are stored in a place registered as
|
||||
a @dfn{garbage-collector root}, which @file{$HOME/.guix-profile} points
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
|
||||
(define-module (guix build profiles)
|
||||
#:use-module (guix build union)
|
||||
#:use-module (guix build utils)
|
||||
#:use-module (guix search-paths)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (ice-9 pretty-print)
|
||||
#:export (build-profile))
|
||||
|
||||
|
@ -28,14 +32,71 @@
|
|||
;;;
|
||||
;;; Code:
|
||||
|
||||
(define (abstract-profile profile)
|
||||
"Return a procedure that replaces PROFILE in VALUE with a reference to the
|
||||
'GUIX_PROFILE' environment variable. This allows users to specify what the
|
||||
user-friendly name of the profile is, for instance ~/.guix-profile rather than
|
||||
/gnu/store/...-profile."
|
||||
(let ((replacement (string-append "${GUIX_PROFILE:-" profile "}")))
|
||||
(match-lambda
|
||||
((search-path . value)
|
||||
(let* ((separator (search-path-specification-separator search-path))
|
||||
(items (string-tokenize* value separator))
|
||||
(crop (cute string-drop <> (string-length profile))))
|
||||
(cons search-path
|
||||
(string-join (map (lambda (str)
|
||||
(string-append replacement (crop str)))
|
||||
items)
|
||||
separator)))))))
|
||||
|
||||
(define (write-environment-variable-definition port)
|
||||
"Write the given environment variable definition to PORT."
|
||||
(match-lambda
|
||||
((search-path . value)
|
||||
(display (search-path-definition search-path value #:kind 'prefix)
|
||||
port)
|
||||
(newline port))))
|
||||
|
||||
(define* (build-profile output inputs
|
||||
#:key manifest)
|
||||
#:key manifest search-paths)
|
||||
"Build a user profile from INPUTS in directory OUTPUT. Write MANIFEST, an
|
||||
sexp, to OUTPUT/manifest."
|
||||
sexp, to OUTPUT/manifest. Create OUTPUT/etc/profile with Bash definitions for
|
||||
all the variables listed in SEARCH-PATHS."
|
||||
;; Make the symlinks.
|
||||
(union-build output inputs
|
||||
#:log-port (%make-void-port "w"))
|
||||
|
||||
;; Store meta-data.
|
||||
(call-with-output-file (string-append output "/manifest")
|
||||
(lambda (p)
|
||||
(pretty-print manifest p))))
|
||||
(pretty-print manifest p)))
|
||||
|
||||
;; Add a ready-to-use Bash profile.
|
||||
(mkdir-p (string-append output "/etc"))
|
||||
(call-with-output-file (string-append output "/etc/profile")
|
||||
(lambda (port)
|
||||
;; The use of $GUIX_PROFILE described below is not great. Another
|
||||
;; option would have been to use "$1" and have users run:
|
||||
;;
|
||||
;; source ~/.guix-profile/etc/profile ~/.guix-profile
|
||||
;;
|
||||
;; However, when 'source' is used with no arguments, $1 refers to the
|
||||
;; first positional parameter of the calling scripts, so we can rely on
|
||||
;; it.
|
||||
(display "\
|
||||
# Source this file to define all the relevant environment variables in Bash
|
||||
# for this profile. You may want to define the 'GUIX_PROFILE' environment
|
||||
# variable to point to the \"visible\" name of the profile, like this:
|
||||
#
|
||||
# GUIX_PROFILE=/path/to/profile
|
||||
# source /path/to/profile/etc/profile
|
||||
#
|
||||
# When GUIX_PROFILE is undefined, the various environment variables refer
|
||||
# to this specific profile generation.
|
||||
\n" port)
|
||||
(let ((variables (evaluate-search-paths (cons $PATH search-paths)
|
||||
(list output))))
|
||||
(for-each (write-environment-variable-definition port)
|
||||
(map (abstract-profile output) variables))))))
|
||||
|
||||
;;; profile.scm ends here
|
||||
|
|
|
@ -598,17 +598,30 @@ the monadic procedures listed in HOOKS--such as an Info 'dir' file, etc."
|
|||
|
||||
(define builder
|
||||
#~(begin
|
||||
(use-modules (guix build profiles))
|
||||
(use-modules (guix build profiles)
|
||||
(guix search-paths))
|
||||
|
||||
(setvbuf (current-output-port) _IOLBF)
|
||||
(setvbuf (current-error-port) _IOLBF)
|
||||
|
||||
(define search-paths
|
||||
;; Search paths of MANIFEST's packages, converted back to their
|
||||
;; record form.
|
||||
(map sexp->search-path-specification
|
||||
'#$(map search-path-specification->sexp
|
||||
(append-map manifest-entry-search-paths
|
||||
(manifest-entries manifest)))))
|
||||
|
||||
(build-profile #$output '#$inputs
|
||||
#:manifest '#$(manifest->gexp manifest))))
|
||||
#:manifest '#$(manifest->gexp manifest)
|
||||
#:search-paths search-paths)))
|
||||
|
||||
(gexp->derivation "profile" builder
|
||||
#:modules '((guix build union)
|
||||
(guix build profiles))
|
||||
#:modules '((guix build profiles)
|
||||
(guix build union)
|
||||
(guix build utils)
|
||||
(guix search-paths)
|
||||
(guix records))
|
||||
#:local-build? #t)))
|
||||
|
||||
(define (profile-regexp profile)
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#:use-module ((gnu packages guile) #:prefix packages:)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (ice-9 regex)
|
||||
#:use-module (ice-9 popen)
|
||||
#:use-module (rnrs io ports)
|
||||
#:use-module (srfi srfi-11)
|
||||
#:use-module (srfi srfi-64))
|
||||
|
||||
|
@ -220,6 +222,30 @@
|
|||
(manifest-entry-search-paths entry)
|
||||
(package-native-search-paths
|
||||
packages:guile-2.0)))))))))
|
||||
|
||||
(test-assertm "etc/profile"
|
||||
;; Make sure we get an 'etc/profile' file that at least defines $PATH.
|
||||
(mlet* %store-monad
|
||||
((guile -> (package
|
||||
(inherit %bootstrap-guile)
|
||||
(native-search-paths
|
||||
(package-native-search-paths packages:guile-2.0))))
|
||||
(entry -> (package->manifest-entry guile))
|
||||
(drv (profile-derivation (manifest (list entry))
|
||||
#:hooks '()))
|
||||
(profile -> (derivation->output-path drv)))
|
||||
(mbegin %store-monad
|
||||
(built-derivations (list drv))
|
||||
(let* ((pipe (open-input-pipe
|
||||
(string-append "source "
|
||||
profile "/etc/profile; "
|
||||
"unset GUIX_PROFILE; set")))
|
||||
(env (get-string-all pipe)))
|
||||
(return
|
||||
(and (zero? (close-pipe pipe))
|
||||
(string-contains env
|
||||
(string-append "PATH=" profile "/bin"))))))))
|
||||
|
||||
(test-end "profiles")
|
||||
|
||||
|
||||
|
|
Reference in New Issue