2017-02-09 189 views
2

我試圖使用一個函數作爲defproject表單中:profiles鍵的值。從一個新項目開始(lein new app test)這工作正常:Dynamic leiningen:profiles

:profiles {} 

(你可能希望!)。但是,如果我將其更改爲:

:profiles (merge {}) 

然後當我運行lein repl它爆炸:

Caused by: java.lang.ClassCastException: clojure.lang.Symbol cannot be cast to java.util.Map$Entry 

我很困惑這個,因爲如果我設置:profiles回空的地圖,並要求這些REPL事情是平等的:

test.core=> (= {} (merge {})) 
true 

我的誤解在哪裏?我錯過了一些基本的東西?這是一個不幸的defproject宏的神器嗎?還有別的嗎?

(Clojure的1.8.0,2.7.1 leiningen,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)) 
    ... 

我可以lein foo binlein bar bin我的心臟的內容。

+0

嘗試unquoting吧'〜(合併{})' – Scott

+0

@Scott,工程。但爲什麼? –

回答

3

如果你unquote你的表格Leiningen將在之前執行表格評估項目地圖。
所以~(merge {})應該工作。

有一個在Leiningen src/leiningen/core/project.clj#L176

稱爲unquote-project功能 「裏面defproject形式,unquoting(〜)允許任意的評價。」

看起來它看起來像unquote項目,讓他們執行。根據該意見,它看起來像這可能消失在3.0,並建議use read-eval syntax


注:如果你只是想合併,你應該看看Profiles文檔的不同模式的值關於MergingComposite Profiles

複合型材

有時將配置文件定義爲其他配置文件的組合很有用。爲此,只需使用矢量而不是地圖作爲配置文件值。這可以用來避免重複:

{: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"]}]} 
+0

謝謝,這只是我需要的凹凸。我會用我的解決方案更新我的問題。 –

2

您不會手動合併配置文件。它們通過自動(正常情況下)或當您使用with-profile關鍵字(手動控制)時合併在一起lein

例如,考慮這個project.clj

(defproject xyz "0.1.0-SNAPSHOT" 

    :dependencies [ [org.clojure/clojure "1.8.0"] 
        [tupelo "0.9.19"] ] 

    :profiles {:dev  {:dependencies [ [org.clojure/test.check "0.9.0"] 
             [criterium "0.4.4"] ] } 
      :sample {:dependencies [medley "0.8.2"] } 
    ... 
) 

project.clj說,該項目總是既需要org.clojure/clojuretupelo。在開發過程中,:dev的地圖將合併到根級,因此:dependencies將更新爲包括test.checkcriterium。但是,創建uberjar時不包括:dev配置文件值,因此這些庫不會包含在交付給用戶的代碼中。

由於:sample不是默認的配置文件之一,如果使用如下命令只會包含:

> lein with-profile sample test 

注意,導致結腸不包含在命令行中,雖然我們使用關鍵字:sample與冒號project.clj文件中。

全部細節在這裏:https://github.com/technomancy/leiningen/blob/master/doc/PROFILES.md#default-profiles

這裏:https://github.com/technomancy/leiningen/blob/master/sample.project.clj

說了這麼多,我通常不需要使用:profiles。除非你有比平常更復雜的東西,否則你通常應該把所有的依賴關係放在根目錄下(即在lein new app xyz爲您提供的(defproject xyz ...)項目中,第一級:dependencies關鍵字。

另一個建議:這個詞在lein項目(目錄名,文件名後綴和其他)中的許多地方都使用過,所以命名項目本身可能會非常混亂test!如果你選擇一個獨特的名字,如xyz,joe或其他任何名字,你會爲自己(和任何其他讀者)節省一些痛苦。

+0

謝謝,但我對配置文件的概念很好(我想!)。我現有的項目有多個市電,有多個配置文件可以與'lein-bin'一起使用。由於所有這些配置文件都非常相似,我想使用一個函數來生成它們(DRY)。 '(merge {})'只是一個返回地圖的示例函數調用; '(散列圖)'給出了相同的結果。 –