使用 use-package vc 进行包安装
tags: use-package
文章目录
在上一篇文章里介绍了 Emacs 30 里, use-package 支持了 :vc 关键字,用于从版本管理工具里下载包,得益于 VC 的功能,Git/SVN 通通都支持。
用法也很简单:
1(use-package bbdb
2 :vc (bbdb :url "https://git.savannah.nongnu.org/git/bbdb.git"
3 :lisp-dir "lisp"
4 :doc "doc/bbdb.texi")):vc 后面跟的是一个 alist,用来描述包信息,在上面示例中:
bbdb包名,也是下载的目录名,通过 vc 下载的包也是在elpa文件夹内,一般来说可以省略,默认就是包名其余的部分是个 plist,常用的属性有:
url仓库地址lisp-dir代码位置,默认是项目根目录rev可以分支名、tag 名、commit id,特殊值:last-release表示最新的 release 分支main-file从这个文件中提取包的 metadata 信息,默认是包名.el
通过上面的 plist 我们就可以轻松的安装任意包的任意版本,不会再出现因为重新安装某个包,导致某些功能失效的问题。相比 submodule,vc 的方式有如下好处:
- 自动包安装依赖
- 自动生成 autoloads
但有一点不完美,vc clone 时是全部历史都下载,一些大型的项目可能会比较慢,目前还没很好解法,只能通过 advice 来兜底:
1(defun my/vc-git-clone (fn remote directory rev)
2 (if (or (not (string-match-p "elpa" directory))
3 (null rev))
4 (funcall fn remote directory rev)
5 (cond
6 ((ignore-errors
7 ;; First try if rev is a branch/tag name
8 ;; https://stackoverflow.com/a/48748567/2163429
9 (vc-git--out-ok "clone" "--depth" "1" "--single-branch" "--branch" rev remote directory)))
10 ((vc-git--out-ok "clone" "--single-branch" remote directory)
11 (let ((default-directory directory))
12 (vc-git--out-ok "checkout" rev))))
13 directory))
14
15(advice-add 'vc-git-clone :around
16 'my/vc-git-clone)代码也比较简单直接,当判断下载的目录在 elpa 中,并且 rev 不为空时,尝试进行浅 clone,如果 rev 不是分支名或标签名,也有个 优化,就是只下载单个分支,然后再切到指定 commit 上。
目前我已经把十几个 submodule 换成了 vc 方式,效果非常不错,下面介绍两个比较特殊的案例:
循环依赖
这是在迁移 dash 时遇到了问题,第一次的配置:
1(use-package dash
2 :vc (dash :url "https://github.com/magnars/dash.el.git"
3 :rev "2.19.1")
4 :defer t)是最基本的用法,但是由于 dash 这个仓库内还有个 dash-functional.el 文件,里面的依赖有 dash,
并且 use-package 会先去加载 functional 这个文件,因此就出现了死循环!
通过阅读 package-vc.el 代码,找到了一个解法:
1(use-package dash
2 :vc (dash :url "https://github.com/magnars/dash.el.git"
3 :ignored-files ("dash-functional.el")
4 :rev "2.19.1")
5 :defer t)利用 ignored-files 来过滤掉不需要的文件,这样就万事大吉了!类似的还有:
1(use-package evil
2 :vc (evil :url "https://github.com/emacs-evil/evil"
3 :ignored-files ("evil-*.el")
4 :rev "1.14.2"))安装前执行脚本
有些包在安装时,需要执行些脚本,比如用了动态模块的就需要先编译好依赖,这时可以用:
:make指定一个 Make 的 target,或:shell-command指定 shell 命令
由于执行脚本会比较危险,因此 Emacs 提供了 package-vc-allow-build-commands 这个变量来控制是否运行脚本,默认是关闭的,可以配置成一个列表,表示运行执行脚本的包,下面是安装我之前写的 omg 时的用法:
1(setq package-vc-allow-build-commands '(omg))
2
3(use-package omg
4 :vc (omg :url "https://github.com/jiacai2050/oh-my-github"
5 :rev "v1.1.0"
6 :make "emacs-dyn"
7 :lisp-dir "emacs")
8 :config
9 (omg-setup))收听方式

反馈
- 对节目有想法或发现内容错误?欢迎来信交流️