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 }