I share my .emacs file between machines, which works great but I use a lot of packages and when emacs starts on a new machine with the .emacs it complains about the missing package. I can ignore it until I install that package, but it's laborious having to manually install packages. Is there a way to install all the packages needed by my .emacs file?
3 Answers
I manage this by dotting require-package
calls around my emacs config, where require-package
is defined as follows:
(defun require-package (package &optional min-version no-refresh)
"Install given PACKAGE, optionally requiring MIN-VERSION.
If NO-REFRESH is non-nil, the available package lists will not be
re-downloaded in order to locate PACKAGE."
(if (package-installed-p package min-version)
t
(if (or (assoc package package-archive-contents) no-refresh)
(package-install package)
(progn
(package-refresh-contents)
(require-package package min-version t)))))
and then elsewhere I'll have code like:
(require-package 'haskell-mode)
(add-hook 'haskell-mode-hook 'interactive-haskell-mode)
If you want to get fancier about it, you can use John Wiegley's use-package package, which has an :ensure
keyword that triggers package installation. But then, you still have to install use-package
itself first, e.g. with a call to package-install
!

- 2,871
- 13
- 17
-
Great solution. – Boccaperta-IT Oct 08 '14 at 19:55
This is one way to do it. I took the idea from Aaron Bedra. Basically you group the packages you want to install. If they are not installed, they will be installed when you start Emacs. If they are already installed, nothing happens.
(defvar custom/packages '(ido-ubiquitous
ido-vertical-mode
flx-ido
smex
browse-kill-ring
hungry-delete
smartscan
org
magit
auctex
latex-pretty-symbols
ebib
latex-preview-pane
latex-extra
adaptive-wrap
clojure-mode
cider
pandoc-mode
multifiles
rainbow-delimiters
bookmark+)
"Default packages")
(defun custom/packages-installed-p ()
(loop for pkg in custom/packages
when (not (package-installed-p pkg)) do (return nil)
finally (return t)))
(unless (custom/packages-installed-p)
(when (not package-archive-contents)
(message "%s" "Refreshing package database...")
(package-refresh-contents)
(dolist (pkg custom/packages)
(when (not (package-installed-p pkg))
(package-install pkg)))))

- 1,556
- 11
- 24
-
1If you are missing packages from the list, but `package-archive-contents` is non-nil, then your `(when (not package-archive-contents) ...` form aborts prematurely, which means that the missing packages don't get installed. – nispio Oct 08 '14 at 20:52
-
Thanks for that. It never happend to me, but it is worth pointing out. – Boccaperta-IT Oct 09 '14 at 07:21
Since I write my configuration in a org file and then use some org-babel magic to make a .el which is loaded later by Emacs, I wrote a script in Python that I run from the same org file and it creates a .el file with every package installed in my emacs configuration, this is how it looks:
** Repositorio de paquetes
<Spanish comments omitted...>
#+begin_src emacs-lisp
(setf package-archives (list (quote ("gnu" . "http://elpa.gnu.org/packages/"))
(quote ("marmalade" . "http://marmalade-repo.org/packages/"))
(quote ("melpa" . "http://melpa.milkbox.net/packages/"))
(quote ("org" . "http://orgmode.org/elpa/"))))
#+end_src
<Spanish comments omitted...>
** Listado, revisión e instalación de paquetes con Melpa
<Spanish comments omitted...>
#+BEGIN_SRC emacs-lisp
(org-babel-do-load-languages
'org-babel-load-languages
'(
(emacs-lisp . t)
(python . t)
)
)
#+END_SRC
#+name: codigopython
#+BEGIN_SRC python :results output :file paquetes.el
import os
if os.path.isdir(os.path.expanduser("~/.emacs.d/elpa/")):
melpapackages = os.listdir(os.path.expanduser("~/.emacs.d/elpa/"))
packagestoinstall = []
for package in melpapackages:
if os.path.isdir(os.path.expanduser("~/.emacs.d/elpa/") + package):
name = package[:package.rfind("-")]
if not name == "archive":
packagestoinstall.append(
"(use-package {0}\n :ensure {0})".format(name))
# Remove any repeated package. This can happen if different directories
# with the same package name exists in the elpa/ directory
packagestoinstall = list(set(packagestoinstall))
# Sort things, please!
packagestoinstall.sort()
print("\n".join(packagestoinstall))
#+END_SRC
#+RESULTS: codigopython
[[file:paquetes.el]]
<Spanish comments omitted...>
#+BEGIN_SRC emacs-lisp :results silent
(unless (file-exists-p (expand-file-name "elpa/archives/melpa" user-emacs-directory))
(package-refresh-contents))
(when (not (package-installed-p 'use-package))
(package-install 'use-package))
(require 'use-package)
(load-file (expand-file-name "paquetes.el" user-emacs-directory))
#+END_SRC
<Spanish comments omitted...>
I just have to move the cursor inside the source block with the python code, do Cc Cc and BAM! I have all my packages installed listed automatically :)
If you want, you can copy the Python snippet and paste it inside a file, so you can call it as a command from your shell, redirecting the output to a file. This in case you don't use org-mode and org-babel for your Emacs configuration!

- 2,702
- 18
- 47