I'm trying to use a function as the value for the :profiles
key in a defproject
form. Starting from a fresh project (lein new app test
) this works fine:
:profiles {}
(as you might hope!). But if I change it to:
:profiles (merge {})
then when I run lein repl
it explodes:
Caused by: java.lang.ClassCastException: clojure.lang.Symbol cannot be cast to java.util.Map$Entry
I'm confused by this since if I set :profiles
back to the empty map and ask the repl these things are equal:
test.core=> (= {} (merge {}))
true
Where is my misunderstanding? Have I missed something basic? Is this an unfortunate artifact of the defproject
macro? Something else?
(clojure 1.8.0, leiningen 2.7.1, java 1.8.0_102)
(def project-name 'myproj)
(def mains ["foo" "bar"])
...
(defn- lein-alias [main]
{ main ["with-profile" main] })
(defn- lein-profile [main]
(let [jar (str main ".jar")
entry `~(str project-name "." main)]
{(keyword main) {:main entry
:bin {:name main}
:jar-name jar
:uberjar-name jar}}))
(defproject project-name "0.1.0"
...
:profiles ~(apply merge (concat (map lein-profile mains) {:uberjar {:aot :all}}))
:aliases ~(apply merge (map lein-alias mains))
...
So now I can lein foo bin
and lein bar bin
to my heart's content.
If you unquote
your form Leiningen will execute the form before the project map is evaluated.
So ~(merge {})
should work.
There is a function called unquote-project
in Leiningen
src/leiningen/core/project.clj#L176
"Inside defproject forms, unquoting (~) allows for arbitrary evaluation."
It looks like it looks items to unquote
to allow them to be execute. Based on the comment it looks like this might go away in 3.0 and suggests use read-eval syntax
Note: If you are just trying to merge values of different profiles you should look at the Profiles documentation About Merging and Composite Profiles
Composite Profiles
Sometimes it is useful to define a profile as a combination of other profiles. To do this, just use a vector instead of a map as the profile value. This can be used to avoid duplication:
{:shared {:port 9229, :protocol "https"}
:qa [:shared {:servers ["qa.mycorp.com"]}]
:stage [:shared {:servers ["stage.mycorp.com"]}]
:production [:shared {:servers ["prod1.mycorp.com", "prod1.mycorp.com"]}]}