1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.dependency.fromDependencies;
20
21 import java.io.BufferedReader;
22 import java.io.BufferedWriter;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStreamReader;
28 import java.io.OutputStreamWriter;
29 import java.io.Writer;
30 import java.util.ArrayList;
31 import java.util.Comparator;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Objects;
35 import java.util.Set;
36 import java.util.regex.Matcher;
37 import java.util.regex.Pattern;
38 import org.apache.maven.artifact.Artifact;
39 import org.apache.maven.plugin.MojoExecutionException;
40 import org.apache.maven.plugins.annotations.Component;
41 import org.apache.maven.plugins.annotations.LifecyclePhase;
42 import org.apache.maven.plugins.annotations.Mojo;
43 import org.apache.maven.plugins.annotations.Parameter;
44 import org.apache.maven.plugins.annotations.ResolutionScope;
45 import org.apache.maven.plugins.dependency.utils.DependencyUtil;
46 import org.apache.maven.project.MavenProjectHelper;
47 import org.apache.maven.project.ProjectBuildingRequest;
48 import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;
49 import org.apache.maven.shared.transfer.repository.RepositoryManager;
50 import org.codehaus.plexus.util.StringUtils;
51
52
53
54
55
56
57
58
59 @Mojo(
60 name = "build-classpath",
61 requiresDependencyResolution = ResolutionScope.TEST,
62 defaultPhase = LifecyclePhase.GENERATE_SOURCES,
63 threadSafe = true)
64
65 public class BuildClasspathMojo extends AbstractDependencyFilterMojo implements Comparator<Artifact> {
66
67 @Parameter(property = "outputEncoding", defaultValue = "${project.reporting.outputEncoding}")
68 private String outputEncoding;
69
70
71
72
73 @Parameter(property = "mdep.stripVersion", defaultValue = "false")
74 private boolean stripVersion = false;
75
76
77
78
79 @Parameter(property = "mdep.stripClassifier", defaultValue = "false")
80 private boolean stripClassifier = false;
81
82
83
84
85
86 @Parameter(property = "mdep.prefix")
87 private String prefix;
88
89
90
91
92 @Parameter(property = "mdep.outputProperty")
93 private String outputProperty;
94
95
96
97
98 @Parameter(property = "mdep.outputFile")
99 private File outputFile;
100
101
102
103
104 @Parameter(property = "mdep.regenerateFile", defaultValue = "false")
105 private boolean regenerateFile;
106
107
108
109
110
111
112
113
114 @Parameter(property = "mdep.fileSeparator", defaultValue = "")
115 private String fileSeparator;
116
117
118
119
120
121
122
123
124
125 @Parameter(property = "mdep.pathSeparator", defaultValue = "")
126 private String pathSeparator;
127
128
129
130
131
132
133
134 @Parameter(property = "mdep.localRepoProperty", defaultValue = "")
135 private String localRepoProperty;
136
137
138
139
140
141
142 @Parameter(defaultValue = "false")
143 private boolean attach;
144
145
146
147
148
149
150 @Parameter(property = "mdep.outputFilterFile", defaultValue = "false")
151 private boolean outputFilterFile;
152
153
154
155
156
157
158
159 @Parameter(property = "mdep.useBaseVersion", defaultValue = "true")
160 private boolean useBaseVersion = true;
161
162
163
164
165 @Component
166 private MavenProjectHelper projectHelper;
167
168 @Component
169 private RepositoryManager repositoryManager;
170
171
172
173
174
175
176
177 @Override
178 protected void doExecute() throws MojoExecutionException {
179
180 boolean isFileSepSet = StringUtils.isNotEmpty(fileSeparator);
181 boolean isPathSepSet = StringUtils.isNotEmpty(pathSeparator);
182
183
184 if (attach && StringUtils.isEmpty(localRepoProperty)) {
185 localRepoProperty = "${M2_REPO}";
186 }
187
188 Set<Artifact> artifacts = getResolvedDependencies(true);
189
190 if (artifacts == null || artifacts.isEmpty()) {
191 getLog().info("No dependencies found.");
192 }
193
194 List<Artifact> artList = new ArrayList<>(artifacts);
195
196 StringBuilder sb = new StringBuilder();
197 Iterator<Artifact> i = artList.iterator();
198
199 if (i.hasNext()) {
200 appendArtifactPath(i.next(), sb);
201
202 while (i.hasNext()) {
203 sb.append(isPathSepSet ? this.pathSeparator : File.pathSeparator);
204 appendArtifactPath(i.next(), sb);
205 }
206 }
207
208 String cpString = sb.toString();
209
210
211
212 if (isFileSepSet) {
213
214 final String pattern = Pattern.quote(File.separator);
215 final String replacement = Matcher.quoteReplacement(fileSeparator);
216 cpString = cpString.replaceAll(pattern, replacement);
217 }
218
219
220 if (outputFilterFile) {
221 cpString = "classpath=" + cpString;
222 }
223
224 if (outputProperty != null) {
225 getProject().getProperties().setProperty(outputProperty, cpString);
226 if (getLog().isDebugEnabled()) {
227 getLog().debug(outputProperty + " = " + cpString);
228 }
229 }
230
231 if (outputFile == null) {
232 getLog().info("Dependencies classpath:" + System.lineSeparator() + cpString);
233 } else {
234 if (regenerateFile || !isUpToDate(cpString)) {
235 storeClasspathFile(cpString, outputFile);
236 } else {
237 this.getLog().info("Skipped writing classpath file '" + outputFile + "'. No changes found.");
238 }
239 }
240 if (attach) {
241 attachFile(cpString);
242 }
243 }
244
245
246
247
248
249 protected void attachFile(String cpString) throws MojoExecutionException {
250 File attachedFile = new File(getProject().getBuild().getDirectory(), "classpath");
251 storeClasspathFile(cpString, attachedFile);
252
253 projectHelper.attachArtifact(getProject(), attachedFile, "classpath");
254 }
255
256
257
258
259
260
261
262 protected void appendArtifactPath(Artifact art, StringBuilder sb) {
263 if (prefix == null) {
264 String file = art.getFile().getPath();
265
266 if (StringUtils.isNotEmpty(localRepoProperty)) {
267 ProjectBuildingRequest projectBuildingRequest = session.getProjectBuildingRequest();
268 File localBasedir = repositoryManager.getLocalRepositoryBasedir(projectBuildingRequest);
269
270 file = StringUtils.replace(file, localBasedir.getAbsolutePath(), localRepoProperty);
271 }
272 sb.append(file);
273 } else {
274
275 sb.append(prefix);
276 sb.append(File.separator);
277 sb.append(DependencyUtil.getFormattedFileName(
278 art, this.stripVersion, this.prependGroupId, this.useBaseVersion, this.stripClassifier));
279 }
280 }
281
282
283
284
285
286
287
288 private boolean isUpToDate(String cpString) {
289 try {
290 String oldCp = readClasspathFile();
291 return Objects.equals(cpString, oldCp);
292 } catch (IOException ex) {
293 this.getLog()
294 .warn("Error while reading old classpath file '" + outputFile + "' for up-to-date check: " + ex);
295
296 return false;
297 }
298 }
299
300
301
302
303
304
305 private void storeClasspathFile(String cpString, File out) throws MojoExecutionException {
306
307 out.getParentFile().mkdirs();
308
309 String encoding = Objects.toString(outputEncoding, "UTF-8");
310
311 try (Writer w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(out), encoding))) {
312 w.write(cpString);
313 getLog().info("Wrote classpath file '" + out + "'.");
314 } catch (IOException ex) {
315 throw new MojoExecutionException("Error while writing to classpath file '" + out, ex);
316 }
317 }
318
319
320
321
322
323
324
325
326 protected String readClasspathFile() throws IOException {
327 if (outputFile == null) {
328 throw new IllegalArgumentException(
329 "The outputFile parameter " + "cannot be null if the file is intended to be read.");
330 }
331
332 if (!outputFile.isFile()) {
333 return null;
334 }
335 StringBuilder sb = new StringBuilder();
336 String encoding = Objects.toString(outputEncoding, "UTF-8");
337
338 try (BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(outputFile), encoding))) {
339 for (String line = r.readLine(); line != null; line = r.readLine()) {
340 sb.append(line);
341 }
342
343 return sb.toString();
344 }
345 }
346
347
348
349
350
351
352
353
354
355
356 @Override
357 public int compare(Artifact art1, Artifact art2) {
358 if (art1 == art2) {
359 return 0;
360 } else if (art1 == null) {
361 return -1;
362 } else if (art2 == null) {
363 return +1;
364 }
365
366 String s1 = art1.getGroupId() + art1.getArtifactId() + art1.getVersion();
367 String s2 = art2.getGroupId() + art2.getArtifactId() + art2.getVersion();
368
369 return s1.compareTo(s2);
370 }
371
372 @Override
373 protected ArtifactsFilter getMarkedArtifactFilter() {
374 return null;
375 }
376
377
378
379
380 public void setOutputFile(File outputFile) {
381 this.outputFile = outputFile;
382 }
383
384
385
386
387 public void setOutputProperty(String theOutputProperty) {
388 this.outputProperty = theOutputProperty;
389 }
390
391
392
393
394 public void setFileSeparator(String theFileSeparator) {
395 this.fileSeparator = theFileSeparator;
396 }
397
398
399
400
401 public void setPathSeparator(String thePathSeparator) {
402 this.pathSeparator = thePathSeparator;
403 }
404
405
406
407
408 public void setPrefix(String thePrefix) {
409 this.prefix = thePrefix;
410 }
411
412
413
414
415 public void setRegenerateFile(boolean theRegenerateFile) {
416 this.regenerateFile = theRegenerateFile;
417 }
418
419
420
421
422 public boolean isStripVersion() {
423 return this.stripVersion;
424 }
425
426
427
428
429 public void setStripVersion(boolean theStripVersion) {
430 this.stripVersion = theStripVersion;
431 }
432
433
434
435
436 public void setLocalRepoProperty(String localRepoProperty) {
437 this.localRepoProperty = localRepoProperty;
438 }
439 }