]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/ImportMavenDependencies.java
Introduce Migration 1.3
[gpl/argeo-slc.git] / runtime / org.argeo.slc.repo / src / main / java / org / argeo / slc / repo / 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;
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.remove();
91 }
92 session.save();
93 syncDistribution(session, artifacts);
94 } catch (Exception e) {
95 throw new SlcException("Cannot import distribution", e);
96 } finally {
97 JcrUtils.logoutQuietly(session);
98 }
99 }
100
101 /**
102 * Generate a POM with all the artifacts declared in root coordinates as
103 * dependencies AND in dependency management.
104 */
105 void createDistPom() {
106 try {
107 Artifact pomArtifact = new DefaultArtifact(rootCoordinates);
108
109 Set<Artifact> registeredArtifacts = new TreeSet<Artifact>(
110 artifactComparator);
111 MavenConventionsUtils.gatherPomDependencies(aetherTemplate,
112 registeredArtifacts, pomArtifact);
113 Artifact sdkArtifact = new DefaultArtifact(distCoordinates);
114 String sdkPom = MavenConventionsUtils.artifactsAsDependencyPom(
115 sdkArtifact, registeredArtifacts);
116 if (log.isDebugEnabled())
117 log.debug("Gathered " + registeredArtifacts.size()
118 + " artifacts:\n" + sdkPom);
119 } catch (Exception e) {
120 throw new SlcException("Cannot resolve distribution", e);
121 }
122 }
123
124 /** Returns all transitive dependencies of dist POM */
125 private Set<Artifact> resolveDistribution() {
126 try {
127 Artifact distArtifact = new DefaultArtifact(distCoordinates);
128 Set<Artifact> artifacts = new TreeSet<Artifact>(artifactComparator);
129
130 DependencyNode node = aetherTemplate
131 .resolveDependencies(distArtifact);
132 addDependencies(artifacts, node, null);
133
134 if (log.isDebugEnabled()) {
135 log.debug("Resolved " + artifacts.size() + " artifacts");
136
137 // Properties distributionDescriptor = generateDistributionDescriptor(artifacts);
138 // ByteArrayOutputStream out = new ByteArrayOutputStream();
139 // distributionDescriptor.store(out, "");
140 // log.debug(new String(out.toByteArray()));
141 // out.close();
142 }
143
144 /*
145 * for (Artifact artifact : registeredArtifacts) { try { Boolean
146 * wasAdded = addArtifact(artifacts, artifact); if (wasAdded) {
147 * DependencyNode node = aetherTemplate
148 * .resolveDependencies(artifact); addDependencies(artifacts, node,
149 * null); } } catch (Exception e) {
150 * log.error("Could not resolve dependencies of " + artifact + ": "
151 * + e.getCause().getMessage()); }
152 *
153 * }
154 *
155 * if (log.isDebugEnabled()) log.debug("Resolved " +
156 * artifacts.size() + " artifacts");
157 *
158 * // distribution descriptor // Properties distributionDescriptor =
159 * // generateDistributionDescriptor(artifacts); //
160 * ByteArrayOutputStream out = new ByteArrayOutputStream(); //
161 * distributionDescriptor.store(out, ""); // log.debug(new
162 * String(out.toByteArray())); // out.close();
163 */
164 return artifacts;
165 } catch (Exception e) {
166 throw new SlcException("Cannot resolve distribution", e);
167 }
168 }
169
170 protected Properties generateDistributionDescriptor(Set<Artifact> artifacts) {
171 Properties distributionDescriptor = new Properties();
172 for (Artifact artifact : artifacts) {
173 log.debug(artifact.getArtifactId() + " [" + artifact.getVersion()
174 + "]\t(" + artifact + ")");
175 distributionDescriptor.setProperty(artifact.getArtifactId() + ":"
176 + artifact.getVersion(), artifact.toString());
177 }
178 return distributionDescriptor;
179 }
180
181 private void syncDistribution(Session jcrSession, Set<Artifact> artifacts) {
182 Set<Artifact> artifactsWithoutSources = new TreeSet<Artifact>(
183 artifactComparator);
184 Long begin = System.currentTimeMillis();
185 try {
186 JcrUtils.mkdirs(jcrSession, artifactBasePath);
187 artifacts: for (Artifact artifact : artifacts) {
188 File jarFile = MavenConventionsUtils.artifactToFile(artifact);
189 if (!jarFile.exists()) {
190 log.warn("Generated file " + jarFile + " for " + artifact
191 + " does not exist");
192 continue artifacts;
193 }
194 artifact.setFile(jarFile);
195
196 try {
197 String parentPath = MavenConventionsUtils
198 .artifactParentPath(artifactBasePath, artifact);
199 Node parentNode;
200 if (!jcrSession.itemExists(parentPath))
201 parentNode = JcrUtils.mkdirs(jcrSession, parentPath,
202 NodeType.NT_FOLDER);
203 else
204 parentNode = jcrSession.getNode(parentPath);
205
206 Node fileNode;
207 if (!parentNode.hasNode(jarFile.getName())) {
208 fileNode = createFileNode(parentNode, jarFile);
209 } else {
210 fileNode = parentNode.getNode(jarFile.getName());
211 }
212
213 if (artifactIndexer.support(fileNode.getPath()))
214 artifactIndexer.index(fileNode);
215 if (jarFileIndexer.support(fileNode.getPath()))
216 jarFileIndexer.index(fileNode);
217 jcrSession.save();
218
219 addPdeSource(jcrSession, artifact, jarFile, artifactsWithoutSources);
220 jcrSession.save();
221
222 if (log.isDebugEnabled())
223 log.debug("Synchronized " + fileNode);
224 } catch (Exception e) {
225 log.error("Could not synchronize " + artifact, e);
226 jcrSession.refresh(false);
227 throw e;
228 }
229 }
230
231 Long duration = (System.currentTimeMillis() - begin) / 1000;
232 if (log.isDebugEnabled()) {
233 log.debug("Synchronized distribution in " + duration + "s");
234 log.debug("The following artifacts have no sources:");
235 for (Artifact artifact : artifactsWithoutSources) {
236 log.debug(artifact);
237 }
238 }
239 } catch (Exception e) {
240 throw new SlcException("Cannot synchronize distribution", e);
241 }
242 }
243
244 /** Try to add PDE sources */
245 private void addPdeSource(Session session, Artifact artifact,
246 File artifactFile, Set<Artifact> artifactsWithoutSources) {
247 ByteArrayOutputStream out = new ByteArrayOutputStream();
248 try {
249 File origSourceFile = null;
250 Artifact origSourceArtifact = new DefaultArtifact(
251 artifact.getGroupId(), artifact.getArtifactId(), "sources",
252 artifact.getExtension(), artifact.getVersion());
253 Artifact targetSourceArtifact = new DefaultArtifact(
254 artifact.getGroupId(),
255 artifact.getArtifactId() + ".source",
256 artifact.getExtension(), artifact.getVersion());
257 try {
258 origSourceFile = aetherTemplate
259 .getResolvedFile(origSourceArtifact);
260 } catch (Exception e) {
261 // also try artifact following the conventions
262 origSourceArtifact = targetSourceArtifact;
263 origSourceFile = aetherTemplate
264 .getResolvedFile(origSourceArtifact);
265 }
266
267 String parentPath = MavenConventionsUtils.artifactParentPath(
268 artifactBasePath, artifact);
269 Node parentNode = JcrUtils.mkdirs(session, parentPath,
270 NodeType.NT_FOLDER);
271 NameVersion bundleNameVersion = RepoUtils
272 .readNameVersion(artifactFile);
273 RepoUtils.packagesAsPdeSource(origSourceFile, bundleNameVersion,
274 out);
275 String targetSourceFileName = MavenConventionsUtils
276 .artifactFileName(targetSourceArtifact);
277 JcrUtils.copyBytesAsFile(parentNode, targetSourceFileName,
278 out.toByteArray());
279 } catch (Exception e) {
280 log.error("Cannot add PDE source for " + artifact + ": " + e);
281 artifactsWithoutSources.add(artifact);
282 } finally {
283 IOUtils.closeQuietly(out);
284 }
285 }
286
287 private Node createFileNode(Node parentNode, File file) {
288 return JcrUtils.copyFile(parentNode, file);
289 }
290
291 /** Recursively adds non optional dependencies */
292 private void addDependencies(Set<Artifact> artifacts, DependencyNode node,
293 String ancestors) {
294 // if (artifacts.contains(node.getDependency().getArtifact()))
295 // return;
296 String currentArtifactId = node.getDependency().getArtifact()
297 .getArtifactId();
298 if (log.isDebugEnabled()) {
299 log.debug("# Add dependency for " + currentArtifactId);
300 if (ancestors != null)
301 log.debug(ancestors);
302 }
303 for (DependencyNode child : node.getChildren()) {
304 if (!child.getDependency().isOptional()) {
305 if (willAdd(child.getDependency().getArtifact())) {
306 addArtifact(artifacts, child.getDependency().getArtifact());
307 addDependencies(artifacts, child, currentArtifactId + "\n"
308 + (ancestors != null ? ancestors : ""));
309 }
310 }
311 }
312 }
313
314 /** @return whether it was added */
315 private Boolean addArtifact(Set<Artifact> artifacts, Artifact artifact) {
316 Boolean willAdd = willAdd(artifact);
317 if (willAdd)
318 artifacts.add(artifact);
319 else
320 log.info("Skip " + artifact);
321 return willAdd;
322 }
323
324 private Boolean willAdd(Artifact artifact) {
325 Boolean willAdd = true;
326 if (excludedArtifacts.contains(artifact.getGroupId() + ":"
327 + artifact.getArtifactId()))
328 willAdd = false;
329 else if (excludedArtifacts.contains(artifact.getGroupId() + ":*"))
330 willAdd = false;
331 return willAdd;
332 }
333
334 public void setAetherTemplate(AetherTemplate aetherTemplate) {
335 this.aetherTemplate = aetherTemplate;
336 }
337
338 public void setExcludedArtifacts(Set<String> excludedArtifactIds) {
339 this.excludedArtifacts = excludedArtifactIds;
340 }
341
342 public void setRootCoordinates(String rootCoordinates) {
343 this.rootCoordinates = rootCoordinates;
344 }
345
346 public void setRepository(Repository repository) {
347 this.repository = repository;
348 }
349
350 public void setWorkspace(String workspace) {
351 this.workspace = workspace;
352 }
353
354 }