diff --git a/src/main/clojure/cemerick/pomegranate/aether.clj b/src/main/clojure/cemerick/pomegranate/aether.clj index f0dd8a1..9d8b4b3 100644 --- a/src/main/clojure/cemerick/pomegranate/aether.clj +++ b/src/main/clojure/cemerick/pomegranate/aether.clj @@ -612,17 +612,6 @@ kwarg to the repository kwarg. (merge {:result result} m)))) coordinates)))) - -(defn- add-version-from-managed-coord - "Given an entry from a coordinates vector, and the corresponding entry from the - managed coordinates vector, update the version number in the coordinate with the - value from the managed coordinate." - [coord managed-coord] - (if-let [managed-version (second managed-coord)] - (vec (concat [(first coord) managed-version] - (nthrest coord 2))) - (throw (IllegalArgumentException. (str "Provided artifact is missing a version: " coord))))) - (defn- coordinates-match? [[dep version & opts] [sdep sversion & sopts]] (let [om (apply hash-map opts) @@ -637,28 +626,68 @@ kwarg to the repository kwarg. (= (:classifier om) (:classifier som))))) -(defn- find-managed-coord - "Given an entry from a coordinates vector, and a managed coordinates vector, find - the entry in the managed coordinates vector (if any) that matches the coordinate." - [coord managed-coords] - (first (filter #(coordinates-match? coord %) managed-coords))) - -(defn- add-version-from-managed-coords-if-missing - "Given a managed coordinates vector and an entry from a coordinates vector, check - to see if the coordinate specifies a version string, and if not, update it with - the version string from the managed coordinates (if it is defined)." - [managed-coords coord] - (if (nil? (second coord)) - (add-version-from-managed-coord coord (find-managed-coord coord managed-coords)) - coord)) - -(defn- merge-versions-from-managed-coords +(defn- coord-map-key + "Creates the unique key for the given coordinate map. This is + essentially a representation of the full maven coordinate except + the version." + [{:keys [project extension classifier]}] + [project extension classifier]) + +(defn- canonical-id [id] + (apply symbol (distinct ((juxt group name) id)))) + +(defn conform-coord + "Returns a map describing the coordinate. The full project ID is + under the :project key and the version, if specified and not nil, + under the :version key. All other specified options appear with + the keys and values specified (including nil values)." + [[project & opts]] + (if project + (let [has-version? (odd? (count opts)) + version (if has-version? (first opts)) + opts (if has-version? (rest opts) opts) + opts-map (apply hash-map opts)] + (-> (if (and has-version? version) {:version version} {}) + (assoc :project (canonical-id project)) + (merge opts-map))))) + +(defn- strip-defaults [dep-map] + (remove #(or (some #{:project :version} %) + (= [:scope "compile"] %) + (= [:extension "jar"] %) + (= [:optional false] %)) dep-map)) + +(defn unform-coord + "Returns the canonical, vector form of a dependency that was + specified as a map." + [{:keys [project version] :as dep-map}] + (-> (if version [project version] [project]) + (cons (strip-defaults dep-map)) + ((partial mapcat identity)) + (vec))) + +(defn- managed-coords-map [managed-coords] + (->> managed-coords + (map conform-coord) + (map (juxt coord-map-key identity)) + (into {}))) + +(defn- merge-managed-coord [managed-coords-m coord] + (let [coord-map (conform-coord coord) + coord-key (coord-map-key coord-map) + managed-coord (get managed-coords-m coord-key) + merged-map (merge managed-coord coord-map)] + (if (:version merged-map) + (unform-coord (into {} (remove (comp nil? second) merged-map))) + (throw (IllegalArgumentException. (str "Provided artifact is missing a version: " coord)))))) + +(defn merge-versions-from-managed-coords "Given a vector of coordinates (e.g. [[group/name <\"version\"> & settings] ..]) where the version field is optional or can be nil, and a vector of managed coordinates, returns an updated vector of coordinates with version numbers merged in from the managed-coordinates vector as necessary." [coordinates managed-coordinates] - (vec (map (partial add-version-from-managed-coords-if-missing managed-coordinates) + (vec (map (partial merge-managed-coord (managed-coords-map managed-coordinates)) coordinates))) (defn- coords->Dependencies diff --git a/src/test/clojure/cemerick/pomegranate/aether_test.clj b/src/test/clojure/cemerick/pomegranate/aether_test.clj index 345b338..74ec4f6 100644 --- a/src/test/clojure/cemerick/pomegranate/aether_test.clj +++ b/src/test/clojure/cemerick/pomegranate/aether_test.clj @@ -548,6 +548,91 @@ ['tester "0.1.0-20120403.012847-1"] nil} (aether/dependency-hierarchy coords deps))))) +(deftest check-canonical-id + (let [f @#'aether/canonical-id] + (are [expect input] (= expect (f input))) + 'foo 'foo + 'foo 'foo/foo + 'foo/bar 'foo/bar)) + +(deftest check-conform-coord + (let [f aether/conform-coord] + (are [expect input] (= expect (f input)) + nil nil + {:project 'foo} '[foo] + {:project 'foo/bar} '[foo/bar] + {:project 'foo} '[foo nil] + {:project 'foo, :version "1.2.3"} '[foo "1.2.3"] + {:project 'foo, :version "1.2.3", :scope "test"} '[foo "1.2.3" :scope "test"] + {:project 'foo, :scope "test"} '[foo :scope "test"] + {:project 'foo, :scope "test"} '[foo nil :scope "test"] + {:project 'foo, :scope nil} '[foo nil :scope nil] + {:project 'foo, :scope "test", :optional true} '[foo :scope "test" :optional true] + {:project 'foo, :version "1.2.3" :exclusions '[[bar]]} '[foo "1.2.3" :exclusions [[bar]]]))) + +(deftest check-unform-coord + (let [f aether/unform-coord] + (are [expect input] (= expect (f input)) + '[foo] {:project 'foo} + '[foo/bar] {:project 'foo/bar} + '[foo "1.2.3"] {:project 'foo, :version "1.2.3"} + '[foo "1.2.3" :scope "test"] {:project 'foo, :version "1.2.3", :scope "test"} + '[foo :scope "test"] {:project 'foo, :scope "test"} + '[foo :scope nil] {:project 'foo, :scope nil} + + '[foo :scope "test"] {:project 'foo, :scope "test"} + '[foo] {:project 'foo, :scope "compile"} + '[foo :optional true] {:project 'foo, :optional true} + '[foo] {:project 'foo, :optional false} + '[foo :extension "zip"] {:project 'foo, :extension "zip"} + '[foo] {:project 'foo, :extension "jar"} + + '[foo "1.2.3" :exclusions [[bar]]] {:project 'foo, :version "1.2.3" :exclusions '[[bar]]}))) + +(deftest check-merge-managed-coord + (let [f @#'aether/merge-managed-coord + managed-coords-map @#'aether/managed-coords-map + managed-coords-m (managed-coords-map + '[[demo "1.0.0"] + [demo-test "2.0.0" :scope "test"] + [demo-compile "3.0.0" :scope "compile"] + [demo-excl "4.0.0" :exclusions [[demo] [demo-test]]]])] + (is (thrown-with-msg? IllegalArgumentException #"Provided artifact is missing a version: " + (f nil nil))) + (is (thrown-with-msg? IllegalArgumentException #"Provided artifact is missing a version: \[demo-unk\]" + (f nil '[demo-unk]))) + (is (= '[demo "1.0.0"] (f nil '[demo/demo "1.0.0"]))) + (is (= '[demo "1.0.0"] (f managed-coords-m '[demo]))) + (is (= '[demo "1.0.0"] (f managed-coords-m '[demo nil]))) + (is (= '[demo-test "2.0.0" :scope "test"] (f managed-coords-m '[demo-test]))) + (is (= '[demo-test "2.0.0" :scope "provided"] (f managed-coords-m '[demo-test :scope "provided"]))) + (is (= '[demo-test "2.0.0"] (f managed-coords-m '[demo-test :scope "compile"]))) + (is (= '[demo-test "2.0.0"] (f managed-coords-m '[demo-test :scope nil]))) + (is (= '[demo-compile "3.0.0"] (f managed-coords-m '[demo-compile]))) + (is (= '[demo-excl "4.0.0" :exclusions [[demo] [demo-test]]] (f managed-coords-m '[demo-excl]))) + (is (= '[demo-excl "4.0.0"] (f managed-coords-m '[demo-excl :exclusions nil]))))) + +;; simple functionality test; edge cases checked in underlying functions +(deftest check-merge-versions-from-managed-coords + (let [canonical-form #(-> % aether/conform-coord aether/unform-coord) + + managed-coords '[[demo "1.0.0"] + [demo-test "2.0.0" :scope "test"] + [demo-provided "3.0.0" :scope "provided"] + [demo-compile "3.0.1" :scope "compile"] + [demo-excl "4.0.0" :exclusions [[demo] [demo-test]]]] + local-coords '[[foo "1.0.0" :scope "test"] + [foo/bar "2.0.0" :exclusions [[demo]] :scope "compile"]] + + coords (concat local-coords '[[demo] + [demo-test "2.0.0"] + [demo-provided] + [demo-compile] + [demo-excl]]) + merged-coords (aether/merge-versions-from-managed-coords coords managed-coords) + expected-coords (map canonical-form (concat managed-coords local-coords))] + (is (= (set merged-coords) (set expected-coords))))) + (comment "tests needed for: repository authentication