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

类库的使用是小菜一碟,但让系统使用正确的类库却远非易事。很多语言都通过仓库来解决该问题,其中仓库托管了类库、元数据以及工具,人们可以通过这种方式轻松从仓库中获取正确版本的类库。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 [email protected]:

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

你可能感兴趣的:(使用Clojars与Leiningen自动管理Clojure类库及依赖)