A reproducible build is getting closer
Problem
One of the problems with GNU Emacs is that it is difficult to create a reproducible build. Of course, you can always make yourself a container and run Emacs using Docker, Podman or even Kubernetes… But I’m not talking about such complex cases now.
So, the essence of the problem: if you create a file init.el
and debug it, then after 2-3 months running Emacs with it on another computer will most likely lead to installation errors or package incompatibility.
Authors of various programming languages and technologies have solved the problem of package incompatibility in different ways. Since I used to write in Python, it's closest to me REQUIREMENTS
-files.
June will most likely fill REQUIREMENTS
So:
django
django-rest-framework
pillow
psycopg2
Middle is called that because it has seen some crap, so the package versions will be nailed down:
django==5.1.1
django-rest-framework==3.15.2
pillow==10.4.0
psycopg2<3
The senior will build a container with the specified dependencies and will use it and only that.
Solutions
What about Emacs? For a very long time there was no way to use fixed versions of packages from archives like MELPA. The fact is that archives do not store version history, but provide access only to the latest release of the package. Need I say that MELPA packages often break?
MELPA Stable does not solve the problem, because it collects packages not of the stable version, but of any package in general, as long as it contains a version control system tag.
Quote from README
Packages in MELPA are built directly from the latest package source code in the upstream repositories, but we also build and publish packages corresponding to the latest tagged code in those repositories, where version tags exist. These packages are published in a separate package archive called MELPA Stable. Most users should prefer MELPA over MELPA Stable.
They tried to solve the problem of fixing dependencies in Emacs in different ways. For this (but not only this) reason, projects such as:
Straight.el
El-get
Quelpa
Cask
Eask
Each of them has its own characteristics, and many have poor documentation. The Eask project seemed especially enchanting in this regard, which officially recommends not to read a site with its own documentation.
There are also solutions that offer to add package code as Git sub-modules. But that's not our way, right?
package-vc-install
The Emacs authors figured out how to solve the problem of fixing package versions, and at the same time preserve functionality package.el
. Meet us! package-vc-install.el
!
Starting with version 29.1, the package became available in Emacs package-vc-install
which is almost the same as package.el
only allows you to install specified versions of packages from specified sources.
Function package-vc-install
takes as input the name of the package and a dictionary with source settings. The keys of this dictionary can have the following values:
:url
— link to the repository. You can use the path to a local directory.:branch
— branch name, tag name or commit hash.:lisp-dir
— path to the directory with files.el
. This field must be filled in if the package files are not stored in the root directory.:doc
— path to the directory with documentation. This field must be completed if you want to collect documentation along with the package. But in general this is not necessary.
There are other keys, see for more details. GNU Emacs documentation.
Cons?
You have to pay for everything, and package-vc-install
no exception. You will have to:
independently search for repositories of the required packages;
install the client of the corresponding version control system into the system;
independently track package updates.
There is good news: if you update use-package
up to version 2.4.6
then the necessary functionality is already built in:
(use-package delight
:ensure t
:vc (:url "https://git.savannah.nongnu.org/git/delight.git"
:rev "1.7"))
(use-package ace-window
:ensure t
:vc (
:url "https://github.com/abo-abo/ace-window.git"
:rev "0.10.0")
:bind (:map global-map
("M-o" . ace-window)))
See details in package documentation on the GNU ELPA website.