Baulk

Stella981
• 阅读 533

前言

相对于其他操作系统,我更习惯使用 Windows,但一直以来 Windows 缺乏官方的包管理器,而第三方无论是 Scoop 还是 Chocolatey 都无法满足我独特的需求,我的要求很简单,所有的软件包都应该使用绿色解压模式,这包括了 MSI 安装包,另外安装软件时不应该修改系统和用户环境变量。包管理工具应该足够快,还要支持创建启动器等等。

从毕业工作以来,我开发了 clangbuilder,一个简化在 Windows 上使用 Visual Studio 构建 LLVM/Clang 的工具(含 GUI 工具),为了解决安装构建 LLVM 时所需工具依赖的问题,后来多次开坑编写各种软件,多年的失败经验与认知不断积累,于是在今年这个环球同此凉热的年份,我开始了新坑 ➡ baulk,baulk 花费了我半年的下班时间,现在基本可用,ReadMe 也写好了,应该可以给大家分享一下了。

安装和使用 Baulk

这个步骤只有四五步,下载 baulk 二进制包,解压 baulk 二进制包,点击 baulkterminal,更新元数据,安装你需要的软件,🆗,你可以使用 baulk 安装的软件了。

baulk update
# i 是 install 的别名
# baulk i cmake curl 7z ...
baulk install cmake curl 7z
cmake --version

baulk 升级命令可以使用如下命令:

baulk update
baulk upgrade

也可以使用别名:

# u 是特殊的别名,包含 update 和 upgrade 两个步骤
# baulk update and upgrade
baulk u

升级 baulk 自身可以使用帮助程序 baulk-update

baulk-update

卸载软件也很容易:

# r 是 uninstall 的别名
baulk uninstall 7z

在开发 baulk 时,我就决定只支持 Windows 10 1903 或更新的版本,好处显而易见,可以使用 Windows Terminal,利用 ANSI 转义输出颜色,体验非常不错:

Baulk

baulk 提供了 baulk-exec 在命令行中执行 baulk-exec 可以初始化 baulk 环境,还提供了 ssh-askpass-baulk,ssh-askpass-baulk 用于 TunnelSSH 某些 ssh 无法打开标准输入时请求输入密码,截图如下:

Baulk

在 baulk 中我引入了 VirtualEnv 机制,这种机制能够使得用户并行安装多个软件版本,在 baulk-exec,baulkterminal 中通过指定参数支持启动任意的 VENV,baulk 还提供了 baulk-dock 能够选择按照特定的 VENV 启动环境:

Baulk

在 Baulk 元数据存储库 bucket,收录了 OpenJDK8(Java),OpenJDK9(Java),GraalVM8(Java),Zulu14(Java),Go(golang),DMD(dlang) 等支持 VENV 的包,如果有人想把 Ruby 收录一下,在 Windows 上实现类似 rbenv 功能也不是什么难事。

Baulk 的内幕

入门说完,可以稍稍讲一下 Baulk 的实现细节,baulk 的包管理类似于 Scoop,即将包的元数据存储在 Github 上,官方源为 baulk/bucket,baulk 还可以通过编写 $BAULK_ROOT/config/baulk.json 添加新的源,或者删除某个源,如果不同的源中存在相同名字的包,baulk 还能根据 bucket 的权重去选择使用哪个源,但目前为止,只有 baulk/bucket 一个源。

{
    "bucket": [
        {
            "description": "Baulk default bucket",
            "name": "Baulk",
            "url": "https://github.com/baulk/bucket",
            "weights": 100
        }
    ]
}

baulk update 命令更新 bucket,这里我们使用了 Github Atom RSS 机制,以官方源为例,通过 HTTP 请求项目的 commits/master.atom 获得当前的最新的 commitID,如果本地不存在或者与其不同,则说明 bucket 有更新,于是 baulk 下载对应的 bucket 的压缩包,解压完成元数据的更新。然后检测本地已安装的包是否存在更新版本,存在就输出提示。

GET https://github.com/baulk/bucket/commits/master.atom

当人们运行 baulk upgrade 时,就会真正的升级已安装的包,更新元数据和升级分开这种机制类似于 apt-get,为了简化操作,baulk 提供了 baulk u 别名将 update/upgrade 合并在一起简化升级。

在 Baulk 中,安装软件大的步骤只有解压和生成启动器(创建符号链接),不存在什么执行初始化脚本,修改注册表,关联文件打开方式等等等等等。我的想法是最好做到隔离互不影响,因此,在开发 baulk 的过程中,我一直时朝这个方向去设计。在 baulk 中的 package 中,存在 extension 的关键字,extension 用于描述 package 压缩包(安装包)如何被 baulk 解压缩, extension 支持 zip, msi, 7z, exetar,baulk 按照 extension 的类型执行相应的解压缩程序。扩展的解压程序如下:

扩展

解压程序

限制

exe

-

-

zip

内置,基于 minizip

