4

Baulk - 一次有趣的尝试

 2 years ago
source link: https://forcemz.net/toolset/2021/07/20/BaulkTalk/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

作为一个程序员,你认为你做过的最让你自豪的东西是什么?作为了一个菜鸡程序员,很遗憾,我拿不出什么像样的作品,工作上也只是站在前人的肩膀上,做了一些微小的改动。如果硬要说一个作品是我最得意的,我会选择 Baulk,它是一个极简的 Windows 包管理器,开发这个工具花费了我大量的业余时间,我很多有意思的构想也在开发 baulk 的过程中付诸实现了。Baulk [bɔːk] 其含义是错误;失败;障碍(等于balk) 或是 阻止;错过;推诿(等于balk);对于绝大多数人来说,2020 年有一个坠落的魔幻开局,到了今年,新冠疫情的阴影任然笼罩全球,Baulk 诞生于 2020 年 3 月 9 日,那个时候我确实是挫败的吧。Baulk 还可以翻译成梁木,阴云将逐渐消散,baulk 也可以成为 梁木

我认为 Baulk 是个有趣的工具,在这篇文章中,我将说一说它为什么会有趣。

为什么会有 Baulk

为什么会有 Baulk,我想到了一个词文人相轻,总觉得自己能够写出更好的软件,他人写的并不能满足我的需求,于是乎,也就有了 Baulk。

《典论·论文》- 曹丕: 文人相轻,自古而然.傅毅之于班固,伯仲之间耳.而固小之,与弟超书曰:“武仲以能属文,为兰台令史,下笔不能自休.”夫人善于自见.而文非一体,鲜能备善,是以各以所长,相轻所短.里语曰:“家有弊帚,享之千金.”斯不自见之患也。

在开发 Baulk 很长一段时间,我使用 PowerShell 开发了一个简单的包管理软件 devi,这个软件最初用于 Clang on Windows 的构建工具的安装,升级。毕竟重复得一次次手动下载安装一些软件总显得有些愚蠢,就如同我们重复说同样的话会被别人觉得怪异。

使用 PowerShell 开发的 devi 缺点也很明显,慢,尽管我是一个 PowerShell 粉丝,但事实我也需要说出来,PowerShell 的加载速度慢,毕竟它需要加载 PowerShell 解析引擎,如果还加载一些启动配置文件,那个速度就很感人了。

