]> source.dussan.org Git - archiva.git/blob
70e52f6079c03ff8a1167e94261bbd51804d07ee
[archiva.git] /
1 package org.apache.archiva.repository.maven.content;
2
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements.  See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership.  The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License.  You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  */
20
21 import org.apache.archiva.common.utils.VersionUtil;
22 import org.apache.archiva.metadata.maven.MavenMetadataReader;
23 import org.apache.archiva.model.ArchivaRepositoryMetadata;
24 import org.apache.archiva.model.SnapshotVersion;
25 import org.apache.archiva.repository.content.ItemSelector;
26 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
27 import org.apache.archiva.repository.storage.StorageAsset;
28 import org.apache.commons.lang3.StringUtils;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31 import org.springframework.stereotype.Service;
32
33 import javax.inject.Inject;
34 import javax.inject.Named;
35 import java.util.Comparator;
36 import java.util.LinkedList;
37 import java.util.regex.Pattern;
38
39 /**
40  * Helper class that contains certain maven specific methods
41  */
42 @Service( "MavenContentHelper" )
43 public class MavenContentHelper
44 {
45
46     private static final Logger log = LoggerFactory.getLogger( MavenContentHelper.class );
47     public static final Pattern UNIQUE_SNAPSHOT_NUMBER_PATTERN = Pattern.compile( "^([0-9]{8}\\.[0-9]{6}-[0-9]+)(.*)" );
48
49
50     @Inject
51     @Named( "metadataReader#maven" )
52     MavenMetadataReader metadataReader;
53
54     public static final String METADATA_FILENAME = "maven-metadata.xml";
55     public static final String METADATA_REPOSITORY_FILENAME = "maven-metadata-repository.xml";
56
57     public MavenContentHelper() {
58
59     }
60
61     public void setMetadataReader( MavenMetadataReader metadataReader )
62     {
63         this.metadataReader = metadataReader;
64     }
65
66     /**
67      * Returns the namespace string for a given path in the repository
68      *
69      * @param namespacePath the path to the namespace in the directory
70      * @return the namespace string that matches the given path.
71      */
72     public static String getNamespaceFromNamespacePath( final StorageAsset namespacePath) {
73         LinkedList<String> names = new LinkedList<>( );
74         StorageAsset current = namespacePath;
75         while (current.hasParent()) {
76             names.addFirst( current.getName() );
77             current = current.getParent( );
78         }
79         return String.join( ".", names );
80     }
81
82     /**
83      * Returns the artifact version for the given artifact directory and the item selector
84      */
85     public String getArtifactVersion( StorageAsset artifactDir, ItemSelector selector) {
86         if (selector.hasArtifactVersion()) {
87             return selector.getArtifactVersion();
88         } else if (selector.hasVersion()) {
89             if ( VersionUtil.isGenericSnapshot( selector.getVersion() ) ) {
90                 return getLatestArtifactSnapshotVersion( artifactDir, selector.getVersion( ) );
91             } else {
92                 return selector.getVersion( );
93             }
94         } else {
95             throw new IllegalArgumentException( "No version set on the selector " );
96         }
97     }
98
99
100     /**
101      *
102      * Returns the latest snapshot version that is referenced by the metadata file.
103      *
104      * @param artifactDir the directory of the artifact
105      * @param snapshotVersion the generic snapshot version (must end with '-SNAPSHOT')
106      * @return the real version from the metadata
107      */
108     public String getLatestArtifactSnapshotVersion( StorageAsset artifactDir, String snapshotVersion) {
109         final StorageAsset metadataFile = artifactDir.resolve( METADATA_FILENAME );
110         StringBuilder version = new StringBuilder( );
111         try
112         {
113             ArchivaRepositoryMetadata metadata = metadataReader.read( metadataFile );
114
115             // re-adjust to timestamp if present, otherwise retain the original -SNAPSHOT filename
116             SnapshotVersion metadataVersion = metadata.getSnapshotVersion( );
117             if ( metadataVersion != null && StringUtils.isNotEmpty( metadataVersion.getTimestamp( ) ) )
118             {
119                 version.append( snapshotVersion, 0, snapshotVersion.length( ) - 8 ); // remove SNAPSHOT from end
120                 version.append( metadataVersion.getTimestamp( ) ).append( "-" ).append( metadataVersion.getBuildNumber( ) );
121                 return version.toString( );
122             }
123         }
124         catch ( RepositoryMetadataException e )
125         {
126             // unable to parse metadata - LOGGER it, and continue with the version as the original SNAPSHOT version
127             log.warn( "Invalid metadata: {} - {}", metadataFile, e.getMessage( ) );
128         }
129         final String baseVersion = StringUtils.removeEnd( snapshotVersion, "-SNAPSHOT" );
130         final String prefix = metadataFile.getParent( ).getParent( ).getName( ) + "-"+baseVersion+"-";
131         return artifactDir.list( ).stream( ).filter( a -> a.getName( ).startsWith( prefix ) )
132             .map( a -> StringUtils.removeStart( a.getName( ), prefix ) )
133             .map( n -> UNIQUE_SNAPSHOT_NUMBER_PATTERN.matcher( n ) )
134             .filter( m -> m.matches( ) )
135             .map( m -> baseVersion+"-"+m.group( 1 ) )
136             .sorted( Comparator.reverseOrder() ).findFirst().orElse( snapshotVersion );
137     }
138
139
140     /**
141      * Returns a artifact filename that corresponds to the given data.
142      * @param artifactId the selector data
143      * @param artifactVersion the artifactVersion
144      * @param classifier the artifact classifier
145      * @param extension the file extension
146      */
147     static String getArtifactFileName( String artifactId, String artifactVersion,
148                                        String classifier, String extension )
149     {
150         StringBuilder fileName = new StringBuilder( artifactId ).append( "-" );
151         fileName.append( artifactVersion );
152         if ( !StringUtils.isEmpty( classifier ) )
153         {
154             fileName.append( "-" ).append( classifier );
155         }
156         fileName.append( "." ).append( extension );
157         return fileName.toString( );
158     }
159
160     /**
161      * Returns the classifier for a given selector. If the selector has no classifier, but
162      * a type set. The classifier is generated from the type.
163      *
164      * @param selector the artifact selector
165      * @return the classifier or empty string if no classifier was found
166      */
167     static String getClassifier( ItemSelector selector )
168     {
169         if ( selector.hasClassifier( ) )
170         {
171             return selector.getClassifier( );
172         }
173         else if ( selector.hasType( ) )
174         {
175             return getClassifierFromType( selector.getType( ) );
176         }
177         else
178         {
179             return "";
180         }
181     }
182
183     /**
184      * Returns a classifier for a given type. It returns only classifier for the maven default types
185      * that are known.
186      *
187      * @param type the type of the artifact
188      * @return the classifier if one was found, otherwise a empty string
189      */
190     static String getClassifierFromType( final String type )
191     {
192         String testType = type.trim( ).toLowerCase( );
193         switch (testType.length( ))
194         {
195             case 7:
196                 if ("javadoc".equals(testType)) {
197                     return "javadoc";
198                 }
199             case 8:
200                 if ("test-jar".equals(testType))
201                 {
202                     return "tests";
203                 }
204             case 10:
205                 if ("ejb-client".equals(testType)) {
206                     return "client";
207                 }
208             case 11:
209                 if ("java-source".equals(testType)) {
210                     return "sources";
211                 }
212             default:
213                 return "";
214         }
215
216     }
217
218     /**
219      * Returns the type that matches the given classifier and extension
220      *
221      * @param classifierArg the classifier
222      * @param extensionArg the extension
223      * @return the type that matches the combination of classifier and extension
224      */
225     static String getTypeFromClassifierAndExtension( String classifierArg, String extensionArg )
226     {
227         String extension = extensionArg.toLowerCase( ).trim( );
228         String classifier = classifierArg.toLowerCase( ).trim( );
229         if ( StringUtils.isEmpty( extension ) )
230         {
231             return "";
232         }
233         else if ( StringUtils.isEmpty( classifier ) )
234         {
235             return extension;
236         }
237         else if ( classifier.equals( "tests" ) && extension.equals( "jar" ) )
238         {
239             return "test-jar";
240         }
241         else if ( classifier.equals( "client" ) && extension.equals( "jar" ) )
242         {
243             return "ejb-client";
244         }
245         else if ( classifier.equals( "sources" ) && extension.equals( "jar" ) )
246         {
247             return "java-source";
248         }
249         else if ( classifier.equals( "javadoc" ) && extension.equals( "jar" ) )
250         {
251             return "javadoc";
252         }
253         else
254         {
255             return extension;
256         }
257     }
258
259     /**
260      * If the selector defines a type and no extension, the extension can be derived from
261      * the type.
262      *
263      * @param selector the item selector
264      * @return the extension that matches the type or the default extension "jar" if the type is not known
265      */
266     static String getArtifactExtension( ItemSelector selector )
267     {
268         if ( selector.hasExtension( ) )
269         {
270             return selector.getExtension( );
271         }
272         else if ( selector.hasType( ) )
273         {
274             final String type = selector.getType( ).trim().toLowerCase( );
275             switch (type.length()) {
276                 case 3:
277                     if ("pom".equals(type) || "war".equals(type) || "ear".equals(type) || "rar".equals(type)) {
278                         return type;
279                     }
280                 default:
281                     return "jar";
282
283             }
284         }
285         else
286         {
287             return "jar";
288         }
289     }
290 }