支持 deflate/bzip2/zstd,不支持加密和 deflate64(deflate64 可以使用 7z

msi

内置,基于 MSI API

此方式仅作解压,和在资源管理器点击安装不同

7z

优先级:
baulk7z - Baulk 发行版
7z - 使用 baulk install 安装的
7z - 环境变量中的

tar.* 之类格式解压不能一次完成,因此建议使用 tar 解压 tar.* 压缩包

tar

优先级:
baulktar - BaulkTar bsdtar 的现代重构
bsdtar - Baulk 构建版
MSYS2 tar - Git for Windows 携带的
Windows tar

Windows 内置的 tar 不支持 xz(基于 libarchive bsdtar),但 baulk 构建的 bsdtar 支持,解压 zip 时均不不支持 deflate64

baulk 的哲学是不要修改系统和用户环境变量,环境变量的生效应该是和终端关联或者启动器关联,因此,在 baulk 中,我编写了 baulkterminal 和 baulk-exec 以及 baulk-dock 程序,baulkterminal 主要用于用户通过创建桌面快捷方式或者将 baulkterminal 添加到桌面、文件夹右键菜单,通过用户点击快速打开初始化 Baulk 环境的 Windows Terminal(如果没有安装 Windows Terminal 则打开 Windows 控制台),而 baulk-exec 则是一个启动器,在运行 baulk-exec 时,根据输入的命令行参数 baulk-exec 初始化环境变量,然后启动相关的子命令,比如 Windows 操作系统中没有安装 cmake,而 baulk 安装了 cmake,以下命令就能够正常运行:

# 打印 cmake 版本信息
baulk-exec cmake --version

为了避免环境变量中 PATH 条目过多,降低 SearchPath 搜索相关命令的命中率,baulk 使用了 links 机制,对于一些不依赖自身目录下的 dll 的命令,我们使用创建符号链接的方式将其软连接到 baulk 根目录的 bin\links 目录,如果自身依赖发行携带的 dll,或者需要处理 GetModuleFileName 且没有正确处理符号链接行为的命令,我们使用 launchers 机制,根据命令的类型调用 MSVC 生成特定的启动器,启动器大小 5K 左右,体积能够接受。如果用户没有安装 Visual Studio,则使用 baulk-lnk 实现相关逻辑(baulk-lnk 需要解析 baulk.linkmeta.json,效率有一点点损失)。baulk 在环境变量和启动器这块做了很多事情,需要解析 PE 可执行文件的信息,还需要获得 PE 文件的版本信息,在之前使用 PowerShell 编写的 devi 中,同样是这样做的,但 PowerShell 脚本执行不太快,baulk 相比是一个巨大的效率提升。

baulk 使用 WinHTTP 实现 HTTP 下载功能,能够很好的处理代理的情况,另外,baulk 还会解析 HTTPS_PROXY 环境变量,还支持 --https-proxy 设置代理,但是,我们建议应该优先使用支持设置 Windows 系统代理的工具。

baulk 基于 minizip 内置了 zip 提取能力,支持使用 ZSTD 压缩算法的 ZIP 文件,这比市面上很多压缩软件要快一步。baulk 还内置了 bela::hash 支持 SHA2(SHA224, SHA256, SHA384, SHA512) SHA3(SHA3-224, SHA3-256, SHA3-384, SHA3-512),以及 BLAKE3。由于安全问题不支持 MD5 和 SHA1,因此在 bucket 存储包哈希时应该选择使用这里列出的哈希算法,哈希字符串使用前缀匹配,默认即无前缀时为 SHA256。

  constexpr HashPrefix hnmaps[] = {
      {L"BLAKE3", hash_t::BLAKE3},     // BLAKE3
      {L"SHA224", hash_t::SHA224},     // SHA224
      {L"SHA256", hash_t::SHA256},     // SHA256
      {L"SHA384", hash_t::SHA384},     // SHA384
      {L"SHA512", hash_t::SHA512},     // SHA512
      {L"SHA3", hash_t::SHA3},         // SHA3 alias for SHA3-256
      {L"SHA3-224", hash_t::SHA3_224}, // SHA3-224
      {L"SHA3-256", hash_t::SHA3_256}, // SHA3-256
      {L"SHA3-384", hash_t::SHA3_384}, // SHA3-384
      {L"SHA3-512", hash_t::SHA3_512}, // SHA3-512
  };

Baulk VirtualEnv 介绍

这里需要重点说的时 Baulk VirtualEnv,很多时候,开发者不得不并行安装一个软件的多个版本以适配不同的开发需求,但这些软件在处理环境变量的时候并没有做的那么好,因此有了 VirtualEnv 这样的工具,比如 rbenv 。baulk 目前能够很好的大多数编程语言开发工具的 VirtualEnv,以下截图是加载 Zulu14(Java JDK) 和 Go 的截图:

Baulk

目前 baulkterminal 和 baulk-exec 能够加载任意的 venv,baulk-dock 仅支持一个。

最后

baulk 花费了我很多的时间,我自己用还是很好用的,并且 baulk 沉淀了我这些年来在 Windows 系统上的技术积累,所以写一篇文章记录一下还是有一些必要的。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
35岁,真的是程序员的一道坎吗?
“程序员35岁是道坎”,“程序员35岁被裁”……这些话咱们可能都听腻了,但每当触及还是会感到丝丝焦虑,毕竟每个人都会到35岁。而国内互联网环境确实对35岁以上的程序员不太友好:薪资要得高,却不如年轻人加班猛;虽说经验丰富,但大部分公司并不需要太资深的程序员。但35岁危机并不是不可避免的,比如你可以不断精进技术,将来做技术管理或者
Wesley13 Wesley13
3年前
35岁是技术人的天花板吗?
35岁是技术人的天花板吗?我非常不认同“35岁现象”,人类没有那么脆弱,人类的智力不会说是35岁之后就停止发展,更不是说35岁之后就没有机会了。马云35岁还在教书,任正非35岁还在工厂上班。为什么技术人员到35岁就应该退役了呢?所以35岁根本就不是一个问题,我今年已经37岁了,我发现我才刚刚找到自己的节奏,刚刚上路。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这