11

我想知道在 Raku 中创建 CLI 应用程序时推荐哪些步骤(例如 shebang 行和包装脚本)。我对将与 Zef 一起安装的脚本以及将单独分发的脚本的信息感兴趣。

文档提供了示例frobnicate程序:

# inside "frobnicate.raku" 
sub MAIN(Str $file where *.IO.f, Int  :$length = 24, Bool :$verbose) { #`(body omitted)}

我可以运行它raku frobnicate.raku——脚本的一个很好的解决方案,但对于一个真正的程序来说不是很好。

如果我想让它更像一个标准程序,我可以创建一个frobnicate如下文件:

#!/usr/bin/env raku
sub MAIN(Str $file where *.IO.f, Int  :$length = 24, Bool :$verbose) { #`(body omitted)}

我可以使该文件可执行chmod +x并将其移动到我的目录中$PATH;然后我可以用命令 frobnicate frobnicate。到目前为止,所有这些都非常有意义,并且就像任何其他脚本语言一样。

然而,这一切都没有利用 Raku 的编译。因此,执行更多处理的 CLI 应用程序MAIN可能会变得有点慢(即使是生成--help输出)。因此,下一步是允许预编译该应用程序,但我不太确定如何执行此操作。

与泽夫

当我查看使用 Zef 安装 Raku 程序后执行的脚本时,它们几乎都具有以下形式:

#!/usr/bin/env perl6
sub MAIN(:$name, :$auth, :$ver, *@, *%) {
    CompUnit::RepositoryRegistry.run-script("frobnicate", :$name, :$auth, :$ver);
}

而且,当我检查包的来源时,这CompUnit::RepositoryRegistry.run-script条线不存在。所以我猜Zef添加了它?如果是这样,在编写脚本时我需要做些什么来确保 Zef 将使用此包装器并且包装器将起作用?

这条评论有助于理解发生了什么,尽管我仍然不确定我 100% 明白)。

没有 Zef

我想编写用户无需通过 Zef 安装即可运行的脚本(尽管这是我推荐的安装方法)。有没有办法在run-script没有 Zef 的情况下使用上面显示的方法?或者我应该做类似以下的事情,我也见过:

#!/usr/bin/env raku
use Frobnicate::CLI

(然后将实际功能移动到Frobnicate/CLI.rakumod文件中)。

如果我走这条路,我需要指示用户下载frobnicate上面的包装脚本和Frobnicate/CLI.rakumod文件,对吗?(也就是说,没有办法在单个文件中执行此操作,是吗?)

假设我确实需要让我的用户下载两个文件,我应该让他们在哪里安装这些文件? frobnicate需要进入他们的目录PATH,但是呢Frobnicate/CLI.rakumod?是否需要将其复制到他们的 Raku 模块搜索路径中(如果需要,什么命令会显示该路径是什么)?或者我可以frobnicate以某种方式修改包装器(可能通过更改rakuraku -Ilib或类似的方式?),让他们将两者都安装到他们的目录中PATH

在把所有这些都打出来之后,我可能会觉得我在想这个问题。如果是这样,也请告诉我!无论如何,如果我能更好地理解这一点,我很乐意在文档的相关部分添加更多细节。

4

2 回答 2

8

所以我猜Zef添加了它?

CompUnit::Repository::Installation 添加它

为什么会在那里?一个原因是因为某些包装器需要管理同名的 bin 脚本,否则如果它们在同一个目录中会发生冲突。

有没有办法在没有 Zef 的情况下使用上面显示的 run-script 方法?

run-script 仅适用于 CompUnit::Repository::Installation - 如果您不安装模块,则run-script不会感兴趣

假设我确实需要让我的用户下载两个文件,我应该让他们在哪里安装这些文件?

那么推荐/惯用的方法是使用核心 raku 功能来安装东西(即使用 zef)。否则,您应该在哪里放置一些代码是 a) 无关紧要或 b) 将主要依赖于您的环境,您的操作系统的惯用方式等。

是否需要将其复制到他们的 Raku 模块搜索路径中(如果需要,什么命令会向他们显示该路径是什么)

