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