Leiningen用于自动化Clojure项目
它提供各种与项目相关的任务:包括
1. 创建新项目
2. 为项目抓取依赖包
3. 运行测试
4. 运行一个完全可配置的REPL
5. 编译Java源文件
6. 运行项目
7. 为项目生成maven风格的“pom”文件以进行互操作
8. 编译和打包项目
9. 将库发布到Clojars等存储库
10. 运行用Clojure编写的自定义自动化任务(leiningen插件)
获取帮助
lein help
Leiningen项目文件
项目是一个包含一组Clojure(可能还有Java)源文件的目录,以及一些关于它们的元数据。 元数据存储在项目根目录中名为project.clj的文件中,它会告诉你:
1. 项目名字
2. 项目简介
3. 项目依赖关系
4. Clojure的版本
5. 去哪里找到源文件
6. 哪个是app的主命名空间
等等
创建一个项目
在此示例中,我们使用的是app模板,该模板适用于应用app而非库。 省略app参数将使用适用于库的默认模板。
目录布局
在这里,我们有了项目的README,一个包含代码的src/目录,一个test/目录,以及一个描述Leiningen项目的project.clj文件。 src /my_stuff/core.clj文件对应于my-stuff.core命名空间。
文件名到命名空间映射约定
请注意,我们使用my-stuff.core而不仅仅是my-stuff,因为在Clojure中不鼓励使用单段命名空间。 另请注意,名称中带有破折号的命名空间将具有以下划线命名的相应文件,因为JVM无法在名称中加载带有破折号的文件。 命名空间的复杂性是新手混淆的常见原因,虽然它们大多数超出了本教程的范围,但您可以在其他地方阅读它们。
project.clj
如果你没有用简短的句子填写 :description,你的项目将很难在搜索结果中找到。 :url也需要天上相应的值。 在某些时候,您还需要充实README.md文件,但是现在让我们跳过设置 :dependencies。 请注意,Clojure在这里只是另一种依赖。 与大多数语言不同,这里可以轻松切换到任何版本的Clojure。
Dependencies依赖
概述
Clojure是一种托管语言,Clojure库的分发方式与其他JVM语言相同,同样是以jar文件的方式。
Jar文件基本上只是.zip文件,带有一些额外的JVM特定元数据。 它们通常包含.class文件(JVM字节码)和.clj源文件,但它们也可以包含其他内容,如配置文件,JavaScript文件或带有静态数据的文本文件。
已发布的JVM库具有identifiers(artifact group,artifact id)和version等属性。
Artifact IDs, Groups, and Versions
你可以使用其网络界面或通过lein search $TERM 搜索Clojars。 在撰写本文时,在clj-http的Clojars页面上显示了以下内容:
[clj-http "2.0.0"]
它还显示了依赖项的Maven和Gradle语法。 您可以将Leiningen版本直接复制到project.clj中的 :dependencies 向量中。 因此,例如,如果您将示例project.clj中的:dependencies行更改为
Leiningen会自动下载clj-http jar并确保它在你的类路径上。 如果你想明确地告诉lein下载新的依赖项,你可以使用lein deps,但如果不这样做,它将按需发生。
在向量内,“clj-http”被称为“artifact id”。 “2.0.0”是版本。 有些库也会有“group id”,显示如下:
[com.cedarsoft.utils.legacy/hibernate "1.3.7"]
group id 是斜杠之前的部分。 特别是对于Java库,它通常是反向域名。 Clojure库通常使用相同的group-id和artifact-id(与clj-http一样),在这种情况下,您可以省略group-id。 如果有一个库是更大的组的一部分(例如ring-jetty-adapter是ring项目的一部分),则group-id在所有子项目中通常是相同的。
Snapshot Versions快照版本
有时版本将以“-SNAPSHOT”结尾。 这意味着它不是正式版本,而是开发版本。 我们不鼓励依赖snapshot依赖包,但如果您需要尚未进入版本化的错误修复等,有时是必要的。 但是,快照版本不会一直使用下去,因此非开发版本永远不会依赖于您无法控制的快照版本。 将快照依赖项添加到项目将导致Leiningen每天主动寻找最新版本的依赖项(而正常发布版本则缓存在本地存储库中),因此如果您有大量快照,它将减慢速度。
请注意,某些库使其group-id和artifact-id与它们在jar中提供的命名空间相对应,但这只是一种约定。 无法保证它们完全匹配,因此在编写 :require和 :import子句之前,请查阅库的文档。
Repositories 库
依赖关系存储在artifact存储库中。 如果您熟悉Perl的CPAN,Python的Cheeseshop(又名PyPi),Ruby的rubygems.org或Node.js的NPM,那就是一样的了。 Leiningen重用现有的JVM存储库基础结构。 有几个流行的开源存储库。 默认情况下,Leiningen将使用其中两个:clojars.org和Maven Central。
Clojars是Clojure社区的集中式maven存储库,而Central则适用于更广泛的JVM社区。
您可以通过在project.clj中设置 :repositories键来添加第三方存储库。 有关如何执行此操作的示例,请参阅sample.project.clj。 此示例使用其他存储库,例如Sonatype存储库,可以访问库的最新SNAPSHOT开发版本(Clojure或Java)。 它还包含有关存储库的其他相关设置,例如更新频率。
Checkout Dependencies 检出依赖项
有时需要并行开发两个项目,但运行lein install并重新启动repl以获取更改非常不方便。 Leiningen提供了一种名为checkout dependencies(或只是checkout)的解决方案。 要使用它,请在项目根目录中创建一个名为checkouts的目录,如下所示:
然后,在checkouts目录下,创建符号链接到您需要的项目的根目录。 符号链接的名称无关紧要 , Leiningen只关注所有这些文件以查找要使用的project.clj文件。 传统上,它们与它们指向的目录具有相同的名称。
位于checkouts目录下的库优先于从存储库中提取,但这不能代替在主项目:dependencies依赖项; 它只是为了方便而补充它。 也就是说,给定上面的目录层次结构,project.clj应该包含如下内容:
请注意,Maven的groupid “com.megacorp”对checkout这种方式没有影响。在checkout中,suchwow和commons链接看起来是一样的,并且groupid层次结构不需要以“commons”实际布局在磁盘上的方式出现。。
在您更新了依赖项之后,lein仍然需要能够在某些存储库(如clojars或〜/ .m2目录)中找到该库。如果lein抱怨像“Could not find artifact suchwow:jar:0.3.9”这样的消息,那么project.clj和suchwow / project.clj可能会使用不同的版本号。您也可能同时处理主项目和suchwow项目,两个项目文件中的版本号已经失效,但仍你然在本地Maven存储库中使用旧版本。在suchwow目录中运行lein install。也就是说:这样的版本号在三个地方必须相同:在howwow的project.clj中,在主项目的project.clj中,以及在主项目使用的某个存储库中。
如果您更改checkout项目的依赖项,您仍然必须运行lein install并重新启动repl;只是源变化会立即被提取。
chekcout是一项可选功能;并非每个正在处理该项目的人都会拥有相同的checkout,因此在推送或合并之前,您的项目应该无需checkout。
确保在使用chekcout时不要覆盖基本配置文件。在实践中,通常意味着使用lein with-profile + foo run而不是lein with-profile foo run。
Search 搜索
Leiningen支持使用命令lein search $TERM 搜索远程Maven存储库以匹配jar。 目前仅支持搜索Central和Clojars。
JVM参数设置
要将额外的参数传递给JVM,请设置 :jvm-opts向量。 这将覆盖Leiningen设置的任何默认JVM选项。
:jvm-opts ["-Xmx1g"]
如果要将编译器参数传递给Clojure编译器,也可以在此处执行此操作。
你还可以在JVM_OPTS环境变量中将选项传递给Leiningen。 如果要为Leiningen JVM提供自定义选项,请将它们设置为LEIN_JVM_OPTS。
运行代码
运行一个REPL(read-eval-print loop):
REPL是一个交互式提示框,您可以在其中输入任意代码以在项目的上下文中运行。 由于我们已经将clj-http添加到 :dependencies,因此我们可以将它与来自项目自己的src/目录中的my-stuff.core命名空间的代码一起加载:
对-main的调用同时显示println输出(“Hello,World!”)和返回值(nil)。
内置文档可通过doc获得,您可以使用source检查函数的来源:
如果已经准备好了-main函数中的代码并且不需要以交互方式输入代码,则运行任务更简单:
提供-m参数将告诉Leiningen在另一个名称空间中查找-main函数。 在project.clj中设置默认值:main可以省略-m。
对于长期运行的lein run进程,您可能希望使用更高阶的trampoline任务来节省内存,这允许Leiningen JVM进程在启动项目的JVM之前退出。
lein trampoline run -m my-stuff.server 5000
如果你要在:java-source-paths或者 :aot中列出的Clojure名称空间中编译任何Java文件,它们将始终通过run,repl等调用在Leiningen运行任何其他代码之前完成此编译。
Tests 测试
如果我们在test suite 中补充它们将变得更有用。有时,如果你有一个大的test suite,你一次只想运行一个或两个命名空间; lein test my-stuff.core-test可以做到这一点。您也可能想要使用测试选择器来分解测试;请参阅lein help test以获取更多详细信息。
从命令行运行lein test适用于回归测试,对于需要更严格反馈循环的测试模式,JVM过慢的启动时间让它不适合这件事。在这些情况下,要么保持一个打开的repl以运行对 clojure.test/run-tests 的适当调用,要么在编辑器的基础中查看,例如clojure-test-mode。
请记住,虽然保持正在运行的进程很方便,但是该进程很容易进入一个不反映磁盘上的文件的状态 - 加载然后从文件中删除的函数将保留在内存中,使其成为可能很容易错过因缺少功能而导致的问题(通常被称为“getting slimed”)。因此,建议在提交代码之前运行lein test。
Profiles
profiles用于在不同的上下文中将各种内容添加到项目映射中。 例如,在lein测试运行期间,:test profile的内容(如果存在)将合并到项目映射中。 您可以使用此选项来启用仅应在测试运行期间应用的配置,方法是将包含配置文件的目录通过 :resource-paths或其他方式添加到类路径中。 有关详细信息,请参阅lein help profiles
除非另有说明,否则Leiningen会将默认的配置文件集合并到项目地图中。 这包括来自 :user 配置文件,来自project.clj的 :dev配置文件(如果存在),以及内置 :base 配置文件,其中包含nREPL和优化等开发工具,这些工具以运行时性能为代价来加快启动时间。 永远不要使用默认配置文件
用Clojure做什么
一般情况下
1. 分发给终端用户的应用程序
2. 服务器端应用程序
3. 用于其他Clojure项目使用的库
首先,你通常会构建一个uberjar。 对于库,您需要将它们发布到Clojars或私有存储库等存储库。 对于服务器端应用程序, 使用lein new app myapp生成项目将启动一些适用于非库项目的额外默认值,或者您可以浏览Clojars上的可用模板,以获取特定Web技术或其他项目类型等内容。
Uberjar
最简单的方法是分发一个uberjar。 这是一个单独的可执行jar文件,最适合提供给非技术用户。 为此,您需要在project.clj中指定 :main 作为一个主命名空间,并确保它被添加到 :aot中已进行AOT(Ahead Of Time)编译。到目前为止,我们的project.clj文件应如下所示:
我们还添加了一个dev dependencies,ring-devel。 ring-devel在uberjars中不可用,如果将此项目发布到存储库,则不会将其视为依赖项。
您指定的命名空间需要包含一个-main函数,该函数将在运行standalone jar时调用。 此命名空间应在顶部的ns表单中具有(:gen-class)声明。 -main函数将传递命令行参数。 让我们在src/my_stuff/core.clj中尝试一些简单的方法:
准备生产uberjar
这将创建一个包含所有依赖项内容的jar包。 用户可以通过简单的java调用来运行它,或者只是通过双击jar文件在某些系统上运行它。
您可以使用java命令行工具运行常规(非超级)jar,但这需要自己构建类路径,因此对于最终用户来说这不是一个好的解决方案。
当然,如果您的用户已经安装了Leiningen,您可以指示他们使用如上所述的lein run。
翻译自:https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md
翻译者:Eyck Luo