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.IOException;
24  import java.io.StringReader;
25  import java.io.Writer;
26  import java.nio.charset.Charset;
27  import java.nio.file.Files;
28  import java.util.Objects;
29  
30  import org.apache.maven.artifact.Artifact;
31  import org.apache.maven.artifact.ArtifactUtils;
32  import org.apache.maven.plugin.logging.Log;
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         }
116 
117         String classifierString = "";
118 
119         if (!removeClassifier && StringUtils.isNotEmpty(artifact.getClassifier())) {
120             classifierString = "-" + artifact.getClassifier();
121         }
122         destFileName.append(artifact.getArtifactId()).append(versionString);
123         destFileName.append(classifierString).append(".");
124         destFileName.append(artifact.getArtifactHandler().getExtension());
125 
126         return destFileName.toString();
127     }
128 
129     /**
130      * Formats the outputDirectory based on type.
131      *
132      * @param useSubdirsPerScope if a new sub directory should be used for each scope.
133      * @param useSubdirsPerType if a new sub directory should be used for each type.
134      * @param useSubdirPerArtifact if a new sub directory should be used for each artifact.
135      * @param useRepositoryLayout if dependencies must be moved into a Maven repository layout, if set, other settings
136      *            will be ignored.
137      * @param removeVersion if the version must not be mentioned in the filename
138      * @param removeType if the type must not be mentioned in the filename
139      * @param outputDirectory base outputDirectory.
140      * @param artifact information about the artifact.
141      * @return a formatted File object to use for output.
142      */
143     public static File getFormattedOutputDirectory(
144             boolean useSubdirsPerScope,
145             boolean useSubdirsPerType,
146             boolean useSubdirPerArtifact,
147             boolean useRepositoryLayout,
148             boolean removeVersion,
149             boolean removeType,
150             File outputDirectory,
151             Artifact artifact) {
152         StringBuilder sb = new StringBuilder(128);
153         if (useRepositoryLayout) {
154             // group id
155             sb.append(artifact.getGroupId().replace('.', File.separatorChar)).append(File.separatorChar);
156             // artifact id
157             sb.append(artifact.getArtifactId()).append(File.separatorChar);
158             // version
159             sb.append(artifact.getBaseVersion()).append(File.separatorChar);
160         } else {
161             if (useSubdirsPerScope) {
162                 sb.append(artifact.getScope()).append(File.separatorChar);
163             }
164             if (useSubdirsPerType) {
165                 sb.append(artifact.getType()).append("s").append(File.separatorChar);
166             }
167             if (useSubdirPerArtifact) {
168                 String artifactString = getDependencyId(artifact, removeVersion, removeType);
169                 sb.append(artifactString).append(File.separatorChar);
170             }
171         }
172         return new File(outputDirectory, sb.toString());
173     }
174 
175     private static String getDependencyId(Artifact artifact, boolean removeVersion, boolean removeType) {
176         StringBuilder sb = new StringBuilder();
177 
178         sb.append(artifact.getArtifactId());
179 
180         if (!removeVersion) {
181             sb.append("-");
182             sb.append(artifact.getVersion());
183         }
184 
185         if (StringUtils.isNotEmpty(artifact.getClassifier())) {
186             sb.append("-");
187             sb.append(artifact.getClassifier());
188         }
189 
190         // if the classifier and type are the same (sources), then don't
191         // repeat.
192         // avoids names like foo-sources-sources
193         if (!removeType && !Objects.equals(artifact.getClassifier(), artifact.getType())) {
194             sb.append("-");
195             sb.append(artifact.getType());
196         }
197 
198         return sb.toString();
199     }
200 
201     /**
202      * Writes the specified string to the specified file.
203      *
204      * @param string the string to write
205      * @param file the file to write to
206      * @param append append to existing file or not
207      * @param log ignored
208      * @throws IOException if an I/O error occurs
209      * @deprecated specify an encoding instead of a log
210      */
211     @Deprecated
212     public static synchronized void write(String string, File file, boolean append, Log log) throws IOException {
213         write(string, file, append, "UTF-8");
214     }
215 
216     /**
217      * Writes the specified string to the specified file.
218      *
219      * @param string the string to write
220      * @param file the file to write to
221      * @param append append to existing file or not
222      * @param encoding character set name
223      * @throws IOException if an I/O error occurs
224      */
225     public static synchronized void write(String string, File file, boolean append, String encoding)
226             throws IOException {
227         Files.createDirectories(file.getParentFile().toPath());
228 
229         try (Writer writer = Files.newBufferedWriter(file.toPath(), Charset.forName(encoding))) {
230             writer.write(string);
231         }
232     }
233 
234     /**
235      * Writes the specified string to the log at info level.
236      *
237      * @param string the string to write
238      * @param log where to log information
239      * @throws IOException if an I/O error occurs
240      */
241     public static synchronized void log(String string, Log log) throws IOException {
242         try (BufferedReader reader = new BufferedReader(new StringReader(string))) {
243             reader.lines().forEach(log::info);
244         }
245     }
246 
247     /**
248      * Mainly used to parse excludes, includes configuration.
249      *
250      * @param str the string to split
251      * @return the result items
252      */
253     public static String[] tokenizer(String str) {
254         String s = cleanToBeTokenizedString(str);
255         if (s.isEmpty()) {
256             return new String[0];
257         }
258         return cleanToBeTokenizedString(str).split(",");
259     }
260 
261     /**
262      * Clean up configuration string before it can be tokenized.
263      *
264      * @param str the string which should be cleaned
265      * @return cleaned up string
266      */
267     public static String cleanToBeTokenizedString(String str) {
268         String ret = "";
269         if (!(str == null || str.isEmpty())) {
270             // remove initial and ending spaces, plus all spaces next to commas
271             ret = str.trim().replaceAll("\\s*,\\s*", ",");
272         }
273 
274         return ret;
275     }
276 }