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