1 个不稳定版本
0.1.1 | 2024年2月20日 |
---|
#1304 在 解析实现
在 lisi 中使用
60KB
2K SLoC
文献编程工具套件
这是一套用于文献编程的程序。它们试图使这个过程尽可能流畅。
基本设计决策
该软件是用 Rust 编写的。它使用自己的工具来生成 Rust 源代码。
每个逻辑部分都分离在其自己的子 crate 中。大多数这些子 crate 在这个 crate 中定义了同名的命令行工具。在每个子 crate 文件夹中,我们都有一个 <name>.adoc
文件,这是该子 crate 的主要源文件。
子 crate 有
asciidoctrine:: 一个可扩展的 asciidoctrine/asciidoctrine.adoc#, asciidoc 解释器。目前还不是非常成熟。lisi:: 一个灵活的 lisi/lisi.adoc#, 文献编程工具,用于 tangle 和 weave。目前有一些基本功能。ansicht:: 一个 ansicht/ansicht.adoc#, 可视编程工具,主要用于与文献编程工具结合使用。目前只是一个草案。dolmetscher:: 一个 <<dolmetscher/dolmetscher.adoc#, 翻译辅助工具>>。目前只是一个草案。
我认为 asciidoc 比 markdown 更优秀,所以我们使用这个作为我们的基本输入格式。
安装
要安装和使用此软件,有一些不同的选项
//从您的发行版包管理器安装::下载预编译的二进制文件::对于Windows,您可以下载通过github actions构建的https://nightly.link/kober-systems/literate_programming_toolsuite/actions/runs/8063422942/lisi-Windows.zip[最新 Windows二进制文件] 使用Docker镜像::您可以使用Docker Hub上的预编译镜像lammermann/lisi。如果您想修改Dockerfile本身的代码,可以在dockerfile, separate section中找到代码。使用cargo安装::运行[[install_with_cargo]]cargo install --force --path lisi
从源代码构建::这通常意味着您想为项目做出贡献或修改代码以供个人使用。您可以在文档的build_instructions, later in this document中找到说明。NixOS/nix::安装::[[install_with_nix]]nix-env -i -f lisi.nix
本地构建::[[source, sh, save]] .build.sh
[[build_instructions]]
从源代码构建
如果您想修改程序以适应您的用例,您将需要构建和编译代码。
构建工具集需要几个步骤。
[source, sh, save] .build.sh
set -e # <4>
[check_generated_sources_are_vcs_clean](#check_generated_sources_are_vcs_clean) # <1>
[generate_sources](#generate_sources)
[build_and_test](#build_and_test)
[update_docs](#update_docs)
[ask_for_vcs_check_in](#ask_for_vcs_check_in) # <2>
[publish_on_crates_io](#publish_on_crates_io)
[ask_for_local_install](#ask_for_local_install) # <3>
<1> 如果我们手动编辑了一些生成的源代码,我们可能不希望在我们将它们合并回asciidoc源代码之前被我们的构建过程覆盖。 <2> 一旦我们的构建成功,有很大可能性我们希望将更改保存到我们的版本控制系统中。 <3> 如果一切顺利,我们可能想在本地上安装我们的新版本的工具集。 <4> 当某个步骤失败时,我们希望脚本结束
先决条件
您的计算机上必须安装一些程序,才能发布一个版本的《literate programming toolsuite
》。
git:: 目前发布在github上,因此我们需要git。rust, cargo, 等:: 这些程序是用rust编写的,因此我们需要rust工具链。asciidoc:: 目前我们需要asciidcotor
来构建文档。在未来的版本中,计划使用我们自己的asciidoctrine
程序。我们的文档生成过程还有一些额外的依赖项。asciidcotor-diagram::: 用于我们的图表。ditaa::: 用于我们的图表。pygments::: 用于源代码高亮。
检查生成的文件在VCS中是否未更改
也许我们已经手动编辑了一些我们的生成源文件。在这种情况下,我们希望在生成文件之前得到警告。这样我们就可以检查是否想将更改放入我们的asciidoc源代码中,或者是否不关心它们是否被覆盖。
我们假设所有更改的文件(不是asciidoc文件)都可能被覆盖。
[[check_generated_sources_are_vcs_clean]] [source, sh]
changed_files=`git diff --name-only | grep --invert-match '\.adoc$'`
if [[ ! -z "$changed_files" ]]; then
while true; do
echo "some files are modified"
echo "$changed_files"
read -p "Do you wish continue anyway? [yes|no] " yn
case $yn in
[Yy]* ) break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
fi
生成源文件
[[generate_sources]] [source, sh]
echo "Start generating source files ..."
cd asciidoctrine/
lisi -o ../docs/asciidoctrine/asciidoctrine.lisi.html asciidoctrine.adoc \
|| echo "lisi is currenty not installed"
cd ..
cd lisi
lisi -o /dev/null lisi.adoc || echo "lisi is currenty not installed" # <1>
# The new generated source must be able to
# generate itself
cargo run --manifest-path ../Cargo.toml --bin lisi -- -o lisi.html lisi.adoc
cd ..
cargo run --bin lisi -- -o /dev/null README.adoc # <2>
echo "Generating source files done!"
<1> 我们使用预安装的lisi
版本来构建源文件。这有助于我们如果生成的源文件中存在错误。如果我们还没有安装lisi
版本,没有问题,脚本将只给出警告,并在下一步生成源文件。 <2> 由于lisi
目前无法评估带有用户命令行输入的脚本,我们需要定期刷新构建脚本。
构建和测试
[[build_and_test]] [source, sh]
cargo test
为GitHub页面构建网站
稍后我们将使用 asciidoctrine
单独完成这项工作。
[[更新文档]] [来源,shell]
echo "Start generating html files ..."
asciidoctor \
[asciidoctor-styles](#asciidoctor-styles)
-D docs \
README.adoc -o index.html
asciidoctor \
[asciidoctor-styles](#asciidoctor-styles)
-D docs/lisi \
lisi/lisi.adoc
asciidoctor \
[asciidoctor-styles](#asciidoctor-styles)
-D docs/asciidoctrine \
asciidoctrine/asciidoctrine.adoc
asciidoctor \
[asciidoctor-styles](#asciidoctor-styles)
-D docs/ansicht \
ansicht/ansicht.adoc
asciidoctor \
[asciidoctor-styles](#asciidoctor-styles)
-D docs/dolmetscher \
dolmetscher/dolmetscher.adoc
echo "Generating html files done!"
我们有一些通用的样式应该在所有文件中保持一致
[[asciidoctor-styles]] [来源,shell]
-r asciidoctor-diagram \
-a source-highlighter=pygments \
-a toc=left \
-a icons=font \
-a toclevels=4 \
-a data-uri \
-a reproducible \
黑客指南
如果您想修改代码以满足自己的需求,可以参考以下描述我的处理过程
更改源代码:这是一个文献程序,所以这里的真相是 asciidoc 文档。然而,我经常将文献文档和生成的源代码视为同一程序的两种不同视图。为了保持它们同步,我在从文献源重新生成源代码之前,确保将我对生成的源代码所做的任何更改提交到版本控制系统(VCS)。然后,我可以查看生成的源代码和我的修改版本之间的差异,并根据需要相应地更改文献源,直到生成的代码不再与 VCS 中的代码有差异。+ 当两个源同步时,我就可以随意修改文献源,并直接重新生成源代码。编译:在整个修改过程中,我都在循环中编译和测试。为此,我使用 watchexec 作为我的“穷人的 CI”。提交:当错误被修复或功能被实现等时,我将我的修改提交到 VCS。检查:过了一段时间,我想发布。在这里,我执行以下操作:检查文献和生成的源代码是否同步。重新渲染文档。推送到 GitHub。让 CI 执行其工作。
穷人的 CI
每当 Rust 文件更改时,我们希望重新构建和测试程序。
[来源,shell,保存] .auto_build_loop.sh
watchexec -w . -c -e rs,toml --no-vcs-ignore -- "[build_and_test](#build_and_test)"
每当 asciidoc 文件更改时,我们希望重新生成源文件。但在我们能够这样做之前,我们必须确保当前源文件和生成的源文件同步。
TODO 这并不容易,因为当 asciidoc 文件被修改时,它们会生成“脏”的源文件(从版本控制系统的角度来看)。因此,我们必须以某种方式存储这些更改,以便它们看起来是同步的。
请求将更改提交到 VCS
[[请求 VCS 提交]] [来源,shell]
while true; do
git diff; # <1>
read -p "Do you wish to commit your changes to git? [yes|no] " yn
case $yn in
[Yy]* )
git add .; # <2>
git commit; # <2>
break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
<1> 在提交一切之前,我们应该进行最后的审查。<2> 通常我们知道我们在做什么,可以添加一切并继续,但如果我们在提交中看到了我们不希望包含的内容,我们应该在提交之前停止(通过让提交消息为空或通过在其他 shell 中更改包含的块)。
在我们的计算机上安装工具
[[请求本地安装]] [来源,shell]
while true; do
read -p "Do you wish to install this program? [yes|no] " yn
case $yn in
[Yy]* )
[install_with_nix](#install_with_nix);
break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
审查过程
每当主分支或通过拉取请求更新代码时,都会进行审查。审查的主要部分遵循本节中记录的指南。
TODO GitHub Actions
发布
当一切顺利时,是时候考虑发布了。
[[发布到 Crates.io]] [来源,shell]
cargo publish --dry-run -p asciidoctrine
while true; do
read -p "Do you wish to publish asciidoctrine? [yes|no] " yn
case $yn in
[Yy]* )
cargo login;
cargo publish --dry-run -p asciidoctrine;
break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
cargo publish --dry-run -p lisi
while true; do
read -p "Do you wish to publish lisi? [yes|no] " yn
case $yn in
[Yy]* )
cargo login;
cargo publish --dry-run -p lisi;
break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
[[Dockerfile]]
Dockerfile
要在 ci-scripts(至少是我的用例)中使用 lisi
,有一个现成的 Docker 镜像是非常方便的。然而,当涉及到 Docker 镜像大小时,大小是关键。因此,我们在 Dockerfile 中使用了多个不同的阶段
- 一个用于构建我们的软件,并包含所有构建依赖项
- 一个只包含我们的最终二进制文件和最小运行时依赖项,以实现小型镜像大小
[来源,Dockerfile,保存] .Dockerfile
[docker_build_step](#docker_build_step)
[docker_final_image_step](#docker_final_image_step)
为了构建后来具有最小运行时依赖的二进制文件,我们使用musl目标,它允许我们构建静态编译的二进制文件。为此,我们使用基于alpine的rust docker镜像。
[[docker_build_step]] [source, Dockerfile]
FROM rust:alpine AS builder
RUN apk --no-cache add g++ # <1>
WORKDIR /home/rust/
COPY . .
RUN cargo test
RUN cargo build --release
RUN strip target/release/lisi # <2>
<1>由于某种奇怪的原因,我们只能在安装了g++
的系统上编译(参见相关的bug 这里)。<2>构建二进制文件后,我们可以通过striping它们来显著减小大小。
构建我们的程序后,我们基于alpine(因为它体积小)创建一个新的镜像,并将我们的二进制文件复制过来。
[[docker_final_image_step]] [source, Dockerfile]
FROM alpine:latest
WORKDIR /home/lisi
COPY --from=builder /home/rust/target/release/lisi .
ENV PATH="${PATH}:/home/lisi"
TODO github actions for docker image
依赖项
~22–35MB
~340K SLoC