使用 Clojars 与 Leiningen 自动管理 Clojure 类库及依赖

阅读数:2470 2009 年 11 月 30 日

话题:JavaRubyDevOps语言 & 开发文化 & 方法

类库的使用是小菜一碟,但让系统使用正确的类库却远非易事。很多语言都通过仓库来解决该问题,其中仓库托管了类库、元数据以及工具,人们可以通过这种方式轻松从仓库中获取正确版本的类库。Ruby 世界的解决方案就是 Ruby Gems,它既是一个工具同时也是一个打包格式;托管于 Rubyforge(Gems 将于不久之后迁移到 GemCutter 系统上,因为后者提供了更好的灵活性)的默认仓库使得发布与使用 Gems 变得异常简单。而在 Java 世界中,Maven则是一个流行的解决方案。

新仓库Clojars旨在简化 Clojure 类库的共享与使用。Leiningen是由Phil Hagelberg创建的用于 Clojure 的构建工具,其目的在于让开发者能够轻松将 Clojure 类库发布到 Clojars 上,同时使用者也可以拿来就用且保证是其 Clojure 程序所需的。

InfoQ 有幸采访到了 Clojars 的创建者 Alex Osborne 以了解 Clojars 背后的动机、实现及工具等相关信息。

InfoQ:Clojars 是如何使用 Maven 的?如果从 Clojars 上安装了某些东西,我最终得到的是什么,类库的 Maven 安装抑或是其他什么东西?

Clojars 本身仅仅只是个仓库而已,其使用 Maven 的唯一目的就是将 jar 包和元数据放到结构中,这也是大多数构建工具的做法。所谓“安装”某些东西其实指的就是所有一切都完全依赖于构建工具。如果使用 Leiningen 或是 Maven 的话,我们将需要安装一个本地 Maven 仓库。Leingingen 仅仅把本地 Maven 仓库看作是一个缓存并将所有依赖复制到项目中名为“lib”的目录下,这样其他工具如 swank-clojure 就能找到他们了。这也意味着用户只需设定 classpath 即可而无需任何其他工具,可以这样做:

java -cp 'src:classes:lib/*' myproject.main



我非常推崇 Ruby Gems 能够安装可执行文件的做法,这样用户就可以从命令行执行了(比如说”rails“和”rake“)。我觉得我们也应该采取类似的方式,但目前还没有具体的计划。不过现在 Leiningen 插件已经在朝这个方向努力了。

InfoQ:如果我想往 Clojars 上增加一个类库,那需要创建哪些元数据呢,最好的处理方式是什么?

Clojars 仅仅需要一个最简单的 Maven 风格的 pom.xml 文件即可。至少需要指定 artifactId、groupId、version 及 dependencies,同时最好添上一些元数据字段,如 description、url 和 license 以便 Clojars 站点能够索引并搜索到他们,但我不打算强制用户这么去做。目前搜索功能还是非常基本的,然而我希望能够对其进行改进并为 Leiningen 增加一个搜索命令,这样用户甚至都不需要离开终端就能完成这一切。

POM 语法本身是非常单调乏味的,到处都充斥着 XML 命名空间和 schema,如果不打算通过 IDE 插件来生成该文件的话,我建议你使用 Leiningen 格式,如下所示:

(defproject myproject "0.1.0"
  :description "An example project."
  :dependencies [[org.clojure/clojure "1.1.0-alpha-SNAPSHOT"]
                 [org.clojure/clojure-contrib "1.0-SNAPSHOT"]
                 [compojure "0.3.1"]])



可以通过如下命令让 Leiningen 导出 POM:

lein pom



然后通过如下命令将其添加到 Clojars 上:

scp pom.xml myproject-0.1.0.jar clojars@clojars.org:



lein-clojars 插件可以将这两个命令简化为”lein push“这一条命令,但正如你所见,实际上并非所有东西都能够简化。:-)

有时我会通过“lein pom”命令为 Java 项目创建 POM 模板。你可以使用 Maven 的方式实现这一点,但我却记不住那么多的命令。

InfoQ:你想对那些常常陷入 Maven 梦魇的人们说些什么呢?

哈哈,肯定不止你一个人受此折磨。简单项目的构建就应该简单一些,我希望 Clojars 和 Leiningen 能够百尺竿头,更进一步,让你睡个好觉。

InfoQ:听说你正在用一个名叫Compojure的 Clojure Web 框架为 Clojars 构建 Web 前端,感觉 Compojure 怎么样?

我已经习惯于使用 Sinatra 和 Haml 并搭配 Ruby,因此 Compojure 是个很自然的选择。到目前为止,我觉得它很不错。我是一个“最小化工具”的狂热分子,只希望这些工具能恰到好处地简化日常开发而不会变得过于复杂和难于操控。

