Clojure

Clojure CLI 参考手册

安装

Clojure CLI 可通过 Homebrew、bash/posix 脚本或 Powershell(取决于平台)进行安装。有关详细信息,请参阅 安装指南,有关版本信息,请参阅 发行页。您还可以阅读 指南,了解更详细的教程。有关构建工件,请查看 tools.build 指南

任何版本的 Clojure CLI 都可以使用任何版本的 Clojure 语言。通常最好使用最新 版本的 CLI,以获得最新的功能和修复。对于版本为 A.B.C[.D] 的 CLI 版本,在 REPL 中使用的默认 Clojure 版本 为 A.B.C,但您可以在依赖项中指定更旧的(或更新的!)语言版本。

用法

通过 clojureclj 调用 CLI。通常,您可以交替使用它们,但 clj 中包含 rlwrap 以用于扩展键盘编辑,这对于 REPL 特别有用。本参考在 REPL 示例中使用 clj,在非 REPL 示例中使用 clojure

Clojure CLI 的每次执行都会通过确定所有路径、依赖项和主入口点,然后在 JVM 上调用程序,从而运行一个 Clojure 程序。主要执行类型由 -X-T-M(或其不存在)决定。配置由一个或多个 deps.edn 文件与 命令行选项 共同定义。

主要命令

启动一个 REPL(默认)
clj [clj-opts] [-Aaliases]

执行函数 (-X)
clojure [clj-opts] -X[aliases] my/fn? [kpath v …​] kv-map?

运行工具 (-T)
clojure [clj-opts] -T[name|aliases] my/fn [kpath v …​] kv-map?

运行 main 命名空间或脚本 (-M)
clojure [clj-opts] -M[aliases] [init-opts] [main-opts] [args]

选项索引

exec-opts:
 -Aaliases    Apply aliases
 -X[aliases]  Invoke function, using aliases
 -Ttoolname   Invoke tool by local name
 -T[aliases]  Invoke tool using aliases
 -M[aliases]  Invoke clojure.main, using aliases
 -P           Prepare deps but don't exec

clj-opts:
 -Jopt        Pass JVM option
 -Sdeps EDN   Extra deps.edn data
 -Srepro      Ignore user deps.edn file
 -Spath       Compute and echo classpath
 -Stree       Print dependency tree
 -Scp CP      Use this classpath, ignore deps.edn
 -Sforce      Force classpath computation
 -Sverbose    Print path info
 -Sdescribe   Print env and command parsing info
 -Sthreads    Set specific number of download threads
 -Strace      Write dep expansion trace.edn
 --version    Print version to stdout and exit
 -version     Print version to stderr and exit
 --help -h -? Print this help message

Programs provided by :deps alias:
 -X:deps list          Print deps list+licenses
 -X:deps tree          Print deps tree
 -X:deps find-versions Find available lib versions
 -X:deps prep          Prepare all unprepped libs in deps
 -X:deps mvn-pom       Generate pom.xml for deps.edn
 -X:deps mvn-install   Install maven jar to local repo

启动一个 REPL

使用此选项可启动一个 Clojure REPL。

clj [clj-opts] [-Aaliases]

要运行一个 REPL,请在没有参数的情况下调用 clj

它适用于任何目录,无论是使用 deps.edn 还是不使用 deps.edn。如果您不在 项目目录 中,使用的 Clojure 版本将取决于 root deps.edn(与 CLI 版本号中的版本号相匹配)中 org.clojure 依赖项中的 Clojure 语言版本或 配置目录 中用户 deps.edn(通常未指定)。

要提供修改别名类路径JVM 属性,请使用“`-A`”连同一个或多个连接的别名关键字

clj -A:test

clj -A:test:dev

执行函数 (-X)

Clojure CLI 可以执行项目类路径上的任何函数,该函数将关键字参数作为输入放入映射中。

clojure [clj-opt*] -X[aliases] [a/fn] [kpath v]* kv-map?

函数执行最终需要以下信息

函数及其参数可以通过别名中的数据和/或命令行提供。

别名可以包含以下 arg 映射键

  • :exec-fn - 如果命令行中未提供任何一个,则使用函数符号

  • :exec-args - 在执行exec-fn时要包含的主键值映射

  • :ns-default - 解析 exec-fn 时要使用的默认命名空间符号

  • :ns-aliases - 解析 exec-fn 时要使用的别名符号到命名空间符号的映射

如果在指定别名中定义了要调用的函数,则函数在命令行中是可选的。如果在命令行中指定函数符号,则会覆盖别名中的:exec-fn,并且会按照别名中的:ns-default:ns-aliases进行解析

:exec-args形成一个基本映射,与命令行上的键和值以及结尾的 kv 映射合并,按此顺序合并。

命令行上的键可以是关键字或矢量键路径(与assoc-in中使用的相同),以便指定嵌套键。命令行上的最后一个 arg 是键值可选的结尾映射。请参阅有关键和键路径引号的后续章节,以获得有关如何正确指定 edn 键和值的更多详细信息。

运行工具 (-T)

工具是项目类路径之外的函数。使用-T运行工具函数与使用-X运行项目函数相同,但未包含项目类路径。

clojure [clj-opt*] -T[name|aliases] a/fn [kpath v]* kv-map?

在为工具构建类路径时,不包括项目:deps:paths

工具 deps 包含在工具别名或工具名称中。可以安装带有简称的本地工具以供使用。已安装的工具可在具有相同用户配置的任何项目上使用。请参阅工具安装以了解更多详细信息。

