Merge tag 'v2.3.20' into testing
[gpl/argeo-jcr.git] / org.argeo.slc.repo / src / org / argeo / slc / repo / maven / AetherUtils.java
diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/AetherUtils.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/AetherUtils.java
new file mode 100644 (file)
index 0000000..e8b07c1
--- /dev/null
@@ -0,0 +1,161 @@
+package org.argeo.slc.repo.maven;
+
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.FilenameUtils;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.slc.SlcException;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.graph.DependencyNode;
+
+/** Utilities related to Aether */
+public class AetherUtils {
+       public final static String SNAPSHOT = "SNAPSHOT";
+       // hacked from aether
+       public static final Pattern SNAPSHOT_TIMESTAMP = Pattern
+                       .compile("^(.*-)?([0-9]{8}.[0-9]{6}-[0-9]+)$");
+
+       private final static CmsLog log = CmsLog.getLog(AetherUtils.class);
+
+       /** Logs a dependency node and its transitive dependencies as a tree. */
+       public static void logDependencyNode(int depth,
+                       DependencyNode dependencyNode) {
+               if (!log.isDebugEnabled())
+                       return;
+
+               StringBuffer prefix = new StringBuffer(depth * 2 + 2);
+               // prefix.append("|-");
+               for (int i = 0; i < depth * 2; i++) {
+                       prefix.append(' ');
+               }
+               Artifact artifact = dependencyNode.getDependency().getArtifact();
+               log.debug(prefix + "|-> " + artifact.getArtifactId() + " ["
+                               + artifact.getVersion() + "]"
+                               + (dependencyNode.getDependency().isOptional() ? " ?" : ""));
+               for (DependencyNode child : dependencyNode.getChildren()) {
+                       logDependencyNode(depth + 1, child);
+               }
+       }
+
+       /**
+        * Converts a path (relative to a repository root) to an {@link Artifact}.
+        * 
+        * @param path
+        *            the relative path
+        * @param type
+        *            the layout type, currently ignored because only the 'default'
+        *            Maven 2 layout is currently supported:
+        *            /my/group/id/artifactId/
+        *            version/artifactId-version[-classifier].extension
+        * @return the related artifact or null if the file is not an artifact
+        *         (Maven medata data XML files, check sums, etc.)
+        */
+       public static Artifact convertPathToArtifact(String path, String type) {
+               // TODO rewrite it with regexp (unit tests first!)
+
+               // normalize
+               if (path.startsWith("/"))
+                       path = path.substring(1);
+
+               // parse group id
+               String[] tokensSlash = path.split("/");
+               if (tokensSlash.length < 4)
+                       return null;
+               StringBuffer groupId = new StringBuffer(path.length());
+               for (int i = 0; i < tokensSlash.length - 3; i++) {
+                       if (i != 0)
+                               groupId.append('.');
+                       groupId.append(tokensSlash[i]);
+               }
+               String artifactId = tokensSlash[tokensSlash.length - 3];
+               String baseVersion = tokensSlash[tokensSlash.length - 2];
+               String fileName = tokensSlash[tokensSlash.length - 1];
+
+               if (!fileName.startsWith(artifactId))
+                       return null;
+               // FIXME make it configurable? (via an argument?)
+               if (FilenameUtils.isExtension(fileName, new String[] { "sha1", "md5" }))
+                       return null;
+
+               String extension = FilenameUtils.getExtension(fileName);
+               String baseName = FilenameUtils.getBaseName(fileName);
+
+               // check since we assume hereafter
+               if (!baseName.startsWith(artifactId))
+                       throw new SlcException("Base name '" + baseName
+                                       + " does not start with artifact id '" + artifactId
+                                       + "' in " + path);
+
+               boolean isSnapshot = baseVersion.endsWith("-" + SNAPSHOT);
+               String baseBaseVersion = isSnapshot ? baseVersion.substring(0,
+                               baseVersion.length() - SNAPSHOT.length() - 1) : baseVersion;
+               int artifactAndBaseBaseVersionLength = artifactId.length() + 1
+                               + baseBaseVersion.length() + 1;
+               String classifier = null;
+               if (baseName.length() > artifactAndBaseBaseVersionLength) {
+                       String dashRest = baseName
+                                       .substring(artifactAndBaseBaseVersionLength);
+                       String[] dashes = dashRest.split("-");
+
+                       if (isSnapshot) {
+                               if (dashes[0].equals(SNAPSHOT)) {
+                                       if (dashRest.length() > SNAPSHOT.length() + 1)
+                                               classifier = dashRest.substring(SNAPSHOT.length() + 1);
+
+                               } else {
+                                       if (dashes.length > 2)// assume no '-' in classifier
+                                               classifier = dashes[2];
+                               }
+                       } else {
+                               if (dashes.length > 0)
+                                       classifier = dashes[0];
+                       }
+               }
+
+               // classifier
+               // String classifier = null;
+               // int firstDash = baseName.indexOf('-');
+               // int classifierDash = baseName.lastIndexOf('-');
+               // if (classifierDash > 0 && classifierDash != firstDash) {
+               // classifier = baseName.substring(classifierDash + 1);
+               // }
+               // if (isSnapshot && classifier != null) {
+               // if (classifier.equals(SNAPSHOT))
+               // classifier = null;
+               // else
+               // try {
+               // Long.parseLong(classifier); // build number
+               // // if not failed this is a timestamped version
+               // classifier = null;
+               // } catch (NumberFormatException e) {
+               // // silent
+               // }
+               // }
+
+               // version
+               String version = baseName.substring(artifactId.length() + 1);
+               if (classifier != null)
+                       version = version.substring(0,
+                                       version.length() - classifier.length() - 1);
+
+               // consistency checks
+               if (!isSnapshot && !version.equals(baseVersion))
+                       throw new SlcException("Base version '" + baseVersion
+                                       + "' and version '" + version + "' not in line in " + path);
+               if (!isSnapshot && isSnapshotVersion(version))
+                       throw new SlcException("SNAPSHOT base version '" + baseVersion
+                                       + "' and version '" + version + "' not in line in " + path);
+
+               DefaultArtifact artifact = new DefaultArtifact(groupId.toString(),
+                               artifactId, classifier, extension, version);
+               return artifact;
+       }
+
+       /** Hacked from aether */
+       public static boolean isSnapshotVersion(String version) {
+               return version.endsWith(SNAPSHOT)
+                               || SNAPSHOT_TIMESTAMP.matcher(version).matches();
+       }
+
+}