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