(define-module (cross-shells build set-search-paths)
#:use-module (guix search-paths)
#:use-module (guix build gnu-build-system)
#:use-module (guix build utils)
#:use-module (guix build gremlin)
#:use-module (guix elf)
#:use-module (ice-9 ftw)
#:use-module (ice-9 match)
#:use-module (ice-9 regex)
#:use-module (ice-9 format)
#:use-module (ice-9 ftw)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-19)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
#:use-module (srfi srfi-26)
#:use-module (rnrs io ports)
#:export (produce-/etc/profile
produce-activation))
(define* (produce-/etc/profile #:key target inputs outputs native-inputs
(search-paths '()) (native-search-paths '())
#:allow-other-keys)
(define input-directories
;; The "source" input can be a directory, but we don't want it for search
;; paths. See <https://issues.guix.gnu.org/44924>.
(match (alist-delete "source" inputs)
(((_ . dir) ...)
dir)))
(define native-input-directories
;; When cross-compiling, the source appears in native-inputs rather than
;; inputs.
(match (and=> native-inputs (cut alist-delete "source" <>))
(((_ . dir) ...)
dir)
(#f ;not cross-compiling
'())))
(mkdir-p (string-append (assoc-ref outputs "out") "/etc"))
(call-with-output-file (string-append (assoc-ref outputs "out") "/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 script, so we cannot rely
;; on it.
(let* ((path (search-path-as-list '("bin" "sbin")
(append native-input-directories
(if target
'()
input-directories))))
(value (list->search-path-as-string path ":")))
(unless (string-null? value)
(format port "export ~a=\"~a:$PATH\"~%" "PATH" value)))
(for-each (match-lambda
((env-var (files ...) separator type pattern)
(let* ((path (search-path-as-list files input-directories
#:type type
#:pattern pattern))
(value (list->search-path-as-string path separator)))
(unless (string-null? value)
(format port "export ~a=\"~a~a$~a\"~%" env-var value separator env-var)))))
search-paths)
(for-each (match-lambda
((env-var (files ...) separator type pattern)
(let* ((path (search-path-as-list files native-input-directories
#:type type
#:pattern pattern))
(value (list->search-path-as-string path separator)))
(unless (string-null? value)
(format port "export ~a=\"~a~a$~a\"~%" env-var value separator env-var)))))
native-search-paths))))
(define* (produce-activation #:key target inputs outputs native-inputs
#:allow-other-keys)
(let* ((out (assoc-ref outputs "out"))
(profile (string-append out "/etc/profile"))
(bin (string-append out "/bin"))
(activate (string-append bin "/activate")))
(mkdir-p bin)
(call-with-output-file activate
(lambda (port)
(format port "#!~a~%(source ~a && $SHELL)"
(search-input-file inputs "/bin/bash")
profile)))
(chmod activate #o555)))