X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=runtime%2Forg.argeo.slc.repo%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fslc%2Frepo%2Fmaven%2FImportMavenDependencies.java;h=0bda72b7e87e91d272eaa86e0cf7d5b99f767345;hb=44c43b9c874d7c6edd4327f180d5506b3e9c99e6;hp=8aff3de08f21beba8d54e10cccd87097bde7c841;hpb=6a0f4cf1c0a1b49004b8c3dbc075f7202f7536f1;p=gpl%2Fargeo-slc.git diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/ImportMavenDependencies.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/ImportMavenDependencies.java index 8aff3de08..0bda72b7e 100644 --- a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/ImportMavenDependencies.java +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/ImportMavenDependencies.java @@ -1,190 +1,349 @@ +/* + * Copyright (C) 2007-2012 Mathieu Baudier + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.argeo.slc.repo.maven; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.StringReader; -import java.io.StringWriter; import java.util.Comparator; import java.util.HashSet; import java.util.Properties; import java.util.Set; import java.util.TreeSet; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Repository; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; +import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.NameVersion; import org.argeo.slc.SlcException; import org.argeo.slc.aether.AetherTemplate; -import org.argeo.slc.aether.AetherUtils; +import org.argeo.slc.repo.ArtifactIndexer; +import org.argeo.slc.repo.JarFileIndexer; +import org.argeo.slc.repo.RepoConstants; +import org.argeo.slc.repo.RepoUtils; import org.sonatype.aether.artifact.Artifact; import org.sonatype.aether.graph.DependencyNode; import org.sonatype.aether.util.artifact.DefaultArtifact; -import org.sonatype.aether.util.graph.PreorderNodeListGenerator; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; +/** + * Import all the dependencies listed in a POM and their dependency graphs to a + * workspace. + */ public class ImportMavenDependencies implements Runnable { private final static Log log = LogFactory .getLog(ImportMavenDependencies.class); private AetherTemplate aetherTemplate; - private String rootCoordinates; + private String rootCoordinates = "org.argeo.dep:versions-all:pom:1.2.0"; + private String distCoordinates = "org.argeo.tp:dist:pom:1.3.0"; private Set excludedArtifacts = new HashSet(); + private Repository repository; + private String workspace; + + private String artifactBasePath = RepoConstants.ARTIFACTS_BASE_PATH; + + private ArtifactIndexer artifactIndexer = new ArtifactIndexer(); + private JarFileIndexer jarFileIndexer = new JarFileIndexer(); + private Comparator artifactComparator = new Comparator() { + public int compare(Artifact o1, Artifact o2) { + return o1.getArtifactId().compareTo(o2.getArtifactId()); + } + }; + public void run() { + // resolve + Set artifacts = resolveDistribution(); + + // sync + sync(artifacts); + } + + void sync(Set artifacts) { + Session session = null; try { - Artifact pomArtifact = new DefaultArtifact(rootCoordinates); + session = JcrUtils.loginOrCreateWorkspace(repository, workspace); + // clear + NodeIterator nit = session.getNode(artifactBasePath).getNodes(); + while (nit.hasNext()) { + Node node = nit.nextNode(); + if (node.isNodeType(NodeType.NT_FOLDER) + || node.isNodeType(NodeType.NT_UNSTRUCTURED)) + node.remove(); + } + session.save(); + + // sync + syncDistribution(session, artifacts); + } catch (Exception e) { + throw new SlcException("Cannot import distribution", e); + } finally { + JcrUtils.logoutQuietly(session); + } + } - // { - // DependencyNode node = aetherTemplate - // .resolveDependencies(pomArtifact); - // - // PreorderNodeListGenerator nlg = new PreorderNodeListGenerator(); - // node.accept(nlg); - // - // for (Artifact artifact : nlg.getArtifacts(true)) { - // log.debug(artifact); - // } - // AetherUtils.logDependencyNode(0, node); - // } - - Comparator artifactComparator = new Comparator() { - public int compare(Artifact o1, Artifact o2) { - return o1.getArtifactId().compareTo(o2.getArtifactId()); - } - }; + /** + * Generate a POM with all the artifacts declared in root coordinates as + * dependencies AND in dependency management. + */ + void createDistPom() { + try { + Artifact pomArtifact = new DefaultArtifact(rootCoordinates); Set registeredArtifacts = new TreeSet( artifactComparator); - parsePom(aetherTemplate, registeredArtifacts, pomArtifact); + MavenConventionsUtils.gatherPomDependencies(aetherTemplate, + registeredArtifacts, pomArtifact); + Artifact sdkArtifact = new DefaultArtifact(distCoordinates); + String sdkPom = MavenConventionsUtils.artifactsAsDependencyPom( + sdkArtifact, registeredArtifacts); if (log.isDebugEnabled()) log.debug("Gathered " + registeredArtifacts.size() - + " artifacts"); + + " artifacts:\n" + sdkPom); + } catch (Exception e) { + throw new SlcException("Cannot resolve distribution", e); + } + } - // Resolve and add non-optional dependencies + /** Returns all transitive dependencies of dist POM */ + private Set resolveDistribution() { + try { + Artifact distArtifact = new DefaultArtifact(distCoordinates); Set artifacts = new TreeSet(artifactComparator); - for (Artifact artifact : registeredArtifacts) { - try { - addArtifact(artifacts, artifact); - DependencyNode node = aetherTemplate - .resolveDependencies(artifact); - addDependencies(artifacts, node); - } catch (Exception e) { - log.error("Could not resolve dependencies of " + artifact - + ": " + e.getCause().getMessage()); - } - } + DependencyNode node = aetherTemplate + .resolveDependencies(distArtifact); + addDependencies(artifacts, node, null); - if (log.isDebugEnabled()) + if (log.isDebugEnabled()) { log.debug("Resolved " + artifacts.size() + " artifacts"); - Properties distributionDescriptor = new Properties(); - for (Artifact artifact : artifacts) { - log.debug(artifact.getArtifactId() + " [" - + artifact.getVersion() + "]\t(" + artifact + ")"); - distributionDescriptor.setProperty(artifact.getArtifactId() - + ":" + artifact.getVersion(), artifact.toString()); + + // Properties distributionDescriptor = + // generateDistributionDescriptor(artifacts); + // ByteArrayOutputStream out = new ByteArrayOutputStream(); + // distributionDescriptor.store(out, ""); + // log.debug(new String(out.toByteArray())); + // out.close(); } - ByteArrayOutputStream out = new ByteArrayOutputStream(); - distributionDescriptor.store(out, ""); - log.debug(new String(out.toByteArray())); - out.close(); + /* + * for (Artifact artifact : registeredArtifacts) { try { Boolean + * wasAdded = addArtifact(artifacts, artifact); if (wasAdded) { + * DependencyNode node = aetherTemplate + * .resolveDependencies(artifact); addDependencies(artifacts, node, + * null); } } catch (Exception e) { + * log.error("Could not resolve dependencies of " + artifact + ": " + * + e.getCause().getMessage()); } + * + * } + * + * if (log.isDebugEnabled()) log.debug("Resolved " + + * artifacts.size() + " artifacts"); + * + * // distribution descriptor // Properties distributionDescriptor = + * // generateDistributionDescriptor(artifacts); // + * ByteArrayOutputStream out = new ByteArrayOutputStream(); // + * distributionDescriptor.store(out, ""); // log.debug(new + * String(out.toByteArray())); // out.close(); + */ + return artifacts; } catch (Exception e) { - throw new SlcException("Cannot resolve", e); + throw new SlcException("Cannot resolve distribution", e); } } - /** Recursively adds non optional dependencies */ - private void addDependencies(Set artifacts, DependencyNode node) { - for (DependencyNode child : node.getChildren()) { - if (!child.getDependency().isOptional()) { - addArtifact(artifacts, child.getDependency().getArtifact()); - addDependencies(artifacts, child); - } + protected Properties generateDistributionDescriptor(Set artifacts) { + Properties distributionDescriptor = new Properties(); + for (Artifact artifact : artifacts) { + log.debug(artifact.getArtifactId() + " [" + artifact.getVersion() + + "]\t(" + artifact + ")"); + distributionDescriptor.setProperty(artifact.getArtifactId() + ":" + + artifact.getVersion(), artifact.toString()); } + return distributionDescriptor; } - private void addArtifact(Set artifacts, Artifact artifact) { - if (!excludedArtifacts.contains(artifact.getGroupId() + ":" - + artifact.getArtifactId())) - artifacts.add(artifact); - } + /** Write artifacts to the target workspace, skipping excluded ones */ + protected void syncDistribution(Session jcrSession, Set artifacts) { + Set artifactsWithoutSources = new TreeSet( + artifactComparator); + Long begin = System.currentTimeMillis(); + try { + JcrUtils.mkfolders(jcrSession, artifactBasePath); + artifacts: for (Artifact artifact : artifacts) { + // skip excluded + if (excludedArtifacts.contains(artifact.getGroupId() + ":" + + artifact.getArtifactId())) { + if (log.isDebugEnabled()) + log.debug("Exclude " + artifact); + continue artifacts; + } - /** - * Directly parses Maven POM XML format in order to find all artifacts - * references under the dependency and dependencyManagement tags. This is - * meant to migrate existing pom registering a lot of artifacts, not to - * replace Maven resolving. - */ - protected void parsePom(AetherTemplate aetherTemplate, - Set artifacts, Artifact pomArtifact) { - if (log.isDebugEnabled()) - log.debug("Gather dependencies for " + pomArtifact); + File jarFile = MavenConventionsUtils.artifactToFile(artifact); + if (!jarFile.exists()) { + log.warn("Generated file " + jarFile + " for " + artifact + + " does not exist"); + continue artifacts; + } + artifact.setFile(jarFile); - try { - File file = aetherTemplate.getResolvedFile(pomArtifact); - DocumentBuilder documentBuilder = DocumentBuilderFactory - .newInstance().newDocumentBuilder(); - Document doc = documentBuilder.parse(file); - - // properties - Properties props = new Properties(); - props.setProperty("project.version", pomArtifact.getBaseVersion()); - NodeList properties = doc.getElementsByTagName("properties"); - if (properties.getLength() > 0) { - NodeList propertiesElems = properties.item(0).getChildNodes(); - for (int i = 0; i < propertiesElems.getLength(); i++) { - if (propertiesElems.item(i) instanceof Element) { - Element property = (Element) propertiesElems.item(i); - props.put(property.getNodeName(), - property.getTextContent()); + try { + String parentPath = MavenConventionsUtils + .artifactParentPath(artifactBasePath, artifact); + Node parentNode; + if (!jcrSession.itemExists(parentPath)) + parentNode = JcrUtils.mkfolders(jcrSession, parentPath); + else + parentNode = jcrSession.getNode(parentPath); + + Node fileNode; + if (!parentNode.hasNode(jarFile.getName())) { + fileNode = createFileNode(parentNode, jarFile); + } else { + fileNode = parentNode.getNode(jarFile.getName()); } + + if (artifactIndexer.support(fileNode.getPath())) + artifactIndexer.index(fileNode); + if (jarFileIndexer.support(fileNode.getPath())) + jarFileIndexer.index(fileNode); + jcrSession.save(); + + addPdeSource(jcrSession, artifact, jarFile, + artifactsWithoutSources); + jcrSession.save(); + + if (log.isDebugEnabled()) + log.debug("Synchronized " + fileNode); + } catch (Exception e) { + log.error("Could not synchronize " + artifact, e); + jcrSession.refresh(false); + throw e; } } - // dependencies (direct and dependencyManagement) - NodeList dependencies = doc.getElementsByTagName("dependency"); - for (int i = 0; i < dependencies.getLength(); i++) { - Element dependency = (Element) dependencies.item(i); - String groupId = dependency.getElementsByTagName("groupId") - .item(0).getTextContent().trim(); - String artifactId = dependency - .getElementsByTagName("artifactId").item(0) - .getTextContent().trim(); - String version = dependency.getElementsByTagName("version") - .item(0).getTextContent().trim(); - if (version.startsWith("${")) { - String versionKey = version.substring(0, - version.length() - 1).substring(2); - if (!props.containsKey(versionKey)) - throw new SlcException("Cannot interpret version " - + version); - version = props.getProperty(versionKey); - } - NodeList scopes = dependency.getElementsByTagName("scope"); - if (scopes.getLength() > 0 - && scopes.item(0).getTextContent().equals("import")) { - // recurse - parsePom(aetherTemplate, artifacts, new DefaultArtifact( - groupId, artifactId, "pom", version)); - } else { - // TODO: deal with scope? - // TODO: deal with type - String type = "jar"; - Artifact artifact = new DefaultArtifact(groupId, - artifactId, type, version); - artifacts.add(artifact); + Long duration = (System.currentTimeMillis() - begin) / 1000; + if (log.isDebugEnabled()) { + log.debug("Synchronized distribution in " + duration + "s"); + log.debug("The following artifacts have no sources:"); + for (Artifact artifact : artifactsWithoutSources) { + log.debug(artifact); } } } catch (Exception e) { - throw new SlcException("Cannot process " + pomArtifact, e); + throw new SlcException("Cannot synchronize distribution", e); + } + } + + /** Try to add PDE sources */ + private void addPdeSource(Session session, Artifact artifact, + File artifactFile, Set artifactsWithoutSources) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + File origSourceFile = null; + Artifact origSourceArtifact = new DefaultArtifact( + artifact.getGroupId(), artifact.getArtifactId(), "sources", + artifact.getExtension(), artifact.getVersion()); + Artifact newSourceArtifact = new DefaultArtifact( + artifact.getGroupId(), + artifact.getArtifactId() + ".source", + artifact.getExtension(), artifact.getVersion()); + try { + origSourceFile = aetherTemplate + .getResolvedFile(origSourceArtifact); + } catch (Exception e) { + // also try artifact following the conventions + origSourceArtifact = newSourceArtifact; + origSourceFile = aetherTemplate + .getResolvedFile(origSourceArtifact); + } + + String newSourceParentPath = MavenConventionsUtils + .artifactParentPath(artifactBasePath, newSourceArtifact); + Node newSourceParentNode = JcrUtils.mkfolders(session, + newSourceParentPath); + NameVersion bundleNameVersion = RepoUtils + .readNameVersion(artifactFile); + RepoUtils.packagesAsPdeSource(origSourceFile, bundleNameVersion, + out); + String newSourceFileName = MavenConventionsUtils + .artifactFileName(newSourceArtifact); + JcrUtils.copyBytesAsFile(newSourceParentNode, newSourceFileName, + out.toByteArray()); + } catch (Exception e) { + log.error("Cannot add PDE source for " + artifact + ": " + e); + artifactsWithoutSources.add(artifact); + } finally { + IOUtils.closeQuietly(out); } } + private Node createFileNode(Node parentNode, File file) { + return JcrUtils.copyFile(parentNode, file); + } + + /** Recursively adds non optional dependencies */ + private void addDependencies(Set artifacts, DependencyNode node, + String ancestors) { + // if (artifacts.contains(node.getDependency().getArtifact())) + // return; + String currentArtifactId = node.getDependency().getArtifact() + .getArtifactId(); + if (log.isDebugEnabled()) { + log.debug("# Add dependency for " + currentArtifactId); + if (ancestors != null) + log.debug(ancestors); + } + for (DependencyNode child : node.getChildren()) { + if (!child.getDependency().isOptional()) { + if (willAdd(child.getDependency().getArtifact())) { + addArtifact(artifacts, child.getDependency().getArtifact()); + addDependencies(artifacts, child, currentArtifactId + "\n" + + (ancestors != null ? ancestors : "")); + } + } + } + } + + /** @return whether it was added */ + private Boolean addArtifact(Set artifacts, Artifact artifact) { + Boolean willAdd = willAdd(artifact); + if (willAdd) + artifacts.add(artifact); + else + log.info("Skip " + artifact); + return willAdd; + } + + private Boolean willAdd(Artifact artifact) { + Boolean willAdd = true; + if (excludedArtifacts.contains(artifact.getGroupId() + ":" + + artifact.getArtifactId())) + willAdd = false; + else if (excludedArtifacts.contains(artifact.getGroupId() + ":*")) + willAdd = false; + return willAdd; + } + public void setAetherTemplate(AetherTemplate aetherTemplate) { this.aetherTemplate = aetherTemplate; } @@ -197,4 +356,20 @@ public class ImportMavenDependencies implements Runnable { this.rootCoordinates = rootCoordinates; } + public void setRepository(Repository repository) { + this.repository = repository; + } + + public void setWorkspace(String workspace) { + this.workspace = workspace; + } + + public void setDistCoordinates(String distCoordinates) { + this.distCoordinates = distCoordinates; + } + + public void setArtifactBasePath(String artifactBasePath) { + this.artifactBasePath = artifactBasePath; + } + }