View Javadoc
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 }