(#2067) add support for managed-dependencies

This commit provides initial support for `managed-dependencies`,
where dependency version numbers may be specified in a separate
section called `managed-dependencies`, and those version numbers
will be used for any deps in the main `dependencies` section
that do not explicitly specify a version number.

This is a precursor to being able to specify a "parent" project
that could be used to consolidate version numbers of common
dependencies across a large number of libraries.
This commit is contained in:
Chris Price 2016-04-10 15:26:06 -07:00
parent 49abe11085
commit 27782edb2e
11 changed files with 111 additions and 45 deletions

View file

@ -250,10 +250,12 @@
(def ^:private get-dependencies-memoized
(memoize
(fn [dependencies-key {:keys [repositories local-repo offline? update
checksum mirrors] :as project}
(fn [dependencies-key managed-dependencies-key
{:keys [repositories local-repo offline? update
checksum mirrors] :as project}
{:keys [add-classpath? repository-session-fn] :as args}]
{:pre [(every? vector? (get project dependencies-key))]}
{:pre [(every? vector? (get project dependencies-key))
(every? vector? (get project managed-dependencies-key))]}
(try
((if add-classpath?
pomegranate/add-dependencies
@ -264,6 +266,7 @@
:repositories (->> repositories
(map add-repo-auth)
(map (partial update-policies update checksum)))
:managed-coordinates (get project managed-dependencies-key)
:coordinates (get project dependencies-key)
:mirrors (->> mirrors
(map add-repo-auth)
@ -407,13 +410,17 @@
#(-> % aether/repository-session
(pedantic/use-transformer ranges overrides))))
(defn ^:internal get-dependencies [dependencies-key project & args]
(defn ^:internal get-dependencies [dependencies-key managed-dependencies-key
project & args]
(let [ranges (atom []), overrides (atom [])
session (pedantic-session project ranges overrides)
args (assoc (apply hash-map args) :repository-session-fn session)
trimmed (select-keys project [dependencies-key :repositories :checksum
:local-repo :offline? :update :mirrors])
deps-result (get-dependencies-memoized dependencies-key trimmed args)]
trimmed (select-keys project [dependencies-key managed-dependencies-key
:repositories :checksum :local-repo :offline?
:update :mirrors])
deps-result (get-dependencies-memoized dependencies-key
managed-dependencies-key
trimmed args)]
(pedantic-do (:pedantic? project) @ranges @overrides)
deps-result))
@ -486,16 +493,11 @@
(doseq [[_ {:keys [native-prefix file]}] snap-deps]
(extract-native-dep! native-path file native-prefix))))))
(defn resolve-dependencies
"Delegate dependencies to pomegranate. This will ensure they are
downloaded into ~/.m2/repository and that native components of
dependencies have been extracted to :native-path. If :add-classpath?
is logically true, will add the resolved dependencies to Leiningen's
classpath.
Returns a seq of the dependencies' files."
[dependencies-key {:keys [native-path] :as project} & rest]
(let [dependencies-tree (apply get-dependencies dependencies-key project rest)
(defn resolve-managed-dependencies
"TODO"
[dependencies-key managed-dependencies-key project & rest]
(let [dependencies-tree (apply get-dependencies dependencies-key
managed-dependencies-key project rest)
jars (->> dependencies-tree
(aether/dependency-files)
(filter #(re-find #"\.(jar|zip)$" (.getName %))))]
@ -504,13 +506,33 @@
(extract-native-dependencies project jars dependencies-tree))
jars))
(defn resolve-dependencies
"Delegate dependencies to pomegranate. This will ensure they are
downloaded into ~/.m2/repository and that native components of
dependencies have been extracted to :native-path. If :add-classpath?
is logically true, will add the resolved dependencies to Leiningen's
classpath.
Returns a seq of the dependencies' files."
[dependencies-key project & rest]
(apply resolve-managed-dependencies dependencies-key nil project rest))
(defn managed-dependency-hierarchy
"TODO"
[dependencies-key managed-dependencies-key project & options]
;; TODO: explain private call
(if-let [deps-list (#'aether/merge-versions-from-managed-coords
(get project dependencies-key)
(get project managed-dependencies-key))]
(aether/dependency-hierarchy deps-list
(apply get-dependencies dependencies-key
managed-dependencies-key
project options))))
(defn dependency-hierarchy
"Returns a graph of the project's dependencies."
[dependencies-key project & options]
(if-let [deps-list (get project dependencies-key)]
(aether/dependency-hierarchy deps-list
(apply get-dependencies dependencies-key
project options))))
(apply managed-dependency-hierarchy dependencies-key nil project options))
(defn- normalize-path [root path]
(let [f (io/file path) ; http://tinyurl.com/ab5vtqf
@ -533,7 +555,7 @@
(seq
(->> (filter ext-dependency? (:dependencies project))
(assoc project :dependencies)
(resolve-dependencies :dependencies)
(resolve-managed-dependencies :dependencies :managed-dependencies)
(map (memfn getAbsolutePath)))))
(defn ^:internal checkout-deps-paths
@ -561,7 +583,8 @@
(:resource-paths project)
[(:compile-path project)]
(checkout-deps-paths project)
(for [dep (resolve-dependencies :dependencies project)]
(for [dep (resolve-managed-dependencies
:dependencies :managed-dependencies project)]
(.getAbsolutePath dep)))
:when path]
(normalize-path (:root project) path)))

View file

@ -83,7 +83,7 @@
((juxt :source-paths :test-paths :resource-paths) project))]
(.mkdirs (io/file path))))
(write-pom-properties project)
(classpath/resolve-dependencies :dependencies project)
(classpath/resolve-managed-dependencies :dependencies :managed-dependencies project)
(run-prep-tasks project)
(deliver @prep-blocker true)
(reset! prep-blocker (promise)))
@ -221,7 +221,7 @@
(defn ^:internal classpath-arg [project]
(let [classpath-string (string/join java.io.File/pathSeparatorChar
(classpath/get-classpath project))
agent-tree (classpath/get-dependencies :java-agents project)
agent-tree (classpath/get-dependencies :java-agents nil project)
;; Seems like you'd expect dependency-files to walk the whole tree
;; here, but it doesn't, which is what we want. but maybe a bug?
agent-jars (aether/dependency-files (aether/dependency-hierarchy
@ -334,7 +334,7 @@
(when (:debug project)
(System/setProperty "clojure.debug" "true"))
;; :dependencies are loaded the same way as plugins in eval-in-leiningen
(project/load-plugins project :dependencies)
(project/load-plugins project :dependencies :managed-dependencies)
(doseq [path (classpath/get-classpath project)]
(pomegranate/add-classpath path))
(doseq [opt (get-jvm-args project)

View file

@ -686,13 +686,14 @@
(def ^:private registered-wagon-files (atom #{}))
(defn load-plugins
([project key]
(when (seq (get project key))
([project dependencies-key managed-dependencies-key]
(when (seq (get project dependencies-key))
(ensure-dynamic-classloader)
(let [repos-project (update-in project [:repositories] meta-merge
(:plugin-repositories project))]
(classpath/resolve-dependencies key repos-project
:add-classpath? true)))
(classpath/resolve-managed-dependencies
dependencies-key managed-dependencies-key repos-project
:add-classpath? true)))
(doseq [wagon-file (-> (.getContextClassLoader (Thread/currentThread))
(.getResources "leiningen/wagons.clj")
(enumeration-seq))
@ -701,6 +702,7 @@
(aether/register-wagon-factory! hint (eval factory))
(swap! registered-wagon-files conj wagon-file))
project)
([project dependencies-key] (load-plugins project dependencies-key nil))
([project] (load-plugins project :plugins)))
(defn plugin-vars [project type]

View file

@ -2,7 +2,6 @@
(:use [clojure.test]
[leiningen.core.classpath])
(:require [clojure.java.io :as io]
[clojure.set :as set]
[leiningen.core.user :as user]
[leiningen.test.helper :as lthelper]
[leiningen.core.project :as project]))
@ -17,7 +16,8 @@
(defn m2-file [f]
(io/file (System/getProperty "user.home") ".m2" "repository" f))
(def project {:dependencies '[[org.clojure/clojure "1.3.0"]
(def project {:managed-dependencies '[[org.clojure/clojure "1.3.0"]]
:dependencies '[[org.clojure/clojure]
[ring/ring-core "1.0.0"
:exclusions [commons-codec]]]
:checkout-deps-shares [:source-paths :resource-paths
@ -38,7 +38,9 @@
(m2-file "ring/ring-core/1.0.0/ring-core-1.0.0.jar")
(m2-file (str "commons-fileupload/commons-fileupload/1.2.1/"
"commons-fileupload-1.2.1.jar"))}
(set (resolve-dependencies :dependencies project)))))
(set (resolve-managed-dependencies :dependencies
:managed-dependencies
project)))))
(deftest test-dependency-hierarchy
(doseq [f (reverse (file-seq (io/file (:root project))))]
@ -49,7 +51,9 @@
{[commons-fileupload "1.2.1"] nil
[commons-io "1.4"] nil
[javax.servlet/servlet-api "2.5"] nil}}
(dependency-hierarchy :dependencies project))))
(managed-dependency-hierarchy :dependencies
:managed-dependencies
project))))
(def directories
(vec (map lthelper/pathify

View file

@ -8,7 +8,8 @@
[leiningen.core.project :as project])
(:import (java.io File)))
(def project {:dependencies '[[org.clojure/clojure "1.3.0"]]
(def project {:managed-dependencies '[[org.clojure/clojure "1.3.0"]]
:dependencies '[[org.clojure/clojure]]
:root "/tmp/lein-sample-project"
:repositories project/default-repositories
:target-path "/tmp/lein-sample-project/target"

View file

@ -69,8 +69,8 @@
(def tree-command
"A mapping from the tree-command to the dependency key it should print a tree
for."
{":tree" :dependencies
":plugin-tree" :plugins})
{":tree" [:dependencies :managed-dependencies]
":plugin-tree" [:plugins nil]})
@ -121,16 +121,22 @@ force them to be updated, use `lein -U $TASK`."
(let [project (project/merge-profiles
project
[{:pedantic? (quote ^:displace warn)}])
hierarchy (classpath/dependency-hierarchy
(tree-command command)
[dependencies-key managed-dependencies-key] (tree-command command)
hierarchy (classpath/managed-dependency-hierarchy
dependencies-key
managed-dependencies-key
project)]
(walk-deps hierarchy print-dep))
(= command ":verify")
(if (user/gpg-available?)
(walk-deps (classpath/dependency-hierarchy :dependencies project)
(walk-deps (classpath/managed-dependency-hierarchy
:dependencies
:managed-dependencies
project)
(partial verify project))
(main/abort (str "Could not verify - gpg not available.\n"
"See `lein help gpg` for how to setup gpg.")))
:else (classpath/resolve-dependencies :dependencies project))
:else (classpath/resolve-managed-dependencies
:dependencies :managed-dependencies project))
(catch DependencyResolutionException e
(main/abort (.getMessage e))))))

View file

@ -177,7 +177,8 @@ be deactivated."
(let [whitelisted (select-keys project project/whitelist-keys)
project (-> (project/unmerge-profiles project [:default])
(merge whitelisted))
deps (->> (classpath/resolve-dependencies :dependencies project)
deps (->> (classpath/resolve-managed-dependencies
:dependencies :managed-dependencies project)
(filter #(.endsWith (.getName %) ".jar")))
jars (cons (io/file jar) deps)]
(write-components project jars out)))

View file

@ -2,10 +2,9 @@
(:use [clojure.test]
[leiningen.deps]
[leiningen.test.helper :only [sample-project m2-dir native-project
managed-deps-project
delete-file-recursively]])
(:require [clojure.java.io :as io]
[leiningen.core.main :as main]
[leiningen.core.classpath :as classpath]
[leiningen.core.utils :as utils]
[leiningen.core.eval :as eval]))
@ -128,3 +127,11 @@
(set (for [f (rest (file-seq (io/file (first (eval/native-arch-paths
native-project)))))]
(.getName f))))))
(deftest ^:online test-managed-deps
(let [managed-deps [["rome" "0.9"] ["jdom" "1.0"]]]
(doseq [[n v] managed-deps]
(delete-file-recursively (m2-dir n v) :silently))
(deps managed-deps-project)
(doseq [[n v] managed-deps]
(is (.exists (m2-dir n v)) (str n " was not downloaded.")))))

View file

@ -65,6 +65,8 @@
(def with-classifiers-project (read-test-project "with-classifiers"))
(def managed-deps-project (read-test-project "managed-deps"))
(defn abort-msg
"Catches main/abort thrown by calling f on its args and returns its error
message."

View file

@ -6,7 +6,8 @@
[clojure.xml :as xml]
[leiningen.test.helper :refer [sample-no-aot-project
uberjar-merging-project
provided-project]])
provided-project
managed-deps-project]])
(:import (java.io File FileOutputStream)
(java.util.zip ZipFile)))
@ -64,3 +65,10 @@
_ (uberjar provided-project)]
(is (= 1 (:exit (sh "java" "-jar" filename))))
(is (= 0 (:exit (sh "java" bootclasspath "-jar" filename))))))
(deftest test-uberjar-managed-dependencies
(uberjar managed-deps-project)
(let [filename (str "test_projects/managed-deps/target/"
"mgmt-0.99.0-SNAPSHOT-standalone.jar")
uberjar-file (File. filename)]
(is (= true (.exists uberjar-file)))))

View file

@ -0,0 +1,12 @@
(def clj-version "1.3.0")
(defproject mgmt "0.99.0-SNAPSHOT"
:description "A test project"
:managed-dependencies [[~(symbol "org.clojure" "clojure") ~clj-version]
[rome ~(str "0." "9")]
[ring/ring "1.0.0"]]
:dependencies [[org.clojure/clojure]
[rome/rome nil]
[ring]])