2020 年上半年,我终于开始不再忍受基于 PowerShell 的 devi,于是就开始使用 C++17(后来升级为 C++20) 开发新的包管理器 baulk,在 Windows 上有 scoop、chocolatey 这样优秀的开源包管理器,但它们都是基于 PowerShell(C#) 开发,然后在环境变量和安装机制上也与 Baulk 有一些分歧。这些不同之处也是 baulk 存在的原因。

Baulk 有哪些特色

在 baulk 的 ReadMe 页面,介绍了 baulk 的一些特色,但很繁杂,并不是很容易了解全,这里再次简单的介绍一下。

Baulk 是一个绿色的包管理器

在 baulk 的设计哲学中,便携,绿色是其管理软件的宗旨,这衍生出来一些特性,baulk 在安装软件的过程中所执行的动作只有:

  1. 解压压缩包
  2. 移动到安装目录
  3. 创建命令的符号链接或者启动器

为了实现解压各种格式的安装包,baulk 将 Golang 的 archive/ziparchive/tar 使用 C++20 重新实现,提供了 .ziptar.* 等格式的解压能力。其中 zip 解压缩相比于 Minizip 新增支持 deflate64 解压缩能力,与 7z 的 zip 解压缩相比,支持 zstd,可以说 baulk 的解压缩能力还是不错的,另外,baulk 集成了 google 的 Compact Encoding Detection(CED for short) 支持文本编码的自动识别,而一些旧的 zip 文件名并非使用 UTF-8,导致在不同的代码也共享具有中文或者其他多字节编码的文件名的 zip 文件查看或者解压缩乱码,这个问题在 baulk 中被基本解决。

baulk 创新的使用了 Linux/macOS 的安装-软链接技术,这样能够合并 PATH 环境变量的条目数,降低操作系统在搜索环境变量的次数,对的你没看错,操作系统在查找 PATH 中的命令时需要一个目录去找,如果环境变量 PATH 组成的目录太多,会导致搜索次数太多,另外还有一个非常严重的问题,PATH 条目过多还存在 环境变量冲突的影响。baulk 的软链机制就很好的解决了这些问题。有些程序依赖自身目录下的动态链接库,并没有正确处理 GetModuleFilename,所以我们还增加了启动器的机制,当用户安装了 Visual Studio (c++ compiler exists),我们会生成极简的启动源码,编译成启动器,如果没有则会使用 baulk-lnk.exe 代理,baulk-lnk.exe 需要分析安装信息,所以要慢一点点,只有一点点,不会太多。

Baulk 的环境隔离特性

baulk 作为一个绿色的包管理器,一个很强的特性是环境隔离机制,为了支持并行安装同类软件的多个版本,我在 baulk 中引入了虚拟环境隔离机制,对于像 JDK/Golang/DMD/node.js 这样的软件,用户需要安装多个版本并且相互不影响,这个时候 baulk 就派上大用场了,baulk 也不需要像 RVM(ruby) 那样麻烦就能做到提供一套通用解决方案:

下面以 zulu(JDK 的著名发行版)为例,在这里我们支持的 venv 能够指定 category,这是一个大的分类,比如所有的 JDK 发行版的分类就应该是 java,而 path 则告知 baulk-exec 在加载虚拟环境时需要追加的 PATH 环境变量,而 env 则是除了 path 之外其他追加的环境变量,这些变量都支持推导,baulk 内置一些变量可以帮助开发者更好的展开环境变量。

{
    "description": "Zulu is certified build of OpenJDK",
    "version": "16.0.2",
    "homepage": "https://www.azul.com/",
    "url64": "https://cdn.azul.com/zulu/bin/zulu16.32.15-ca-jdk16.0.2-win_x64.zip",
    "url64.hash": "SHA256:2b9ad008596c535c0b4da6ddabe56b35af3198cf00a933b1e60e074a30f31047",
    "urlarm64": "https://cdn.azul.com/zulu/bin/zulu16.30.17-ca-jdk16.0.1-win_aarch64.zip",
    "urlarm64.hash": "SHA256:5263cfc5f9526a5cb9520111d5abb506c6cad18bd1d1ea165d0f218cfd1318c3",
    "extension": "zip",
    "venv": {
        "category": "java",
        "path": "${BAULK_PKGROOT}\\bin",
        "env": [
            "JAVA_HOME=${BAULK_PKGROOT}"
        ]
    }
}

当然,baulk 还支持 includelib 这类特殊的环境变量,这些单独抽出来是为了方便追加。另外 baulk 还支持 dependencies 机制,比如 kotlin-native 就依赖 zulu。

baulk 虚拟环境的精髓在 baulk-exec 中得以实现,其命令行如下:

baulk-exec - Baulk extend executor
Usage: baulk-exec [option] <command> [<args>] ...
  -h|--help            Show usage text and quit
  -v|--version         Show version number and quit
  -V|--verbose         Make the operation more talkative
  -C|--cleanup         Create clean environment variables to avoid interference
  -W|--cwd             Set the command startup directory
  -A|--arch            Select a specific arch, use native architecture by default
  -E|--venv            Choose to load a specific package virtual environment
  --vs                 Load Visual Studio related environment variables
  --vs-preview         Load Visual Studio (Preview) related environment variables
  --clang              Add Visual Studio's built-in clang to the PATH environment variable
  --time               Summarize command system resource usage

Example:
  baulk-exec -V --vs TUNNEL_DEBUG=1 pwsh

Built-in alias:
  winsh          A fake shell. It may be pwsh or powershell and cmd.
  pwsh           PowerShell Core
  pwsh-preview   PowerShell Core Preview

对了,如果用户觉得环境变量乱糟糟的,可以使用 -C/--cleanup 机制避免外部混乱的环境变量带来干扰,为了方便 C++ 开发,baulk 支持初始化 Visual C++ 环境变量,--clang 则可以初始化 Visual Studio 内置的 clang,当然你还可以使用 --time 去分析执行某个命令所消耗的时间。

 >$ baulk-exec --time baulk unzip .\DG520884_x64.zip
x DiskGenius\VPreview.dll
run command 'baulk unzip .\DG520884_x64.zip' use time:
Creation: 625.6us
Kernel:   125ms
User:     93.75ms
Exit:     231.0306ms
Wall:     231.9762ms

Baulk 的其他功能

baulk 还实现了许多其他的功能,限于篇幅长度也就不一一说了,有兴趣可以访问 [baulk/ReadMe.zh-CN.md at master · baulk/baulk (github.com)] 提出建议或者参与到项目的贡献当中。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK