Clojure
Leiningen

Leiningenのprofileを合成する

やりたいこと

  • あるプロジェクトを、元々使っていたライブラリに加え、派生したライブラリ(この例の場合はDatomic on-premとDatomic Cloud)のそれぞれに対応するようにしたい。Datomicへ接続する機能は同じだが、オンプレミス版とクラウド版は異なるクライアントライブラリを要求するので、環境に応じて使い分けたい。

Leiningenにはprofileがある

  • もともと下記のようなprofileが設定されている。
(defproject org.onyxplatform/onyx-datomic "0.12.5.1-SNAPSHOT"
...
  :profiles {:dev {:dependencies [[com.datomic/datomic-free "0.9.5544"]
                                  [aero "0.2.0"]]
                   :plugins [[lein-set-version "0.4.1"]
                             [lein-update-dependency "0.1.2"]
                             [lein-pprint "1.1.1"]]
                   :resource-paths ["test-resources/"]}
             :circle-ci {:jvm-opts ["-Xmx4g"]}})

  • com.datomic/datomic-freeはオンプレミス用なので、クラウド向けの開発をするときは除外したい。なので、:datomic-onpremという新しいprofileを作成し、ライブラリをそのprofile配下の:dependenciesに移動した。さらにクラウド用のライブラリも:datomic-cloudprofileを作成して定義した。
(defproject org.onyxplatform/onyx-datomic "0.12.5.1-SNAPSHOT"
...
  :profiles {:dev {:dependencies [[aero "0.2.0"]]
                   :plugins [[lein-set-version "0.4.1"]
                             [lein-update-dependency "0.1.2"]
                             [lein-pprint "1.1.1"]]
                   :resource-paths ["test-resources/"]}
             :circle-ci {:jvm-opts ["-Xmx4g"]}
             :datomic-onprem {:dependencies [[com.datomic/datomic-free "0.9.5544"]]
             :datomic-cloud {:dependencies [[com.datomic/client-cloud "0.8.50"]]}}})
  • オンプレミス版を取り込むためには、with-profileで指定すれば良い。+接頭辞は、デフォルトのprofile群を置き換えずに、デフォルトに追加することを意味する。
lein with-profile +datomic-onprem [task]

だが、破壊的変更は避けたい

  • しかし、これでは、今までの振る舞いを維持するために、既存のビルドスクリプトに with-profile +datomic-onpremを追加しなければならない。こういった類の留意点が増えると管理しきれなくなるので、極力避けるべきである。特にオープンソースでは誰が使っているか分からないし、READMEに追記しても読んでもらえる可能性は低い。
  • そこで、default profileを書き換えることにする。最後の行に注目。
(defproject org.onyxplatform/onyx-datomic "0.12.5.1-SNAPSHOT"
...
  :profiles {:dev {:dependencies [[aero "0.2.0"]]
                   :plugins [[lein-set-version "0.4.1"]
                             [lein-update-dependency "0.1.2"]
                             [lein-pprint "1.1.1"]]
                   :resource-paths ["test-resources/"]}
             :circle-ci {:jvm-opts ["-Xmx4g"]}
             :datomic-onprem {:dependencies [[com.datomic/datomic-free "0.9.5544"]]}
             :datomic-cloud {:dependencies [[com.datomic/client-cloud "0.8.50"]]}
             :default [:base :system :user :provided :dev :datomic-onprem]})

  • これでwith-profileを指定しなくても元のふるまいを維持することができた。

でも、クラウド版を使うにはオンプレミス版を除外しなければならない

  • 今度はdefaultでcloud-onpremが含まれているので、クラウド版を使うのには、下記のprofile設定が必要。
lein with-profile +datomic-cloud,-datomic-onprem [task]

-接頭辞は、defaultから除外して無効化する意味を持つ。

  • 目的は達成したが、クラウド版を使うのにオンプレミス版を除外しなければいけない、というのは、この2つの相互排他的な関係性が分かっていないと忘れてしまいがち。

default以外でもComposite profilesを定義することができる!

...
             :default [:base :system :user :provided :dev :datomic-onprem]
             :cloud   [:base :system :user :provided :dev :datomic-cloud]})

  • これで、profileを一つ定義するだけでクラウド版に切り替えられる!
lein with-profile cloud [task]