Just under a year ago I decided to totally rewrite my GNU emacs config. As I wrote at the time, it’d been following me around all sorts of machines since the early 1990s, starting life on an OS/2 Warp machine and travelling via MS-DOS, GNU/Linux, Windows and, these days, macOS.

The changes I made last year have served me really well, but there were two related issues with it that bothered me a little: the fact that I was maintaining a local library of elisp code in the repository and, worse still, I was storing the packages I’d installed from elpa and melpa in the repository as well.

While this did mean it was pretty easy for me to start up a new installation of emacs on a machine – all I had to do was clone the repo and run up emacs – I wasn’t happy with the duplication involved. I didn’t like holding code in my .emacs.d repo that was already held in package archives.

The solution I saw was in two parts:

  1. Get some of my code, that might be useful to others, into melpa.
  2. Somehow sort my own package archive for my personal code.

Over the past week or so I’ve worked on this approach. It initially started with me tackling item 1 above: I tidied up and submitted obfusurl.el, protocols.el, services.el, thinks.el and uptimes.el. This was a really helpful process in that it allowed me to brush up on my elisp and emacs knowledge. It’s a good 15+ years since I last wrote any significant elisp code and things have moved on a little in that time.

Having done that I’d managed to move a handful of my own packages out of my local library of code, and so out of my .emacs.d repo, but it left me with the problem of what to do with the rest of it.

That’s when I discovered package-x and:

,----[ C-h f package-upload-buffer RET ]
| package-upload-buffer is an interactive compiled Lisp function in
| ‘package-x.el’.
| (package-upload-buffer)
| Upload the current buffer as a single-file Emacs Lisp package.
| If ‘package-archive-upload-base’ does not specify a valid upload
| destination, prompt for one.

(plus package-upload-file too, of course). This meant I could, in effect, start my own personal package archive and look at tackling issue 2 above.

This did give me one small problem though: how and where would I host the archive? I did consider hosting it on a DigitalOcean droplet, but that felt a little like overkill for something so simple. And then I realised: GitHub Pages! All I needed to do was keep the package archive in its own repo (which I would have done anyway) and then make the whole repo the source for a GitHub Pages site. A quick test later and… it worked!

So, by this point, I’d farmed some of my code off to melpa, and now had the rest of it in “delpa” (which I’d called my personal archive). I could now use the emacs package management system to install third party packages and also my own.

But I was still left with one issue: I was still holding the installed packages inside my .emacs.d repo by way of ensuring that all machines were in sync in terms of what was installed. Now I needed to work out how to solve that.

Around this time, as luck would have it, @tarsius had suggested I look at a package called use-package by @jwiegley. This was the bit I was missing.

With use-package I would be able to declare which packages I needed, how they’d be installed and, most important of all, it could be set to handle the fact that the package wasn’t even installed. If a package is requested and there is no local install use-package is smart enough to get the emacs package system to install it.

So, given that, all I need to do was create a startup file that would declare the packages I use and I’d have a setup that should, once I’d cloned .emacs.d, self-install.

Except… yeah, one more issue. use-package isn’t part of GNU emacs yet so I’d need a method of getting it to auto-install so it could then handle everything else. As it was that was as easy as adding this to the start of my init.el.

;; Make sure the package system is up and running early on.
(require 'package)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
(add-to-list 'package-archives '("delpa" . "http://blog.davep.org/delpa/"))

;; Bootstrap `use-package'
(unless (package-installed-p 'use-package)
  (package-install 'use-package))

With that in place I was able to nuke all my config on a machine, clone a fresh copy of .emacs.d (having now ceased tracking and storing the installed packages in that repo), run up emacs, wait a few moments and then find that everything was installed and ready to use.


My .emacs.d is now a lot smaller than it was before and, I think, even easier to maintain. Right now I think I’m very close to the ideal emacs config that I wanted to create when I did the complete rewrite a year ago.