Borg で始める Emacs のパッケージ管理

こちらは [ソニックガーデン プログラマ Advent Calendar 2024](https://qiita.com/advent-calendar/2024/sonicgarden) の12日目の記事です。
ブレずに Emacs のパッケージ管理について書いていきます。

# 最初に簡単なまとめ
- [Borg](https://github.com/emacscollective/borg) を使えば Emacs のパッケージをたぶん完全にコントロールできる
- 導入は少し大変

# Emacs のパッケージ管理
Emacs 24 で [package.el](https://mail.gnu.org/archive/html/info-gnu/2012-06/msg00007.html) が本体に含まれるようになって以降、Emacs におけるパッケージの導入・管理はとても簡単にできるようになりました。
また、Emacs 29 からは [use-package](https://github.com/jwiegley/use-package) も本体に含まれるようになり、シンプルで分かりやすい設定を書けるようになっています。

これらのツールでは簡単にパッケージやその設定を管理できる一方、意識しなければ更新時に何が変わったのかはあまり見えず、また依存関係も複雑で Emacs が起動しなくなってしまう(そしてその復旧で数時間かかったり)こともときどきあります。
最初に少し手間はかかりますが、Borg を使い始めてからはそういった困りごとはほぼなくなって快適に過ごせているので、今回紹介してみようと思います。

# Borg とは
- Emacs のパッケージを [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) として管理するパッケージ
- 依存関係を含めて、どのパッケージのどのバージョン(commit hash)をインストールするかをユーザーが指定する
- パッケージの更新についても Git のログを見た上でユーザー自身が判断する

# Borg の導入と設定
## 追加のパッケージマネージャーとして導入する場合
[こちら](https://emacsmirror.net/manual/borg/Use-as-secondary-package-manager.html) を参照して導入しましょう。
私はやったことがないので分かりません。

## 最初から導入する場合
基本は [ここ](https://emacsmirror.net/manual/borg/Bootstrapping-from-scratch.html) に書いてある通りなんですが、簡単に説明していきます。

### 最初に Makefile を用意
最終的に `make` コマンドを通してビルドなどできるようになりますがまだ使いません、とりあえず置いておきましょう。
次回以降にセットアップするときは `make bootstrap-borg` ですべてが完了します。
```makefile:Makefile
DRONES_DIR = $(shell git config "borg.drones-directory" || echo "lib")

-include $(DRONES_DIR)/borg/borg.mk

bootstrap-borg:
	@git submodule--helper clone --name borg --path $(DRONES_DIR)/borg --url https://github.com/emacscollective/borg.git
	@cd $(DRONES_DIR)/borg; git symbolic-ref HEAD refs/heads/main
	@cd $(DRONES_DIR)/borg; git reset --hard HEAD
```

### Borg 本体を Submodule として追加
ゼロからの構築なので Borg 本体がまだありません、Submodule として追加しておきましょう。
```shell
git submodule add --name borg https://github.com/emacscollective/borg.git lib/borg
```

### Borg の初期設定
Borg を使ってパッケージ管理をするための設定です。
`package.el` でのパッケージ管理はしないのでこのタイミングで止めておきます。
```emacs-lisp:early-init.el
(setq package-enable-at-startup nil)
```

```emacs-lisp:init.el
(add-to-list 'load-path (expand-file-name "lib/borg" user-emacs-directory))
(require 'borg)
(borg-initialize)
```

### epkg および依存パッケージの追加
この段階で `git` のコマンドを使用してパッケージ管理はできるようになっているのですが、まだ不便なので便利に扱えるように関連パッケージを追加します。
```shell
git submodule add --name closql https://github.com/emacscollective/closql lib/closql
git submodule add --name emacsql https://github.com/skeeto/emacsql lib/emacsql
git submodule add --name compat https://github.com/emacs-compat/compat lib/compat
git submodule add --name llama https://github.com/tarsius/llama lib/llama
git submodule add --name epkg https://github.com/emacscollective/epkg lib/epkg
git config -f .gitmodules submodule.emacsql.no-byte-compile emacsql-pg.el
echo /epkgs/ >> .gitignore
```

### Magit の追加と設定
`M-x borg-assimilate` から `magit` を追加(依存関係にある `dash`, `with-editor` を先に追加する必要があります)後、以下の設定を追記してください。
```emacs-lisp:init.el
(with-eval-after-load 'magit
  (magit-add-section-hook 'magit-status-sections-hook
                          'magit-insert-modules
                          'magit-insert-stashes
                          'append))
```

### 設定完了
これで設定完了です。
後は `borg-xxxx` 系のコマンドを使って自由にパッケージを管理できます。

## ちょっとした使い方
### パッケージの更新
1. `magit` を開いて `f m` でサブモジュールの更新を取得(fetch)
1. 個別のサブモジュールごとに更新内容を確認して `F u` で取込み(pull)
1. `M-x borg-build` で再ビルド
    - コマンドラインから `make build` で一括ビルドも可能です

### `load-path` を追加したい場合
複数のパスから `.el` ファイルをロードしたい場合があります。
その場合は `.gitmodules` ファイルを開いて `load-path` (複数指定可) を設定します。
```ini:.gitmodules
[submodule "corfu"]
	path = lib/corfu
	url = https://github.com/minad/corfu
	load-path = .
	load-path = extensions
```
### 追加したいパッケージが見つからない
`epkg` で管理しているデータが古くなっている可能性があります。
`M-x epkg-update` を実行してデータを更新しましょう。

# 最後に
導入のハードルは少し高めですが、ぜひみなさんも Borg を使って快適なパッケージ管理をしてみましょう。
13日目は @sincrare です、お楽しみに！