3

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?

Malabarba
  • 22,878
  • 6
  • 78
  • 163
voodoogiant
  • 131
  • 2

3 Answers3

1

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!

sanityinc
  • 2,871
  • 13
  • 17
0

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)))))
Boccaperta-IT
  • 1,556
  • 11
  • 24
  • 1
    If 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
0

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!

shackra
  • 2,702
  • 18
  • 47