EmacsTalk

使用 use-package vc 进行包安装

  tags: use-package

文章目录

在上一篇文章里介绍了 Emacs 30 里, use-package 支持了 :vc 关键字,用于从版本管理工具里下载包,得益于 VC 的功能,Git/SVN 通通都支持。

用法也很简单:

(use-package bbdb
  :vc (bbdb :url "https://git.savannah.nongnu.org/git/bbdb.git"
            :lisp-dir "lisp"
            :doc "doc/bbdb.texi"))

:vc 后面跟的是一个 alist,用来描述包信息,在上面示例中:

通过上面的 plist 我们就可以轻松的安装任意包的任意版本,不会再出现因为重新安装某个包,导致某些功能失效的问题。相比 submodule,vc 的方式有如下好处:

但有一点不完美,vc clone 时是全部历史都下载,一些大型的项目可能会比较慢,目前还没很好解法,只能通过 advice 来兜底:

(defun my/vc-git-clone (fn remote directory rev)
  (if (or (not (string-match-p "elpa" directory))
          (null rev))
      (funcall fn remote directory rev)
    (cond
     ((ignore-errors
        ;; First try if rev is a branch/tag name
        ;; https://stackoverflow.com/a/48748567/2163429
        (vc-git--out-ok "clone" "--depth" "1" "--single-branch" "--branch" rev remote directory)))
     ((vc-git--out-ok "clone" "--single-branch" remote directory)
      (let ((default-directory directory))
        (vc-git--out-ok "checkout" rev))))
    directory))

(advice-add 'vc-git-clone :around
            'my/vc-git-clone)

代码也比较简单直接,当判断下载的目录在 elpa 中,并且 rev 不为空时,尝试进行浅 clone,如果 rev 不是分支名或标签名,也有个 优化,就是只下载单个分支,然后再切到指定 commit 上。

目前我已经把十几个 submodule 换成了 vc 方式,效果非常不错,下面介绍两个比较特殊的案例:

循环依赖

这是在迁移 dash 时遇到了问题,第一次的配置:

(use-package dash
  :vc (dash :url "https://github.com/magnars/dash.el.git"
            :rev "2.19.1")
  :defer t)

是最基本的用法,但是由于 dash 这个仓库内还有个 dash-functional.el 文件,里面的依赖有 dash, 并且 use-package 会先去加载 functional 这个文件,因此就出现了死循环! 通过阅读 package-vc.el 代码,找到了一个解法:

(use-package dash
  :vc (dash :url "https://github.com/magnars/dash.el.git"
            :ignored-files "dash-functional.el"
            :rev "2.19.1")
  :defer t)

利用 ignored-files 来过滤掉不需要的文件,这样就万事大吉了!

安装前执行脚本

有些包在安装时,需要执行些脚本,比如用了动态模块的就需要先编译好依赖,这时可以用:

  • :make 指定一个 Make 的 target,或
  • :shell-command 指定 shell 命令

由于执行脚本会比较危险,因此 Emacs 提供了 package-vc-allow-build-commands 这个变量来控制是否运行脚本,默认是关闭的,可以配置成一个列表,表示运行执行脚本的包,下面是安装我之前写的 omg 时的用法:

(setq package-vc-allow-build-commands '(omg))

(use-package omg
  :vc (omg :url "https://github.com/jiacai2050/oh-my-github"
           :rev "v1.1.0"
           :make "emacs-dyn"
           :lisp-dir "emacs")
  :config
  (omg-setup))

收听方式

反馈