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