:use-package-ensure-system-package
The :ensure-system-package keyword allows you to ensure certain executables are available on your system alongside your package declarations.[1]
To use this extension, add this immediately after loading use-package:
(use-package use-package-ensure-system-package)Now you can use the :ensure-system-package keyword. Here’s an example usage:
(use-package foo
:ensure-system-package foo)This will expect a global binary package to exist called foo. If it does not, it will use your system package manager to attempt an install of a binary by the same name asynchronously. This requires the GNU ELPA package ‘system-packages’, so for this to work you must install that first.
One way of making sure it is installed is with use-package together with :ensure.
(use-package system-packages
:ensure t)For example, on a Debian GNU/Linux system, this would call ‘apt-get install foo’.
If the package is named differently than the binary, you can use a cons in the form of (binary . package-name). For example:
(use-package foo
:ensure-system-package
(foocmd . foo))On a Debian GNU/Linux system, this would call apt install foo if Emacs could not locate the executable foocmd.[2]
:ensure-system-package can also take a cons where the cdr is a string that will get called by (async-shell-command) to install if it isn’t found. This does not depend on any external package.
(use-package tern
:ensure-system-package (tern . "npm i -g tern"))To install several packages, you can pass in a list of conses:
(use-package ruby-mode
:ensure-system-package
((rubocop . "gem install rubocop")
(ruby-lint . "gem install ruby-lint")
(ripper-tags . "gem install ripper-tags")
(pry . "gem install pry")))Finally, in case the package dependency does not provide a global executable, you can ensure that packages exist by checking the presence of a file by providing a string like so:
(use-package dash-at-point
:if (eq system-type 'darwin)
:ensure-system-package
("/Applications/Dash.app" . "brew cask install dash")):ensure-system-package will use system-packages-install to install system packages, except where a custom command has been specified, in which case it will be executed verbatim by async-shell-command.
The user options system-packages-package-manager and system-packages-use-sudo are honored, but not for custom commands. Custom commands should include the call to sudo in the command if needed.
On macOS, your
exec-pathmight be different if you are starting Emacs as a GUI app instead of from a shell. If you find that Emacs on macOS cannot find some executables that you know are already installed, you could try the ‘exec-path-from-shell’ package. ↩︎For manual testing, you could use the
executable-findfunction, which is what ‘system-packages’ uses internally. ↩︎