feat(cli): introduce DOOMPROFILELOAD{FILE,PATH} envvars

- Adds $DOOMPROFILELOADFILE: Controls where to read and write the
  profile loader. Changing this may be helpful for users on nix/guix,
  who have deployed Doom to a read-only location. This sets
  `doom-profile-load-file`.
- Changed profile load file's default location (used to be
  $EMACSDIR/profiles/init.el, is now $EMACSDIR/profiles/load.el). The
  gitignore was updated to reflect this.
- Adds $DOOMPROFILELOADPATH: A colon-delimited list of profile config
  files and directories (semi-colon on Windows) which dictate what Doom
  reads in order to discover your profiles. Config files are required to
  have an *.el extension. This sets `doom-profile-load-path`.
- Changes the nomenclature around this loader script. I used to refer to
  it as the profile bootstrapper. I'll now refer to it as the profile
  load file, and I've renamed `doom-profiles-bootstrap-file` to
  `doom-profile-load-file` to reflect this.
- The variables `doom-profile-dirs` and `doom-profile-config-files` were
  merged into doom-profile-load-path.
- Both envvars have also been documented in `doom help` (and
  $DOOMPROFILE's has been updated).

Ref: #6794
This commit is contained in:
Henrik Lissner 2022-09-17 22:02:50 +02:00
parent 7fc0cbff5e
commit f99cf0ccc8
No known key found for this signature in database
GPG key ID: B60957CA074D39A3
5 changed files with 76 additions and 51 deletions

2
.gitignore vendored
View file

@ -1,5 +1,5 @@
# machine generated doom profiles or metadata # machine generated doom profiles or metadata
/profiles/init.*el /profiles/*.el
/.local*/ /.local*/
# possible user config files # possible user config files

View file

@ -139,11 +139,24 @@ ENVIRONMENT VARIABLES:
option also sets this variable. option also sets this variable.
`$DOOMPROFILE' `$DOOMPROFILE'
(Not implemented yet) Which Doom profile to activate (default: \"current\"). Which Doom profile to activate (default: \"_@0\"). The `--profile' option
also sets this variable.
`$DOOMPROFILESDIR' `$DOOMPROFILELOADFILE'
(Not implemented yet) Where to find or write generated Doom profiles Doom generates a profile loader script on 'doom sync' or 'doom profiles
(default: `$EMACSDIR'/profiles). sync'. By default, this file is written to and loaded from
$EMACSDIR/profiles/load.el. Set this envvar to change that. Note that this
envvar must be in scope for both interactive and non-interactive sessions
for it to be effective. This is especially useful for folks on Nix/Guix, who
have deployed Doom to a read-only directory.
Note: this file *must* end with a .el extension. It will be byte-compiled
after it is generated.
`$DOOMPROFILELOADPATH'
A colon-delimited (semi-colon on Windows) list of profile config files or
directories under which Doom will search for implicit profiles. See
`var:doom-profile-load-path' for its default value.
EXIT CODES: EXIT CODES:
0 Successful run 0 Successful run

View file

@ -74,14 +74,19 @@
(setq user-emacs-directory (expand-file-name init-dir)))) (setq user-emacs-directory (expand-file-name init-dir))))
;; FIX: Discard the switch to prevent "invalid option" errors later. ;; FIX: Discard the switch to prevent "invalid option" errors later.
(push (cons "--profile" (lambda (_) (pop argv))) command-switch-alist) (push (cons "--profile" (lambda (_) (pop argv))) command-switch-alist)
;; Running 'doom sync' will (re)generate a lightweight profile ;; Running 'doom sync' or 'doom profile sync' (re)generates a light
;; bootstrapper in $EMACSDIR/profiles/init.el, after reading ;; profile loader in $EMACSDIR/profiles/load.el (or
;; $EMACSDIR/profiles.el, $DOOMDIR/profiles, ;; $DOOMPROFILELOADFILE), after reading `doom-profile-load-path'. This
;; $XDG_CONFIG_HOME/doom-profiles.el, and ~/.doom-profiles.el. All it ;; loader requires `$DOOMPROFILE' be set to function.
;; needs is for `$DOOMPROFILE' to be set.
(setenv "DOOMPROFILE" profile) (setenv "DOOMPROFILE" profile)
(or (load (expand-file-name (format "profiles/init.%d.elc" emacs-major-version) (or (load (expand-file-name
user-emacs-directory) (format (let ((lfile (getenv-internal "DOOMPROFILELOADFILE")))
(if lfile
(concat (string-remove-suffix ".el" lfile)
".%d.elc")
"profiles/load.%d.elc"))
emacs-major-version)
user-emacs-directory)
'noerror (not init-file-debug) 'nosuffix) 'noerror (not init-file-debug) 'nosuffix)
(user-error "Profiles not initialized yet; run 'doom sync' first")))) (user-error "Profiles not initialized yet; run 'doom sync' first"))))

