core: update environment variables management

* add new dotfile function `dotspacemacs/user-env`
* add ignored env. vars with variable spacemacs-ignored-environment-variables
* ignore env vars: SSH_AUTH_SOCK and DBUS_SESSION_BUS_ADDRESS
* update documentation in DOCUMENTATION.org
* update .spacemacs.template with new function
* rename environment file from spacemacs.env to .spacemacs.env
* move location of .spacemacs.env file to home or dotdirectory
* add a header to the generated .spacemacs.env file to explain what it is
* make SPC f e e fallbacks to the function dotspacemacs/user-env if the user
  manages the env var by themselves
* make SPC f e E call the new function dotspacemacs/user-env
* sort environment variables in .spacemacs.env file
This commit is contained in:
syl20bnr 2018-07-03 01:20:06 -04:00
parent a087ee2ece
commit a013d86874
7 changed files with 145 additions and 63 deletions

View File

@ -438,6 +438,21 @@ are caught and signaled to user in spacemacs buffer."
(error-message-string err))
t))))))
(defun dotspacemacs/call-user-env ()
"Call the function `dotspacemacs/user-env'."
(interactive)
(dotspacemacs|call-func dotspacemacs/user-env "Calling dotfile user env..."))
(defun dotspacemacs/go-to-function (func)
"Open the dotfile and goes to FUNC function."
(interactive)
(find-function func))
(defun dotspacemacs/go-to-user-env ()
"Go to the `dotspacemacs/user-env' function."
(interactive)
(dotspacemacs/go-to-function 'dotspacemacs/user-env))
(defun dotspacemacs//check-layers-changed ()
"Check if the value of `dotspacemacs-configuration-layers'
changed, and issue a warning if it did."
@ -520,8 +535,7 @@ Called with `C-u C-u' skips `dotspacemacs/user-config' _and_ preleminary tests."
(setq dotspacemacs-editing-style
(dotspacemacs//read-editing-style-config
dotspacemacs-editing-style))
;; reload environment variables
(spacemacs/load-env)
(dotspacemacs/call-user-env)
;; try to force a redump when reloading the configuration
(let ((spacemacs-force-dump t))
(configuration-layer/load))

View File

@ -13,10 +13,19 @@
(require 'load-env-vars)
(defvar spacemacs-env-vars-file
(concat (or dotspacemacs-directory spacemacs-private-directory) "spacemacs.env")
(concat (or dotspacemacs-directory user-home-directory) ".spacemacs.env")
"Absolute path to the env file where environment variables are set.")
(defun spacemacs/init-env (&optional force)
(defvar spacemacs-ignored-environment-variables
'("SSH_AUTH_SOCK"
"DBUS_SESSION_BUS_ADDRESS")
"Ignored environments variables. This env. vars are not import in the
`.spacemacs.env' file.")
(defvar spacemacs--spacemacs-env-loaded nil
"non-nil if `spacemacs/load-spacemacs-env' has been called at least once.")
(defun spacemacs//init-spacemacs-env (&optional force)
"Attempt to fetch the environment variables from the users shell.
This solution is far from perfect and we should not rely on this function
a lot. We use it only to initialize the env file when it does not exist
@ -26,44 +35,74 @@ current contents of the file will be overwritten."
(when (or force (not (file-exists-p spacemacs-env-vars-file)))
(with-temp-file spacemacs-env-vars-file
(let ((shell-command-switch "-ic"))
(insert (shell-command-to-string "env"))))
(insert
(concat
"# ---------------------------------------------------------------------------\n"
"# Spacemacs environment variables\n"
"# ---------------------------------------------------------------------------\n"
"# This file has been generated by Spacemacs. It contains all found\n"
"# environment variables defined in your default shell except the\n"
"# black listed variables defined in `spacemacs-ignored-environment-variables'.\n"
"#\n"
"# You can safely edit this file, Spacemacs won't overwite it unless you call\n"
"# the function `spacemacs/force-init-spacemacs-env'."
"\n"
"# If you don't want to use this file and manage your environment variables\n"
"# yourself then remove the call to `spacemacs/load-spacemacs-env' from your\n"
"# `dotspacemacs/user-env' function in your dotfile and replace it with your\n"
"# own initialization code. You can use `exec-path-from-shell' if you add it\n"
"# to your additional packages or simply use `setenv' and\n"
"# `(add-to-list 'exec-path ...)' which are built-in.\n"
"#\n"
"# It is recommended to get used to this file as it unambiguously and\n"
"# explicitly set the values of your environment variables.\n"
"# ---------------------------------------------------------------------------\n"
"\n"
"# Environment variables:\n"
"# ----------------------\n"))
(insert (string-join
(sort (split-string (shell-command-to-string "env") "\n")
'string-lessp)
"\n"))
(dolist (v spacemacs-ignored-environment-variables)
(flush-lines v (point-min) (point-max)))))
(spacemacs-buffer/warning
(concat "Spacemacs tried to import your environment variables from "
"your shell and saved them to `%s'. "
"Please check that the values are correct by calling "
"`spacemacs/edit-env' function and update the file if needed. "
"If you later need to add environment variables add them to this "
"file.")
(concat "Spacemacs has imported your environment variables from "
"your shell and saved them to `%s'.\n"
"Open this file for more info (SPC e e) or call "
"`spacemacs/edit-env' function.")
spacemacs-env-vars-file)))
(defun spacemacs/force-init-env ()
(defun spacemacs/force-init-spacemacs-env ()
"Forces a reinitialization of environment variables."
(interactive)
(spacemacs/init-env t))
(spacemacs//init-spacemacs-env t))
(defun spacemacs/edit-env ()
"Open the env file for edition."
(interactive)
(if (file-exists-p spacemacs-env-vars-file)
(if (and spacemacs--spacemacs-env-loaded
(file-exists-p spacemacs-env-vars-file))
(progn
(find-file spacemacs-env-vars-file)
(when (fboundp 'dotenv-mode)
(dotenv-mode)))
(message "Cannot file env file `%s'" spacemacs-env-vars-file)))
;; fallback to the dotspacemacs/user-env
(dotspacemacs/go-to-user-env)))
(defun spacemacs/load-env (&optional force)
"Load the environment variables from the env file.
If FORCE is non-nil then force the loading of environment variables from env
(defun spacemacs/load-spacemacs-env (&optional force)
"Load the environment variables from the `.spacemacs.env' file.
If FORCE is non-nil then force the loading of environment variables from env.
file."
(interactive "P")
;; TODO make it work on Microsoft Windows as well
;; it should work everywhere
(when (or force (and (display-graphic-p)
(or (eq system-type 'darwin)
(eq system-type 'gnu/linux)
(eq window-system 'x)))))
(if (file-exists-p spacemacs-env-vars-file)
(progn
(load-env-vars spacemacs-env-vars-file)
(message "Environment variables loaded."))
(message "Cannot file env file `%s'" spacemacs-env-vars-file)))
(spacemacs//init-spacemacs-env)
(setq spacemacs--spacemacs-env-loaded t)
(load-env-vars spacemacs-env-vars-file))
(provide 'core-env)

View File

@ -147,8 +147,9 @@ the final step of executing code in `emacs-startup-hook'.")
(if dotspacemacs-mode-line-unicode-symbols
(setq-default spacemacs-version-check-lighter "[⇪]"))
;; load environment variables
(spacemacs/init-env)
(spacemacs/load-env)
(if (fboundp 'dotspacemacs/user-env)
(dotspacemacs/call-user-env)
(spacemacs/load-spacemacs-env))
;; install the dotfile if required
(dotspacemacs/maybe-install-dotfile))

View File

@ -81,7 +81,7 @@
(when (string-equal "PATH" key)
(let ((paths (split-string value path-separator)))
(dolist (p paths)
(add-to-list 'exec-path p))))
(add-to-list 'exec-path p 'append))))
(setenv key value))))
;;;###autoload

View File

@ -425,6 +425,14 @@ It should only modify the values of Spacemacs settings."
;; (default nil)
dotspacemacs-pretty-docs nil))
(defun dotspacemacs/user-env ()
"Environment variables setup.
This function defines the environment variables for your Emacs session. By
default it calls `spacemacs/load-spacemacs-env' which loads the environment
variables declared in `~/.spacemacs.env' or `~/.spacemacs.d/.spacemacs.env'.
See the header of this file for more information."
(spacemacs/load-spacemacs-env))
(defun dotspacemacs/user-init ()
"Initialization for user code:
This function is called immediately after `dotspacemacs/init', before layer
@ -435,9 +443,9 @@ If you are unsure, try setting them in `dotspacemacs/user-config' first."
(defun dotspacemacs/user-load ()
"Library to load while dumping.
This function is called while dumping Spacemacs configuration. You can
`require' or `load' the libraries of your choice that will be included
in the dump."
This function is called only while dumping Spacemacs configuration. You can
`require' or `load' the libraries of your choice that will be included in the
dump."
)
(defun dotspacemacs/user-config ()

View File

@ -62,6 +62,9 @@
- [[#the-vim-surround-case][The vim-surround case]]
- [[#evil-plugins][Evil plugins]]
- [[#environment-variables-and-path][Environment variables and PATH]]
- [[#default-behavior][Default behavior]]
- [[#managing-environment-variables-by-yourself][Managing environment variables by yourself]]
- [[#note-about-the-function-dotspacemacsuser-env][Note about the function dotspacemacs/user-env]]
- [[#binding-keys][Binding keys]]
- [[#gui-elements][GUI Elements]]
- [[#color-themes][Color themes]]
@ -559,6 +562,8 @@ configuration at the beginning and end of Spacemacs loading process:
- =dotspacemacs/user-init= is called immediately after =dotspacemacs/init=,
before layer configuration. This function is mostly useful for variables
that need to be set before packages are loaded.
- =dotspacemacs/user-env= is called before the layers and packages configuration
and it is responsible to setup environment variables.
- =dotspacemacs/user-config= is called at the very end of Spacemacs
initialization after layers configuration. This is the place where most of
your configurations should be done. Unless it is explicitly specified that a
@ -1001,30 +1006,45 @@ Spacemacs ships with the following evil plugins:
| [[https://github.com/jaypei/emacs-neotree][NeoTree]] | mimic [[https://github.com/scrooloose/nerdtree][NERD Tree]] |
* Environment variables and PATH
If you launch Emacs from a shell then Emacs process will inherit the environment
variables from your shell so you won't get any issue.
Environment variables are handled by the function =dotspacemacs/user-env= of
your dotfile.
On the other hand if you launch Emacs from a launcher without using a shell then
Emacs may not see your environment variables. This is especially true for macOS
users but it can happen to GNU/Linux too.
** Default behavior
By default, the function =dotspacemacs/user-env= only calls the function
=spacemacs/load-spacemacs-env= which loads the environment variables from
the file =~/.spacemacs.env=. This file is automatically created for you by
Spacemacs and it is initialized with the environment variables of your
system as well as the environment variables of your default shell.
To fix this issue Spacemacs first tries to import your shell environment
variable by calling =<shell> -ic env=. It then writes the result to the
=spacemacs.env= file whose location is =~/.emacs.d/private/env= or
=~/.spacemacs.d/env= directory depending on what you are using.
To open this file use ~SPC f e e~. You can edit it to change or add/remove
environment variables. Use ~SPC f e E~ to reload it.
Then Spacemacs loads the environment variables from the =spacemacs.env= file
directly. It won't call your shell anymore at startup. If you need to add new
environment variables or modify them you'll need to edit the =spacemacs.env=
file. You can open this file with ~SPC f e e~ or call the function
=spacemacs/edit-env=.
Some dynamic environment variables are ignored by Spacemacs when it first
creates the =~/.spacemacs.env= file. These ignored variables are listed in
the variable =spacemacs-ignored-environment-variables=.
At any point in time you can force an import of your shell environment variables
with ~SPC f e C-e~. Note that this function will overwrite the contents of your
=spacemacs.env= file.
It is possible to for a new import of system and shell environment variables
with ~SPC f e C-e~. Note that this action will overwrite =~/.spacemacs.env=.
You can reload the environment variables from the =spacemacs.env= file with ~SPC
f e E~.
** Managing environment variables by yourself
For full flexibility you can bypass the default behavior simply by removing
the call to =spacemacs/load-spacemacs-env= from your =dotspacemacs/user-env=
function.
From there you can choose to use the popular package =exec-path-from-shell=
or just call built-in functions like =setenv= or =(add-to-list 'exec-path ...)=.
If you choose to handle the environment variables by yourself then ~SPC f e e~
will go to the function =dotspacemacs/user-env= instead of opening the file
=~/.spacemacs.env=. In all cases ~SPC f e E~ calls the function
=dotspacemacs/user-env= so you can update your variables in place.
** Note about the function dotspacemacs/user-env
Its possible that you don't have this function defined if you have an older
dotfile. It is recommended to update your dotfile by adding this function,
see the file =~/.emacs.d/core/template/.spacemacs.template= to copy it.
If you don't create such function then Spacemacs assumes you are using the
default behavior described above.
* Binding keys
Key sequences are bound to commands in Emacs in various keymaps. The most basic
@ -2390,19 +2410,19 @@ Frame manipulation commands (start with ~F~):
Convenient key bindings are located under the prefix ~SPC f e~ to quickly
navigate between =Emacs= and Spacemacs specific files.
| Key Binding | Description |
|---------------+----------------------------------------------------------------------|
| ~SPC f e d~ | open the spacemacs dotfile (=~/.spacemacs=) |
| ~SPC f e D~ | open =ediff= buffer of =~/.spacemacs= and =.spacemacs.template= |
| ~SPC f e e~ | open the =spacemacs.env= file where environment variables are set |
| ~SPC f e E~ | reload the environment variables by reading the =spacemacs.env= file |
| ~SPC f e C-e~ | reinitialize the =spacemacs.env= file from shell |
| ~SPC f e f~ | discover the =FAQ= |
| ~SPC f e i~ | open the all mighty =init.el= |
| ~SPC f e l~ | locate an Emacs library |
| ~SPC f e R~ | resync the dotfile with spacemacs |
| ~SPC f e U~ | update packages |
| ~SPC f e v~ | display and copy the spacemacs version |
| Key Binding | Description |
|---------------+---------------------------------------------------------------------------------------------------------|
| ~SPC f e d~ | open the spacemacs dotfile (=~/.spacemacs=) |
| ~SPC f e D~ | open =ediff= buffer of =~/.spacemacs= and =.spacemacs.template= |
| ~SPC f e e~ | open the =~/.spacemacs.env= file where environment variables are set or goes to =dotspacemacs/user-env= |
| ~SPC f e E~ | reload the environment variables by executing the function =dotspacemacs/user-env= |
| ~SPC f e C-e~ | reinitialize the =~/.spacemacs.env= file by importing system and shell environment variables |
| ~SPC f e f~ | discover the =FAQ= |
| ~SPC f e i~ | open the all mighty =init.el= |
| ~SPC f e l~ | locate an Emacs library |
| ~SPC f e R~ | resync the dotfile with spacemacs |
| ~SPC f e U~ | update packages |
| ~SPC f e v~ | display and copy the spacemacs version |
**** Browsing files in completion buffer
In =vim= style and =hybrid= style with the variable

View File

@ -205,8 +205,8 @@
"fed" 'spacemacs/find-dotfile
"feD" 'spacemacs/ediff-dotfile-and-template
"fee" 'spacemacs/edit-env
"feE" 'spacemacs/load-env
"fe C-e" 'spacemacs/force-init-env
"feE" 'dotspacemacs/call-user-env
"fe C-e" 'spacemacs/force-init-spacemacs-env
"feR" 'dotspacemacs/sync-configuration-layers
"fev" 'spacemacs/display-and-copy-version
"feU" 'configuration-layer/update-packages