1 package org.apache.maven.repository.discovery;
4 * Copyright 2001-2005 The Apache Software Foundation.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 import org.apache.maven.artifact.Artifact;
20 import org.apache.maven.artifact.factory.ArtifactFactory;
21 import org.codehaus.plexus.util.StringUtils;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.Iterator;
27 import java.util.LinkedList;
28 import java.util.List;
29 import java.util.StringTokenizer;
32 * Artifact discoverer for the legacy repository layout (Maven 1.x).
35 * @author Brett Porter
37 public class LegacyArtifactDiscoverer
38 extends AbstractArtifactDiscoverer
40 private ArtifactFactory artifactFactory;
42 public List discoverArtifacts( File repositoryBase, String blacklistedPatterns, boolean includeSnapshots )
44 List artifacts = new ArrayList();
46 String[] artifactPaths = scanForArtifactPaths( repositoryBase, blacklistedPatterns );
48 for ( int i = 0; i < artifactPaths.length; i++ )
50 String path = artifactPaths[i];
52 Artifact artifact = buildArtifact( path );
53 if ( artifact != null )
55 if ( includeSnapshots || !artifact.isSnapshot() )
57 artifacts.add( artifact );
65 private Artifact buildArtifact( String path )
67 StringTokenizer tokens = new StringTokenizer( path, "/\\" );
69 int numberOfTokens = tokens.countTokens();
71 if ( numberOfTokens != 3 )
73 addKickedOutPath( path );
78 String groupId = tokens.nextToken();
80 String type = tokens.nextToken();
82 if ( type.endsWith( "s" ) )
84 type = type.substring( 0, type.length() - 1 );
87 // contains artifactId, version, classifier, and extension.
88 String avceGlob = tokens.nextToken();
90 LinkedList avceTokenList = new LinkedList();
92 StringTokenizer avceTokenizer = new StringTokenizer( avceGlob, "-" );
93 while ( avceTokenizer.hasMoreTokens() )
95 avceTokenList.addLast( avceTokenizer.nextToken() );
98 String lastAvceToken = (String) avceTokenList.removeLast();
100 if ( lastAvceToken.endsWith( ".tar.gz" ) )
102 type = "distribution-tgz";
104 lastAvceToken = lastAvceToken.substring( 0, lastAvceToken.length() - ".tar.gz".length() );
106 avceTokenList.addLast( lastAvceToken );
108 else if ( lastAvceToken.endsWith( "sources.jar" ) )
110 type = "java-source";
112 lastAvceToken = lastAvceToken.substring( 0, lastAvceToken.length() - ".jar".length() );
114 avceTokenList.addLast( lastAvceToken );
116 else if ( lastAvceToken.endsWith( ".zip" ) )
118 type = "distribution-zip";
120 lastAvceToken = lastAvceToken.substring( 0, lastAvceToken.length() - ".zip".length() );
122 avceTokenList.addLast( lastAvceToken );
126 int extPos = lastAvceToken.lastIndexOf( '.' );
130 String ext = lastAvceToken.substring( extPos + 1 );
131 if ( type.equals( ext ) )
133 lastAvceToken = lastAvceToken.substring( 0, extPos );
135 avceTokenList.addLast( lastAvceToken );
139 addKickedOutPath( path );
146 // TODO: this is obscene - surely a better way?
147 String validVersionParts = "([Dd][Ee][Vv][_.0-9]*)|" + "([Ss][Nn][Aa][Pp][Ss][Hh][Oo][Tt])|" +
148 "([0-9][_.0-9a-zA-Z]*)|" + "([Gg]?[_.0-9ab]*([Pp][Rr][Ee]|[Rr][Cc]|[Gg]|[Mm])[_.0-9]*)|" +
149 "([Aa][Ll][Pp][Hh][Aa][_.0-9]*)|" + "([Bb][Ee][Tt][Aa][_.0-9]*)|" + "([Rr][Cc][_.0-9]*)|" +
150 "([Tt][Ee][Ss][Tt][_.0-9]*)|" + "([Dd][Ee][Bb][Uu][Gg][_.0-9]*)|" +
151 "([Uu][Nn][Oo][Ff][Ff][Ii][Cc][Ii][Aa][Ll][_.0-9]*)|" + "([Cc][Uu][Rr][Rr][Ee][Nn][Tt])|" +
152 "([Ll][Aa][Tt][Ee][Ss][Tt])|" + "([Ff][Cc][Ss])|" + "([Rr][Ee][Ll][Ee][Aa][Ss][Ee][_.0-9]*)|" +
153 "([Nn][Ii][Gg][Hh][Tt][Ll][Yy])|" + "([AaBb][_.0-9]*)";
155 // let's discover the version, and whatever's leftover will be either
156 // a classifier, or part of the artifactId, depending on position.
157 // Since version is at the end, we have to move in from the back.
158 Collections.reverse( avceTokenList );
160 StringBuffer classifierBuffer = new StringBuffer();
161 StringBuffer versionBuffer = new StringBuffer();
163 boolean firstVersionTokenEncountered = false;
164 boolean firstToken = true;
166 int tokensIterated = 0;
167 for ( Iterator it = avceTokenList.iterator(); it.hasNext(); )
169 String token = (String) it.next();
171 boolean tokenIsVersionPart = token.matches( validVersionParts );
173 StringBuffer bufferToUpdate;
175 // NOTE: logic in code is reversed, since we're peeling off the back
176 // Any token after the last versionPart will be in the classifier.
177 // Any token UP TO first non-versionPart is part of the version.
178 if ( !tokenIsVersionPart )
180 if ( firstVersionTokenEncountered )
186 bufferToUpdate = classifierBuffer;
191 firstVersionTokenEncountered = true;
193 bufferToUpdate = versionBuffer;
202 bufferToUpdate.insert( 0, '-' );
205 bufferToUpdate.insert( 0, token );
210 getLogger().debug( "After parsing loop, state of buffers:\no Version Buffer: \'" + versionBuffer +
211 "\'\no Classifier Buffer: \'" + classifierBuffer + "\'\no Number of Tokens Iterated: " + tokensIterated );
213 // Now, restore the proper ordering so we can build the artifactId.
214 Collections.reverse( avceTokenList );
217 "Before repairing bad version and/or cleaning up used tokens, avce token list is:\n" + avceTokenList );
219 // if we didn't find a version, then punt. Use the last token
220 // as the version, and set the classifier empty.
221 if ( versionBuffer.length() < 1 )
223 if ( avceTokenList.size() > 1 )
225 int lastIdx = avceTokenList.size() - 1;
227 versionBuffer.append( avceTokenList.get( lastIdx ) );
228 avceTokenList.remove( lastIdx );
232 getLogger().debug( "Cannot parse version from artifact path: \'" + path + "\'." );
234 "artifact-version-classifier-extension remaining tokens is: \'" + avceTokenList + "\'" );
237 classifierBuffer.setLength( 0 );
241 getLogger().debug( "Removing " + tokensIterated + " tokens from avce token list." );
243 // if everything is kosher, then pop off all the classifier and
244 // version tokens, leaving the naked artifact id in the list.
245 avceTokenList = new LinkedList( avceTokenList.subList( 0, avceTokenList.size() - tokensIterated ) );
248 getLogger().debug( "Now, remainder of avce token list is:\n" + avceTokenList );
250 StringBuffer artifactIdBuffer = new StringBuffer();
253 for ( Iterator it = avceTokenList.iterator(); it.hasNext(); )
255 String token = (String) it.next();
263 artifactIdBuffer.append( '-' );
266 artifactIdBuffer.append( token );
269 String artifactId = artifactIdBuffer.toString();
271 int lastVersionCharIdx = versionBuffer.length() - 1;
272 if ( lastVersionCharIdx > -1 && versionBuffer.charAt( lastVersionCharIdx ) == '-' )
274 versionBuffer.setLength( lastVersionCharIdx );
277 String version = versionBuffer.toString();
279 if ( version.length() < 1 )
284 getLogger().debug( "Extracted artifact information from path:\n" + "groupId: \'" + groupId + "\'\n" +
285 "artifactId: \'" + artifactId + "\'\n" + "type: \'" + type + "\'\n" + "version: \'" + version + "\'\n" +
286 "classifier: \'" + classifierBuffer + "\'" );
288 Artifact result = null;
290 if ( classifierBuffer.length() > 0 )
292 getLogger().debug( "Creating artifact with classifier." );
294 result = artifactFactory.createArtifactWithClassifier( groupId, artifactId, version, type,
295 classifierBuffer.toString() );
299 if ( StringUtils.isNotEmpty( groupId ) && StringUtils.isNotEmpty( artifactId ) &&
300 StringUtils.isNotEmpty( version ) && StringUtils.isNotEmpty( type ) )
302 result = artifactFactory.createArtifact( groupId, artifactId, version, Artifact.SCOPE_RUNTIME, type );
306 result.setFile( new File( path ) );