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