diff --git a/interop/src/de/janthomae/leiningenplugin/leiningen/LeiningenAPI.clj b/interop/src/de/janthomae/leiningenplugin/leiningen/LeiningenAPI.clj index fdcb147..4b7940b 100644 --- a/interop/src/de/janthomae/leiningenplugin/leiningen/LeiningenAPI.clj +++ b/interop/src/de/janthomae/leiningenplugin/leiningen/LeiningenAPI.clj @@ -36,6 +36,72 @@ (zipmap (map name (keys m)) (vals m)))) +(defn remove-modules + "Remove any modules from s that are in the sequence to-remove. + + deps - in the format of the :dependencies values in the leiningen project file. [[groupid/artifact \"version\"]] + to-remove - the dependencies to remove, in the format [groupid/artifact1 groupid/artifact2] - the version is explicitly not included. + + What this is doing is allowing us to specify a set of artifacts which we don't want aether to retrieve. + This is usually the case when we have another leiningen module created in IntelliJ that isn't in a repository. + See issue 18 for more details and discussion" + [deps to-remove] + (if (empty? to-remove) + deps + (remove nil? + (for [d deps + r to-remove] + (if (= (first d) r) + nil + d))))) + + +(defn group + "Copied from the private aether/group." + [group-artifact] + (or (namespace group-artifact) (name group-artifact))) + +(defn dep-vec-to-map + "Convert a dependency vector into a map. + + Arguments: + A vector in the format of a leiningen dependency declaration." + [[group-artifact version & {:keys [scope optional exclusions] :as opts}]] + (merge {:groupid (group group-artifact) :artifactid (name group-artifact) :version version} opts)) + +(defn dep-map-to-vec + "Convert a dependency map back into a dependency declaration vector as used in leiningen" + [{:keys [groupid artifactid version] :as m}] + (reduce #(conj %1 (first %2) (second %2)) + [(if (= groupid artifactid) + (symbol groupid) + (symbol groupid artifactid)) + version] + (seq (dissoc m :groupid :artifactid :version)))) + +(defn add-exclusions + "Add exclusions to any dependencies so that aether won't attempt to retrieve them. This is handy when + we are working with artifacts which are not in a remote repository. The particular use case that inspired this + was in Issue 18 where we had multiple modules in a project that reference each other. + + This implicitly adds other modules that are loaded in IntelliJ into the exclusion list and right now supports only the + groupname/artifactid specification for an exclusion. + + Arguments: + deps - in the vector of vectors format of the :dependencies values in the leiningen project file. [[groupid.artifact \"version\"]] + exclusions - the dependencies to add to each of deps exclusions list, in the format [groupid/artifact1 groupid/artifact2]. + At this time we don't support any more complex exclusion definitions as we don't need them." + [deps exclusions] + (if (empty? exclusions) + deps + (for [d deps] + (let [m (dep-vec-to-map d) + e (:exclusions m) + e (if (nil? e) [] e) + exs (reduce conj e exclusions)] + (-> (assoc m :exclusions exs) + dep-map-to-vec))))) + (defn -loadDependencies "Retrieve all of the dependencies (including transitive) which are in the :dependencies list in the project file. - args: prj-file-path - path to the project.clj file - appears to work with relative or absolute diff --git a/interop/test/de/janthomae/leiningenplugin/leiningen/LeinigenAPITest.clj b/interop/test/de/janthomae/leiningenplugin/leiningen/LeinigenAPITest.clj index 697ee8c..1ec6d8b 100644 --- a/interop/test/de/janthomae/leiningenplugin/leiningen/LeinigenAPITest.clj +++ b/interop/test/de/janthomae/leiningenplugin/leiningen/LeinigenAPITest.clj @@ -18,3 +18,91 @@ (map #(contains? % :artifactid ) result) => (has every? true?) (map #(contains? % :file ) result) => (has every? true?) (map #(contains? % :groupid ) result) => (has every? true?))) + +;Test for the scenario when we have one leiningen module dependent on another. +;Some of these module declarations were taken from the leiningen sample project file to ensure compatibility. +(def module-a '[com.example/module "0.0.1-SNAPSHOT" :exclusions [midje]]) +(def module-b '[midje "1.4.0"]) +(def module-c '[org.jclouds/jclouds "1.0" :classifier "jdk15" :scope "test"]) +(def module-d '[net.sf.ehcache/ehcache "2.3.1" :extension "pom"]) +(def module-e '[log4j "1.2.15" :exclusions [[javax.mail/mail :extension "jar"] [javax.jms/jms :classifier "*"] com.sun.jdmk/jmxtools com.sun.jmx/jmxri]]) + +(facts + "About our dependency vector to map conversions and vice versa. Basically, making sure I can round trip convert these dependency vectors." + (let [a (dep-vec-to-map module-a) + b (dep-vec-to-map module-b) + c (dep-vec-to-map module-c) + d (dep-vec-to-map module-d) + e (dep-vec-to-map module-e)] + a => (contains {:groupid "com.example" :artifactid "module" :version "0.0.1-SNAPSHOT" :exclusions '[midje]}) + (count a) => 4 + b => (contains {:groupid "midje" :artifactid "midje" :version "1.4.0"}) + (count b) => 3 + c => (contains {:groupid "org.jclouds" :artifactid "jclouds" :version "1.0" :classifier "jdk15" :scope "test"}) + (count c) => 5 + d => (contains {:groupid "net.sf.ehcache" :artifactid "ehcache" :version "2.3.1" :extension "pom"}) + (count d) => 4 + e => (contains {:groupid "log4j" :artifactid "log4j" :version "1.2.15" :exclusions '[[javax.mail/mail :extension "jar"] [javax.jms/jms :classifier "*"] com.sun.jdmk/jmxtools com.sun.jmx/jmxri]}) + (dep-map-to-vec a) => module-a + (dep-map-to-vec b) => module-b + (dep-map-to-vec c) => module-c + (dep-map-to-vec d) => module-d + (dep-map-to-vec e) => module-e)) + + +(def exclusion-a 'exclude/a) +(def exclusion-b 'b) +(def exclusion-c 'com.example/module) +(def to-remove [exclusion-a exclusion-b]) + +(facts + "About how we remove modules from the dependencies list" + (let [result (remove-modules [module-a module-b] [exclusion-c])] + (count result) => 1 + (first (take 2 result)) => module-b) + (let [result (remove-modules [module-a module-b] [])] + (count result) => 2)) + +(facts + "About how we add a single exclusion to a single dependency" + (let [results (add-exclusions [module-a] [exclusion-a]) + r (first results) + m (dep-vec-to-map r) + exs (:exclusions m)] + (count results) => 1 + (count exs) => 2 + exs => (contains exclusion-a))) + +(facts + "About how we add multiple exclusions to a single dependency" + (let [exclusions [exclusion-a exclusion-b exclusion-c] + results (add-exclusions [module-a] exclusions) + r (first results) + m (dep-vec-to-map r) + exs (:exclusions m)] + (count results) => 1 + (count exs) => 4 + exs => (contains (conj exclusions 'midje) :in-any-order) + )) + +(facts + "About how we add exclusions to a list of dependencies" + (let [results (add-exclusions [module-a module-b module-c module-d module-e] [exclusion-a]) + r (first results)] + (count results) => 5 + (doseq [r results] + (let [m (dep-vec-to-map r) + exs (:exclusions m)] + exs => (contains exclusion-a))))) + +(facts + "Testing with empty exclusions vector." + (let [results (add-exclusions [module-a] []) + r (first results) + m (dep-vec-to-map r) + exs (:exclusions m)] + (count results) => 1 + exs => '[midje])) + +;(def project-1 (assoc p/defaults :dependencies deps)) +;(cp/dependency-hierarchy :dependencies project-1) \ No newline at end of file