source: trunk/abcl/contrib/abcl-asdf/maven-embedder.lisp @ 13804

Last change on this file since 13804 was 13804, checked in by Mark Evenson, 11 years ago

Fix for maven-3.0.4.

Part of the process of cleaning up ABCL-ASDF to work with more Maven
versions.

Seems to be failing for OS X Maven 3.0.4, so need to do a round of testing.

Add system definition of ABCL-ASDF-TEST which becomes the behavior for
invoking ASDF:TEST-SYSTEM on ABCL-ASDF. Really update to version
"0.5.0".

Correct misspellings.

TODO: figure out a list of repos to iteratively search.

TODO: overload the system defintion version mechanism to allow
non-integer values, or just use the IRI class?

TODO: be more verbose on searching/downloading Maven artifacts as it
can be quite slow for large amounts of artifacts.

File size: 7.6 KB
Line 
1;;; Use the Aether system in a default maven distribution to download
2;;; and install dependencies.
3;;;
4;;; https://docs.sonatype.org/display/AETHER/Home
5;;;
6
7(in-package :abcl-asdf)
8
9(require :abcl-contrib)
10(require :jss)
11
12#|
13Test:
14(resolve-dependencies "org.slf4j" "slf4j-api" "1.6.1")
15
16(resolve-dependencies "org.apache.maven" "maven-aether-provider" "3.0.3")
17|#
18
19(defvar *mavens* '("/opt/local/bin/mvn3" "mvn3" "mvn" "mvn.bat")
20  "Locations to search for the Maven executable.")
21
22(defun find-mvn () 
23  (dolist (mvn-path *mavens*)
24    (let ((mvn 
25           (handler-case 
26               (truename (read-line (sys::process-output 
27                                     (sys::run-program "which" `(,mvn-path)))))
28             (end-of-file () nil))))
29      (when mvn
30        (return-from find-mvn mvn)))))
31
32(defun find-mvn-libs ()
33  (let ((mvn (find-mvn)))
34    (unless mvn
35      (warn "Failed to find Maven3 libraries.")
36      (return-from find-mvn-libs))
37    (truename (make-pathname 
38               :defaults (merge-pathnames "../lib/" mvn)
39               :name nil :type nil))))
40
41(defparameter *mvn-libs-directory*
42  nil
43  "Location of 'maven-core-3.<m>.<p>.jar', 'maven-embedder-3.<m>.<p>.jar' etc.")
44
45(defun mvn-version ()
46  (let* ((line
47         (read-line (sys::process-output 
48                     (sys::run-program 
49                      (namestring (find-mvn)) '("-version")))))
50         (pattern (#"compile" 
51                   'regex.Pattern
52                   "Apache Maven ([0-9]+)\\.([0-9]+)\\.([0-9]+)"))
53         (matcher (#"matcher" pattern line))
54         (found (#"find" matcher)))
55    (unless found 
56      (return-from mvn-version nil))
57    (mapcar #'parse-integer
58            `(,(#"group" matcher 1)
59              ,(#"group" matcher 2)
60              ,(#"group" matcher 3)))))
61
62(defun ensure-mvn-version ()
63  "Return t if Maven version is 3.0.3 or greater."
64  (let* ((version (mvn-version))
65         (major (first version))
66         (minor (second version))
67         (patch (third version)))
68    (or 
69     (and (>= major 3)
70          (>= minor 1))
71     (and (>= major 3)
72          (>= major 0)
73          (>= patch 3)))))
74
75(defparameter *init* nil)
76
77(defun init ()
78  (unless *mvn-libs-directory*
79    (setf *mvn-libs-directory* (find-mvn-libs)))
80  (unless (probe-file *mvn-libs-directory*)
81    (error "You must download maven-3.0.3 from http://maven.apache.org/download.html, then set ABCL-ASDF:*MVN-DIRECTORY* appropiately."))
82  (unless (ensure-mvn-version)
83    (error "We need maven-3.0.3 or later."))
84  (add-directory-jars-to-class-path *mvn-libs-directory* nil)
85  (setf *init* t))
86
87(defparameter *http-wagon-implementations*
88  `("org.apache.maven.wagon.providers.http.HttpWagon" ;; introduced as default with maven-3.0.3
89    "org.apache.maven.wagon.providers.http.LightweightHttpWagon"))
90
91(defun make-wagon-provider ()
92  (unless *init* (init))
93  (java:jinterface-implementation 
94   "org.sonatype.aether.connector.wagon.WagonProvider"
95   "lookup"
96   (lambda (role-hint)
97     (if (string-equal "http" role-hint)
98         (some (lambda (provider) (java:jnew provider)) *http-wagon-implementations*)
99       java:+null+))
100   "release"
101   (lambda (wagon)
102     (declare (ignore wagon)))))
103
104(defun repository-system ()
105  (unless *init* (init))
106  (let ((locator 
107         (java:jnew "org.apache.maven.repository.internal.DefaultServiceLocator"))
108        (repository-connector-factory-class 
109         (java:jclass "org.sonatype.aether.spi.connector.RepositoryConnectorFactory"))
110        (wagon-repository-connector-factory-class
111         (java:jclass "org.sonatype.aether.connector.wagon.WagonRepositoryConnectorFactory"))
112        (wagon-provider-class 
113         (java:jclass "org.sonatype.aether.connector.wagon.WagonProvider"))
114        (repository-system-class
115         (java:jclass "org.sonatype.aether.RepositorySystem")))
116    (#"addService" locator
117                   repository-connector-factory-class 
118                   wagon-repository-connector-factory-class)
119    (#"setServices" locator
120                    wagon-provider-class
121                    (java:jnew-array-from-list 
122                     "org.sonatype.aether.connector.wagon.WagonProvider"
123                     (list 
124                      (make-wagon-provider))))
125    (#"getService" locator
126                   repository-system-class)))
127       
128(defun new-session (repository-system)
129  (let ((session 
130         (java:jnew (jss:find-java-class "MavenRepositorySystemSession")))
131        (local-repository 
132         (java:jnew (jss:find-java-class "LocalRepository")
133                  (namestring (merge-pathnames ".m2/repository/"
134                                               (user-homedir-pathname))))))
135    (#"setLocalRepositoryManager" 
136     session
137     (#"newLocalRepositoryManager" repository-system local-repository))))
138
139(defun resolve-artifact (group-id artifact-id &optional (version "LATEST" versionp))
140  "Dynamically resolve Maven dependencies for item with GROUP-ID and ARTIFACT-ID at VERSION.
141
142Declared dependencies are not attempted to be located.
143
144If unspecified, the string \"LATEST\" will be used for the VERSION.
145
146Returns a string containing the necessary jvm classpath entries packed
147in Java CLASSPATH representation."
148
149  (unless versionp
150    (warn "Using LATEST for unspecified version."))
151  (let* ((system 
152          (repository-system))
153         (session 
154          (new-session system))
155         (repository 
156          (jss:new "org.sonatype.aether.repository.RemoteRepository"
157                   "central" "default" "http://repo1.maven.org/maven2/"))
158         (artifact-string (format nil "~A:~A:~A"
159                                  group-id artifact-id version))
160         (artifact 
161          (jss:new "org.sonatype.aether.util.artifact.DefaultArtifact" artifact-string))
162         (artifact-request 
163          (java:jnew "org.sonatype.aether.resolution.ArtifactRequest")))
164    (#"setArtifact" artifact-request artifact)
165    (#"addRepository" artifact-request repository)
166    (#"resolveArtifact" system session artifact-request)))
167
168(defun resolve-dependencies (group-id artifact-id &optional (version "LATEST" versionp))
169  "Dynamically resolve Maven dependencies for item with GROUP-ID and ARTIFACT-ID at VERSION.
170
171All recursive dependencies will be visited before resolution is successful.
172
173If unspecified, the string \"LATEST\" will be used for the VERSION.
174
175Returns a string containing the necessary jvm classpath entries packed
176in Java CLASSPATH representation."
177  (unless *init* (init))
178  (unless versionp
179    (warn "Using LATEST for unspecified version."))
180  (let* ((system 
181          (repository-system))
182         (session 
183          (new-session system))
184         (artifact
185          (java:jnew (jss:find-java-class "aether.util.artifact.DefaultArtifact")
186                     (format nil "~A:~A:~A"
187                             group-id artifact-id version)))
188         (dependency 
189          (java:jnew (jss:find-java-class "aether.graph.Dependency")
190                     artifact "compile"))
191         (central
192          (java:jnew (jss:find-java-class "RemoteRepository")
193                     "central" "default" "http://repo1.maven.org/maven2/"))
194         (collect-request (java:jnew (jss:find-java-class "CollectRequest"))))
195    (#"setRoot" collect-request dependency)
196    (#"addRepository" collect-request central)
197    (let* ((node 
198            (#"getRoot" (#"collectDependencies" system session collect-request)))
199           (dependency-request 
200            (java:jnew (jss:find-java-class "DependencyRequest")
201                       node java:+null+))
202           (nlg 
203            (java:jnew (jss:find-java-class "PreorderNodeListGenerator"))))
204      (#"resolveDependencies" system session dependency-request)
205      (#"accept" node nlg)
206      (#"getClassPath" nlg))))
207
208
209
210
211         
212
Note: See TracBrowser for help on using the repository browser.