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(); } }