要按名称运行工具,请使用-Ttoolname,例如-Tlinter。要按别名运行工具,请使用-T:linter(别名始终是关键字)。

-X 不同,工具函数必须指定在命令行中,不能指定在工具别名或已安装的工具配置中。否则,工具函数和参数在别名和命令行中的指定方式与 -X 相同。

运行主命名空间或脚本 (-M)

可以用 -M exec-opt 调用 clojure.main,这样能支持使用 -main 函数调用命名空间或 Clojure 脚本

clojure [clj-opt*] -M[aliases] [main-opts]

deps.edn 提取 -M 别名并组合形成一个 arg 映射。arg 映射可以修改类路径或提供 :main-opts,这是字符串主选项的向量。参见 clojure.main 页面,以详细了解可用参数。

常见用法

# run single expression:
clojure -M -e '(+ 1 1)'

# run Clojure namespace with main entry point:
clojure -M -m my.app

# run standalone Clojure script
clojure -M script.clj

主选项可以在 别名 中使用 arg 映射键 :main-opts 提供 - 合并别名时,提供的任何 :main-opts 都会替换之前别名中的 :main-opts-M 之后的命令行中的额外选项会被追加到合并的别名 arg 映射中找到的选项中。

选项

-A 别名

-A获取一个或多个连接的别名别名,这些别名总是简单的或限定关键字,例如,-A:test-A:test:perf/benchmark

虽然 -A 可以用于所有执行命令,但它是 REPL 执行 中唯一的 exec-opt,这也是使用它的最常见原因。

-X[别名]

-X获取一个或多个连接的别名别名,这些别名总是简单的或限定关键字,例如,-X:test-X:test:perf/benchmark

-X exec-opt 指示 函数执行-X 之后的所有参数由该执行上下文定义。所有 clj-opts (-S-P 等) 都应位于 -X 之前。

-T 工具名称、-T[别名]

-T 获取工具名称(始终是符号,不是关键字)或一个或多个连接的别名别名,这些别名总是简单的或限定关键字,例如,-T:test-T:test:perf/benchmark

-T exec-opt 指示 工具执行-T 之后的所有参数由该执行上下文定义。所有 clj-opts (-S-P 等) 都应位于 -T 之前。

-M[别名]

-M 获取一个或多个连接的别名别名,这些别名总是简单的或限定关键字,例如,-M:test-M:test:perf/benchmark

-M exec-opt 指示 clojure.main 执行-M 之后的所有参数由该执行上下文定义。所有 clj-opts (-S-P 等) 都应位于 -M 之前。

-P

在所有其他 exec-opts( -A-X-M-T) 之前使用 -P 以进行完全依赖项扩展、下载依赖项和缓存类路径,但实际上不执行函数、工具、主函数等。

-Jopt

使用 -J 为应提供给您的程序的任何 JVM 选项加前缀( -J 将被剥离)。例如, -J-Xmx1g-J-XX:+HeapDumpOnOutOfMemoryError-J 可用于运行程序的所有执行模式(repl、 -X-T-M)。

另请参阅 JVM opts,了解有关提供 JVM opts 的更多方法。

-Sdeps deps

使用 -Sdeps 在命令行上提供一个额外的 deps.edn 源。它用作合并中的最后一个 deps 源。deps 数据需要为命令行适当 引用

-Srepro

使用 -Srepro 从 deps 源中省略用户 deps.edn。这省略了任何用户特定配置,以确保命令对其他人可重复。

Clojure deps 源

-Spath

使用 -Spath 计算和打印类路径。

-Stree

使用 -Stree 计算并打印依赖关系树。请参阅 依赖关系扩展 页面,了解有关树打印输出的更多信息。

-Scp CP

使用此选项后,将不计算类路径,而使用提供的类路径。这在测试或调试时非常有用。一般来说,你应该让 Clojure CLI 根据 deps.edn 设置计算(并缓存)你的类路径。

-Sforce

此标志将标记现有的缓存类路径(如果存在)标记为陈旧。类路径将被重新计算并缓存。

-Sverbose

打印 Clojure CLI 查找并使用的环境和路径信息,主要用于调试各种配置和缓存目录的位置。

此标志不会改变命令行中可能指定的任何其他执行,因此它可用于调试特定命令的缓存文件的位置。

-Sdescribe

打印配置设置作为 edn 数据并退出。它与 -Sverbose 在功能上有重叠,但可能对编程使用有用。

-Sthreads N

默认情况下,dep 扩展将使用基于处理器数量大小的线程池完成。使用此设置可以更改扩展期间使用的线程数。设置为 1 会使用一个线程序列化扩展。

-Strace

-Stree-X:deps tree 打印的依赖项树通常包含足够的信息,可以调试为什么选择特定的库或库版本。但是,如果您需要更多信息,此标记会将信息打印至 trace.edn 文件中,该文件可在 Ask Clojure 上发布 tools.deps 问题时使用。

--version、-version

将 Clojure CLI 版本打印至 stdout (--version) 或 stderr (-version)。请注意,虽然 Clojure CLI 版本确定执行中使用的默认 Clojure 版本,但任何版本的 CLI 都可以使用任何版本的 Clojure,Clojure 版本可以在 deps.edn 文件中设置,以更改该版本。

有关更多版本和变更日志信息,请参阅 tools release 页面。

--help、-h、-?

将帮助打印至控制台。另请参阅 man clojure

别名

在项目上下文中调用命令时,通常需要指定命令行上难以引用的复杂数据。作为 Clojure 程序员,我们强烈倾向于使用 Clojure 语法 (edn) 指定此类数据。deps.edn 文件格式允许我们定义任意 Clojure 数据,并使用 别名为该数据指定名称。别名只是为 edn 数据命名的关键字。

