I’ve blogged about a little elisp snippet I use to install my preferred base set of Emacs packages before. Thanks for all the feedback, it definitely helped improve the code.
One issue that kept annoying me is that there is no simple way to tell ELPA to mainly pull packages from melpa-stable and only fall back to melpa for those packages I can’t get on melpa-stable yet. I decided to extend my code to handle that situation with some manual inputs as I know which packages can’t be found on melpa-stable. It proved surprisingly easy to do so after mulling over the problem a little.
First, I updated my function install-required-packages
so that it accepts an optional parameter containing a list of packages repositories. When the parameter is non-nil, I make a temporary copy of the existing packages-archives list to preserve my default settings and replace it with the list that’s been passed in. Then the function checks and install the packages as before and then restores the original package-archives variable. The code now looks like this:
(defun install-required-packages (package-list &optional package-archive-list)
(when (>= emacs-major-version 24)
(if package-archive-list
(setq temp-package-archives package-archives
package-archives package-archive-list))
(package-refresh-contents)
(mapc (lambda (package)
(unless (require package nil t)
(package-install package)))
package-list)
(if package-archive-list
(setq package-archives temp-package-archives))))
As you can see, the function is now a just little more complicated thanks to the additional state preservation code. The big bonus is that it now lets me specify which packages I don’t want to pull from my list of default repositories. To make things easier I also pre-populated the lists of my preferred ELPA repos:
(setq stable-package-archives '(("ELPA" . "http://tromey.com/elpa/")
("gnu"> . "http://elpa.gnu.org/packages/")
("melpa-stable" . "http://stable.melpa.org/packages/")
("marmalade" . "http://marmalade-repo.org/packages/"))
unstable-package-archives '(("melpa" . "http://melpa.org/packages/")))
Now I can simply tell ELPA which packages should be pulled from the default repositories and which ones come from the special repositories:
(install-required-packages '(smex zenburn-theme zen-and-art-theme htmlize cider clojure-mode rainbow-delimiters))
(install-required-packages '(bm icicles) unstable-package-archives)
Quite simple, isn’t it?
Obviously this is still work in progress. The whole approach feels clunky to me and that suggests there is room for improvement. Yes, it works and there is a lot to be said for that, but ideally I would like to build it out in such a way that I specify with package to pull from which repository and add functionality to semi-automatically update the packages as well. I don’t like the idea of fully automated upgrades - especially not from melpa - as I’ve ended up with broken packages before when I took that approach, but a manually triggered auto-update.
Isn’t it great that we spend hours customizing our tools to save five minutes?