dotslash 技术

在 git 仓库中经常会看到大家存放二进制文件,但这样会存在两个问题:

  1. 二进制文件是分平台的,不同的平台下会使用不同的二进制文件。
  2. 二进制文件会增加 git 仓库的体积。

看到了 facebook 的一个开源项目 datslash,用来解决 git 仓库中存放二进制文件的问题。

安装

在 mac 上执行如下操作:

1
curl -LSfs https://github.com/facebook/dotslash/releases/latest/download/dotslash-macos.tar.gz | tar fxz - -C /usr/local/bin/dotslash

执行 dotslash --version 验证是否安装成功。

功能演示

cloudx 项目中存在一个二进制文件 build/rclone,在构建镜像时会将将该二进制文件 copy 到容器镜像中,以该文件来进行演示。

步骤 1:创建支持上传的 HTTP 服务器

打开一个新的终端窗口:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
mkdir /tmp/dotslash-server
cd /tmp/dotslash-server

# 创建支持 PUT 上传的 HTTP 服务器脚本
cat > server.py << 'EOF'
import http.server
import os

class UploadHandler(http.server.SimpleHTTPRequestHandler):
    def do_PUT(self):
        path = self.translate_path(self.path)
        length = int(self.headers['Content-Length'])
        with open(path, 'wb') as f:
            f.write(self.rfile.read(length))
        self.send_response(201)
        self.end_headers()

if __name__ == '__main__':
    server = http.server.HTTPServer(('', 18000), UploadHandler)
    print('Server running on http://localhost:18000')
    print('Upload with: curl -T <file> http://localhost:18000/<filename>')
    server.serve_forever()
EOF

# 启动服务器
python3 server.py

步骤 2:创建 artifacts 目录并打包 rclone

1
2
3
4
5
6
7
cd ~/git/cloudx/cloudx/build

#  rclone 打包为 tar.gz
tar -czvf rclone-linux-amd64.tar.gz rclone

# 使用 curl 上传到文件服务器
curl -T rclone-linux-amd64.tar.gz http://localhost:18000/rclone-linux-amd64.tar.gz

步骤 3:计算文件大小和 hash

1
2
3
4
5
# 获取文件大小(字节)
stat -f%z rclone-linux-amd64.tar.gz

# 计算 BLAKE3 hash
dotslash -- b3sum rclone-linux-amd64.tar.gz

记录输出的 size 和 digest 值。

步骤 4:备份原 rclone 并创建 DotSlash 文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
cd ~/git/cloudx/cloudx/build

# 备份原二进制文件
rm rclone

# 创建 DotSlash 文件(将 <SIZE>  <DIGEST> 替换为步骤 3 获取的值)
cat > rclone << 'EOF'
#!/usr/bin/env dotslash

{
  "name": "rclone",
  "platforms": {
    "macos-x86_64": {
      "size": 20717235,
      "hash": "blake3",
      "digest": "9e97c4cfdbadb16faae7cbc09754e116e1aa247effcff03d7bb6aac327432bf6",
      "format": "tar.gz",
      "path": "rclone",
      "providers": [
        {
          "url": "http://localhost:18000/rclone-linux-amd64.tar.gz"
        }
      ]
    },
    "macos-aarch64": {
      "size": 20717235,
      "hash": "blake3",
      "digest": "9e97c4cfdbadb16faae7cbc09754e116e1aa247effcff03d7bb6aac327432bf6",
      "format": "tar.gz",
      "path": "rclone",
      "providers": [
        {
          "url": "http://localhost:18000/rclone-linux-amd64.tar.gz"
        }
      ]
    }
  }
}
EOF

# 添加可执行权限
chmod +x rclone

步骤 5:验证 DotSlash 文件

1
2
3
4
5
6
7
cd ~/git/cloudx/cloudx/build
# 运行 DotSlash 文件(首次会从 HTTP 服务器下载)
./rclone version
# 查看 DotSlash 缓存目录
dotslash -- cache-dir
# 再次运行(使用缓存)
./rclone version

实现分析

dotslash 会将文件缓存在 dotslash -- cache-dir 对应的路径上,目录结构如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# tree /Users/kuring/Library/Caches/dotslash
/Users/kuring/Library/Caches/dotslash
├── 2b
   └── a8aa2c317454319085d18e1d9831031dab48bf
       └── rclone
└── locks
    └── 2b
        └── a8aa2c317454319085d18e1d9831031dab48bf

# ll /Users/kuring/Library/Caches/dotslash/2b/a8aa2c317454319085d18e1d9831031dab48bf/rclone 
-r-xr-xr-x@ 1 kuring  staff    58M Jan 26 12:27 /Users/kuring/Library/Caches/dotslash/2b/a8aa2c317454319085d18e1d9831031dab48bf/rclone

整体实现比较简单,代码行数:

dotslash 的局限性:

  1. dotslash 仅能针对代码仓库中的可执行文件来做替换,且必须是可执行文件执行的时候,对于代码仓库中非可执行文件无法处理。因为 dotslash 替换替换文件的时机是发生在执行可执行文件的时候。