From f99cf0ccc8e781ea00c10e0159affe4073151e91 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Sat, 17 Sep 2022 22:02:50 +0200 Subject: [PATCH] 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 --- .gitignore | 2 +- bin/doom | 21 +++++++++++--- early-init.el | 19 ++++++++----- lisp/cli/profiles.el | 19 ++++++------- lisp/doom-profiles.el | 66 ++++++++++++++++++++++++------------------- 5 files changed, 76 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index acb81ccc7..124310e16 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # machine generated doom profiles or metadata -/profiles/init.*el +/profiles/*.el /.local*/ # possible user config files diff --git a/bin/doom b/bin/doom index b270ae943..8450cebae 100755 --- a/bin/doom +++ b/bin/doom @@ -139,11 +139,24 @@ ENVIRONMENT VARIABLES: option also sets this variable. `$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' - (Not implemented yet) Where to find or write generated Doom profiles - (default: `$EMACSDIR'/profiles). + `$DOOMPROFILELOADFILE' + Doom generates a profile loader script on 'doom sync' or 'doom 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: 0 Successful run diff --git a/early-init.el b/early-init.el index 45f5d7194..b7ee3d854 100644 --- a/early-init.el +++ b/early-init.el @@ -74,14 +74,19 @@ (setq user-emacs-directory (expand-file-name init-dir)))) ;; FIX: Discard the switch to prevent "invalid option" errors later. (push (cons "--profile" (lambda (_) (pop argv))) command-switch-alist) - ;; Running 'doom sync' will (re)generate a lightweight profile - ;; bootstrapper in $EMACSDIR/profiles/init.el, after reading - ;; $EMACSDIR/profiles.el, $DOOMDIR/profiles, - ;; $XDG_CONFIG_HOME/doom-profiles.el, and ~/.doom-profiles.el. All it - ;; needs is for `$DOOMPROFILE' to be set. + ;; Running 'doom sync' or 'doom profile sync' (re)generates a light + ;; profile loader in $EMACSDIR/profiles/load.el (or + ;; $DOOMPROFILELOADFILE), after reading `doom-profile-load-path'. This + ;; loader requires `$DOOMPROFILE' be set to function. (setenv "DOOMPROFILE" profile) - (or (load (expand-file-name (format "profiles/init.%d.elc" emacs-major-version) - user-emacs-directory) + (or (load (expand-file-name + (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) (user-error "Profiles not initialized yet; run 'doom sync' first")))) diff --git a/lisp/cli/profiles.el b/lisp/cli/profiles.el index 463a601e5..867c69673 100644 --- a/lisp/cli/profiles.el +++ b/lisp/cli/profiles.el @@ -38,17 +38,16 @@ :benchmark t (let* ((old-profiles (doom-profiles-read doom-cli-known-profiles-file)) (new-profiles (doom-profiles-autodetect)) - (init-file doom-profiles-bootstrap-file) - (version (doom-file-read init-file :by 'read :noerror t)) + (load-file doom-profile-load-file) + (version (doom-file-read load-file :by 'read :noerror t)) (recreate? (or (not reload?) (doom-profiles-outdated-p)))) - (unless (file-exists-p init-file) - (print! (warn "No profile manifest found. Generating one...")) + (unless (file-exists-p load-file) + (print! (warn "No profile loader found. Generating one...")) (print-group! (print! (start "Regenerating it..."))) (setq recreate? t)) (unless (equal (or version doom-version) doom-version) - (print! (warn "Detected version mismatch in profile manifest (%s != %s)" - version - doom-version)) + (print! (warn "Detected version mismatch in profile loader (%s != %s)" + version doom-version)) (print! (start "Generating profile manifest...")) (setq recreate? t)) (print-group! @@ -70,9 +69,9 @@ (dolist (p removed) (print! (item "Removed %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-profiles-save new-profiles) - (print! (success "Regenerated profile bootstrapper: %s") - (path doom-profiles-bootstrap-file))))))))) + (doom-profiles-save new-profiles load-file) + (print! (success "Regenerated profile loader: %s") + (path load-file))))))))) ;; diff --git a/lisp/doom-profiles.el b/lisp/doom-profiles.el index 5e68b1cc8..ffb24ea34 100644 --- a/lisp/doom-profiles.el +++ b/lisp/doom-profiles.el @@ -8,31 +8,37 @@ ;;; Variables ;;; File/directory variables -(defvar doom-profiles-dir doom-data-dir +(defvar doom-profiles-generated-dir doom-data-dir "Where generated profiles are kept. Profile directories are in the format {data-profiles-dir}/$NAME/@/$VERSION, for example: '~/.local/share/doom/_/@/0/'") -(defvar doom-profile-dirs - (list (file-name-concat doom-user-dir "profiles") - (file-name-concat doom-emacs-dir "profiles")) - "A list of directories to search for implicit Doom profiles in.") +(defvar doom-profile-load-path + (if-let (path (getenv-internal "DOOMPROFILELOADPATH")) + (mapcar #'expand-file-name (split-string-and-unquote path path-separator)) + (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 - (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")) - "A list of potential locations for a profiles.el file. +`doom-profiles-initialize' loads and merges all profiles defined in the above +files/directories, then writes a profile load script to +`doom-profile-load-file'. -`doom-profiles-initialize' will load and merge all profiles defined in the above -files, and will write a summary profiles.el to the first entry in this -variable.") +Can be changed externally by setting $DOOMPROFILELOADPATH to a colon-delimited +list of paths or profile config files (semi-colon delimited on Windows).") -(defvar doom-profiles-bootstrap-file - (file-name-concat doom-emacs-dir (format "profiles/init.el" emacs-major-version)) - "Where Doom writes its interactive profile bootstrap script.") +(defvar doom-profile-load-file + (if-let (loader (getenv-internal "DOOMPROFILELOADFILE")) + (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) "TODO") @@ -113,21 +119,23 @@ run.") :key #'car))))))) (nreverse profiles))) -(defun doom-profiles-autodetect () +(defun doom-profiles-autodetect (&optional _internal?) "Return all known profiles as a nested alist. -This reads all profiles in `doom-profile-config-files', then reads implicit profiles -living in `doom-profile-dirs', then caches them in `doom--profiles'. If RELOAD? -is non-nil, refresh the cache." - (doom-profiles-read doom-profile-config-files - doom-profile-dirs)) +This reads all profile configs and directories in `doom-profile-load-path', then +caches them in `doom--profiles'. If RELOAD? is non-nil, refresh the cache." + (doom-profiles-read doom-profile-load-path + ;; TODO: Add in v3 + ;; (if internal? doom-profiles-generated-dir) + )) (defun doom-profiles-outdated-p () - "Return non-nil if files in `doom-profile-loader-file' are outdated." - (cl-loop for file in doom-profile-config-files - if (or (not (file-exists-p doom-profiles-bootstrap-file)) - (file-newer-than-file-p file doom-profiles-bootstrap-file) - (not (equal (doom-file-read doom-profiles-bootstrap-file :by 'read) + "Return non-nil if files in `doom-profile-load-file' are outdated." + (cl-loop for path in doom-profile-load-path + when (string-suffix-p path ".el") + if (or (not (file-exists-p doom-profile-load-file)) + (file-newer-than-file-p path doom-profile-load-file) + (not (equal (doom-file-read doom-profile-load-file :by 'read) doom-version))) return t)) @@ -153,7 +161,7 @@ is non-nil, refresh the cache." (defun doom-profiles-save (profiles &optional file) "Generate a profile bootstrapper for Doom to load at startup." (unless file - (setq file doom-profiles-bootstrap-file)) + (setq file doom-profile-load-file)) (doom-file-write file (let ((profilesym (make-symbol "profile")) (deferredsym (make-symbol "deferred-vars")))