一个关于包管理方法(基于git)的构思

用过各种各样的包管理方法(package.el, straighel.el, submodule, borg等),目前使用的是在submodule上增功能的borg,很好用,但有一些小缺点始终觉得不太舒服,

第一是利用submodule的方法在删除包特别是其依赖的时候相对繁琐,经常容易漏。个人倾向于包的安装和配置在一起,而不是单独有一个文件(.gitmodule)来维护,这样只要我删除声明就意味着包的失效和删除,类似于straight那种。第二是submodule的浅克隆和更新混在一起比较麻烦,经常出错。但喜欢borg对特殊build的简化,比straight.el简洁多了。

因此,最近想做一个懒人版的简单包,可能是重复造轮子,目的是为了简洁,透明,同时满足自己的需求。

我大概有以下几个设想

  1. 完全基于 git, 这样近乎所有的包都可以用统一的方法安装,同时节省大量其他管理方法的代码
  2. 基于声明式的安装,只要在包的配置里加一句声明就会安装包,删除声明,包就不会被添加到load-path(这里初步想法是自动根据声明语句统计出来一个list,然后对不在list里的包路径进行删除,在list里的包就会自动添加到load-path和自动编译)。
  3. 完全不自动处理依赖。换而是在安装包的时候直接写把依赖的声明写到这个包旁边,不用的时候就连包带依赖的声明一起删了,这样不会遗漏,而且不怕有一些包被很多包依赖,因为只要有一处声明还在就不会被删除。
  4. 可以基于命令行控制(更新安装编译卸载),保证了每次打开emacs很干净不会出现乱七八糟的报告或者错误。也可以交互式
  5. 支持浅克隆和更新,可能就不用submodule了直接用git clone,通过增加一个commit id变量来控制版本
  6. 支持一键更新和单独更新,更新时会把每个包当前commit的log和最新commit之间的所有log按照一定格式打出,方便快速了解更新了什么,也可以根据commit来回退。
  7. 支持传递一组形如“make install”的字符串列表给包,用户可以对一些包进行简洁的控制
  8. 如果对包有pr,就直接在git目录里操作就好

这些想法一气呵成就写出来了,感觉在脑子里萦绕很久了。最开始是想去对straight进行改造,因为他满足了大部分需求,后来感觉straight本身太复杂了,而且很多功能我也用不到。我的预想是包的代码量要小,方便后续维护拓展或者是其他新手的学习。而且我认为管理包时越少的控制,将来越容易排错。

但我没写过包,做出来估计需要一段时间,而且不知道写这种包有没有意义,毕竟这种轮子太多了,大佬们感兴趣求指点一下我

大概像下面这样

  (easy-install package-b :host "github" :repo "xxx/package-b" :commit-id "asdsadad") ;; 依赖
  (easy-install package-c :host "gitlab" :repo "xxx/package-c" :build "make" "make install") ;; 依赖
  
  (easy-install package-a)
  (require 'package-a)
  (with-eval-after-load 'package-a
    ...)

这不就是 straight.el嘛?不如给straight.el增加个关闭自动解决依赖的功能。

对的,我最开始其实就是想对straight进行更改,也尝试了一下,能力有限,发现有几个地方比较难做,第一个是打印更新log,这里如果在命令行解析straight并进行比对再打印,非常麻烦。第二个,striaght安装一些包比如eaf需要写不少代码,这里我认为是过于复杂化了,基于submodule之类的方案可以很简单的安装,这里我倾向于更透明化和易懂的方式。最后一个比较麻烦的地方是,straight其实分为build和repo,通过编译和软连接的方式添加路径,我发现这种情况下有一些包期望当前路径是git仓库然后才能进行编译,会不好装。

说来说去,其实我觉得包管理不应该复杂的绕来绕去,像submodule那样简单直接就好,简单就意味着稳定和容易排除包的错误

也许,我需要的仅仅是对git做一些包裹哈哈哈

简单写了个git submodule 批量更新和打印package log的脚本,borg也可用(我就是在borg上用的)

  1. 会对master或者main 分支的代码进行更新
  2. 对更新进行汇总,按照更新的commit以一种相对漂亮的方式打印出log,并暂存于/tmp/git_update_log方便继续查看。

效果如下,有更新的包会打印出,没有更新的包仅打印名字

代码如下,颜色或样式不满意可随意调整

log_file=/tmp/git_update_log
rm $log_file
touch $log_file

function pull() {
    log_file=/tmp/git_update_log
    PN=$(basename $(pwd))
    last_commit=$(git rev-parse HEAD)
        git checkout master || git checkout main; echo $PN >> $log_file&&git pull; git log $last_commit...HEAD --no-merges --color --graph --date=format:'%Y-%m-%d %H:%M:%S' --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Cblue %s %sCgreen(%cd) %C(bold blue)<%an>%Creset' --abbrev-commit >>$log_file;
}

export -f pull
git submodule foreach 'pull' && cat $log_file

将上述代码存到./etc/update_submodule.sh,可直接在Makefile加一句以方便使用

update:
	./etc/update_submodule.sh
1 个赞