BREAKING CHANGE: This restructures the project in preparation for Doom to be split into two repos. Users that have reconfigured Doom's CLI stand a good chance of seeing breakage, especially if they've referred to any core-* feature, e.g. (after! core-cli-ci ...) To fix it, simply s/core-/doom-/, i.e. (after! doom-cli-ci ...) What this commit specifically changes is: - Renames all core features from core-* to doom-* - Moves core/core-* -> lisp/doom-* - Moves core/autoloads/* -> lisp/lib/* - Moves core/templates -> templates/ Ref: #4273
140 lines
6.2 KiB
EmacsLisp
140 lines
6.2 KiB
EmacsLisp
;;; lisp/cli/env.el --- envvar file generator -*- lexical-binding: t; -*-
|
|
;;; Commentary:
|
|
;;; Code:
|
|
|
|
;;
|
|
;;; Variables
|
|
|
|
(defvar doom-env-file (doom-path doom-profile-data-dir "env")
|
|
"The location of your envvar file, generated by `doom env`.
|
|
|
|
This file contains environment variables scraped from your shell environment,
|
|
which is loaded at startup (if it exists). This is helpful if Emacs can't
|
|
\(easily) be launched from the correct shell session (particularly for MacOS
|
|
users).")
|
|
|
|
(defvar doom-env-deny
|
|
'(;; Unix/shell state that shouldn't be persisted
|
|
"^HOME$" "^\\(OLD\\)?PWD$" "^SHLVL$" "^PS1$" "^R?PROMPT$" "^TERM\\(CAP\\)?$"
|
|
"^USER$" "^GIT_CONFIG" "^INSIDE_EMACS$"
|
|
;; X server or services' variables that shouldn't be persisted
|
|
"^DISPLAY$" "^DBUS_SESSION_BUS_ADDRESS$" "^XAUTHORITY$" "^XDG_SESSION_TYPE$"
|
|
;; Windows+WSL envvars that shouldn't be persisted
|
|
"^WSL_INTEROP$"
|
|
;; ssh and gpg variables (likely to become stale)
|
|
"^SSH_\\(AUTH_SOCK\\|AGENT_PID\\)$" "^\\(SSH\\|GPG\\)_TTY$"
|
|
"^GPG_AGENT_INFO$"
|
|
;; Internal Doom envvars
|
|
"^DEBUG$" "^INSECURE$" "^\\(EMACS\\|DOOM\\)DIR$" "^__")
|
|
"Environment variables to omit from envvar files.
|
|
|
|
Each string is a regexp, matched against variable names to omit from
|
|
`doom-env-file'.")
|
|
|
|
(defvar doom-env-allow '()
|
|
"Environment variables to include in envvar files.
|
|
|
|
This overrules `doom-env-deny'. Each string is a regexp, matched against
|
|
variable names to omit from `doom-env-file'.")
|
|
|
|
|
|
;;
|
|
;;; Commands
|
|
|
|
(defcli! env
|
|
((allow-only ("--allow-all"))
|
|
(deny-only ("--deny-all"))
|
|
(output-file ("-o" path) "Write envvar file to non-standard PATH.")
|
|
;; TODO (refresh? ("-r" "--refresh"))
|
|
&multiple
|
|
(rules ("-a" "--allow" "-d" "--deny" regexp) "Allow/deny envvars that match REGEXP"))
|
|
"(Re)generates envvars file from your shell environment.
|
|
|
|
The envvars file is created by scraping the current shell environment into
|
|
newline-delimited KEY=VALUE pairs. Typically by running '$SHELL -ic env' (or
|
|
'$SHELL -c set' on windows). Doom loads this file at startup (if it exists) to
|
|
ensure Emacs mirrors your shell environment (particularly to ensure PATH and
|
|
SHELL are correctly set).
|
|
|
|
This is useful in cases where you cannot guarantee that Emacs (or the daemon)
|
|
will be launched from the correct environment (e.g. on MacOS or through certain
|
|
app launchers on Linux).
|
|
|
|
This file is automatically regenerated when you run this command or 'doom sync'.
|
|
However, 'doom sync' will only regenerate this file if it exists.
|
|
|
|
Why this over exec-path-from-shell?
|
|
|
|
1. `exec-path-from-shell' spawns (at least) one process at startup to scrape
|
|
your shell environment. This can be arbitrarily slow depending on the
|
|
user's shell configuration. A single program (like pyenv or nvm) or config
|
|
framework (like oh-my-zsh) could undo all of Doom's startup optimizations
|
|
in one fell swoop.
|
|
|
|
2. `exec-path-from-shell' only scrapes some state from your shell. You have to
|
|
be proactive in order to get it to capture all the envvars relevant to your
|
|
development environment.
|
|
|
|
I'd rather it inherit your shell environment /correctly/ (and /completely/)
|
|
or not at all. It frontloads the debugging process rather than hiding it
|
|
until you least want to deal with it."
|
|
(let ((env-file (doom-path (or output-file doom-env-file))))
|
|
(with-temp-file env-file
|
|
(setq-local coding-system-for-write 'utf-8-unix)
|
|
(print! (start "%s envvars file")
|
|
(if (file-exists-p env-file)
|
|
"Regenerating"
|
|
"Generating"))
|
|
(print-group!
|
|
(goto-char (point-min))
|
|
(insert
|
|
";; -*- mode: lisp-interaction; coding: utf-8-unix; -*-\n"
|
|
";; ---------------------------------------------------------------------------\n"
|
|
";; This file was auto-generated by `doom env'. It contains a list of environment\n"
|
|
";; variables scraped from your default shell (based on your settings for \n"
|
|
";; `doom-env-allow' and `doom-env-deny').\n"
|
|
";;\n"
|
|
(if (file-equal-p env-file doom-env-file)
|
|
(concat ";; It is NOT safe to edit this file. Changes will be overwritten next time you\n"
|
|
";; run 'doom sync'. To create a safe-to-edit envvar file use:\n;;\n"
|
|
";; doom env -o ~/.doom.d/myenv\n;;\n"
|
|
";; And load it with (doom-load-envvars-file \"~/.doom.d/myenv\").\n")
|
|
(concat ";; This file is safe to edit by hand, but needs to be loaded manually with:\n;;\n"
|
|
";; (doom-load-envvars-file \"path/to/this/file\")\n;;\n"
|
|
";; Use 'doom env -o path/to/this/file' to regenerate it."))
|
|
"\n")
|
|
;; We assume that this noninteractive session was spawned from the user's
|
|
;; interactive shell, so simply dump `process-environment' to a file.
|
|
;;
|
|
;; This should be well-formatted, in case humans want to hand-modify it.
|
|
(let* ((denylist (remq nil (append (if deny-only '(".")) (list allow-only) doom-env-deny)))
|
|
(allowlist (remq nil (append (if allow-only '(".")) (list deny-only) doom-env-allow))))
|
|
(dolist (rule rules)
|
|
(push (cdr rule) (if (member (car rule) '("-a" "--allow"))
|
|
allowlist
|
|
denylist)))
|
|
(insert "(")
|
|
(dolist (env (get 'process-environment 'initial-value))
|
|
(catch 'skip
|
|
(let* ((var (car (split-string env "=")))
|
|
(pred (doom-rpartial #'string-match-p var)))
|
|
(when (seq-find pred denylist)
|
|
(if (seq-find pred allowlist)
|
|
(doom-log "Whitelisted %s" var)
|
|
(doom-log "Ignored %s" var)
|
|
(throw 'skip t)))
|
|
(insert (prin1-to-string env) "\n "))))
|
|
(insert ")"))
|
|
(print! (success "Generated %s") (path env-file))
|
|
t))))
|
|
|
|
(defcli! (env (clear c)) ()
|
|
"Deletes the default envvar file."
|
|
(let ((env-file (abbreviate-file-name doom-env-file)))
|
|
(unless (file-exists-p env-file)
|
|
(user-error "No envvar file to delete: %s" env-file))
|
|
(delete-file env-file)
|
|
(print! (success "Deleted %s") (path env-file))))
|
|
|
|
(provide 'doom-cli-env)
|
|
;;; env.el ends here
|