Merge pull request #810 from technomancy/last-wins
change with-profile from first-wins to last-wins
This commit is contained in:
commit
eda91bdf05
7 changed files with 295 additions and 257 deletions
|
@ -6,6 +6,7 @@
|
|||
:dependencies [[org.clojure/clojure "1.4.0"]
|
||||
[bultitude "0.1.7"]
|
||||
[classlojure "0.6.6"]
|
||||
[useful "0.8.6"]
|
||||
[robert/hooke "1.1.2"]
|
||||
[com.cemerick/pomegranate "0.0.13"
|
||||
:exclusions [org.slf4j/slf4j-api]]]
|
||||
|
|
|
@ -9,12 +9,62 @@
|
|||
[leiningen.core.utils :as utils]
|
||||
[leiningen.core.ssl :as ssl]
|
||||
[leiningen.core.user :as user]
|
||||
[leiningen.core.classpath :as classpath])
|
||||
[leiningen.core.classpath :as classpath]
|
||||
[useful.fn :refer [fix]]
|
||||
[useful.seq :refer [update-first]]
|
||||
[useful.map :refer [update update-each]])
|
||||
(:import (clojure.lang DynamicClassLoader)
|
||||
(java.io PushbackReader)))
|
||||
|
||||
;; # Project definition and normalization
|
||||
|
||||
(defn artifact-map
|
||||
[id]
|
||||
{:artifact-id (name id)
|
||||
:group-id (or (namespace id) (name id))})
|
||||
|
||||
(defn exclusion-map
|
||||
"Transform an exclusion vector into a map that is easier to combine with
|
||||
meta-merge. This allows a profile to override specific exclusion options."
|
||||
[spec]
|
||||
(when-let [[id & {:as opts}] (fix spec symbol? vector)]
|
||||
(-> opts
|
||||
(merge (artifact-map id))
|
||||
(with-meta (meta spec)))))
|
||||
|
||||
(defn exclusion-vec
|
||||
"Transform an exclusion map back into a vector of the form:
|
||||
[name/group & opts]"
|
||||
[exclusion]
|
||||
(when-let [{:keys [artifact-id group-id]} exclusion]
|
||||
(into [(symbol group-id artifact-id)]
|
||||
(apply concat (dissoc exclusion :artifact-id :group-id)))))
|
||||
|
||||
(defn dependency-map
|
||||
"Transform a dependency vector into a map that is easier to combine with
|
||||
meta-merge. This allows a profile to override specific dependency options."
|
||||
[dep]
|
||||
(when-let [[id version & {:as opts}] dep]
|
||||
(-> opts
|
||||
(merge (artifact-map id))
|
||||
(assoc :version version)
|
||||
(update :exclusions #(when % (map exclusion-map %)))
|
||||
(with-meta (meta dep)))))
|
||||
|
||||
(defn dependency-vec
|
||||
"Transform a dependency map back into a vector of the form:
|
||||
[name/group \"version\" & opts]"
|
||||
[dep]
|
||||
(when-let [{:keys [artifact-id group-id version]} dep]
|
||||
(-> dep
|
||||
(update :exclusions #(when % (map exclusion-vec %)))
|
||||
(dissoc :artifact-id :group-id :version)
|
||||
(->> (apply concat)
|
||||
(into [(symbol group-id artifact-id) version]))
|
||||
(with-meta (meta dep)))))
|
||||
|
||||
(declare meta-merge)
|
||||
|
||||
(defn- unquote-project
|
||||
"Inside defproject forms, unquoting (~) allows for arbitrary evaluation."
|
||||
[args]
|
||||
|
@ -26,23 +76,61 @@
|
|||
identity
|
||||
args))
|
||||
|
||||
(def defaults {:source-paths ["src"]
|
||||
:resource-paths ["resources"]
|
||||
:test-paths ["test"]
|
||||
:native-path "target/native"
|
||||
:compile-path "target/classes"
|
||||
:target-path "target"
|
||||
:prep-tasks ["javac" "compile"]
|
||||
:repositories [["central" {:url "http://repo1.maven.org/maven2/"}]
|
||||
;; TODO: point to releases-only before 2.0 is out
|
||||
["clojars" {:url "https://clojars.org/repo/"}]]
|
||||
:deploy-repositories [["clojars" {:url "https://clojars.org/repo/"
|
||||
:username :gpg
|
||||
:password :gpg}]]
|
||||
:jar-exclusions [#"^\."]
|
||||
:jvm-opts ["-XX:+TieredCompilation"]
|
||||
:certificates ["clojars.pem"]
|
||||
:uberjar-exclusions [#"(?i)^META-INF/[^/]*\.(SF|RSA|DSA)$"]})
|
||||
(def defaults
|
||||
{:source-paths ["src"]
|
||||
:resource-paths ["resources"]
|
||||
:test-paths ["test"]
|
||||
:native-path "target/native"
|
||||
:compile-path "target/classes"
|
||||
:target-path "target"
|
||||
:prep-tasks ["javac" "compile"]
|
||||
:jar-exclusions [#"^\."]
|
||||
:jvm-opts ["-XX:+TieredCompilation"]
|
||||
:certificates ["clojars.pem"]
|
||||
:uberjar-exclusions [#"(?i)^META-INF/[^/]*\.(SF|RSA|DSA)$"]})
|
||||
|
||||
(defn- dep-key
|
||||
"The unique key used to dedupe dependencies."
|
||||
[[id version & opts]]
|
||||
(-> (apply hash-map opts)
|
||||
(select-keys [:classifier :extension])
|
||||
(assoc :id id)))
|
||||
|
||||
(defn- add-dep [deps dep]
|
||||
(let [k (dep-key dep)]
|
||||
(update-first deps #(= k (dep-key %))
|
||||
(fn [existing]
|
||||
(dependency-vec
|
||||
(meta-merge (dependency-map existing)
|
||||
(dependency-map dep)))))))
|
||||
|
||||
(defn- add-repo [repos repo]
|
||||
(let [[id opts] repo
|
||||
opts (fix opts string? (partial hash-map :url))]
|
||||
(update-first repos #(= id (first %))
|
||||
(fn [[_ existing]]
|
||||
[id (meta-merge existing opts)]))))
|
||||
|
||||
(def empty-dependencies
|
||||
(with-meta [] {:reduce add-dep}))
|
||||
|
||||
(def empty-repositories
|
||||
(with-meta [] {:reduce add-repo}))
|
||||
|
||||
(def empty-paths
|
||||
(with-meta [] {:prepend true}))
|
||||
|
||||
(def default-repositories
|
||||
(with-meta
|
||||
[["central" {:url "http://repo1.maven.org/maven2/"}]
|
||||
;; TODO: point to releases-only before 2.0 is out
|
||||
["clojars" {:url "https://clojars.org/repo/"}]]
|
||||
{:reduce add-repo}))
|
||||
|
||||
(def deploy-repositories
|
||||
(with-meta
|
||||
[["clojars" {:url "https://clojars.org/repo/", :password :gpg, :username :gpg}]]
|
||||
{:reduce add-repo}))
|
||||
|
||||
(defn make
|
||||
([project project-name version root]
|
||||
|
@ -53,12 +141,27 @@
|
|||
:version version
|
||||
:root root)))
|
||||
([project]
|
||||
(-> (merge defaults project)
|
||||
(dissoc :eval-in-leiningen :omit-default-repositories)
|
||||
(assoc :eval-in (or (:eval-in project)
|
||||
(if (:eval-in-leiningen project)
|
||||
:leiningen, :subprocess))
|
||||
:offline? (not (nil? (System/getenv "LEIN_OFFLINE")))))))
|
||||
(let [repos (if (:omit-default-repositories project)
|
||||
(do (println "WARNING:"
|
||||
":omit-default-repositories is deprecated;"
|
||||
"use :repositories ^:replace [...] instead.")
|
||||
empty-repositories)
|
||||
default-repositories)]
|
||||
(meta-merge
|
||||
{:repositories repos
|
||||
:plugin-repositories repos
|
||||
:deploy-repositories deploy-repositories
|
||||
:plugins empty-dependencies
|
||||
:dependencies empty-dependencies
|
||||
:source-paths empty-paths
|
||||
:resource-paths empty-paths
|
||||
:test-paths empty-paths}
|
||||
(-> (merge defaults project)
|
||||
(dissoc :eval-in-leiningen :omit-default-repositories)
|
||||
(assoc :eval-in (or (:eval-in project)
|
||||
(if (:eval-in-leiningen project)
|
||||
:leiningen, :subprocess))
|
||||
:offline? (not (nil? (System/getenv "LEIN_OFFLINE")))))))))
|
||||
|
||||
(defmacro defproject
|
||||
"The project.clj file must either def a project map or call this macro.
|
||||
|
@ -69,73 +172,20 @@
|
|||
(def ~'project
|
||||
(make args# '~project-name ~version root#))))
|
||||
|
||||
(defn- de-dupe-repo [[repositories seen?] [id settings]]
|
||||
;; repositories from user profiles can be just credentials, so check :url
|
||||
(if (or (seen? id) (not (:url settings)))
|
||||
[repositories seen?]
|
||||
[(conj repositories [id settings]) (conj seen? id)]))
|
||||
(defn- add-exclusions [exclusions dep]
|
||||
(dependency-vec
|
||||
(meta-merge (dependency-map dep)
|
||||
{:exclusions (map exclusion-map exclusions)})))
|
||||
|
||||
(defn- mapize-settings [repositories]
|
||||
(for [[id settings] repositories]
|
||||
[id (if (string? settings) {:url settings} settings)]))
|
||||
|
||||
(defn normalize-repos [project]
|
||||
;; TODO: got to be a way to tidy this up
|
||||
(let [project (update-in project [:repositories] mapize-settings)
|
||||
project (if (:deploy-repositories project)
|
||||
(update-in project [:deploy-repositories] mapize-settings)
|
||||
project)
|
||||
project (if (:plugin-repositories project)
|
||||
(update-in project [:plugin-repositories] mapize-settings)
|
||||
project)]
|
||||
(assoc project :repositories
|
||||
(first (reduce de-dupe-repo
|
||||
(if-not (:omit-default-repositories project)
|
||||
[(:repositories defaults)
|
||||
(set (map first (:repositories defaults)))]
|
||||
[[] #{}]) (:repositories project))))))
|
||||
|
||||
(defn- without-version [[id version & other]]
|
||||
(-> (apply hash-map other)
|
||||
(select-keys [:classifier :extension])
|
||||
(assoc :id id)))
|
||||
|
||||
(defn- dedupe-step [[deps seen] x]
|
||||
(if (seen (without-version x))
|
||||
;; this would be so much cleaner if we could just re-use profile-merge
|
||||
;; logic, but since :dependencies are a vector, the :replace/:displace
|
||||
;; calculations don't apply to nested vectors inside :dependencies.
|
||||
(let [[seen-dep] (filter #(= (first %) (first x)) deps)]
|
||||
(if (or (:displace (meta seen-dep)) (:replace (meta x)))
|
||||
[(assoc deps (.indexOf deps seen-dep) x) seen]
|
||||
[deps seen]))
|
||||
[(conj deps x) (conj seen (without-version x))]))
|
||||
|
||||
(defn- dedupe-deps [deps]
|
||||
(first (reduce dedupe-step [[] #{}] deps)))
|
||||
|
||||
(defn- exclude [exclusions deps dep]
|
||||
(conj deps
|
||||
(if (empty? exclusions)
|
||||
dep
|
||||
(let [exclusions-offset (.indexOf dep :exclusions)]
|
||||
(if (pos? exclusions-offset)
|
||||
(update-in dep [(inc exclusions-offset)]
|
||||
(comp vec distinct (partial into exclusions)))
|
||||
(-> dep
|
||||
(conj :exclusions)
|
||||
(conj exclusions)))))))
|
||||
|
||||
(defn- add-exclusions [deps exclusions]
|
||||
(reduce (partial exclude exclusions) [] deps))
|
||||
|
||||
(defn normalize-deps [project]
|
||||
(-> project
|
||||
(update-in [:dependencies] dedupe-deps)
|
||||
(update-in [:dependencies] add-exclusions (:exclusions project))))
|
||||
|
||||
(defn normalize-plugins [project]
|
||||
(update-in project [:plugins] dedupe-deps))
|
||||
(defn- add-global-exclusions [project]
|
||||
(let [{:keys [dependencies exclusions]} project]
|
||||
(if-let [exclusions (and (seq dependencies) (seq exclusions))]
|
||||
(assoc project
|
||||
:dependencies (with-meta
|
||||
(mapv (partial add-exclusions exclusions)
|
||||
dependencies)
|
||||
(meta dependencies)))
|
||||
project)))
|
||||
|
||||
(defn- absolutize [root path]
|
||||
(str (if (.isAbsolute (io/file path))
|
||||
|
@ -152,17 +202,7 @@
|
|||
:else project))
|
||||
|
||||
(defn absolutize-paths [project]
|
||||
(let [project (reduce absolutize-path project (keys project))]
|
||||
(assoc project :compile-path (or (:compile-path project)
|
||||
(str (io/file (:target-path project)
|
||||
"classes"))))))
|
||||
|
||||
(defn remove-aliases [project]
|
||||
(dissoc project :deps :eval-in-leiningen))
|
||||
|
||||
(def ^{:arglists '([project])} normalize
|
||||
"Normalize project map to standard representation."
|
||||
(comp normalize-repos normalize-deps absolutize-paths remove-aliases))
|
||||
(reduce absolutize-path project (keys project)))
|
||||
|
||||
;; # Profiles: basic merge logic
|
||||
|
||||
|
@ -175,7 +215,7 @@
|
|||
(def default-profiles
|
||||
"Profiles get merged into the project map. The :dev, :provided, and :user
|
||||
profiles are active by default."
|
||||
(atom {:default [:dev :provided :user :base]
|
||||
(atom {:default [:base :user :provided :dev]
|
||||
:base {:resource-paths ["dev-resources"]
|
||||
:plugins [['lein-newnew "0.3.5"]]
|
||||
:checkout-deps-shares [:source-paths
|
||||
|
@ -188,34 +228,48 @@
|
|||
|
||||
(defn- meta-merge
|
||||
"Recursively merge values based on the information in their metadata."
|
||||
[result latter]
|
||||
(cond (-> result meta :displace)
|
||||
latter
|
||||
[left right]
|
||||
(cond (or (-> left meta :displace)
|
||||
(-> right meta :replace))
|
||||
(with-meta right
|
||||
(merge (-> left meta (dissoc :displace))
|
||||
(-> right meta (dissoc :replace))))
|
||||
|
||||
(-> latter meta :replace)
|
||||
latter
|
||||
(-> left meta :reduce)
|
||||
(-> left meta :reduce
|
||||
(reduce left right)
|
||||
(with-meta (meta left)))
|
||||
|
||||
;; TODO: last-wins breaks here
|
||||
(and (map? result) (map? latter))
|
||||
(merge-with meta-merge result latter)
|
||||
(nil? left) right
|
||||
(nil? right) left
|
||||
|
||||
(and (set? result) (set? latter))
|
||||
(set/union latter result)
|
||||
(and (map? left) (map? right))
|
||||
(merge-with meta-merge left right)
|
||||
|
||||
(and (coll? result) (coll? latter))
|
||||
(concat latter result)
|
||||
(and (set? left) (set? right))
|
||||
(set/union right left)
|
||||
|
||||
(= (class result) (class latter)) latter
|
||||
(and (coll? left) (coll? right))
|
||||
(if (or (-> left meta :prepend)
|
||||
(-> right meta :prepend))
|
||||
(-> (concat right left)
|
||||
(with-meta (merge (meta left)
|
||||
(select-keys (meta right) [:displace]))))
|
||||
(concat left right))
|
||||
|
||||
:else (doto latter (println "has a type mismatch merging profiles."))))
|
||||
(= (class left) (class right)) right
|
||||
|
||||
:else
|
||||
(do (println left "and" right "have a type mismatch merging profiles.")
|
||||
right)))
|
||||
|
||||
(defn- apply-profiles [project profiles]
|
||||
;; We reverse because we want profile values to override the project, so we
|
||||
;; need "last wins" in the reduce, but we want the first profile specified by
|
||||
;; the user to take precedence.
|
||||
(reduce (partial merge-with meta-merge)
|
||||
(reduce (fn [project profile]
|
||||
(with-meta
|
||||
(meta-merge project profile)
|
||||
(meta-merge (meta project) (meta profile))))
|
||||
project
|
||||
(reverse profiles)))
|
||||
profiles))
|
||||
|
||||
(defn- lookup-profile
|
||||
"Lookup a profile in the given profiles map, warning when the profile doesn't
|
||||
|
@ -266,18 +320,11 @@
|
|||
(when-not (pomegranate/modifiable-classloader? cl)
|
||||
(.setContextClassLoader thread (DynamicClassLoader. cl)))))
|
||||
|
||||
(defn- merge-plugin-repositories [project]
|
||||
(if-let [pr (:plugin-repositories project)]
|
||||
(if (:omit-default-repositories project)
|
||||
(assoc project :repositories pr)
|
||||
(update-in project [:repositories] concat pr))
|
||||
project))
|
||||
|
||||
(defn load-plugins
|
||||
([project key]
|
||||
(when (seq (get project key))
|
||||
(ensure-dynamic-classloader)
|
||||
(classpath/resolve-dependencies key (merge-plugin-repositories project)
|
||||
(classpath/resolve-dependencies key project
|
||||
:add-classpath? true))
|
||||
(doseq [wagon-file (-> (.getContextClassLoader (Thread/currentThread))
|
||||
(.getResources "leiningen/wagons.clj")
|
||||
|
@ -290,9 +337,8 @@
|
|||
(defn plugin-vars [project type]
|
||||
(for [[plugin _ & {:as opts}] (:plugins project)
|
||||
:when (get opts type true)]
|
||||
(with-meta (symbol (str (name plugin) ".plugin")
|
||||
(name type))
|
||||
{:optional true})))
|
||||
(-> (symbol (str (name plugin) ".plugin") (name type))
|
||||
(with-meta {:optional true}))))
|
||||
|
||||
(defn- plugin-hooks [project]
|
||||
(plugin-vars project :hooks))
|
||||
|
@ -354,13 +400,14 @@
|
|||
"Compute a fresh version of the project map, including and excluding the
|
||||
specified profiles."
|
||||
[project include-profiles & [exclude-profiles]]
|
||||
(let [without-profiles (:without-profiles (meta project) project)
|
||||
(let [project (:without-profiles (meta project) project)
|
||||
profile-map (apply dissoc (read-profiles project) exclude-profiles)
|
||||
profiles (map (partial lookup-profile profile-map) include-profiles)]
|
||||
(-> without-profiles
|
||||
(-> project
|
||||
(apply-profiles profiles)
|
||||
(normalize)
|
||||
(vary-meta merge {:without-profiles without-profiles
|
||||
(absolutize-paths)
|
||||
(add-global-exclusions)
|
||||
(vary-meta merge {:without-profiles project
|
||||
:included-profiles include-profiles
|
||||
:excluded-profiles exclude-profiles}))))
|
||||
|
||||
|
|
|
@ -28,11 +28,11 @@
|
|||
:eval-in :leiningen,
|
||||
:license {:name "Eclipse Public License"}
|
||||
|
||||
:dependencies '[[leiningen-core "2.0.0-SNAPSHOT"]
|
||||
[clucy "0.2.2" :exclusions [org.clojure/clojure]]
|
||||
[lancet "1.0.1"]
|
||||
:dependencies '[[leiningen-core/leiningen-core "2.0.0-SNAPSHOT"]
|
||||
[clucy/clucy "0.2.2" :exclusions [[org.clojure/clojure]]]
|
||||
[lancet/lancet "1.0.1"]
|
||||
[robert/hooke "1.1.2"]
|
||||
[stencil "0.2.0"]],
|
||||
[stencil/stencil "0.2.0"]],
|
||||
:twelve 12 ; testing unquote
|
||||
|
||||
:repositories [["central" {:url "http://repo1.maven.org/maven2/"}]
|
||||
|
@ -41,73 +41,82 @@
|
|||
(deftest test-read-project
|
||||
(let [actual (read (.getFile (io/resource "p1.clj")))]
|
||||
(doseq [[k v] expected]
|
||||
(is (= (k actual) v)))
|
||||
(is (= v (k actual))))
|
||||
(doseq [[k path] paths
|
||||
:when (string? path)]
|
||||
(is (= (k actual) (str (:root actual) "/" path))))
|
||||
(is (= (str (:root actual) "/" path)
|
||||
(k actual))))
|
||||
(doseq [[k path] paths
|
||||
:when (coll? path)]
|
||||
(is (= (k actual) (for [p path] (str (:root actual) "/" p)))))))
|
||||
(is (= (for [p path] (str (:root actual) "/" p))
|
||||
(k actual))))))
|
||||
|
||||
;; TODO: test omit-default
|
||||
;; TODO: test reading project that doesn't def project
|
||||
|
||||
(def test-profiles (atom {:qa {:resource-paths ["/etc/myapp"]}
|
||||
:test {:resource-paths ["test/hi"]}
|
||||
:repl {:dependencies '[[org.clojure/tools.nrepl
|
||||
"0.2.0-beta6"
|
||||
:exclusions
|
||||
[org.clojure/clojure]]
|
||||
[org.thnetos/cd-client "0.3.4"
|
||||
:exclusions
|
||||
[org.clojure/clojure]]]}
|
||||
:repl {:dependencies
|
||||
'[[org.clojure/tools.nrepl "0.2.0-beta6"
|
||||
:exclusions [org.clojure/clojure]]
|
||||
[org.thnetos/cd-client "0.3.4"
|
||||
:exclusions [org.clojure/clojure]]]}
|
||||
:tes :test
|
||||
:dev {:test-paths ["test"]}}))
|
||||
|
||||
(deftest test-merge-profile-paths
|
||||
(with-redefs [default-profiles test-profiles]
|
||||
(is (= ["/etc/myapp" "test/hi" "blue-resources" "resources"]
|
||||
(-> {:resource-paths ["resources"]
|
||||
:profiles {:blue {:resource-paths ["blue-resources"]}}}
|
||||
(merge-profiles [:qa :tes :blue])
|
||||
(-> (make
|
||||
{:resource-paths ["resources"]
|
||||
:profiles {:blue {:resource-paths ["blue-resources"]}}})
|
||||
(merge-profiles [:blue :tes :qa])
|
||||
:resource-paths)))
|
||||
(is (= ["/etc/myapp" "test/hi" "blue-resources"]
|
||||
(-> {:resource-paths ^:displace ["resources"]
|
||||
:profiles {:blue {:resource-paths ["blue-resources"]}}}
|
||||
(merge-profiles [:qa :tes :blue])
|
||||
(-> (make
|
||||
{:resource-paths ^:displace ["resources"]
|
||||
:profiles {:blue {:resource-paths ["blue-resources"]}}})
|
||||
(merge-profiles [:blue :tes :qa])
|
||||
:resource-paths)))
|
||||
(is (= ["replaced"]
|
||||
(-> {:resource-paths ["resources"]
|
||||
:profiles {:blue {:resource-paths ^:replace ["replaced"]}}}
|
||||
(merge-profiles [:blue :qa :tes])
|
||||
(-> (make
|
||||
{:resource-paths ["resources"]
|
||||
:profiles {:blue {:resource-paths ^:replace ["replaced"]}}})
|
||||
(merge-profiles [:tes :qa :blue])
|
||||
:resource-paths)))
|
||||
(is (= {:url "http://" :username "u" :password "p"}
|
||||
(-> {:repositories [["foo" {:url "http://" :creds :gpg}]]
|
||||
:profiles {:blue {:repositories {"foo"
|
||||
^:replace {:url "http://"
|
||||
:username "u"
|
||||
:password "p"}}}}}
|
||||
(-> (make
|
||||
{:repositories [["foo" {:url "http://" :creds :gpg}]]
|
||||
:profiles {:blue {:repositories {"foo"
|
||||
^:replace {:url "http://"
|
||||
:username "u"
|
||||
:password "p"}}}}})
|
||||
(merge-profiles [:blue :qa :tes])
|
||||
:repositories
|
||||
last last)))))
|
||||
|
||||
;; TODO
|
||||
(deftest test-merge-profile-deps
|
||||
(with-redefs [default-profiles test-profiles]
|
||||
(let [project {:resource-paths ["resources"]
|
||||
:profiles {:dev {:dependencies
|
||||
'[^:displace [org.thnetos/cd-client "0.3.0"]
|
||||
[org.clojure/tools.nrepl "0.2.0-beta2"]]}}}
|
||||
cp (-> (merge-profiles project [:dev :repl])
|
||||
(classpath/get-classpath))]
|
||||
(is (some (partial re-find #"nrepl-0.2.0-beta2") cp))
|
||||
(is (some (partial re-find #"cd-client-0.3.4") cp)))))
|
||||
(let [project (make
|
||||
{:resource-paths ["resources"]
|
||||
:dependencies '[^:displace [org.foo/bar "0.1.0" :foo [1 2]]
|
||||
[org.foo/baz "0.2.0" :foo [1 2]]
|
||||
[org.foo/zap "0.3.0" :foo [1 2]]]
|
||||
:profiles {:dev {:dependencies
|
||||
'[[org.foo/bar "0.1.2"]
|
||||
[org.foo/baz "0.2.1"]
|
||||
^:replace [org.foo/zap "0.3.1"]]}}})]
|
||||
(is (= '[[org.foo/bar "0.1.2"]
|
||||
[org.foo/baz "0.2.1" :foo [1 2]]
|
||||
[org.foo/zap "0.3.1"]]
|
||||
(-> (merge-profiles project [:dev])
|
||||
:dependencies))))))
|
||||
|
||||
(deftest test-global-exclusions
|
||||
(is (= '[[org.clojure/clojure]
|
||||
[org.clojure/clojure pomegranate]
|
||||
[org.clojure/clojure]]
|
||||
(map #(:exclusions (apply hash-map %))
|
||||
(is (= '[[[org.clojure/clojure]]
|
||||
[[pomegranate/pomegranate] [org.clojure/clojure]]
|
||||
[[org.clojure/clojure]]]
|
||||
(map #(distinct (:exclusions (apply hash-map %)))
|
||||
(-> {:dependencies
|
||||
'[[lancet "1.0.1"]
|
||||
[leiningen-core "2.0.0-SNAPSHOT" :exclusions [pomegranate]]
|
||||
|
@ -158,66 +167,51 @@
|
|||
:without-profiles)))))
|
||||
|
||||
(deftest test-merge-anon-profiles
|
||||
(let [expected-result {:A 1 :C 3 :profiles {:a {:A 1}
|
||||
:b {:B 2}}
|
||||
:repositories [["central" {:url "http://repo1.maven.org/maven2/"}]
|
||||
["clojars" {:url "https://clojars.org/repo/"}]]
|
||||
:dependencies [], :compile-path "classes"}]
|
||||
(is (= expected-result
|
||||
(-> {:profiles {:a {:A 1} :b {:B 2}}}
|
||||
(merge-profiles [:a {:C 3}]))))))
|
||||
(is (= {:A 1, :C 3}
|
||||
(-> {:profiles {:a {:A 1} :b {:B 2}}}
|
||||
(merge-profiles [{:C 3} :a])
|
||||
(dissoc :profiles)))))
|
||||
|
||||
(deftest test-composite-profiles
|
||||
(let [expected-result {:A '(2 3 1), :B 2, :C 3,
|
||||
:repositories [["central" {:url "http://repo1.maven.org/maven2/"}]
|
||||
["clojars" {:url "https://clojars.org/repo/"}]]
|
||||
:dependencies [], :compile-path "classes"}]
|
||||
(is (= expected-result
|
||||
(-> {:profiles {:a [:c :b]
|
||||
:b [:d {:A [1] :B 1 :C 1}]
|
||||
:c {:A [2] :B 2}
|
||||
:d {:A [3] :C 3}}}
|
||||
(merge-profiles [:a])
|
||||
(dissoc :profiles))))))
|
||||
(is (= {:A '(1 3 2), :B 2, :C 3}
|
||||
(-> {:profiles {:a [:b :c]
|
||||
:b [{:A [1] :B 1 :C 1} :d]
|
||||
:c {:A [2] :B 2}
|
||||
:d {:A [3] :C 3}}}
|
||||
(merge-profiles [:a])
|
||||
(dissoc :profiles)))))
|
||||
|
||||
(deftest test-override-default
|
||||
(let [expected-result {:A 1, :B 2, :C 3
|
||||
:repositories [["central" {:url "http://repo1.maven.org/maven2/"}]
|
||||
["clojars" {:url "https://clojars.org/repo/"}]]
|
||||
:dependencies [], :compile-path "classes"}]
|
||||
(is (= expected-result
|
||||
(-> {:profiles {:a {:A 1 :B 2}
|
||||
:b {:B 2 :C 2}
|
||||
:c {:C 3}
|
||||
:default [:c :b :a]}}
|
||||
(merge-profiles [:default])
|
||||
(dissoc :profiles))))))
|
||||
(is (= {:A 1, :B 2, :C 3}
|
||||
(-> {:profiles {:a {:A 1 :B 2}
|
||||
:b {:B 2 :C 2}
|
||||
:c {:C 3}
|
||||
:default [:a :b :c]}}
|
||||
(merge-profiles [:default])
|
||||
(dissoc :profiles)))))
|
||||
|
||||
(deftest test-unmerge-profiles
|
||||
(let [expected-result {:A 1 :C 3 :profiles {:a {:A 1}
|
||||
:b {:B 2}
|
||||
:c {:C 3}}
|
||||
:repositories [["central" {:url "http://repo1.maven.org/maven2/"}]
|
||||
["clojars" {:url "https://clojars.org/repo/"}]]
|
||||
:dependencies [], :compile-path "classes"}]
|
||||
(is (= expected-result
|
||||
(let [expected {:A 1 :C 3}]
|
||||
(is (= expected
|
||||
(-> {:profiles {:a {:A 1}
|
||||
:b {:B 2}
|
||||
:c {:C 3}}}
|
||||
(merge-profiles [:a :b :c])
|
||||
(unmerge-profiles [:b]))))
|
||||
(is (= expected-result
|
||||
(unmerge-profiles [:b])
|
||||
(dissoc :profiles))))
|
||||
(is (= expected
|
||||
(-> {:profiles {:a {:A 1}
|
||||
:b {:B 2}
|
||||
:c {:C 3}}}
|
||||
(merge-profiles [:a :b :c {:D 4}])
|
||||
(unmerge-profiles [:b {:D 4}]))))))
|
||||
(unmerge-profiles [:b {:D 4}])
|
||||
(dissoc :profiles))))))
|
||||
|
||||
(deftest test-dedupe-deps
|
||||
(is (= '[[org.clojure/clojure "1.4.0"]
|
||||
(is (= '[[org.clojure/clojure "1.3.0"]
|
||||
[org.clojure/clojure "1.3.0" :classifier "sources"]]
|
||||
(-> {:dependencies '[[org.clojure/clojure "1.4.0"]
|
||||
[org.clojure/clojure "1.3.0" :classifier "sources"]
|
||||
[org.clojure/clojure "1.3.0"]]}
|
||||
(normalize-deps)
|
||||
(-> (make
|
||||
{:dependencies '[[org.clojure/clojure "1.4.0"]
|
||||
[org.clojure/clojure "1.3.0" :classifier "sources"]
|
||||
[org.clojure/clojure "1.3.0"]]})
|
||||
(:dependencies)))))
|
|
@ -177,6 +177,13 @@
|
|||
[key (name val)]))]
|
||||
[:licenses [:license tags]]))))
|
||||
|
||||
(defn- resource-tags [project type]
|
||||
(if-let [resources (seq (:resource-paths project))]
|
||||
(let [types (keyword (str (name type) "s"))]
|
||||
(vec (concat [types]
|
||||
(for [resource resources]
|
||||
[type [:directory resource]]))))))
|
||||
|
||||
(defmethod xml-tags ::build
|
||||
([_ [project test-project]]
|
||||
(let [[src & extra-src] (concat (:source-paths project)
|
||||
|
@ -185,14 +192,8 @@
|
|||
[:build
|
||||
[:sourceDirectory src]
|
||||
(xml-tags :testSourceDirectory test)
|
||||
(if-let [resources (seq (:resource-paths project))]
|
||||
(vec (concat [:resources]
|
||||
(for [resource resources]
|
||||
[:resource [:directory resource]]))))
|
||||
(if-let [resources (seq (:resource-paths test-project))]
|
||||
(vec (concat [:testResources]
|
||||
(for [resource resources]
|
||||
[:testResource [:directory resource]]))))
|
||||
(resource-tags project :resource)
|
||||
(resource-tags test-project :testResource)
|
||||
(if-let [extensions (seq (:extensions project))]
|
||||
(vec (concat [:extensions]
|
||||
(for [[dep version] extensions]
|
||||
|
|
|
@ -141,7 +141,7 @@ Also accepts a second parameter for fetching successive pages."
|
|||
;; Maven's indexer requires over 1GB of free space for a <100M index
|
||||
(let [orig-tmp (System/getProperty "java.io.tmpdir")
|
||||
new-tmp (io/file (user/leiningen-home) "indices" "tmp")
|
||||
project (or project (project/normalize-repos project/defaults))
|
||||
project (or project (project/make {}))
|
||||
contexts (doall (map add-context (:repositories project)))]
|
||||
(try
|
||||
(.mkdirs new-tmp)
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
rests (mapcat rest forms)
|
||||
;; This won't pick up :jvm-args that come from profiles, but it
|
||||
;; at least gets us :dependencies.
|
||||
project (project/normalize-deps (assoc project :dependencies
|
||||
(apply concat deps)))
|
||||
project (project/merge-profiles project {:dependencies deps})
|
||||
command (eval/shell-command project (concat '(do) inits rests))]
|
||||
(string/join " " (if (win-batch?)
|
||||
(map quote-arg command)
|
||||
|
|
|
@ -33,14 +33,10 @@
|
|||
([project profile]
|
||||
(with-profile project :test-pom profile))
|
||||
([project name profile]
|
||||
(let [{:keys [included-profiles
|
||||
without-profiles]} (meta project)]
|
||||
(-> without-profiles
|
||||
(update-in [:profiles] #(assoc % name profile))
|
||||
(project/merge-profiles
|
||||
(if (some #{name} included-profiles)
|
||||
included-profiles
|
||||
(conj included-profiles name)))))))
|
||||
(-> project
|
||||
(vary-meta update-in [:without-profiles :profiles]
|
||||
assoc name profile)
|
||||
(project/merge-profiles [name]))))
|
||||
|
||||
(deftest test-pom-default-values
|
||||
(let [xml (xml/parse-str (make-pom sample-project))]
|
||||
|
@ -179,37 +175,37 @@
|
|||
[[ring-mock
|
||||
:classifier "cla"
|
||||
:extension "dom"]]]]})))]
|
||||
(is (= ["peridot" "org.clojure" "rome" "ring"]
|
||||
(is (= ["org.clojure" "rome" "ring" "peridot"]
|
||||
(map #(first-in % [:dependency :groupId])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= [ "peridot" "clojure" "rome" "ring"]
|
||||
(is (= ["clojure" "rome" "ring" "peridot"]
|
||||
(map #(first-in % [:dependency :artifactId])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= ["0.0.5" "1.3.0" "0.9" "1.0.0"]
|
||||
(is (= ["1.3.0" "0.9" "1.0.0" "0.0.5"]
|
||||
(map #(first-in % [:dependency :version])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= ["provided" nil nil nil]
|
||||
(is (= [nil nil nil "provided"]
|
||||
(map #(first-in % [:dependency :scope])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= ["true" nil nil nil]
|
||||
(is (= [nil nil nil "true"]
|
||||
(map #(first-in % [:dependency :optional])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= ["sources" nil nil nil]
|
||||
(is (= [nil nil nil "sources"]
|
||||
(map #(first-in % [:dependency :classifier])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= ["pom" nil nil nil]
|
||||
(is (= [nil nil nil "pom"]
|
||||
(map #(first-in % [:dependency :type])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= ["ring-mock" nil nil nil]
|
||||
(is (= [nil nil nil "ring-mock"]
|
||||
(map #(first-in % [:dependency :exclusions :exclusion :artifactId])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= ["ring-mock" nil nil nil]
|
||||
(is (= [nil nil nil "ring-mock"]
|
||||
(map #(first-in % [:dependency :exclusions :exclusion :groupId])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= ["cla" nil nil nil]
|
||||
(is (= [nil nil nil "cla"]
|
||||
(map #(first-in % [:dependency :exclusions :exclusion :classifier])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= ["dom" nil nil nil]
|
||||
(is (= [nil nil nil "dom"]
|
||||
(map #(first-in % [:dependency :exclusions :exclusion :type])
|
||||
(deep-content xml [:project :dependencies])))))
|
||||
(let [xml (xml/parse-str
|
||||
|
@ -219,19 +215,19 @@
|
|||
:scope "provided"
|
||||
:exclusions
|
||||
[ring-mock]]]})))]
|
||||
(is (= ["peridot" "org.clojure" "rome" "ring"]
|
||||
(is (= ["org.clojure" "rome" "ring" "peridot"]
|
||||
(map #(first-in % [:dependency :groupId])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= [ "peridot" "clojure" "rome" "ring"]
|
||||
(is (= ["clojure" "rome" "ring" "peridot"]
|
||||
(map #(first-in % [:dependency :artifactId])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= ["0.0.5" "1.3.0" "0.9" "1.0.0"]
|
||||
(is (= ["1.3.0" "0.9" "1.0.0" "0.0.5"]
|
||||
(map #(first-in % [:dependency :version])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= ["provided" nil nil nil]
|
||||
(is (= [nil nil nil "provided"]
|
||||
(map #(first-in % [:dependency :scope])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= ["ring-mock" nil nil nil]
|
||||
(is (= [nil nil nil "ring-mock"]
|
||||
(map #(first-in % [:dependency :exclusions :exclusion :artifactId])
|
||||
(deep-content xml [:project :dependencies]))))
|
||||
(is (= [nil nil nil nil]
|
||||
|
|
Loading…
Reference in a new issue