InfoQ:Clojars 托管在何处?仓库在哪里?

目前,它都放在一个小型的 Linode.com VPS 上,仓库也仅仅是磁盘上的普通文件而已(通过 lighttpd 向外提供服务)。Web 部分运行在 Jetty 中并使用 SQLite 数据库存储元数据,同时执行搜索等功能。对于类库的增添来说,我使用 Nailgun 通过 SSH 连接到运行着的应用。我用 Clojure 实现了一个 scp 服务器(它真的只是一个很简单的协议),它会检查上传的 POM 和 jar 的正确性以及是否通过 Maven 部署到仓库中。如果仓库变得足够大,我可能会将实际的 jar 文件迁移到 Amazon S3 上,但不打算对网站和元数据进行升级。

InfoQ:你提到 Clojars 类似于 Gemcutter;那你是如何处理诸如保存类库名、forking 等事情的?难道仅仅是先来先得么?

这个问题不好回答,我已经就该问题思考很长时间了,但尚未得到完美的答案。幸运的是,与 Gems 不同,POM 已经具备了命名空间机制(groupId),因此可供我们选择的也更多了。

我发现对于 Maven 来说,很多时候 groupId 都很碍事。我仅仅想用官方版本的“compojure”却并不关心其作者是谁,托管在何处。你经常会看到 Maven 类库的版本增加到 0.3 时可能还一直托管在 GitHub 上,因此会有形如“com.github.weavejester.compojure”的旧版本 groupId,但在他们有了新的域名后就会突然将其变为“org.compojure”。之后你会使用错误的版本,2 个月后才发现项目一直都是按照旧版本的类库开发的,这也说明了为何文档不匹配的原因所在。当然了,这么做的肯定不止我一个。

有一种事实上的标准用以规范类库的版本,那就是将 groupId 与 artifactId 设为相同的值。Phil Hagelberg 决定为 Leiningen 采取这种方式,因此在提到“compojure”时实际上说的是“compojure/compojure”,我也对 Clojars 采取了这种方式。我知道 Maven 的拥护者可能不赞成这个观点,但我觉得他们过于理想化了。 CPAN、PyPI 和 RubyGems 已经表明在实践中这并非那么重要,尤其是在你拥有中央仓库时更是如此。当然了,这只是偶尔才会出现的问题,但将域名作为命名空间会让事情变得复杂,不仅对于“类库作者”是这样,对于“类库使用者”来说更是如此。

但另一方面我有时还需要进行一些调整。或许官方版本的 Compojure 依赖于 Jetty,而我却想让其与 Server X 协同工作,但上面却不同意并拒绝了我给出的修复措施。或许我想用别人写的类库,但该类库并没有放到 Clojars 或 Maven Center 上,我不想说出他们的名字。对于这些情况来说确实需要一种命名空间机制。因此对于这类用法,我推荐在添加 jar 时将其 groupId 命名为“org.clojars.username”这种形式。我想将其命名为 username/project 而非 org.clojars.username/project,这里包含完整域名的方式其实更好。它表明了这并非官方版本并鼓励使用这种简易形式来标明官方版本。

目前在你首次添加具有特定 groupId 的 jar 时你就会成为该 jar 的唯一拥有者,其他人都无法再添加了。你可以通过网站将其他成员添加到组中。因此我们的原则就是先到先得。Clojure 社区是一个非常友好和成熟的社区,我觉得这么做不会产生什么问题,但如果有人反对这么做并且造成大家责权不分的话,我可能会帮下忙将保留的标准 group 名标注出来直到类别划分清楚为止。我觉得在问题出现时才进行处理要比中央集权的方式好一些,因为后者会浪费大家的时间并导致提交者和审批者彼此间的不信任。

InfoQ:要想与 Clojars 交互需要使用哪些工具?

我对 Phil 为 Leiningen 所做的一切感到非常满意。我对其的感觉与 Compojure 和 Sinatra 一样,它确实做到了“刚刚好”也不会妨碍你。但它也使用了 Maven 风格的仓库,因此你无需重新打包用于 Clojure 程序的所有 Java 类库。这里我向大家推荐 Leiningen,但实际上你可以将 Clojars 与任何能够从 Maven 仓库中下载的依赖工具搭配使用,大多数 Java 工具都是可以的。

对于类库的添加来说,除了 scp 以外你无需 Leiningen 或是 Maven 或是任何其他工具,事实上 scp 已经安装在每台 Unix 系统上了,很多 Windows 开发者都将其安装在了 PuTTY、MSysGit 或是 Cygwin 上。因此如果你想手动管理依赖、构建以及通过 Shell 脚本添加类库,那就去做吧。

查看英文原文:Clojars and Leiningen Automate Library and Dependency Management for Clojure