1 个不稳定版本

0.1.1 2024年2月20日

#1304解析实现


lisi 中使用

MIT 许可证

60KB
2K SLoC

文献编程工具套件

这是一套用于文献编程的程序。它们试图使这个过程尽可能流畅。

link link link link

基本设计决策

该软件是用 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