View Javadoc
1   package org.apache.maven.plugins.dependency.utils;
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   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.BufferedReader;
23  import java.io.File;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.OutputStreamWriter;
27  import java.io.StringReader;
28  import java.io.Writer;
29  import java.util.Objects;
30  
31  import org.apache.maven.artifact.Artifact;
32  import org.apache.maven.artifact.ArtifactUtils;
33  import org.apache.maven.plugin.logging.Log;
34  import org.codehaus.plexus.util.StringUtils;
35  
36  /**
37   * Utility class with static helper methods.
38   * 
39   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
40   */
41  public final class DependencyUtil
42  {
43  
44      /**
45       * Builds the file name. If removeVersion is set, then the file name must be reconstructed from the artifactId,
46       * Classifier (if used) and Type. Otherwise, this method returns the artifact file name.
47       * 
48       * @param artifact File to be formatted.
49       * @param removeVersion Specifies if the version should be removed from the file name.
50       * @return Formatted file name in the format artifactId-[version]-[classifier].[type]
51       * @see #getFormattedFileName(Artifact, boolean, boolean)
52       */
53      public static String getFormattedFileName( Artifact artifact, boolean removeVersion )
54      {
55          return getFormattedFileName( artifact, removeVersion, false );
56      }
57  
58      /**
59       * Builds the file name. If removeVersion is set, then the file name must be reconstructed from the groupId (if
60       * <b>prependGroupId</b> is true) artifactId, Classifier (if used) and Type. Otherwise, this method returns the
61       * artifact file name.
62       * 
63       * @param artifact File to be formatted.
64       * @param removeVersion Specifies if the version should be removed from the file name.
65       * @param prependGroupId Specifies if the groupId should be prepended to the file name.
66       * @return Formatted file name in the format [groupId].artifactId-[version]-[classifier].[type]
67       */
68      public static String getFormattedFileName( Artifact artifact, boolean removeVersion, boolean prependGroupId )
69      {
70          return getFormattedFileName( artifact, removeVersion, prependGroupId, false );
71      }
72  
73      /**
74       * Builds the file name. If removeVersion is set, then the file name must be reconstructed from the groupId (if
75       * <b>prependGroupId</b> is true) artifactId, Classifier (if used), and Type. Otherwise, this method returns the
76       * artifact file name.
77       * 
78       * @param artifact file to be formatted
79       * @param removeVersion Specifies if the version should be removed from the file name
80       * @param prependGroupId Specifies if the groupId should be prepended to the file name
81       * @param useBaseVersion Specifies if the baseVersion of the artifact should be used instead of the version
82       * @return Formatted file name in the format [groupId].artifactId-[version]-[classifier].[type]
83       */
84      public static String getFormattedFileName( Artifact artifact, boolean removeVersion, boolean prependGroupId,
85                                                 boolean useBaseVersion )
86      {
87          return getFormattedFileName( artifact, removeVersion, prependGroupId, useBaseVersion, false );
88      }
89  
90      /**
91       * Builds the file name. If removeVersion is set, then the file name must be reconstructed from the groupId (if
92       * <b>prependGroupId</b> is true) artifactId, Classifier (if used) and Type. Otherwise, this method returns the
93       * artifact file name.
94       * 
95       * @param artifact File to be formatted.
96       * @param removeVersion Specifies if the version should be removed from the file name.
97       * @param prependGroupId Specifies if the groupId should be prepended to the file name.
98       * @param useBaseVersion Specifies if the baseVersion of the artifact should be used instead of the version.
99       * @param removeClassifier Specifies if the classifier of the artifact should be remved from the file name.
100      * @return Formatted file name in the format [groupId].artifactId-[version]-[classifier].[type]
101      */
102     public static String getFormattedFileName( Artifact artifact, boolean removeVersion, boolean prependGroupId,
103                                                boolean useBaseVersion, boolean removeClassifier )
104     {
105         StringBuilder destFileName = new StringBuilder();
106 
107         if ( prependGroupId )
108         {
109             destFileName.append( artifact.getGroupId() ).append( "." );
110         }
111 
112         String versionString;
113         if ( !removeVersion )
114         {
115             if ( useBaseVersion )
116             {
117                 versionString = "-" + ArtifactUtils.toSnapshotVersion( artifact.getVersion() );
118             }
119             else
120             {
121                 versionString = "-" + artifact.getVersion();
122             }
123         }
124         else
125         {
126             versionString = "";
127         }
128 
129         String classifierString = "";
130 
131         if ( !removeClassifier && StringUtils.isNotEmpty( artifact.getClassifier() ) )
132         {
133             classifierString = "-" + artifact.getClassifier();
134         }
135         destFileName.append( artifact.getArtifactId() ).append( versionString );
136         destFileName.append( classifierString ).append( "." );
137         destFileName.append( artifact.getArtifactHandler().getExtension() );
138 
139         return destFileName.toString();
140     }
141 
142     /**
143      * Formats the outputDirectory based on type.
144      * 
145      * @param useSubdirsPerScope if a new sub directory should be used for each scope.
146      * @param useSubdirsPerType if a new sub directory should be used for each type.
147      * @param useSubdirPerArtifact if a new sub directory should be used for each artifact.
148      * @param useRepositoryLayout if dependencies must be moved into a Maven repository layout, if set, other settings
149      *            will be ignored.
150      * @param removeVersion if the version must not be mentioned in the filename
151      * @param removeType if the type must not be mentioned in the filename
152      * @param outputDirectory base outputDirectory.
153      * @param artifact information about the artifact.
154      * @return a formatted File object to use for output.
155      */
156     public static File getFormattedOutputDirectory( boolean useSubdirsPerScope, boolean useSubdirsPerType,
157                                                     boolean useSubdirPerArtifact, boolean useRepositoryLayout,
158                                                     boolean removeVersion, boolean removeType, File outputDirectory,
159                                                     Artifact artifact )
160     {
161         StringBuilder sb = new StringBuilder( 128 );
162         if ( useRepositoryLayout )
163         {
164             // group id
165             sb.append( artifact.getGroupId().replace( '.', File.separatorChar ) ).append( File.separatorChar );
166             // artifact id
167             sb.append( artifact.getArtifactId() ).append( File.separatorChar );
168             // version
169             sb.append( artifact.getBaseVersion() ).append( File.separatorChar );
170         }
171         else
172         {
173             if ( useSubdirsPerScope )
174             {
175                 sb.append( artifact.getScope() ).append( File.separatorChar );
176             }
177             if ( useSubdirsPerType )
178             {
179                 sb.append( artifact.getType() ).append( "s" ).append( File.separatorChar );
180             }
181             if ( useSubdirPerArtifact )
182             {
183                 String artifactString = getDependencyId( artifact, removeVersion, removeType );
184                 sb.append( artifactString ).append( File.separatorChar );
185             }
186         }
187         return new File( outputDirectory, sb.toString() );
188     }
189 
190     private static String getDependencyId( Artifact artifact, boolean removeVersion, boolean removeType )
191     {
192         StringBuilder sb = new StringBuilder();
193 
194         sb.append( artifact.getArtifactId() );
195 
196         if ( !removeVersion )
197         {
198             sb.append( "-" );
199             sb.append( artifact.getVersion() );
200         }
201 
202         if ( StringUtils.isNotEmpty( artifact.getClassifier() ) )
203         {
204             sb.append( "-" );
205             sb.append( artifact.getClassifier() );
206         }
207 
208         // if the classifier and type are the same (sources), then don't
209         // repeat.
210         // avoids names like foo-sources-sources
211         if ( !removeType && !Objects.equals( artifact.getClassifier(), artifact.getType() ) )
212         {
213             sb.append( "-" );
214             sb.append( artifact.getType() );
215         }
216 
217         return sb.toString();
218     }
219 
220     /**
221      * Writes the specified string to the specified file.
222      * 
223      * @param string the string to write
224      * @param file the file to write to
225      * @param append append to existing file or not
226      * @param log ignored
227      * @throws IOException if an I/O error occurs
228      * @deprecated specify an encoding instead of a log
229      */
230     @Deprecated
231     public static synchronized void write( String string, File file, boolean append, Log log )
232         throws IOException
233     {
234         write( string, file, append, "UTF-8" );
235     }
236     
237     /**
238      * Writes the specified string to the specified file.
239      * 
240      * @param string the string to write
241      * @param file the file to write to
242      * @param append append to existing file or not
243      * @param encoding character set name
244      * @throws IOException if an I/O error occurs
245      */
246     public static synchronized void write( String string, File file, boolean append, String encoding )
247         throws IOException
248     {
249         file.getParentFile().mkdirs(); 
250 
251         try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file, append ), encoding ) )
252         {
253             writer.write( string );
254         }
255     }
256 
257     /**
258      * Writes the specified string to the log at info level.
259      * 
260      * @param string the string to write
261      * @param log where to log information
262      * @throws IOException if an I/O error occurs
263      */
264     public static synchronized void log( String string, Log log )
265         throws IOException
266     {
267         BufferedReader reader = new BufferedReader( new StringReader( string ) );
268 
269         String line;
270 
271         while ( ( line = reader.readLine() ) != null )
272         {
273             log.info( line );
274         }
275 
276         reader.close();
277     }
278 
279     /**
280      * Mainly used to parse excludes, includes configuration.
281      * 
282      * @param str the string to split
283      * @return the result items
284      */
285     public static String[] tokenizer( String str )
286     {
287         return StringUtils.split( cleanToBeTokenizedString( str ), "," );
288     }
289 
290     /**
291      * Clean up configuration string before it can be tokenized.
292      * 
293      * @param str the string which should be cleaned
294      * @return cleaned up string
295      */
296     public static String cleanToBeTokenizedString( String str )
297     {
298         String ret = "";
299         if ( !StringUtils.isEmpty( str ) )
300         {
301             // remove initial and ending spaces, plus all spaces next to commas
302             ret = str.trim().replaceAll( "[\\s]*,[\\s]*", "," );
303         }
304 
305         return ret;
306     }
307 }