View file

@ -38,17 +38,16 @@
:benchmark t :benchmark t
(let* ((old-profiles (doom-profiles-read doom-cli-known-profiles-file)) (let* ((old-profiles (doom-profiles-read doom-cli-known-profiles-file))
(new-profiles (doom-profiles-autodetect)) (new-profiles (doom-profiles-autodetect))
(init-file doom-profiles-bootstrap-file) (load-file doom-profile-load-file)
(version (doom-file-read init-file :by 'read :noerror t)) (version (doom-file-read load-file :by 'read :noerror t))
(recreate? (or (not reload?) (doom-profiles-outdated-p)))) (recreate? (or (not reload?) (doom-profiles-outdated-p))))
(unless (file-exists-p init-file) (unless (file-exists-p load-file)
(print! (warn "No profile manifest found. Generating one...")) (print! (warn "No profile loader found. Generating one..."))
(print-group! (print! (start "Regenerating it..."))) (print-group! (print! (start "Regenerating it...")))
(setq recreate? t)) (setq recreate? t))
(unless (equal (or version doom-version) doom-version) (unless (equal (or version doom-version) doom-version)
(print! (warn "Detected version mismatch in profile manifest (%s != %s)" (print! (warn "Detected version mismatch in profile loader (%s != %s)"
version version doom-version))
doom-version))
(print! (start "Generating profile manifest...")) (print! (start "Generating profile manifest..."))
(setq recreate? t)) (setq recreate? t))
(print-group! (print-group!
@ -70,9 +69,9 @@
(dolist (p removed) (print! (item "Removed %S") (car p))) (dolist (p removed) (print! (item "Removed %S") (car p)))
(dolist (p changed) (print! (item "Changed %S") (car p))) (dolist (p changed) (print! (item "Changed %S") (car p)))
(doom-file-write doom-cli-known-profiles-file (list new-profiles) :mode #o600) (doom-file-write doom-cli-known-profiles-file (list new-profiles) :mode #o600)
(doom-profiles-save new-profiles) (doom-profiles-save new-profiles load-file)
(print! (success "Regenerated profile bootstrapper: %s") (print! (success "Regenerated profile loader: %s")
(path doom-profiles-bootstrap-file))))))))) (path load-file)))))))))
;; ;;

View file