echo $RAKULIB在大多数情况下应该足以显示模块搜索路径,特别是如果他们对安装路径的位置不感兴趣。因此,您可以指示用户设置例如RAKULIB=$FROB_LIB_DIR指向您的库所在的任何位置,如果您希望他们能够运行您的脚本而无需手动指定它raku -I../ frobnicate(因此他们不会将代码复制到任何特殊的地方,他们只是指向他们所在的任何位置例如克隆你的回购)。与$PATH.

或者我可以以某种方式修改 frobnicate 包装器(也许通过将 raku 更改为 raku -Ilib 或类似的东西?)以让他们将两者都安装到其 PATH 上的目录的方式?

我建议不要根据$PATH. 指导用户设置$PATH,不要安装东西$PATH

从技术上讲,您可以添加use lib '../'到您的脚本中,但是use lib在您还希望用户正常安装的脚本中使用它并不理想,因为它在从此类安装运行时添加了一个未使用的、可能被劫持的模块搜索路径。

如果您希望您的代码预编译,那么我建议将其放入一个模块中,并指示您的用户,如果他们不打算安装它,请raku -I../ ./frobnicate在每次使用的基础上调用它,或者类似export RAKULIB="$FROB_LIB_DIR,$RAKULIB"的东西,然后再做./frobnicate一些事情永恒的。或者,如果有人最终实现了脚本的预编译,那么您可以只使用单文件方法。

于 2021-02-24T22:52:23.827 回答
3

关于这个话题的一些评论。

  1. 我认为使用它是最佳的,zef因为zef也会加载依赖项。能够在不使用其他模块的情况下编写 Raku 程序已经很不寻常了,我希望随着更多 Raku 模块的开发,这会变得更加不寻常。

  2. 我忘记了我在系统上安装了哪些模块,并包含在程序中。通过在 中指定所有内容META6.json,然后运行zef test .,提高了确保其他人可以下载该模块的机会。实际上,我找到了确保这一点的最佳方法是创建一个 docker 文件并尝试在 docker 映像/容器中安装一个新模块 - 但这是另一个主题。

  3. 我发现(对于 Linux,我无法评论 Windows)如果我:

    • 在 Raku 中编写一个可执行文件(见下文),让我们调用它MyWonder
    • 放在<distribution>/bin文件夹里,
    • 给它 +x 权限,并且
    • 在发行版的根META6.json文件中指定它
    • (发布分布)

    然后在zef安装发行版时,MyWonder将在命令行上运行(假设它zef本身在命令行上运行,这意味着它PATH包含 zef 的目录)。

  4. 调用旨在在命令行上使用或由桌面调用的程序的最佳(对我而言)方法是:

    • 将以下内容放入MyWonder文件中(无需扩展)
    use v6.d;
    use MyWonderLife;
    
    • 将所有功能放入MyWonderLife.rakumod
    • 确保至少有sub MAIN一个MyWonderLife.rakumod
    • MyWonderLife在文件中指定META6.json(这使得您可以在哪个目录下放置实际文件有很大的灵活性MyWonderLife.rakummod;它不必是lib/
    • 为分布创建一个简单t/basic.rakutest的测试,只有测试use-ok 'MyWonderLife;

    这个秘籍意味着所有功能都由 zef 预编译,因此当用户调用可执行文件时,会有更快的响应。使用 Raku 时最慢的部分是编译程序。通过使用 zef 安装,这在安装期间完成一次。所有语言的程序安装速度都很慢,因此 Raku 程序不会让用户想知道在使用它时发生了什么。

    其次,可以使用几个multi sub MAIN来处理各种调用情况,并使用现在可以处理的命令行选项的范围。虽然这显然在任何脚本中都是可能的,但将它们全部放在一个.rakumod文件中似乎(对我来说)更自然。

    我发现在安装模块时进行大量测试是一件很痛苦的事情,因此我开始将大部分开发和维护测试转移xt/t/.

    最后,有了这个秘籍(假设你在文件中给了发行版 MyWonderLife 的名字META6.json,安装说明MyWonder,假设可以不带参数调用程序很简单:

    使用 zef 安装 MyWonderLife,例如,

    zef install MyWonderLife
    

    并在命令行上使用它,如下所示:

    MyWonder
    
于 2021-02-25T11:26:14.657 回答