Clojure CLI 每次执行模式都有许多配置选项(“arg map”)。它们可以通过别名在 edn map 中进行定义,并可以使用 -A-X-T-M 中的别名在命令行上选择。下面列出了所有 arg map 键 - 除非另有说明,否则这些键在所有执行模式中均有效。

  • 项目依赖项修改器

    • :extra-deps - 应该添加到根 deps 的库到坐标的 map

    • :override-deps - 应该替换根 deps 中 deps 的库到坐标的 map

    • :default-deps - 如果根或传递依赖项中的坐标为 nil,则应该使用的库到坐标的 map

  • 类路径修改器

    • :extra-paths - 要添加到基本路径前的字符串路径(或相同关键字别名)构成的向量

    • :classpath-overrides - 用以替换类路径中库的库到字符串路径的 map

  • 工具 deps 和路径(主要由 -T 使用)

    • :replace-deps (同义词::deps)- 应该替换项目 deps 的库到坐标的 map

    • :replace-paths (同义词::paths)- 应该替换项目路径的路径字符串构成的向量

  • JVM 选项

    • :jvm-opts - 用作 jvm 选项传递的字符串构成的向量

  • 命名空间解析(主要由 -X 和 -T 使用)

    • :ns-aliases - 用于解析符号(例如 :exec-fn)的别名符号到命名空间符号的 map

    • :ns-default - 对不合格符号(例如 :exec-fn)的默认命名空间

  • 函数执行(仅限于 -X 和 -T)

    • :exec-fn - 使用 -X 执行的函数

    • :exec-args - 传递给 -X 的函数参数(可在命令行中覆盖)

  • main (仅限 -M)

    • :main-opts - 传递给 clojure.main 的字符串参数向量列

当提供多个别名时,别名 arg 映射中的键项将使用以下语义合并(按连接后的别名中指定顺序)

  • :extra-deps - 合并

  • :override-deps - 合并

  • :default-deps - 合并

  • :extra-paths - 连接并去重

  • :classpath-overrides - 合并

  • :replace-deps / :deps - 合并

  • :replace-paths / :paths - 连接并去重

  • :jvm-opts - 连接

  • :ns-aliases - 合并

  • :ns-default - 替换(最后一个生效)

  • :exec-fn - 替换(最后一个生效)

  • :exec-args - 如为映射项,则合并,否则替换

  • :main-opts - 替换(最后一个生效)

用于自定义目的的别名

上述别名键项对于 Clojure CLI 执行很有意义,但你也可以将别名定义为任何用途。如果你要创建需要配置的自定义工具,那么定义适用于你工具的众所周知的命名的别名或别名键项是一个良好的做法。请不要往 deps.edn 文件中添加顶层键项——它们可能始终无法通过编程工具进行访问。

由 Clojure CLI 运行的程序给出的执行“运行时依据”,包括所有别名数据。Clojure 1.12 中添加的 clojure.java.basis API 可用于在程序运行时检索别名数据。

命名空间解析

exec-opts 或 arg 映射中的符号(如 :exec-fn)使用以下规则进行解析。

  • 如果函数没有限定符,请在 arg 映射中使用 :ns-default 键项中的命名空间(如果没有,则为错误)

  • 如果函数带有限定符且限定符是 arg 映射中 :ns-aliases 下的别名,请使用该命名空间

  • 否则使用完全限定的函数符号

依赖项

每个依赖项都在 deps.edn 格式中使用 lib 和坐标进行定义,多个 deps 合并成一个映射项(别名 arg 映射键项使用相同的格式)。

deps.edn 来源

