The :ensure-system-package
keyword allows you to ensure certain
executables are available on your system alongside your package
declarations.6
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
.7
: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-path
might 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-find
function,
which is what ‘system-packages’ uses internally.