My favorite feature in leiningen 2

Recently, the leiningen team has released a preview version for leiningen 2. It brings new features to the clojure build tool. But my favorite one is not listed in any document. So I would like to share with you here.

As you know, leiningen is a project oriented tool. It manages dependencies for a particular project. In Java world, Maven and Gradle are also working in this manner.

In contrast, there are tools which manages dependencies in a system scope. For instance, pip(python), npm(nodejs) and gems(ruby). One advantage of these tools is easy for evaluating a library. Concretely, when you want to test pyclj, just run “pip install pyclj” to install it. Then open a REPL and type “import pyclj”. That’s pretty easy.

But in clojure/leiningen, to take a tutorial of “core.logic”, we have following steps:

  1. Find a right directory and type “lein new logic-abc” to create a project.
  2. cd into it, edit project.clj, add core.logic as a dependency
  3. Run `lein deps`
  4. Start a REPL and follow the tutorial

So I guest you must have a lot of empty projects created for such purpose.

Now we could say goodbye to this situation. Leiningen 2 has move its dependency management core to a new library, called pomegranate. Pomegranate wraps aether, which is a maven library created by sonatype. With pomegranate, we can add a maven artifact from repository to REPL classpath. Still on the core.logic example, it becomes much easier:

$ lein2 repl
Welcome to REPL-y!
Clojure 1.3.0
    Exit: Control+D or (exit) or (quit)
