]> git.argeo.org Git - gpl/argeo-slc.git/blob - maven/ImportMavenDependencies.java
Prepare next development cycle
[gpl/argeo-slc.git] / maven / ImportMavenDependencies.java
1 /*
2 * Copyright (C) 2007-2012 Mathieu Baudier
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.argeo.slc.repo.maven;
17
18 import java.io.ByteArrayOutputStream;
19 import java.io.File;
20 import java.util.Comparator;
21 import java.util.HashSet;
22 import java.util.Properties;
23 import java.util.Set;
24 import java.util.TreeSet;
25
26 import javax.jcr.Node;
27 import javax.jcr.NodeIterator;
28 import javax.jcr.Repository;
29 import javax.jcr.Session;
30 import javax.jcr.nodetype.NodeType;
31
32 import org.apache.commons.io.IOUtils;
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.argeo.jcr.JcrUtils;
36 import org.argeo.slc.NameVersion;
37 import org.argeo.slc.SlcException;
38 import org.argeo.slc.aether.AetherTemplate;
39 import org.argeo.slc.repo.ArtifactIndexer;
40 import org.argeo.slc.repo.JarFileIndexer;
41 import org.argeo.slc.repo.RepoConstants;
42 import org.argeo.slc.repo.RepoUtils;
43 import org.sonatype.aether.artifact.Artifact;
44 import org.sonatype.aether.graph.DependencyNode;
45 import org.sonatype.aether.util.artifact.DefaultArtifact;
46
47 /**
48 * Import all the dependencies listed in a POM and their dependency graphs to a
49 * workspace.
50 */
51 public class ImportMavenDependencies implements Runnable {
52 private final static Log log = LogFactory
53 .getLog(ImportMavenDependencies.class);
54
55 private AetherTemplate aetherTemplate;
56 private String rootCoordinates = "org.argeo.dep:versions-all:pom:1.2.0";
57 private String distCoordinates = "org.argeo.tp:dist:pom:1.3.0";
58 private Set<String> excludedArtifacts = new HashSet<String>();
59
60 private Repository repository;
61 private String workspace;
62
63 private String artifactBasePath = RepoConstants.ARTIFACTS_BASE_PATH;
64
65 private ArtifactIndexer artifactIndexer = new ArtifactIndexer();
66 private JarFileIndexer jarFileIndexer = new JarFileIndexer();
67 private Comparator<Artifact> artifactComparator = new Comparator<Artifact>() {
68 public int compare(Artifact o1, Artifact o2) {
69 return o1.getArtifactId().compareTo(o2.getArtifactId());
70 }
71 };
72
73 public void run() {
74 // resolve
75 Set<Artifact> artifacts = resolveDistribution();
76
77 // sync
78 sync(artifacts);
79 }
80
81 void sync(Set<Artifact> artifacts) {
82 Session session = null;
83 try {
84 session = JcrUtils.loginOrCreateWorkspace(repository, workspace);
85 // clear
86 NodeIterator nit = session.getNode(artifactBasePath).getNodes();
87 while (nit.hasNext()) {
88 Node node = nit.nextNode();
89 if (node.isNodeType(NodeType.NT_FOLDER)
90 || node.isNodeType(NodeType.NT_UNSTRUCTURED))
91 node.remove();
92 }
93 session.save();
94
95 // sync
96 syncDistribution(session, artifacts);
97 } catch (Exception e) {
98 throw new SlcException("Cannot import distribution", e);
99 } finally {
100 JcrUtils.logoutQuietly(session);
101 }
102 }
103
104 /**
105 * Generate a POM with all the artifacts declared in root coordinates as
106 * dependencies AND in dependency management.
107 */
108 void createDistPom() {
109 try {
110 Artifact pomArtifact = new DefaultArtifact(rootCoordinates);
111
112 Set<Artifact> registeredArtifacts = new TreeSet<Artifact>(
113 artifactComparator);
114 MavenConventionsUtils.gatherPomDependencies(aetherTemplate,
115 registeredArtifacts, pomArtifact);
116 Artifact sdkArtifact = new DefaultArtifact(distCoordinates);
117 String sdkPom = MavenConventionsUtils.artifactsAsDependencyPom(
118 sdkArtifact, registeredArtifacts);
119 if (log.isDebugEnabled())
120 log.debug("Gathered " + registeredArtifacts.size()
121 + " artifacts:\n" + sdkPom);
122 } catch (Exception e) {
123 throw new SlcException("Cannot resolve distribution", e);
124 }
125 }
126
127 /** Returns all transitive dependencies of dist POM */
128 private Set<Artifact> resolveDistribution() {
129 try {
130 Artifact distArtifact = new DefaultArtifact(distCoordinates);
131 Set<Artifact> artifacts = new TreeSet<Artifact>(artifactComparator);
132
133 DependencyNode node = aetherTemplate
134 .resolveDependencies(distArtifact);
135 addDependencies(artifacts, node, null);
136
137 if (log.isDebugEnabled()) {
138 log.debug("Resolved " + artifacts.size() + " artifacts");
139
140 // Properties distributionDescriptor =
141 // generateDistributionDescriptor(artifacts);
142 // ByteArrayOutputStream out = new ByteArrayOutputStream();
143 // distributionDescriptor.store(out, "");
144 // log.debug(new String(out.toByteArray()));
145 // out.close();
146 }
147
148 /*
149 * for (Artifact artifact : registeredArtifacts) { try { Boolean
150 * wasAdded = addArtifact(artifacts, artifact); if (wasAdded) {
151 * DependencyNode node = aetherTemplate
152 * .resolveDependencies(artifact); addDependencies(artifacts, node,
153 * null); } } catch (Exception e) {
154 * log.error("Could not resolve dependencies of " + artifact + ": "
155 * + e.getCause().getMessage()); }
156 *
157 * }
158 *
159 * if (log.isDebugEnabled()) log.debug("Resolved " +
160 * artifacts.size() + " artifacts");
161 *
162 * // distribution descriptor // Properties distributionDescriptor =
163 * // generateDistributionDescriptor(artifacts); //
164 * ByteArrayOutputStream out = new ByteArrayOutputStream(); //
165 * distributionDescriptor.store(out, ""); // log.debug(new
166 * String(out.toByteArray())); // out.close();
167 */
168 return artifacts;
169 } catch (Exception e) {
170 throw new SlcException("Cannot resolve distribution", e);
171 }
172 }
173
174 protected Properties generateDistributionDescriptor(Set<Artifact> artifacts) {
175 Properties distributionDescriptor = new Properties();
176 for (Artifact artifact : artifacts) {
177 log.debug(artifact.getArtifactId() + " [" + artifact.getVersion()
178 + "]\t(" + artifact + ")");
179 distributionDescriptor.setProperty(artifact.getArtifactId() + ":"
180 + artifact.getVersion(), artifact.toString());
181 }
182 return distributionDescriptor;
183 }
184
185 /** Write artifacts to the target workspace, skipping excluded ones */
186 protected void syncDistribution(Session jcrSession, Set<Artifact> artifacts) {
187 Set<Artifact> artifactsWithoutSources = new TreeSet<Artifact>(
188 artifactComparator);
189 Long begin = System.currentTimeMillis();
190 try {
191 JcrUtils.mkfolders(jcrSession, artifactBasePath);
192 artifacts: for (Artifact artifact : artifacts) {
193 // skip excluded
194 if (excludedArtifacts.contains(artifact.getGroupId() + ":"
195 + artifact.getArtifactId())) {
196 if (log.isDebugEnabled())
197 log.debug("Exclude " + artifact);
198 continue artifacts;
199 }
200
201 File jarFile = MavenConventionsUtils.artifactToFile(artifact);
202 if (!jarFile.exists()) {
203 log.warn("Generated file " + jarFile + " for " + artifact
204 + " does not exist");
205 continue artifacts;
206 }
207 artifact.setFile(jarFile);
208
209 try {
210 String parentPath = MavenConventionsUtils
211 .artifactParentPath(artifactBasePath, artifact);
212 Node parentNode;
213 if (!jcrSession.itemExists(parentPath))
214 parentNode = JcrUtils.mkfolders(jcrSession, parentPath);
215 else
216 parentNode = jcrSession.getNode(parentPath);
217
218 Node fileNode;
219 if (!parentNode.hasNode(jarFile.getName())) {
220 fileNode = createFileNode(parentNode, jarFile);
221 } else {
222 fileNode = parentNode.getNode(jarFile.getName());
223 }
224
225 if (artifactIndexer.support(fileNode.getPath()))
226 artifactIndexer.index(fileNode);
227 if (jarFileIndexer.support(fileNode.getPath()))
228 jarFileIndexer.index(fileNode);
229 jcrSession.save();
230
231 addPdeSource(jcrSession, artifact, jarFile,
232 artifactsWithoutSources);
233 jcrSession.save();
234
235 if (log.isDebugEnabled())
236 log.debug("Synchronized " + fileNode);
237 } catch (Exception e) {
238 log.error("Could not synchronize " + artifact, e);
239 jcrSession.refresh(false);
240 throw e;
241 }
242 }
243
244 Long duration = (System.currentTimeMillis() - begin) / 1000;
245 if (log.isDebugEnabled()) {
246 log.debug("Synchronized distribution in " + duration + "s");
247 log.debug("The following artifacts have no sources:");
248 for (Artifact artifact : artifactsWithoutSources) {
249 log.debug(artifact);
250 }
251 }
252 } catch (Exception e) {
253 throw new SlcException("Cannot synchronize distribution", e);
254 }
255 }
256
257 /** Try to add PDE sources */
258 private void addPdeSource(Session session, Artifact artifact,
259 File artifactFile, Set<Artifact> artifactsWithoutSources) {
260 ByteArrayOutputStream out = new ByteArrayOutputStream();
261 try {
262 File origSourceFile = null;
263 Artifact origSourceArtifact = new DefaultArtifact(
264 artifact.getGroupId(), artifact.getArtifactId(), "sources",
265 artifact.getExtension(), artifact.getVersion());
266 Artifact newSourceArtifact = new DefaultArtifact(
267 artifact.getGroupId(),
268 artifact.getArtifactId() + ".source",
269 artifact.getExtension(), artifact.getVersion());
270 try {
271 origSourceFile = aetherTemplate
272 .getResolvedFile(origSourceArtifact);
273 } catch (Exception e) {
274 // also try artifact following the conventions
275 origSourceArtifact = newSourceArtifact;
276 origSourceFile = aetherTemplate
277 .getResolvedFile(origSourceArtifact);
278 }
279
280 String newSourceParentPath = MavenConventionsUtils
281 .artifactParentPath(artifactBasePath, newSourceArtifact);
282 Node newSourceParentNode = JcrUtils.mkfolders(session,
283 newSourceParentPath);
284 NameVersion bundleNameVersion = RepoUtils
285 .readNameVersion(artifactFile);
286 RepoUtils.packagesAsPdeSource(origSourceFile, bundleNameVersion,
287 out);
288 String newSourceFileName = MavenConventionsUtils
289 .artifactFileName(newSourceArtifact);
290 JcrUtils.copyBytesAsFile(newSourceParentNode, newSourceFileName,
291 out.toByteArray());
292 } catch (Exception e) {
293 log.error("Cannot add PDE source for " + artifact + ": " + e);
294 artifactsWithoutSources.add(artifact);
295 } finally {
296 IOUtils.closeQuietly(out);
297 }
298 }
299
300 private Node createFileNode(Node parentNode, File file) {
301 return JcrUtils.copyFile(parentNode, file);
302 }
303
304 /** Recursively adds non optional dependencies */
305 private void addDependencies(Set<Artifact> artifacts, DependencyNode node,
306 String ancestors) {
307 // if (artifacts.contains(node.getDependency().getArtifact()))
308 // return;
309 String currentArtifactId = node.getDependency().getArtifact()
310 .getArtifactId();
311 if (log.isDebugEnabled()) {
312 log.debug("# Add dependency for " + currentArtifactId);
313 if (ancestors != null)
314 log.debug(ancestors);
315 }
316 for (DependencyNode child : node.getChildren()) {
317 if (!child.getDependency().isOptional()) {
318 if (willAdd(child.getDependency().getArtifact())) {
319 addArtifact(artifacts, child.getDependency().getArtifact());
320 addDependencies(artifacts, child, currentArtifactId + "\n"
321 + (ancestors != null ? ancestors : ""));
322 }
323 }
324 }
325 }
326
327 /** @return whether it was added */
328 private Boolean addArtifact(Set<Artifact> artifacts, Artifact artifact) {
329 Boolean willAdd = willAdd(artifact);
330 if (willAdd)
331 artifacts.add(artifact);
332 else
333 log.info("Skip " + artifact);
334 return willAdd;
335 }
336
337 private Boolean willAdd(Artifact artifact) {
338 Boolean willAdd = true;
339 if (excludedArtifacts.contains(artifact.getGroupId() + ":"
340 + artifact.getArtifactId()))
341 willAdd = false;
342 else if (excludedArtifacts.contains(artifact.getGroupId() + ":*"))
343 willAdd = false;
344 return willAdd;
345 }
346
347 public void setAetherTemplate(AetherTemplate aetherTemplate) {
348 this.aetherTemplate = aetherTemplate;
349 }
350
351 public void setExcludedArtifacts(Set<String> excludedArtifactIds) {
352 this.excludedArtifacts = excludedArtifactIds;
353 }
354
355 public void setRootCoordinates(String rootCoordinates) {
356 this.rootCoordinates = rootCoordinates;
357 }
358
359 public void setRepository(Repository repository) {
360 this.repository = repository;
361 }
362
363 public void setWorkspace(String workspace) {
364 this.workspace = workspace;
365 }
366
367 public void setDistCoordinates(String distCoordinates) {
368 this.distCoordinates = distCoordinates;
369 }
370
371 public void setArtifactBasePath(String artifactBasePath) {
372 this.artifactBasePath = artifactBasePath;
373 }
374
375 }