@ -8,31 +8,37 @@
;;; Variables ;;; Variables
;;; File/directory variables ;;; File/directory variables
(defvar doom-profiles-dir doom-data-dir (defvar doom-profiles-generated-dir doom-data-dir
"Where generated profiles are kept. "Where generated profiles are kept.
Profile directories are in the format {data-profiles-dir}/$NAME/@/$VERSION, for Profile directories are in the format {data-profiles-dir}/$NAME/@/$VERSION, for
example: '~/.local/share/doom/_/@/0/'") example: '~/.local/share/doom/_/@/0/'")
(defvar doom-profile-dirs (defvar doom-profile-load-path
(list (file-name-concat doom-user-dir "profiles") (if-let (path (getenv-internal "DOOMPROFILELOADPATH"))
(file-name-concat doom-emacs-dir "profiles")) (mapcar #'expand-file-name (split-string-and-unquote path path-separator))
"A list of directories to search for implicit Doom profiles in.") (list (file-name-concat doom-user-dir "profiles.el")
(file-name-concat doom-emacs-dir "profiles.el")
(expand-file-name "doom-profiles.el" (or (getenv "XDG_CONFIG_HOME") "~/.config"))
(expand-file-name "~/.doom-profiles.el")
(file-name-concat doom-user-dir "profiles")
(file-name-concat doom-emacs-dir "profiles")))
"A list of profile config files or directories that house implicit profiles.
(defvar doom-profile-config-files `doom-profiles-initialize' loads and merges all profiles defined in the above
(list (file-name-concat doom-user-dir "profiles.el") files/directories, then writes a profile load script to
(file-name-concat doom-emacs-dir "profiles.el") `doom-profile-load-file'.
(expand-file-name "doom-profiles.el" (or (getenv "XDG_CONFIG_HOME") "~/.config"))
(expand-file-name "~/.doom-profiles.el"))
"A list of potential locations for a profiles.el file.
`doom-profiles-initialize' will load and merge all profiles defined in the above Can be changed externally by setting $DOOMPROFILELOADPATH to a colon-delimited
files, and will write a summary profiles.el to the first entry in this list of paths or profile config files (semi-colon delimited on Windows).")
variable.")
(defvar doom-profiles-bootstrap-file (defvar doom-profile-load-file
(file-name-concat doom-emacs-dir (format "profiles/init.el" emacs-major-version)) (if-let (loader (getenv-internal "DOOMPROFILELOADFILE"))
"Where Doom writes its interactive profile bootstrap script.") (expand-file-name loader doom-emacs-dir)
(file-name-concat doom-emacs-dir (format "profiles/load.el" emacs-major-version)))
"Where Doom writes its interactive profile loader script.
Can be changed externally by setting $DOOMPROFILELOADFILE.")
(defvar doom-profile-init-file-name (format "init.%d.el" emacs-major-version) (defvar doom-profile-init-file-name (format "init.%d.el" emacs-major-version)
"TODO") "TODO")
@ -113,21 +119,23 @@ run.")
:key #'car))))))) :key #'car)))))))
(nreverse profiles))) (nreverse profiles)))
(defun doom-profiles-autodetect () (defun doom-profiles-autodetect (&optional _internal?)
"Return all known profiles as a nested alist. "Return all known profiles as a nested alist.
This reads all profiles in `doom-profile-config-files', then reads implicit profiles This reads all profile configs and directories in `doom-profile-load-path', then
living in `doom-profile-dirs', then caches them in `doom--profiles'. If RELOAD? caches them in `doom--profiles'. If RELOAD? is non-nil, refresh the cache."
is non-nil, refresh the cache." (doom-profiles-read doom-profile-load-path
(doom-profiles-read doom-profile-config-files ;; TODO: Add in v3
doom-profile-dirs)) ;; (if internal? doom-profiles-generated-dir)
))
(defun doom-profiles-outdated-p () (defun doom-profiles-outdated-p ()
"Return non-nil if files in `doom-profile-loader-file' are outdated." "Return non-nil if files in `doom-profile-load-file' are outdated."
(cl-loop for file in doom-profile-config-files (cl-loop for path in doom-profile-load-path
if (or (not (file-exists-p doom-profiles-bootstrap-file)) when (string-suffix-p path ".el")
(file-newer-than-file-p file doom-profiles-bootstrap-file) if (or (not (file-exists-p doom-profile-load-file))
(not (equal (doom-file-read doom-profiles-bootstrap-file :by 'read) (file-newer-than-file-p path doom-profile-load-file)
(not (equal (doom-file-read doom-profile-load-file :by 'read)
doom-version))) doom-version)))
return t)) return t))
@ -153,7 +161,7 @@ is non-nil, refresh the cache."
(defun doom-profiles-save (profiles &optional file) (defun doom-profiles-save (profiles &optional file)
"Generate a profile bootstrapper for Doom to load at startup." "Generate a profile bootstrapper for Doom to load at startup."
(unless file (unless file
(setq file doom-profiles-bootstrap-file)) (setq file doom-profile-load-file))
(doom-file-write (doom-file-write
file (let ((profilesym (make-symbol "profile")) file (let ((profilesym (make-symbol "profile"))
(deferredsym (make-symbol "deferred-vars"))) (deferredsym (make-symbol "deferred-vars")))