From a013d868744551114a18433a083a4a6cfb12e1a9 Mon Sep 17 00:00:00 2001 From: syl20bnr Date: Tue, 3 Jul 2018 01:20:06 -0400 Subject: [PATCH] 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 --- core/core-dotspacemacs.el | 18 +++- core/core-env.el | 81 +++++++++++++----- core/core-spacemacs.el | 5 +- core/libs/load-env-vars.el | 2 +- core/templates/.spacemacs.template | 14 +++- doc/DOCUMENTATION.org | 84 ++++++++++++------- .../spacemacs-defaults/keybindings.el | 4 +- 7 files changed, 145 insertions(+), 63 deletions(-) diff --git a/core/core-dotspacemacs.el b/core/core-dotspacemacs.el index f72fa6365..2d433b55f 100644 --- a/core/core-dotspacemacs.el +++ b/core/core-dotspacemacs.el @@ -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)) diff --git a/core/core-env.el b/core/core-env.el index 2e0ce8b51..633706d02 100644 --- a/core/core-env.el +++ b/core/core-env.el @@ -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) diff --git a/core/core-spacemacs.el b/core/core-spacemacs.el index d6add6b03..9d6df5a10 100644 --- a/core/core-spacemacs.el +++ b/core/core-spacemacs.el @@ -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)) diff --git a/core/libs/load-env-vars.el b/core/libs/load-env-vars.el index 2023bda63..46cac81b0 100644 --- a/core/libs/load-env-vars.el +++ b/core/libs/load-env-vars.el @@ -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 diff --git a/core/templates/.spacemacs.template b/core/templates/.spacemacs.template index 6b174da79..211d8d224 100644 --- a/core/templates/.spacemacs.template +++ b/core/templates/.spacemacs.template @@ -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 () diff --git a/doc/DOCUMENTATION.org b/doc/DOCUMENTATION.org index 8259591b7..df580836b 100644 --- a/doc/DOCUMENTATION.org +++ b/doc/DOCUMENTATION.org @@ -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 = -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 diff --git a/layers/+spacemacs/spacemacs-defaults/keybindings.el b/layers/+spacemacs/spacemacs-defaults/keybindings.el index d26df50b0..5d538fb90 100644 --- a/layers/+spacemacs/spacemacs-defaults/keybindings.el +++ b/layers/+spacemacs/spacemacs-defaults/keybindings.el @@ -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