Clojure CLI 将通过合并多达四个 deps edn 来源 来构造路径、依赖项和使用别名的映射项

  • 根 deps - 定义为 tools.deps 库中嵌入的资源,将 Clojure 本身定义为唯一的依赖项(版本将与 Clojure CLI 版本相匹配),以及两个内置别名::deps:test。包括两个内置 Maven 存储库 - Maven 中心和 Clojars。

  • 用户 deps(可选) - 用户配置目录 中的 deps.edn 文件。该文件初始时为空,但可能跨项目定义了其他配置和工具。

  • 项目依赖(可选)- 当前目录中的 deps.edn(又称 项目目录

  • 额外依赖(可选)- 通过命令行中提供的 -Sdeps

依赖来源以上面列举的顺序合并为单个主 deps edn 除了

  • -T 工具执行 - 项目 :deps 被移除,项目 :paths 被替换为 ["."]

  • -Srepro - 用户 :deps 被忽略

合并实质上是 merge-with merge,但对于 :paths 除外,因为只使用了最后一个 deps 来源 :paths

类路径

JVM 类路径由一系列根组成,这些根可以是目录路径或 jar 文件的路径。类(以及 Clojure 文件)通过包或命名空间映射到相对于类路径根的某个路径。例如,java.lang.String 类可以在路径 java/lang/String.class 中找到,clojure.set Clojure 命名空间可以在路径 clojure/set.class(AOT)、clojure/set.cljclojure/set.cljc 中找到。当 JVM 需要加载其中一个文件时,它将在每个根中搜索相对路径,并在找到时加载该路径。

Clojure CLI 将根据以下内容计算类路径

最终所有这些都会组合为

  • 项目路径

  • 依赖项(外部库及其传递依赖项)

项目路径

一旦依赖项和别参数合并完毕,就有 deps.edn 中的 :paths 和别名中的 :extra-paths。这两者都是由向量组成的,并且保留这些向量中的顺序。额外路径始终在路径之前,以便别名可以覆盖项目设置。

请注意,项目路径和额外路径都是相对于当前目录解析的,并且应该仅引用项目内的路径,而不是父目录或兄弟目录。目前,引用项目外部的内容会发出警告,但对它的支持已弃用,未来将移除(转而使用本地依赖项)。

依赖项展开

一旦依赖项合并完毕,便会有一组顶级依赖项,这些依赖项作为依赖关系图的根。该图是从上到下浏览的,并且每个依赖项都将轮流使用适当的 采购商(Maven、Git、本地)进行展开。循环被检测出,并且不会被再次检查。

如果找到了多个相同库的版本,则会执行版本选择过程。依赖项展开 页面对这一过程有更详细的说明,但一般使用的是库的最新版本。但是,无论如何都使用顶级依赖项版本 - 如果您需要指定特定版本或解决冲突,请在顶级依赖项中设置版本。

依赖项从顶部按照图形深度排序,并且在每个级别按库名称按字母顺序排序。

有关 arg map 修改器(例如 :extra-deps:override-deps:default-deps)的更多信息,请参阅 deps.edn 参考信息 页面。

类路径构造

类路径将包含

  • 在最后一个别名中指定的额外路径(相对于项目),按声明顺序排列

  • 在最后一个 deps 中指定的源路径(相对于项目),按声明顺序排列

  • 依赖路径(通常是绝对路径),指的是合适的采购者下载位置中的 jar 或目录

    • 依赖项按照依赖项图的深度从顶部开始排序,然后按库名称按字母顺序排序

类路径还可以通过 arg map 密钥 :classpath-overrides 进一步修改(请参阅 deps.edn 参考信息)。

您可以使用 -Spath 打印计算出的类路径。

JVM 属性

JVM 属性有几个来源

  • 硬编码选项:-XX:-OmitStackTraceInFastThrow

  • $JAVA_OPTS 环境变量

  • 别名 arg map 密钥 :jvm-opts(在主 deps 中跨别名合并)

  • 命令行 -J 选项

所有 JVM 命令行选项已按上述顺序连在一起。在大多数情况下,命令行后面的 JVM 选项将覆盖任何以前的设置,但在所有情况下,连在一起的选项的语义都是 JVM 的语义。没有重复数据删除或替换选项。

CLI 命令

cljclojure 命令是特定于主机的脚本,用于

  1. 解析 CLI 参数

  2. (如果未缓存)启动 JVM 以计算和缓存类路径和其他设置

  3. 启动 JVM 以按照执行选项 -X-T-M 指定的方式运行用户程序

步骤 2 是使用 Clojure CLI 安装的一部分的 uberjar 完成的 - 通常您不控制该 JVM 的类路径或配置(但请参阅 环境变量 了解一些例外情况)。

Java

使用 Clojure CLI 时,您应该安装 Java,并通过以下几种方式之一使用它。需要 Java 8 或更高版本。任何 Java 发行版都可以使用。

按以下顺序检查 Java 来查找

  • $JAVA_CMD 环境变量

  • 路径上的 java

  • $JAVA_HOME/bin/java

如果没有找到,CLI 将停止并显示错误消息。如果 clj -h 成功完成,则找到了 Java 可执行文件。

目录和缓存

Clojure CLI 使用几个重要的目录,本部分详细说明如何计算这些目录。

项目目录

项目目录是当前目录。如果项目目录包含 deps.edn 文件,那么该文件将用作 项目 deps 来源

在远程项目目录的上下文中没有执行选项。

配置目录

配置目录包含

配置目录的计算如下

  • 如果设置了 $CLJ_CONFIG,请使用该路径

  • 如果设置了 $XDG_CONFIG_HOME,请使用 $XDG_CONFIG_HOME/clojure

  • 否则使用 $HOME/.clojure

如果配置目录不存在,则会创建它,并将以下文件复制到其中

  • deps.edn - 默认用户 deps.edn(基本上为空)

  • tools/tools.edn - 用于管理工具的内置工具“tools”

缓存目录

CLI 的每次执行都会使用一个缓存目录来存储已计算的类路径和其他文件。

缓存目录的计算如下

  • 如果当前目录有项目 deps.edn 并且当前目录可写,请使用 ./.cpcache

  • 否则使用 配置目录 中的 .cpcache 目录

缓存目录中的文件是一个缓存,当使用已经计算的类路径时,可以改善启动时间。一般来说,这个缓存永远不会失效,但是你可以使用 -Sforce 来强制对一个特定的命令重新计算,或者在不确定时简单地 rm 缓存目录。

当你安装 CLI 的新版本时,这有时会使缓存失效(如果缓存键的格式发生了变化),导致你之前运行的命令重新计算类路径。

Clojure CLI 从不会删除缓存目录中的文件,因此如果你希望定期清理这些目录,就由你决定了。一个好做法是将 .cpcache/ 包含在你的项目 .gitignore 文件中 - 那里没有什么对与其他项目用户分享是有益的。

环境变量

以下环境变量会影响 CLI 执行(许多在页面其他地方有更详细的描述)

  • CLJ_CONFIG - 用户配置目录,用于存储用户 deps.edn、工具配置和没有项目 deps.edn 的命令的 cpcache(默认 = ~/.clojure

  • XDG_CONFIG_HOME - 如果设置了这个标准变量,将使用 $XDG_CONFIG_HOME/clojure 作为用户配置目录

  • CLJ_CACHE - 用户缓存目录,(默认 = <config-dir>/.cpcache

  • XDG_CACHE_HOME - 如果设置了这个标准变量,将使用 $XDG_CACHE_HOME/clojure 作为用户缓存目录

  • CLJ_JVM_OPTS - 要包含在类路径构建过程的内部调用中的 JVM 选项,它可以用来提供一些东西,比如使用自签名证书下载内部工件的信任库

  • JAVA_CMD - 要使用的 Java 可执行文件的路径

  • JAVA_HOME - 如果没有 $JAVA_CMD,并且路径中没有 java,将尝试使用 $JAVA_HOME/bin/java

  • JAVA_OPTS - 将包含在要执行的用户命令中但未缓存的 JVM 选项。包含在任何 -J 命令行参数和任何 :jvm-opts 之前

  • 访问基于 S3 的 Maven 存储库时,将使用 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY 和其他 AWS 环境变量

  • GITLIBS - 前往 gitlibs 存储目录的路径(默认值 = ~/.gitlibs

  • GITLIBS_COMMAND - 运行的 git 命令(默认值 = git

  • GITLIBS_DEBUG - 设置为 true 以打印正在运行的所有 git 命令

  • CLOJURE_CLI_ALLOW_HTTP_REPO - 设置为 true 以允许 http:// 存储库 URL(这可能会使您的依赖项下载受到中间人攻击的影响)

键和键路径

借助 -X-T exec-opts,您可以在命令行上提供键路径/值对。键路径要么是单个键,要么是键向量,用于引用嵌套键(如 assoc-in 所用)。每个键路径都将用于 assoc-in 到原始 :exec-args 映射,覆盖那里的值。

# Top key override
clj -X:my-fn :val 789

# Nested key override
clj -X:my-fn '[:my :data]' 789

除了在命令行上传递键路径/值对和键路径外,还可以将提供值映射的可选映射作为最终参数传递。该映射将合并并可能覆盖先前提供的键路径/值映射

# Augment the arguments to my-fn
clj -X:a-tool my-fn :val 789 '{:val2 123}'

# Override the arguments to my-fn
clj -X:a-tool my-fn :val 789 '{:val 123}'

# Single map (no kvs) provides arguments to my-fn
clj -X:a-tool my-fn '{:val 789}'

给键和值加引号

命令行上的键和值以 edn 读取。以下数据不加引号即可使用

  • 数字 - 12312.4

  • 布尔值 - truefalse

  • 空值 - nil

  • 符号 - namefoo/bar

  • 关键字 - :id:company/name

这些数据类型需要用单引号包围

  • 字符串 - '"hi there"' - 请注意用单引号和双引号表示 shell 和作为 edn 字符串读取

  • 向量 - '[1 2 3]'

  • 映射 - '{:a 1, :b 2}'

  • 集 - '#{:a :b}'

  • 列表 - '(1 2 3)'

在 Windows 上,WSL2 shell 可以遵循以上建议,但在 cmd.exe 或 Powershell 上,字符串值需要额外的转义引用。不幸的是,命令行 Windows 程序参数转换引用规则以及 Powershell 引用和单词拆分的组合非常复杂

若要传递顶层的字符串值,如果字符串值没有空格,则可以使用 '\"str\"'。如果字符串值有空格(或没有),则应使用 '"""str value"""'

PS D:> clj -X clojure.core/prn :string1 '\"no-spaces\"' :string2 '"""has spaces"""'
{:string1 "no-spaces", :string2 "has spaces"}

对于嵌套在其他集合中的字符串值,如果有空格,则使用双引号;如果没有空格,则使用三引号

PS D:> clj -X clojure.core/prn :val '{:s1 """nospaces""" :s2 ""has spaces""}'
{:val {:s1 "nospaces", :s2 "has spaces"}}

程序

Clojure CLI 旨在提供对具有独立类路径的其他库中的程序(函数)的访问。此功能被利用通过根目录 deps.edn 中的内置别名 :deps 提供扩展功能,它提供了 tools.deps.cli(参见 API)。

依赖项列表

---
clj -X:deps list
---

打印了为类路径选定的所有传递依赖项的已排序列表以及许可证信息(如果找到的话)。其他选项可用于选择别名或其他类路径修改,或修改打印信息。

参见 API 文档

依赖项树

---
clj -X:deps tree
---

打印依赖项树,其中包含在 依赖项扩展过程中确定的包含/排除信息。其他选项可用于选择别名或其他类路径修改,或修改打印信息。

例如,以下内容可用于打印 :test 别名的 deps 树

---
clj -X:deps tree :aliases '[:test]`
---

参见 API 文档

别名列表

---
clj -X:deps aliases
---

此程序根据当前 deps 环境打印命令行中可用的所有别名。其他选项可用于选择别名或其他类路径修改。

参见 API 文档

帮助函数

help/dochelp/dir 函数内省了如何使用某个工具。由于 :deps 别名不包括项目类路径,因此在你自己的项目中执行函数时,这些函数当前都无用。

  • -X:deps help/doc - 使用键 :ns 或其他键 :fn 指定的函数显示 docs 字符串和参数列表;如果两者都没有给出,则使用 :ns-default

  • -X:deps help/dir - 使用键 :ns 提供的命名空间中打印公开函数,如果未给出,则使用 :ns-default

用于列出用于内置 tools 工具的 :ns-default 中的函数集的示例

clojure -A:deps -Ttools help/dir

用于列出别名中函数集的示例

clojure -X:deps:my-alias help/dir

打印 help 命名空间本身的文档字符串(请注意,对于 :depshelp 是在 :ns-aliases 映射中定义的)

clojure -X:deps help/doc :ns help

准备库

使用 Clojure 源的源库可以立即添加到使用它的项目的类路径。但是,一些源库需要在添加之前进行一些准备,例如由于需要 Java 编译或复制/替换资源文件等。Clojure CLI 现在将检测需要准备的项目并防止从源运行该程序,除非已完成准备步骤。

如果你的库需要准备,则将 :deps/prep-lib 键添加至 deps.edn

{:paths ["src" "target/classes"]
 :deps/prep-lib
 {:ensure "target/classes"
  :alias :build
  :fn compile-java}}

:deps/prep-lib 下的键是:

  • :ensure - 如果目录存在,则确定是否需要准备(如果存在,则已准备)

  • :alias - 在准备期间使用 -T 调用的别名

  • :fn - 在准备期间使用 -T 调用的函数

因此,deps.edn 还应当有一个别名,它能够执行指定的 fn。请参见 tools.build 指南,了解如何使用 tools.build 来定义带有可调用函数的构建脚本。

如果你将此 git 库添加为依赖项并尝试运行程序,则 Clojure CLI 将下载它,检测到它需要准备并且尚未准备(不存在“target/classes”路径),然后退出。

为了在依赖树中查找和“准备”库,你可以使用内置 :deps 别名提供的 prep 工具

clj -X:deps prep

准备任务将查找依赖项扩展中的所有库并查找源库,它们根据其 :deps/prep-lib 键需要准备且尚未准备(基于其 :deps/prep-lib 映射中的 :ensure 目录)。这些库将运行别名和函数指定的命令,如下所示:clj -T:<alias> <fn>

在准备了一个库后,对于此 git 库版本的其他用户而言,它无需再次准备。

你应该使用编译 Clojure 代码的准备步骤吗?通常,答案是否定的。机器上此 git 库的所有用户都将共享由准备步骤创建的已准备的类路径。最好将 Clojure 编译器和从属库的选择留给各个使用此库的应用程序。有关使用开发时编译的更多信息,请参阅 开发启动时间指南。

查找版本

要搜索 Maven 或 git 库的可用版本,可以使用内置 :deps 别名提供的 find-versions 工具

clj -X:deps find-versions ...

可以提供的参数是:

  • :lib - git 或 Maven 库名称。git url 将从 git 库名称自动构建。例如,io.github.clojure/tools.deps.graph:git/lib 将构建 git url https://github.com/clojure/tools.deps.graph.git。对于 Maven,使用 Maven 库名称,如 org.clojure/tools.deps.graph

  • :tool - 如果已经安装该工具,则为工具名称

find-versions 将按行将 git 或 Maven 坐标打印至控制台。

本地 Maven 安装

-X:deps mvn-install 程序随 Clojure CLI 提供以提供便利,并且可通过 -X 执行该程序以将 jar 安装到您的本地 Maven 缓存中。

安装参数包含以下选项

Required:
:jar - path to jar file, use pom inside jar by default

To supply an explicit pom file:
:pom - path to pom file (used instead of pom inside the jar)

To generate a minimal pom file:
:lib - qualified symbol like my.org/lib
:version - string
:classifier - string

Other options:
:local-repo - path to local repo (default = ~/.m2/repository)

您可以在命令行中传递必要的覆盖值。

clj -X:deps mvn-install :jar '"/path/to.jar"'

如上所述,edn 字符串必须用双引号引起来,然后为 shell 单引号引起来。

pom 文件必须要么显式提供,要么从 :lib/:version 生成,要么在 .jar 文件中找到(默认)。

生成 Maven pom

使用以下程序用项目的 deps 和路径生成或更新现有的 pom.xml

  • -X:deps mvn-pom - 用 deps 和路径生成(或更新现有)pom.xml

另请参见 API 文档 了解更多信息。

工具

工具是 lib 中提供的函数集合。工具函数以独立于项目 classpath 的自己的 classpath 在一个单独的进程中运行。工具函数接收单个映射参数,并且使用 -T 调用(键值参数语法与 -X 样式执行相同)。

工具 由别名描述(其他用户可以与项目共享),或由机器上安装的本地工具名称描述(可以在项目间共享)。

工具安装

Clojure CLI 中自动安装用于管理工具的工具,名为“tools”。提供了几个有用的函数

  • install - 安装或重新安装工具

  • install-latest - 安装或重新安装最新版本的工具

  • list - 列出所有已安装的工具

  • remove - 移除已安装的工具

  • show - 打印工具的信息和用法

安装

当确定要安装哪个工具版本时,请使用 install 函数按名称安装工具。

clj -Ttools install ...

install-tool 的 arg 为

  • lib - 值是 coord 映射,与 deps.edn 中的相同

  • :as - 工具名称,将用于以后的调用

例如

clj -Ttools install io.github.clojure/tools.deps.graph '{:git/tag "v1.0.63"}' :as deps-graph

在 Windows 中,Powershell 中需要额外的 转义引号

clj -Ttools install io.github.clojure/tools.deps.graph '{:git/tag """v1.0.63"""}' :as deps-graph

请注意,git deps 在工具安装时可以仅使用一个 git 库名称(用于按惯例生成一个 git url)和一个 git 标记来完全描述。或者,coord 可以包含一个显式的 :git/url:git/sha

安装最新版

要查找并一步安装某个工具的最新版本

clj -Ttools install-latest :lib io.github.clojure/tools.deps.graph :as deps-graph

要将现有工具更新到最新版本,也可以只通过名称指定工具

clj -Ttools install-latest :tool deps-graph

列出

要列出所有已安装工具

clj -Ttools list

要删除已安装工具

clj -Ttools remove :tool name

工具编著者的最佳实践

最佳实践

  • 将您的工具以公共 git 库形式提供

  • 将您的工具 api 定义在一个或多个 Clojure 命名空间中,作为一个获取 map 的函数

  • 在 deps.edn 的根目录中创建 :tools/usage 键,并使用 :ns-default 和/或 :ns-aliases 键作为 api 命名空间

  • 使用使对用户而言显而易见的方案给 git 存储库打标签以创建版本。通用惯例是使用诸如“v1.2.3”之类的版本字符串。

工具可以向用户提供以下说明

  • 查找工具版本:clj -X:deps find-versions :lib io.github.USER/TOOL

  • 使用 clj -Ttools install io.github.USER/TOOL '{:git/tag "VERSION"}' :as NAME 安装工具

  • 使用 clj -TNAME f args…​ 调用工具

函数执行协议

某些工具提供了设计用于从另一个进程以编程方式执行的函数,这些函数具有以下约束和预期

  • 该函数应获取单个 map 参数

  • 结果将从函数中返回(照常)

  • 函数抛出的异常将导致故障以及异常数据(通过 Throwable→map)将传递给外部进程,该进程将在 ex-info 中重新抛出该异常

  • 打印输出(默认情况下)不会被捕获

  • 所有结果或异常数据都应该安全地打印出来并且已读返回到另一个进程中的数据

有几个参数 map 键对于Clojure CLI在 -X 或 -T 期间具有特殊意义。所有这些键都会在函数被调用之前从参数 map 中移除

  • :clojure.exec/invoke - true表示使用该协议

  • :clojure.exec/out - true表示在函数执行期间捕获并返回 stdout

  • :clojure.exec/err - true表示在函数执行期间捕获并返回 stderr

结果被包装到已打印的信封 map 中,并包含以下键,并通过 CLI stdout 返回

  • :tag - 根据函数是返回结果还是抛出异常,为 :ret:err

  • :val - 返回值或异常数据,打印为字符串

  • :out - 如果需要,捕获的 stdout 返回

  • :err - 如果需要,捕获的 stderr 返回

  • :ms - 函数执行时间(以毫秒为单位)

自 Clojure 1.12.0-alpha2 起提供了此协议的使用者 API。

采购人员

依赖协变量是由采购人员解释的,采购人员了解特定的协变量类型,并且知道如何查找依赖项,以及如何下载某个库的构件。Clojure CLI 目前支持以下采购人员:MavenGit 以及local(其中同时包括目录和 jar)。基础 tools.deps 库在用作库时支持扩展采购人员。

协变量属性确定使用哪种采购人员。通常,大多数采购人员属性都经过采购人员类型限定(有一些例外)。与采购人员无关的协变量属性使用deps限定符。

某些采购人员可能还会使用相同的限定符在 deps.edn 配置映射的根目录处查找配置属性。

Maven

Maven 采购人员使用限定符mvn,用于从Maven 存储库(Java 生态系统中的标准存储库管理器)中检索库构件。下载库时将其格式化为 .jar 文件,并存储在 Maven 本地存储库缓存中(默认位于 ~/.m2/repository)。其他基于 JVM 的工具也可能会使用此缓存。

有关Maven 协变量类型Maven 采购人员配置的详细信息,请参阅 deps.edn 参考。

经过 Maven 验证的存储库

对于经过验证的存储库中的 Maven 从属项,现有的 Maven 基础设施用于传递凭据。

在您的~/.m2/settings.xml

<settings>
  ...
  <servers>
    <server>
      <id>my-auth-repo</id>
      <username>zango</username>
      <password>123</password>
    </server>
    ...
  </servers>
  ...
</settings>

然后在您的deps.edn 中包含一个名称与服务器 ID 匹配的存储库(此处为my-auth-repo

{:deps
 {authenticated/dep {:mvn/version "1.2.3"}}
 :mvn/repos
 {"my-auth-repo" {:url "https://my.auth.com/repo"}}}

然后像往常一样在:deps 中引用您的依赖项。

Maven S3 存储库

mvn 采购人员还支持连接到托管在AWS S3中的公共和私有 Maven 存储库。在 AWS 上托管的应用程序中访问私有 Maven 存储库时,此功能特别有用。

添加包含 s3 存储库根目录的:mvn/repos

{:deps
 {my/library {:mvn/version "0.1.2"}}
 :mvn/repos
 {"my-private-repo" {:url "s3://my-bucket/maven/releases"}}}

S3 存储分区特定于创建它们的 AWS 区域。s3 传输工具会尝试确定存储分区的所在位置。如果不成功,您可以在 URL 中明确指定存储分区区域:"s3://my-bucket/maven/releases?region=us-west-2"

对于经过验证的存储库,可以按服务器为基础将 AWS 凭据设置在 ~/.m2/settings.xml 中,或者会从 AWS 凭据链(环境变量等)中加载这些凭据。deps.edn 中的存储库名称必须与 settings.xml 中的服务器 ID 匹配

<settings>
  ...
  <servers>
    <server>
      <id>my-private-repo</id>
      <username>AWS_ACCESS_KEY_HERE</username>
      <password>AWS_SECRET_ACCESS_KEY_HERE</password>
    </server>
    ...
  </servers>
  ...
</settings>

可以使用以下其中一种机制在环境中设置 AWS S3 凭据

  1. 设置环境变量AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY

  2. 在 AWS 凭据文件中创建默认配置文件 ~/.aws/credentials(也支持较早的 ~/.aws/config)。

  3. 在 AWS 凭据文件中创建命名配置文件,并使用其名称设置环境变量 AWS_PROFILE

  4. Amazon ECS 容器和实例配置文件凭据也应该可用,但尚未经过测试。

有关更多信息,此 AWS 文档 中的大多数建议都描述了如何定位凭据。但请注意,Java 系统属性选项将无法与 Clojure CLI 一起使用(但如果直接使用 tools.deps 库,则可行)。

Maven 代理

在通过代理访问因特网的环境中,将使用 ~/.m2/settings.xml 中的现有 Maven 配置设置代理连接

<settings>
  ...
  <proxies>
    <proxy>
      <id>my-proxy</id>
      <host>proxy.my.org</host>
      <port>3128</port>
      <nonProxyHosts>localhost|*.my.org</nonProxyHosts>
    </proxy>
  </proxies>
  ...
</settings>

有关更多详细信息,请参阅 Maven代理使用指南

Maven HTTP 标头

要将自定义标头添加到传出 HTTP 请求,将使用 ~/.m2/settings.xml 中的现有 Maven 配置。

<settings>
  ...
  <servers>
    <server>
      <id>my-token-repo</id>
      <configuration>
        <httpHeaders>
          <property>
            <name>Private-Token</name>
            <value>abc123</value>
          </property>
        </httpHeaders>
      </configuration>
    </server>
    ...
  </servers>
  ...
</settings>

settings.xml 中的服务器 ID 必须与 deps.edn 中的存储库名称相匹配

{:mvn/repos
 {"my-token-repo" {:url "https://my.auth.com/repo"}}}

该机制由使用令牌(而非用户名和密码)进行身份验证的存储库使用。

Git

git 采购员支持直接使用托管在 Git 存储库中的基于源的 lib。默认情况下,Git lib 下载到 ~/.gitlibs 目录。结帐并缓存每个作为依赖项包含的 sha 的工作树。

有关Git 坐标类型的详细信息,请参见 deps.edn 参考。

配置和调试

git 采购员将命令行 git(和 ssh)设为 shell。需要 git >= 2.5。一般而言,如果命令行中访问可用,则通过 Clojure CLI 应也可行。Git 预计已安装,默认情况下,git 预计在路径中。有关 ssh 访问,请参阅系统的文档(通常,你将在 ~/.ssh/id_rsa 中注册你的 ssh 密钥)。

可以设置以下环境变量以控制 git 访问

  • GITLIBS - 前往 gitlibs 存储目录的路径(默认值 = ~/.gitlibs

  • GITLIBS_COMMAND - 访问 git 时运行的命令(默认值为 git

  • GITLIBS_DEBUG - 设置为 true 以查看正在运行的实际 git 命令及其输出的日志(默认值为 false

本地

local 采购员将本地目录或 jar 文件包括为一个依赖项。有关本地坐标类型的详细信息,请参见 deps.edn 参考。

术语表

解决某些问题的 Clojure 代码的集合,管理在一个单独的目录根下。在典型(但非排他)用法中,大多数 GitHub repo 保存一个单独的库。每个库都有一个独特的命名空间名称 — 在 Maven 中,这由 group-id/artifact-id 决定。

工件

在容器文件中发布的一个库,该文件捕获库在时间点上的状态,可能经过一些构建过程,用版本标记,包含记录其依赖项的一些清单,并打包在例如 jar 中。

坐标

为使用而选择的库的一个特定版本,其中包含足够的信息来获取和使用该库。

依赖项

在项目/库级别的一种表达式,即声明库需要声明库来提供其某些功能。必须至少指定库名称,也可能指定版本和其他属性。实际(功能)依赖项更精细。

依赖项类型

  • Maven 工件(基于工件的)

  • Git 库(基于源代码的)

  • 本地库(基于源代码的)- 一个本地目录

  • 本地工件(基于工件的)- 一个本地 jar 文件

类路径(和根/路径)

一个由本地“位置”(文件系统目录和/或 jar)组成的有序列表,这些位置将构成运行时 requires/imports 搜索的根路径,作为控制语义的参数提供给 Java。我们不鼓励类路径中的顺序依赖性,这意味着命名空间或资源文件被复制(因此可能损坏)。

展开

给定一组根依赖项,对传递依赖项集进行完全闭包。

解析

给定一组根依赖项和附加修改,创建一个完全展开的依赖项树,然后从每个提到的库生成一个映射到单个要使用的版本,以满足所有从属关系,以及到该源或工件的本地路径。我们还将包括每个条目的那些从属关系。只有当库依赖于某个库的不同主要版本时才会出现冲突。

版本

一个由约定决定的含义的人类编号系统,通常为 x.y.z。一个流行的方案是“语义版本控制”又名“semver”,它为每个级别的更改赋予了含义,例如,第一个主要编号的更改表示破坏性的更改。

版本差异

当依赖项展开包含具有多个指定的“版本”的相同库,但存在相对顺序(按编号或 sha 等)时,就会发生这种情况。当可以建立这种关系时,可以通过选择“较新”或“最新”版本来解决版本差异。

版本冲突

版本冲突发生在依赖项展开包含具有多个“版本”的相同库,这种情况下无法自动选择最佳选择

  • semver 版本破坏(主要版本更改)

  • 不包含任何公共根或祖先的 github sha(例如不同分支或无关仓库上的两个 sha)

  • 跨越不同存储库或存储库类型的版本,无法建立相对关系

Maven 存储库

库工件的存储库,如 Maven central 或 Clojars