10 个版本
0.2.0 | 2023年6月15日 |
---|---|
0.1.8 | 2019年12月15日 |
0.1.6 | 2019年5月31日 |
0.1.4 | 2018年3月30日 |
0.1.1 | 2017年11月25日 |
#13 in #common-mark
38 次每月下载
54KB
1K SLoC
Linky
从 Markdown 文件中提取链接并检查链接是否损坏。
动机
维护 Markdown 文档时,你经常会遇到很多需要处理的链接。Linky 提取所有链接并检查它们,指出损坏的链接,以便您可以修复它们。具体来说,Linky 是为了简化在 GitHub 上维护 Markdown 文档而创建的。
安装
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
使用 Cargo 编译和安装 linky
$ cargo install linky
用法
提取和检查链接
您可以使用 linky 从 Markdown 文件中提取链接,这是您能做的最简单的事情
$ linky example_site/path/to/example.md
example_site/path/to/example.md:3: https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md
example_site/path/to/example.md:4: https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#existing
example_site/path/to/example.md:5: other.md
example_site/path/to/example.md:6: non-existing.md
example_site/path/to/example.md:7: other.md#existing
example_site/path/to/example.md:8: other.md#non-existing
example_site/path/to/example.md:9: #heading
example_site/path/to/example.md:10: #non-existing
example_site/path/to/example.md:11: #heading-with-code
example_site/path/to/example.md:12: #HEADING
输出列出了所有提取的链接及其相应的输入文件和行号。
启用 --check 选项以解析这些链接
$ linky --check example_site/path/to/example.md
example_site/path/to/example.md:3: OK https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md
example_site/path/to/example.md:4: NO_FRAG https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#existing
example_site/path/to/example.md:5: OK other.md
example_site/path/to/example.md:6: NO_DOC non-existing.md
example_site/path/to/example.md:7: OK other.md#existing
example_site/path/to/example.md:8: NO_FRAG other.md#non-existing
example_site/path/to/example.md:9: OK #heading
example_site/path/to/example.md:10: NO_FRAG #non-existing
example_site/path/to/example.md:11: OK #heading-with-code
example_site/path/to/example.md:12: CASE_FRAG #HEADING
现在,每行都添加了一个状态标记,指示解析的结果。一个 OK
标记表示解析成功,没有备注。有关链接解析的详细信息,请参阅链接解析部分。
递归目录遍历
Linky 不会自动执行目录遍历。相反,它与 find 和 xargs 集成得很好
$ find example_site -type f -print0 | xargs -0 linky
example_site/path/to/absolute.md:2: /path/to/other.md
example_site/path/to/absolute.md:3: /path/to/non-existing.md
example_site/path/to/absolute.md:4: /path/to/other.md#existing
example_site/path/to/absolute.md:5: /path/to/other.md#non-existing
example_site/path/to/example.md:3: https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md
example_site/path/to/example.md:4: https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#existing
example_site/path/to/example.md:5: other.md
example_site/path/to/example.md:6: non-existing.md
example_site/path/to/example.md:7: other.md#existing
example_site/path/to/example.md:8: other.md#non-existing
example_site/path/to/example.md:9: #heading
example_site/path/to/example.md:10: #non-existing
example_site/path/to/example.md:11: #heading-with-code
example_site/path/to/example.md:12: #HEADING
example_site/path/to/filename with spaces.md:1: #
example_site/path/to/follow.md:2: http://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md
example_site/path/to/follow.md:3: http://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#non-existing
example_site/path/to/fragment.md:2: https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#existing
example_site/path/to/fragment.md:3: https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#non-existing
example_site/path/to/other.md:2: example.md
example_site/path/to/transform.md:2: https://github.com/mattias-p/linky/blob/master/example_site/path/to/non-existing.md
example_site/path/to/transform.md:3: https://github.com/mattias-p/linky/blob/master/example_site/path/to/only-on-example-branch.md
注意: 如果您的路径包含空格,您可能需要使用 find -print0 和 xargs -0 选项。
绝对本地链接
默认情况下,linky 不会解析绝对本地链接。这样,您可以知道哪些链接会重定向。此外,linky 也不知道文档根的位置。
$ linky --check example_site/path/to/absolute.md
example_site/path/to/absolute.md:2: ABSOLUTE /path/to/other.md
example_site/path/to/absolute.md:3: ABSOLUTE /path/to/non-existing.md
example_site/path/to/absolute.md:4: ABSOLUTE /path/to/other.md#existing
example_site/path/to/absolute.md:5: ABSOLUTE /path/to/other.md#non-existing
如果您使用 --root 选项指定文档根,linky 将相对该目录执行解析
$ linky --check --root=example_site example_site/path/to/absolute.md
example_site/path/to/absolute.md:2: OK /path/to/other.md
example_site/path/to/absolute.md:3: NO_DOC /path/to/non-existing.md
example_site/path/to/absolute.md:4: OK /path/to/other.md#existing
example_site/path/to/absolute.md:5: NO_FRAG /path/to/other.md#non-existing
HTTP 重定向
默认情况下,linky 不会遵循 HTTP 重定向。这样,您可以知道哪些链接会重定向。
$ linky --check example_site/path/to/follow.md
example_site/path/to/follow.md:2: HTTP_301 http://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md
example_site/path/to/follow.md:3: HTTP_301 http://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#non-existing
启用 --follow 选项,使 linky 在 HTTP 重定向中进行解析
$ linky --check --follow example_site/path/to/follow.md
example_site/path/to/follow.md:2: OK http://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md
example_site/path/to/follow.md:3: NO_FRAG http://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#non-existing
URI 片段标识符
有时当 Markdown 标题转换为 HTML id 属性时,会添加一个前缀到 id 属性中。例如,GitHub 添加了 "user-content-" 前缀。
首先,让我们尝试不带前缀的示例文件
$ linky --check example_site/path/to/fragment.md
example_site/path/to/fragment.md:2: NO_FRAG https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#existing
example_site/path/to/fragment.md:3: NO_FRAG https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#non-existing
现在,让我们尝试添加那个前缀
$ linky --check --prefix='user-content-' example_site/path/to/fragment.md
example_site/path/to/fragment.md:2: PREFIXED https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#existing
example_site/path/to/fragment.md:3: NO_FRAG https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#non-existing
解析前的链接转换
例如,如果您想检查链接针对姐妹网站的开发版本,您可以将链接通过 sed 管道传递以转换基本 URL。
首先,让我们从示例文件中提取所有链接
$ linky example_site/path/to/transform.md
example_site/path/to/transform.md:2: https://github.com/mattias-p/linky/blob/master/example_site/path/to/non-existing.md
example_site/path/to/transform.md:3: https://github.com/mattias-p/linky/blob/master/example_site/path/to/only-on-example-branch.md
使用sed编辑链接,使它们指向姐妹网站
$ linky example_site/path/to/transform.md | sed 's,/master/,/example/,'
example_site/path/to/transform.md:2: https://github.com/mattias-p/linky/blob/example/example_site/path/to/non-existing.md
example_site/path/to/transform.md:3: https://github.com/mattias-p/linky/blob/example/example_site/path/to/only-on-example-branch.md
注意: 您可能需要小心使用sed表达式,以免无意中转换路径前缀。
最后,将编辑后的链接输出管道传输到另一个实际检查链接的链接过程
$ linky example_site/path/to/transform.md | sed 's,/master/,/example/,' | linky --check
example_site/path/to/transform.md:2: HTTP_404 https://github.com/mattias-p/linky/blob/example/example_site/path/to/non-existing.md
example_site/path/to/transform.md:3: OK https://github.com/mattias-p/linky/blob/example/example_site/path/to/only-on-example-branch.md
解析速度
Linky使用线程池进行链接解析。线程池的大小会影响吞吐量,但输出本身不受影响。
您可以使用环境变量RAYON_NUM_THREADS
设置线程池的大小
$ env RAYON_NUM_THREADS=16 linky --check example_site/path/to/example.md
线程池的默认大小等于进程可用的逻辑CPU核心数。您可能可以通过使用比默认更大的线程池来实现更高的吞吐量。使用time
命令来基准测试合适的大小。
解析细节
如果您想知道为什么某个链接解析到了它获得的任何状态令牌,请将环境变量RUST_LOG
设置为warn
。
$ env RUST_LOG=warn linky --check example_site/path/to/example.md
example_site/path/to/example.md:3: OK https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md
WARN linky > Fragment not found
WARN linky > context: link = https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md
WARN linky > context: fragment = #existing
example_site/path/to/example.md:4: NO_FRAG https://github.com/mattias-p/linky/blob/master/example_site/path/to/other.md#existing
example_site/path/to/example.md:5: OK other.md
WARN linky > Document not found
WARN linky > context: link = /tmp/linky/example_site/path/to/non-existing.md
WARN linky > caused by: No such file or directory (os error 2)
example_site/path/to/example.md:6: NO_DOC non-existing.md
example_site/path/to/example.md:7: OK other.md#existing
WARN linky > Fragment not found
WARN linky > context: link = /tmp/linky/example_site/path/to/other.md
WARN linky > context: fragment = #non-existing
example_site/path/to/example.md:8: NO_FRAG other.md#non-existing
example_site/path/to/example.md:9: OK #heading
WARN linky > Fragment not found
WARN linky > context: link = /tmp/linky/example_site/path/to/example.md
WARN linky > context: fragment = #non-existing
example_site/path/to/example.md:10: NO_FRAG #non-existing
example_site/path/to/example.md:11: OK #heading-with-code
WARN linky > Fragment not found case-sensitively
WARN linky > context: link = /tmp/linky/example_site/path/to/example.md
WARN linky > context: fragment = #HEADING
WARN linky > context: anchor = #heading
example_site/path/to/example.md:12: CASE_FRAG #HEADING
链接解析
本地链接解析为本地文件系统中的可读普通文件和目录。HTTP(S)链接使用GET请求解析到200响应,可选地遵循重定向。目标文档被读取并解码为字符串。
对于HTTP(S)链接,片段解析为HTML锚点。对于本地链接,片段解析为Markdown标题。首先尝试无前缀解析片段,如果失败,则尝试使用每个前缀(如果有),进行解析。
问题
如果您在使用linky
时遇到问题,提供测试Markdown文档和执行详细信息将非常有帮助。
例如
$ env RUST_LOG=debug RUST_BACKTRACE=1 linky --check test.md 2&> linky_err.log
注意:
RUST_LOG
控制日志详细程度。RUST_BACKTRACE
控制在panic时打印堆栈跟踪。
只需将生成的linky_err.log
文件拖放到GitHub的问题编辑器中。遗憾的是,截至2018年2月,GitHub不允许拖放Markdown文件 (*.md)。您可以选择
-
将您的
test.md
文件重命名为test.md.txt
-
使用第三方粘贴服务(例如Hastebin)
-
如果文件不大,可以在问题内部使用代码块内联
´´´Markdown
您的测试Markdown内容...
´´´
许可证
版权所有 2017-2019 Mattias Päivärinta
遵循Apache License, Version 2.0(“许可证”);除非您遵守许可证,否则不得使用此分布中的任何文件。您可以在以下位置获得许可证副本:
http://www.apache.org/licenses/LICENSE-2.0
除非适用法律要求或书面同意,否则在许可证下分发的软件按“现状”分发,不提供任何形式的保证或条件,无论是明示的还是暗示的。有关许可证的具体语言、权限和限制,请参阅许可证。
依赖项
~12–28MB
~466K SLoC