7 个版本
0.1.6 | 2023 年 11 月 18 日 |
---|---|
0.1.5 | 2023 年 10 月 14 日 |
6 在 #codebase
60 每月下载次数
100KB
2.5K SLoC
onchg
一个工具,允许您在代码库的不同文件中保持块同步。
安装
pre-commit 钩子
- repo: https://github.com/aksiksi/onchg-rs
rev: v0.1.6
hooks:
- id: onchg
命令行界面
cargo install onchg
快速入门
视频
https://www.loom.com/share/4018aea2378f4e4e8fcd403a70749cde?sid=19f4c8ec-87b6-4eac-a448-f326695189ee
设置
创建一个空目录
mkdir -p /tmp/onchg/quickstart && cd /tmp/onchg/quickstart
创建两个文件 - docs.md
和 header.h
docs.md
:
cat >docs.md <<EOL
# Docs
## Supported Services
<!--- LINT.OnChange(supported-services) --->
* Main
* Primary
* Other
<!--- LINT.ThenChange(header.h:supported-services) --->
EOL
header.h
:
cat >header.h <<EOL
// LINT.OnChange(supported-services)
typedef enum {
INVALID = 0,
MAIN = 1,
PRIMARY = 2,
OTHER = 3,
} supported_services_t;
// LINT.ThenChange(docs.md:supported-services)
EOL
初始化 Git 仓库并提交这两个文件
git init . && git add . && git commit -m "first commit"
pre-commit
创建一个 pre-commit
配置并安装钩子
cat >.pre-commit-config.yaml <<EOL
repos:
- repo: https://github.com/aksiksi/onchg-rs
rev: v0.1.6
hooks:
- id: onchg
EOL
pre-commit install
更改 header.h
--- a/header.h
+++ b/header.h
@@ -5,6 +5,7 @@ typedef enum {
MAIN = 1,
PRIMARY = 2,
OTHER = 3,
+ NEW = 4,
} supported_services_t;
// LINT.ThenChange(docs.md:supported-services)
暂存并提交
$ git add . && git commit -m "my commit"
onchg....................................................................Failed
- hook id: onchg
- exit code: 1
Root path: /home/aksiksi/onchg/quickstart
Parsed 2 files (2 blocks total):
* /home/aksiksi/onchg/quickstart/docs.md
* /home/aksiksi/onchg/quickstart/header.h
Violations:
* block "supported-services" at /home/aksiksi/onchg/quickstart/docs.md:5 (due to block "supported-services" at /home/aksiksi/onchg/quickstart/header.h:2)
命令行界面
在目录上运行 onchg
$ onchg directory
Root path: /home/aksiksi/onchg/quickstart
Parsed 2 files (2 blocks total):
* /home/aksiksi/onchg/quickstart/docs.md
* /home/aksiksi/onchg/quickstart/header.h
OK.
更改 header.h
中的枚举
--- a/header.h
+++ b/header.h
@@ -5,6 +5,7 @@ typedef enum {
MAIN = 1,
PRIMARY = 2,
OTHER = 3,
+ NEW = 4,
} supported_services_t;
// LINT.ThenChange(docs.md:supported-services)
暂存更改并在仓库模式下运行 onchg
$ git add header.h && onchg repo
Root path: /home/aksiksi/onchg/quickstart
Parsed 2 files (2 blocks total):
* /home/aksiksi/onchg/quickstart/docs.md
* /home/aksiksi/onchg/quickstart/header.h
Violations:
* block "supported-services" at /home/aksiksi/onchg/quickstart/docs.md:5 (due to block "supported-services" at /home/aksiksi/onchg/quickstart/header.h:2)
更改 docs.md
--- a/docs.md
+++ b/docs.md
@@ -6,5 +6,6 @@
* Main
* Primary
* Other
+* New
<!-- LINT.ThenChange(header.h:supported-services) -->
暂存更改并重新运行 onchg
$ git add docs.md && onchg repo
Root path: /home/aksiksi/onchg/quickstart
Parsed 2 files (2 blocks total):
* /home/aksiksi/onchg/quickstart/docs.md
* /home/aksiksi/onchg/quickstart/header.h
OK.
文档
示例
双向依赖
alpha.txt
:
OnChange(my-block)
ThenChange(beta.txt:their-block)
beta.txt
:
OnChange(their-block)
ThenChange(alpha.txt:my-block)
相对路径
alpha.txt
:
OnChange(my-block)
ThenChange(subdir/beta.txt:their-block)
subdir/beta.txt
:
OnChange(their-block)
ThenChange(../alpha.txt:my-block)
根路径
alpha.txt
:
OnChange(my-block)
ThenChange(subdir/beta.txt:their-block)
subdir/beta.txt
:
OnChange(their-block)
ThenChange(//alpha.txt:my-block)
单向 OnChange 和 ThenChange
alpha.txt
:
OnChange()
ThenChange(beta.txt:their-block)
beta.txt
:
OnChange(their-block)
ThenChange()
多重依赖
alpha.txt
:
OnChange(my-block)
ThenChange(beta.txt:their-block, gamma.txt:another)
beta.txt
:
OnChange(their-block)
ThenChange()
gamma.txt
:
OnChange(another)
ThenChange(alpha.txt:my-block, beta.txt:their-block)
嵌套块
alpha.txt
:
OnChange(my-block)
OnChange(inner-block)
ThenChange(beta.txt:their-block)
ThenChange()
beta.txt
:
OnChange(their-block)
ThenChange()
详细信息
onchg
使用 块 来捕获不同文件中代码(或更一般地说文本)部分之间的依赖关系。
块看起来像这样
OnChange( [name] )
ThenChange( [<target>[, ...]] )
OnChange
和 ThenChange
部分可以位于行上的任何位置。这允许您将部分放在任何类型的代码注释内部。
OnChange
接受可选的 name
。如果一个块没有指定名称,它不能被其他块用作目标。这在您想要单向依赖的情况下很有用 - 也就是说,如果这个块发生变化,其他块应该发生变化,但反过来则不成立。
ThenChange
接受零个或多个 target
。块目标具有以下语法
[file][:[block]]
就像 OnChange
一样,如果目标列表为空,ThenChange
也允许单向依赖。
如果指定了目标,它可以是文件或文件中的块。块只是块名称。文件路径必须是以下之一
- 相对:路径相对于当前文件的路径(例如,
abc / / .txt)。
- 相对于根目录:路径以
//
开始,表示该路径相对于根目录。当运行onchg
时,您需要指定此路径。通常,根目录是Git仓库的根目录。
基准测试
合成
设置
- 操作系统:Ubuntu 22.04 虚拟机
- 处理器:10核心AMD 3900x等效(虚拟化)
- 磁盘:Corsair Force MP510 PCIe Gen3 NVMe驱动器
基准名称中的150
和1000
表示分析文件的数量。
与grep
相比,除了在所有文件中找到匹配项外,onchg
还需要
- 将所有块的状态加载到内存中。
- 解析并提取捕获组内容以确保块有效。
- 对所有解析的块运行验证步骤。
[!NOTE] 所有基准测试都经过播种,以便可重复。
稀疏
[!NOTE] 这是一个更现实的基准测试。
每个文件有0-10个块,每个块最多有100行。每行的长度从0-100个字符。
比grep
慢约2倍
directory-sparse/150 time: [2.5643 ms 2.5974 ms 2.6338 ms]
grep-sparse/150 time: [1.6161 ms 1.6241 ms 1.6328 ms]
ripgrep-sparse/150 time: [4.9077 ms 4.9354 ms 4.9640 ms]
directory-sparse/1000 time: [15.186 ms 15.271 ms 15.359 ms]
grep-sparse/1000 time: [6.4750 ms 6.5380 ms 6.6048 ms]
ripgrep-sparse/1000 time: [7.6132 ms 7.6550 ms 7.6980 ms]
密集
[!NOTE] 这更像是一个病理性的最坏情况基准测试。
每个文件有50-100个块。与稀疏基准测试相同的行数和行长设置。
比grep
慢5-6倍
directory-dense/150 time: [11.388 ms 11.469 ms 11.554 ms]
grep-dense/150 time: [3.1692 ms 3.1907 ms 3.2138 ms]
ripgrep-dense/150 time: [6.7027 ms 6.7731 ms 6.8621 ms]
directory-dense/1000 time: [83.987 ms 84.581 ms 85.224 ms]
grep-dense/1000 time: [15.269 ms 15.349 ms 15.430 ms]
ripgrep-dense/1000 time: [15.800 ms 15.901 ms 16.004 ms]
Git仓库
[!NOTE] 这也是一个病理性的最坏情况基准测试。块随机依赖于其他块,即使更改的块相对较少,图也很大。
这与上面的密集基准测试相同,但我们随机修改200个块,将其暂存,并运行onchg repo
。基准测试最终解析了约9500个文件;正如上面所述,块/文件连接度很高。请注意,基准测试在1000个文件中总共生成了约75000个块。
git-repo/200 time: [339.91 ms 340.70 ms 341.53 ms]
为什么这么慢??
两个原因
- 文件遍历是单线程的。
- 仅将暂存的差异渲染到stdout就需要250毫秒!
一个有趣的发现:当通过git
功能使用libgit2
时,基准测试需要额外约250毫秒。在深入研究后,似乎延迟的原因是libgit2
中的差异行迭代器。不知何故,它比将差异渲染到stdout和解析它的时间长2倍!
真实代码库
Linux
[!WARNING] 这将在当前工作目录中克隆完整的Linux内核树(~2GB)。
$ ./benches/linux.sh
Number of lines in Linux kernel: 38566988
Root path: /home/aksiksi/repos/onchg/linux
Parsed 82259 files (2 blocks total):
* /home/aksiksi/repos/onchg/linux/.clang-format
* /home/aksiksi/repos/onchg/linux/.cocciconfig
* /home/aksiksi/repos/onchg/linux/.get_maintainer.ignore
* /home/aksiksi/repos/onchg/linux/.gitattributes
* /home/aksiksi/repos/onchg/linux/.gitignore
* /home/aksiksi/repos/onchg/linux/.mailmap
* /home/aksiksi/repos/onchg/linux/.rustfmt.toml
* /home/aksiksi/repos/onchg/linux/COPYING
* /home/aksiksi/repos/onchg/linux/CREDITS
* /home/aksiksi/repos/onchg/linux/Documentation/.gitignore
* /home/aksiksi/repos/onchg/linux/Documentation/ABI/README
* /home/aksiksi/repos/onchg/linux/Documentation/ABI/obsolete/o2cb
* /home/aksiksi/repos/onchg/linux/Documentation/ABI/obsolete/procfs-i8k
* /home/aksiksi/repos/onchg/linux/Documentation/ABI/obsolete/sysfs-bus-iio
* /home/aksiksi/repos/onchg/linux/Documentation/ABI/obsolete/sysfs-bus-usb
... 82244 files omitted
OK.
real 0m0.628s
user 0m0.779s
sys 0m0.974s
依赖项
~10-23MB
~340K SLoC