View Javadoc
1   /*
2    * Copyright (C) 2007-2012 Argeo GmbH
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.util.regex.Pattern;
19  
20  import org.apache.commons.io.FilenameUtils;
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.argeo.slc.SlcException;
24  import org.eclipse.aether.artifact.Artifact;
25  import org.eclipse.aether.artifact.DefaultArtifact;
26  import org.eclipse.aether.graph.DependencyNode;
27  
28  /** Utilities related to Aether */
29  public class AetherUtils {
30  	public final static String SNAPSHOT = "SNAPSHOT";
31  	// hacked from aether
32  	public static final Pattern SNAPSHOT_TIMESTAMP = Pattern
33  			.compile("^(.*-)?([0-9]{8}.[0-9]{6}-[0-9]+)$");
34  
35  	private final static Log log = LogFactory.getLog(AetherUtils.class);
36  
37  	/** Logs a dependency node and its transitive dependencies as a tree. */
38  	public static void logDependencyNode(int depth,
39  			DependencyNode dependencyNode) {
40  		if (!log.isDebugEnabled())
41  			return;
42  
43  		StringBuffer prefix = new StringBuffer(depth * 2 + 2);
44  		// prefix.append("|-");
45  		for (int i = 0; i < depth * 2; i++) {
46  			prefix.append(' ');
47  		}
48  		Artifact artifact = dependencyNode.getDependency().getArtifact();
49  		log.debug(prefix + "|-> " + artifact.getArtifactId() + " ["
50  				+ artifact.getVersion() + "]"
51  				+ (dependencyNode.getDependency().isOptional() ? " ?" : ""));
52  		for (DependencyNode child : dependencyNode.getChildren()) {
53  			logDependencyNode(depth + 1, child);
54  		}
55  	}
56  
57  	/**
58  	 * Converts a path (relative to a repository root) to an {@link Artifact}.
59  	 * 
60  	 * @param path
61  	 *            the relative path
62  	 * @param type
63  	 *            the layout type, currently ignored because only the 'default'
64  	 *            Maven 2 layout is currently supported:
65  	 *            /my/group/id/artifactId/
66  	 *            version/artifactId-version[-classifier].extension
67  	 * @return the related artifact or null if the file is not an artifact
68  	 *         (Maven medata data XML files, check sums, etc.)
69  	 */
70  	public static Artifact convertPathToArtifact(String path, String type) {
71  		// TODO rewrite it with regexp (unit tests first!)
72  
73  		// normalize
74  		if (path.startsWith("/"))
75  			path = path.substring(1);
76  
77  		// parse group id
78  		String[] tokensSlash = path.split("/");
79  		if (tokensSlash.length < 4)
80  			return null;
81  		StringBuffer groupId = new StringBuffer(path.length());
82  		for (int i = 0; i < tokensSlash.length - 3; i++) {
83  			if (i != 0)
84  				groupId.append('.');
85  			groupId.append(tokensSlash[i]);
86  		}
87  		String artifactId = tokensSlash[tokensSlash.length - 3];
88  		String baseVersion = tokensSlash[tokensSlash.length - 2];
89  		String fileName = tokensSlash[tokensSlash.length - 1];
90  
91  		if (!fileName.startsWith(artifactId))
92  			return null;
93  		// FIXME make it configurable? (via an argument?)
94  		if (FilenameUtils.isExtension(fileName, new String[] { "sha1", "md5" }))
95  			return null;
96  
97  		String extension = FilenameUtils.getExtension(fileName);
98  		String baseName = FilenameUtils.getBaseName(fileName);
99  
100 		// check since we assume hereafter
101 		if (!baseName.startsWith(artifactId))
102 			throw new SlcException("Base name '" + baseName
103 					+ " does not start with artifact id '" + artifactId
104 					+ "' in " + path);
105 
106 		boolean isSnapshot = baseVersion.endsWith("-" + SNAPSHOT);
107 		String baseBaseVersion = isSnapshot ? baseVersion.substring(0,
108 				baseVersion.length() - SNAPSHOT.length() - 1) : baseVersion;
109 		int artifactAndBaseBaseVersionLength = artifactId.length() + 1
110 				+ baseBaseVersion.length() + 1;
111 		String classifier = null;
112 		if (baseName.length() > artifactAndBaseBaseVersionLength) {
113 			String dashRest = baseName
114 					.substring(artifactAndBaseBaseVersionLength);
115 			String[] dashes = dashRest.split("-");
116 
117 			if (isSnapshot) {
118 				if (dashes[0].equals(SNAPSHOT)) {
119 					if (dashRest.length() > SNAPSHOT.length() + 1)
120 						classifier = dashRest.substring(SNAPSHOT.length() + 1);
121 
122 				} else {
123 					if (dashes.length > 2)// assume no '-' in classifier
124 						classifier = dashes[2];
125 				}
126 			} else {
127 				if (dashes.length > 0)
128 					classifier = dashes[0];
129 			}
130 		}
131 
132 		// classifier
133 		// String classifier = null;
134 		// int firstDash = baseName.indexOf('-');
135 		// int classifierDash = baseName.lastIndexOf('-');
136 		// if (classifierDash > 0 && classifierDash != firstDash) {
137 		// classifier = baseName.substring(classifierDash + 1);
138 		// }
139 		// if (isSnapshot && classifier != null) {
140 		// if (classifier.equals(SNAPSHOT))
141 		// classifier = null;
142 		// else
143 		// try {
144 		// Long.parseLong(classifier); // build number
145 		// // if not failed this is a timestamped version
146 		// classifier = null;
147 		// } catch (NumberFormatException e) {
148 		// // silent
149 		// }
150 		// }
151 
152 		// version
153 		String version = baseName.substring(artifactId.length() + 1);
154 		if (classifier != null)
155 			version = version.substring(0,
156 					version.length() - classifier.length() - 1);
157 
158 		// consistency checks
159 		if (!isSnapshot && !version.equals(baseVersion))
160 			throw new SlcException("Base version '" + baseVersion
161 					+ "' and version '" + version + "' not in line in " + path);
162 		if (!isSnapshot && isSnapshotVersion(version))
163 			throw new SlcException("SNAPSHOT base version '" + baseVersion
164 					+ "' and version '" + version + "' not in line in " + path);
165 
166 		DefaultArtifact artifact = new DefaultArtifact(groupId.toString(),
167 				artifactId, classifier, extension, version);
168 		return artifact;
169 	}
170 
171 	/** Hacked from aether */
172 	public static boolean isSnapshotVersion(String version) {
173 		return version.endsWith(SNAPSHOT)
174 				|| SNAPSHOT_TIMESTAMP.matcher(version).matches();
175 	}
176 
177 }