在Clojure中构建CLI脚本
在Clojure中构建CLI脚本的常用/标准方法是什么 我认为这种方法应包括以下特点:在Clojure中构建CLI脚本,clojure,scripting,Clojure,Scripting,在Clojure中构建CLI脚本的常用/标准方法是什么 我认为这种方法应包括以下特点: 一种容易处理参数的方法,stdin/out/err 没有太多的启动时间(理想情况下是有某种JIT),否则就失去了在shell中把东西拼凑在一起的目的 此外,我们有理由期待一种简单的方法,可以在不设置项目的情况下包含一次性依赖项(可能是全局安装) 理想情况下,最好提供一个简单的解决方案使用示例。相当于: #!/bin/bash echo "$@" cat /dev/stdin 注意:我知道
- 一种容易处理参数的方法,stdin/out/err
- 没有太多的启动时间(理想情况下是有某种JIT),否则就失去了在shell中把东西拼凑在一起的目的
- 此外,我们有理由期待一种简单的方法,可以在不设置项目的情况下包含一次性依赖项(可能是全局安装)
#!/bin/bash
echo "$@"
cat /dev/stdin
注意:我知道这个问题以前有人问过。但是这个问题还不完整,答案也没有达成共识,似乎存在的解决方案中也有很大一部分没有达成共识。考虑一下专门为脚本设计的ClojureScript环境
请注意,虽然它同时支持ClojureScript(JAR)和NPM依赖项,但依赖项支持是一个在MacOS和Linux上运行的选项。它使用自托管ClojureScript,启动速度快,目标是JavaScriptCore
它有一个很好的界面,模仿Clojure中的一些东西,这些东西在ClojureScript中没有,例如planck.io
类似于Clojure.java.io
。它支持通过tools.deps.alpha
/deps.edn
加载依赖项
回显stdin
非常简单:
(require '[planck.core :refer [*in* slurp]])
(print (slurp *in*))
和打印命令行参数:
(println *command-line-args*)
具有依赖项的独立脚本(即非项目)示例:
一个警告是,普朗克不支持使用npm依赖项。因此,如果您需要这些,请选择NodeJS的目标
第三种选择是使用Go编写的Clojure解释器。我知道您要求使用非项目创建方法来实现这一点,但由于这一特定问题已经在我脑海中出现了相当长的一段时间,我想我会加入另一种选择 TLDR:跳到下面的“创建可执行CLI命令”部分 背景 我的需求清单与您前一段时间所做的几乎相同,并着手创建可执行jar文件。我不是说通过
java-jar myfile.jar
可执行,而是指自包含的uber jar,您可以像处理任何其他二进制文件一样直接执行
如果您读取了(作为jar文件附着的jar文件是zip文件),事实证明这是可能的。简短的版本是,您需要:
- 用你需要的东西做一个肥罐子
- 在文件开头的二进制jar内容中插入bash/bat/shell脚本
uber jar文件(如果在windows上,请选中可执行文件框)chmod+x
- 重写jar文件元数据记录,以便插入的脚本文本不会使zip文件内部偏移无效
java-jar
仍然有效,并且文件现在也可以直接从命令行执行
此外,按照上述模式,还可以添加对的支持,例如,大大加快cli脚本的启动时间
大约一年前,当我开始研究这个问题时,发现不存在一个用于重写jar文件元数据的最后一点的库。不仅在clojure中,而且在整个JVM上。这仍然让我感到震惊:jvm上所有语言的中心部署单元都是jar文件,而且没有一个库真正读取jar文件的内部内容。与实际的zip文件结构相同的内部结构,而不仅仅是java的ZipFile和friends
此外,我找不到clojure的库,它以干净的方式处理zip文件规范所要求的那种二进制结构
解决方案:
- 八位字节具有我认为的Culjure可用二进制库最干净的接口,因此我为ZIP文件规范所需的特性编写了一个附加的支持。李>
- 然后我创建了一个新的库,它读取和解释zip文件元数据,并且能够进行上面最后一点中描述的偏移量重写李>
- 然后,我在现有的clojure库中创建了一个java脚本,以添加对clj zip meta实现的zip meta重写的支持,并添加对自定义序言脚本的支持,从而能够创建真正的可执行jar,而无需
李>java-jar
- 在此之后,我创建了一个leiningen模板来支持创建cli命令项目,该项目支持上述所有功能,并且具有结构良好的命令行解析设置……或者我认为结构良好的:)。欢迎评论
~> lein new cli-cmd mycmd
~> cd mycmd
~> lein bin
Compiling mycmd.core
Compiling mycmd.core
Created /home/mbjarland/tmp/clj-cmd/mycmd/target/mycmd-0.1.0-SNAPSHOT.jar
Created /home/mbjarland/tmp/clj-cmd/mycmd/target/mycmd-0.1.0-SNAPSHOT-standalone.jar
Creating standalone executable: /home/mbjarland/tmp/clj-cmd/mycmd/target/mycmd
Re-aligning zip offsets
~> target/mycmd
---- debug output, remove for production code ----
options {:port 80, :hostname "localhost", :verbosity 0}
arguments []
errors nil
summary
-p, --port PORT 80 Port number
-H, --hostname HOST localhost Remote host
--detach Detach from controlling process
-v Verbosity level; may be specified multiple times to increase value
-h, --help
--------------------------------------------------
This is my program. There are many like it, but this one is mine.
Usage: mycmd [options] action
Options:
-p, --port PORT 80 Port number
-H, --hostname HOST localhost Remote host
--detach Detach from controlling process
-v Verbosity level; may be specified multiple times to increase value
-h, --help
Actions:
start Start a new server
stop Stop an existing server
status Print a server's status
Please refer to the manual page for more information.
Error: invalid action '' specified!
其中,命令的输出只是我添加到leiningen模板中的样例命令行解析
定制的preamble脚本位于boot/jar preamble.sh
,它支持滴灌。换句话说,如果您的路径上有滴水,生成的可执行文件将使用它,否则它将退回到标准的java-jar
内部启动uber-jar的方式
命令行解析的源代码和cli应用程序的代码按照正常方式在src目录下运行
如果您想进行黑客攻击,可以更改序言脚本并重新运行lein-bin
,新的序言将通过构建过程插入到可执行文件中。
~> lein new cli-cmd mycmd
~> cd mycmd
~> lein bin
Compiling mycmd.core
Compiling mycmd.core
Created /home/mbjarland/tmp/clj-cmd/mycmd/target/mycmd-0.1.0-SNAPSHOT.jar
Created /home/mbjarland/tmp/clj-cmd/mycmd/target/mycmd-0.1.0-SNAPSHOT-standalone.jar
Creating standalone executable: /home/mbjarland/tmp/clj-cmd/mycmd/target/mycmd
Re-aligning zip offsets
~> target/mycmd
---- debug output, remove for production code ----
options {:port 80, :hostname "localhost", :verbosity 0}
arguments []
errors nil
summary
-p, --port PORT 80 Port number
-H, --hostname HOST localhost Remote host
--detach Detach from controlling process
-v Verbosity level; may be specified multiple times to increase value
-h, --help
--------------------------------------------------
This is my program. There are many like it, but this one is mine.
Usage: mycmd [options] action
Options:
-p, --port PORT 80 Port number
-H, --hostname HOST localhost Remote host
--detach Detach from controlling process
-v Verbosity level; may be specified multiple times to increase value
-h, --help
Actions:
start Start a new server
stop Stop an existing server
status Print a server's status
Please refer to the manual page for more information.
Error: invalid action '' specified!
#!/bin/sh
"exec" "clj" "-Sdeps" "{:deps,{hiccup,{:mvn/version,\"1.0.5\"}}}" "$0" "$@"
(ns my-script
(:require
[hiccup.core :as hiccup]))
(println
(hiccup/html
[:div
[:span "Command line args: " (clojure.string/join ", " *command-line-args*)]
[:span "Stdin: " (read-line)]]))
$ chmod +x ~/bin/script.sh
$ echo "stdin" | script.sh command line args
<div><span>Command line args: command, line, args</span><span>Stdin: stdin</span></div>