Commands: (help)
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
          (sourcery function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
Examples from clojuredocs.org:
          (clojuredocs name-here)
          (clojuredocs "ns-here" "name-here")
nil
user=> (use '[cemerick.pomegranate :only (add-dependencies)])
nil
user=> (add-dependencies :coordinates '[[org.clojure/core.logic "0.6.8"]])
{[org.clojure/clojure "1.3.0"] nil, [org.clojure/core.logic "0.6.8"] #{[org.clojure/clojure "1.3.0"]}}
user=> (use  '[clojure.core.logic])
nilWARNING: == already refers to: #'clojure.core/== in namespace: user, being replaced by: #'clojure.core.logic/==
user=> (run* [q] (== q 1))
(1)

Now core.logic is right on you classpath and you are ready to use any functions under the namespace. There’s no need to create project, no need to care about where the jars stored. Just start a REPL at anywhere you want. When you finished, send EOF to the REPL. Nothing to clean up.

My jython dependency manager jip has similar feature as I described above. It does great help to me. So I have been waiting for this feature in leiningen for a long time. Thanks to leiningen guys, it finally comes.

Edit 20120323 21:39

If you want to load libraries from clojars, you should explicitly add clojars in add-dependencies:

(add-dependencies :coordinates '[[incanter "1.2.3"]]
                  :repositories (merge cemerick.pomegranate.aether/maven-central
                                       {"clojars" "http://clojars.org/repo"}))

(The example is copied from Pomegranate document.)

刷HTC EVO 3D GSM

去年买的水货Desire Z在服役了刚刚一年之后就坏了,看来肯定是上了奸商的当。鉴于最近的新手机也没有什么像当时Desire Z那样一见倾心的,这次保守起见买了个行货EVO 3D。买行货的问题不仅是贵(贵很多),而且默认的ROM实在是没法用。几大国产流氓软件堂而皇之地强制安装后台运行,系统连google账户,官方market都没有。

那么只能刷一下了。所有的步骤开始之前都是解锁,按照官方的解锁方式(http://www.htcdev.com)基本上没有什么难度。在我的archlinux上,不需要安装HTC Sync(也没得装),只需要从aur安装android-sdk和android-sdk-platform-tools就有adb和fastboot在PATH里。唯一值得一提的是,在我的系统上fastboot oem get_identifier_token需要sudo,否则会一直wait device。除了这个小插曲以外,按照官方的步骤就可以解锁HBOOT。

接下来就可以刷recovery了,HTC EVO 3D GSM版的codename叫做shootru,比较可靠的一个版本是4.0.1.4-shooteru,可以在网上搜索 cwm-4.0.1.4-shooteru.img 这个文件,比较好找。继续通过 sudo fastboot flash recovery cwm-4.0.1.4-shooteru.img把recovery刷进手机。

接下来就是ROM的选择了。最好的选择是cyanogenmod,EVO 3D分为GSM和CDMA版,cmod 7只支持CDMA版,似乎还没有稳定的正式版。对GSM似乎有正在开发7.2,不过按照他们的说法,自从4.0发布之后,所有人的注意力都转移到基于4.0的cmod9上,所以7.2这个版本希望也比较渺茫。9.0已经有开发版本,但是都有一些还未解决的严重bug。说了这么多就是说我暂时放弃cmod了。

除了cmod,EVO 3D GSM上一个比较被认可的ROM叫做LeeDrOiD.从网站上下载5.3.0的发布版,拷贝到sd卡上,通过recovery就可以安装。安装之前先要清除旧的数据。剩下这一步也没有什么悬念。但是安装之后5.3.0上,WIFI无法启动。必须继续更新kernel,从网站上下载。安装kernel的方法和之前不太一样,不能通过recovery安装。需要用一个叫做FlashImageGUI的工具,可以在网上直接搜索这个名字找到下载。剩下就很简单了。

折腾这么一圈,手机基本上能用了。不过我还是非常期待早日能用上cmod 9.

Clojure on CloudFoundry

In this article, I will show you how to develop and deploy clojure web application on CloudFoundry. As you may know, CloudFoundry is an opensource PaaS backed by VMWare. Java, Ruby and Nodejs are officially supported. As a JVM language, clojure is born to be also available on this platform, although it’s not listed.

CloudFoundry accepts a .war file for Java web application deployment. So you don’t need the ring-jetty-adaptor and a procfile as heroku requires. To help your development and deployment, I strongly recommend the lein-ring plugin:

  :dev-dependencies [[lein-ring "0.5.4"]]

CloudFoundry provides backend services like mysql, redis, mongodb and more. The connection information are stored as environment variables. Here you can find a subset of them.

Take mongodb as example, connection information (host, port, username and password) are encoded as JSON, stored in environment variables. You can get them with this function:

(defn mongo-config [key]
  (if-let [services (System/getenv "VCAP_SERVICES")]
    (let [services-dict (json/read-json services false)]
      (-> services-dict
        (get "mongodb-1.8")
        first
        (get "credentials")
        (get key)))))

In the server bootstrap function, create the mongodb connection:

(defn app-init []
  (def db-conn (make-connection
                 (or (mongo-config "db") "lazypress")
                   :host (or (mongo-config "hostname") "localhost")
                   :port (or (mongo-config "port") 27017)))
  (when-not (nil? (mongo-config "username"))
    (authenticate db-conn
      (mongo-config "username")
      (mongo-config "password")))

By adding check for nil, local databased is also supported. This is pretty convenience for local development. These environment variables are consistent on all cloudfoundry application, so it’s possible to deploy the application on multiple accounts without any changes.

Then you can add your web stuff just like standard clojure web development. (If you are using compojure, place your static files under resource/public.)

Finally, package it. (Suppose your application is named as “lazypress”)

lein ring uberwar lazypress.war

Use the vmc tool to deploy it:

vmc update lazypress

For more usage about the vmc tool, you can read this article.

So you have finished deploying your clojure web application to cloudfoundry.

Backed by spring and vmware, cloudfoundry is more Java-friendly than other PaaS like heroku. You don’t have to start a Java process by yourself (“lein run” isn’t a graceful way to start your app in product environment). And you don’t have to worry about your web container settings (configure jetty with limited options via ring-jetty-adaptor). All you have to do is package the application as a portable war file, which you can deploy to tomcat, glassfish, and also cloudfoundry. The vmc tool could detect you war file and handle it correctly.

Roar for mootools 1.4

早在天下大势还处在分久必合的时候,那时候mootools还有不少简单实用的小库,比如我今天搜索”mootools notification”就找到这个08年的库叫做Roar。不过遗憾的是从那以后,这个库就再也没有更新过了。

Mootools本身也沉寂了很久,这个项目恐怕也要思考自己未来的发展方向了。今年9月Mootools迈进了1.4,API上有一些变化。现在的下载页也能看到with/without backward compatibility的版本分开下载。为了用上Roar,我尝试了这两个版本发现都不能使用。最后downgrade到1.2可以确定Roar本身在当时是没有什么问题。

这么多年对mootools痴心不改,所以顺手维护了一下Roar,现在可以在1.4 without compatibility的发布下运行了。主要是几个小修改,大多是一些多年deprecated函数被正式删除:

  • Type常量,原先的String.type,Object.type现在统一到一个Type对象下,变成Type.isString和Type.isObject
  • $empty 常量被删除了,现在直接用function()或Function.from()代替
  • $pick 方法被Array.pick取代,参数现在也必须接受数组类型了
  • $merge 方法被Object.merge取代
  • $type 被typeOf取代
  • 函数对象的create方法被删除了,现在可以用函数对象的bind方法替代
  • Browser.Engine 被删除了,需要用其他Browser的API替代

修改后的Roar,放在这个gist里,测试过可以在firefox和chromium上健康使用。IE没有做测试。这个08年的库,眼看四年过去了,用起来依然不错。

作为mootools的铁杆,我还是会一直专一地坚守下去的。(于是,我也已经变成了多年前那些我眼中为旧事物顽抗到底的老家伙了)