1 package org.apache.maven.plugin.dependency;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.artifact.Artifact;
23 import org.apache.maven.artifact.ArtifactUtils;
24 import org.apache.maven.artifact.factory.ArtifactFactory;
25 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
26 import org.apache.maven.artifact.repository.ArtifactRepository;
27 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
28 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
29 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
30 import org.apache.maven.artifact.resolver.ArtifactResolver;
31 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
32 import org.apache.maven.artifact.versioning.VersionRange;
33 import org.apache.maven.model.Dependency;
34 import org.apache.maven.plugin.AbstractMojo;
35 import org.apache.maven.plugin.MojoExecutionException;
36 import org.apache.maven.plugin.MojoFailureException;
37 import org.apache.maven.plugins.annotations.Component;
38 import org.apache.maven.plugins.annotations.Mojo;
39 import org.apache.maven.plugins.annotations.Parameter;
40 import org.apache.maven.project.MavenProject;
41 import org.codehaus.plexus.util.FileUtils;
42
43 import java.io.File;
44 import java.io.IOException;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.HashMap;
49 import java.util.HashSet;
50 import java.util.Iterator;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.Set;
54
55
56
57
58
59
60
61
62
63 @Mojo( name = "purge-local-repository", aggregator = true )
64 public class PurgeLocalRepositoryMojo
65 extends AbstractMojo
66 {
67
68 public static final String FILE_FUZZINESS = "file";
69
70 public static final String VERSION_FUZZINESS = "version";
71
72 public static final String ARTIFACT_ID_FUZZINESS = "artifactId";
73
74 public static final String GROUP_ID_FUZZINESS = "groupId";
75
76
77
78
79
80 @Parameter( defaultValue = "${reactorProjects}", readonly = true, required = true )
81 private List<MavenProject> projects;
82
83
84
85
86
87 @Parameter
88 private List<String> excludes;
89
90
91
92
93
94
95
96 @Parameter( property = "exclude" )
97 private String exclude;
98
99
100
101
102
103
104 @Parameter( property = "reResolve", defaultValue = "true" )
105 private boolean reResolve;
106
107
108
109
110 @Parameter( defaultValue = "${localRepository}", readonly = true, required = true )
111 private ArtifactRepository localRepository;
112
113
114
115
116
117 @Component
118 private ArtifactResolver resolver;
119
120
121
122
123 @Component
124 private ArtifactMetadataSource source;
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139 @Parameter( property = "resolutionFuzziness", defaultValue = "file" )
140 private String resolutionFuzziness;
141
142
143
144
145
146 @Parameter( property = "actTransitively", defaultValue = "true" )
147 private boolean actTransitively;
148
149
150
151
152 @Component
153 private ArtifactFactory factory;
154
155
156
157
158 @Parameter( property = "verbose", defaultValue = "false" )
159 private boolean verbose;
160
161
162
163
164
165
166 @Parameter( property = "snapshotsOnly", defaultValue = "false" )
167 private boolean snapshotsOnly;
168
169
170 public void execute()
171 throws MojoExecutionException, MojoFailureException
172 {
173 List<String> exclusionPatterns = buildExclusionPatternsList();
174
175 for ( MavenProject project : projects )
176 {
177 try
178 {
179 refreshDependenciesForProject( project, exclusionPatterns );
180 }
181 catch ( ArtifactResolutionException e )
182 {
183 MojoFailureException failure =
184 new MojoFailureException( this, "Failed to refresh project dependencies for: " + project.getId(),
185 "Artifact resolution failed for project: " + project.getId() );
186 failure.initCause( e );
187
188 throw failure;
189 }
190 }
191 }
192
193 private List<String> buildExclusionPatternsList()
194 {
195 List<String> patterns = new ArrayList<String>();
196
197 if ( exclude != null )
198 {
199 String[] elements = exclude.split( " ?, ?" );
200
201 patterns.addAll( Arrays.asList( elements ) );
202 }
203 else if ( excludes != null && !excludes.isEmpty() )
204 {
205 patterns.addAll( excludes );
206 }
207
208 return patterns;
209 }
210
211 private Map<String, Artifact> createArtifactMap( MavenProject project )
212 {
213 Map<String, Artifact> artifactMap = Collections.emptyMap();
214
215 @SuppressWarnings( "unchecked" ) List<Dependency> dependencies = project.getDependencies();
216
217 List<ArtifactRepository> remoteRepositories = Collections.emptyList();
218
219 Set<Artifact> dependencyArtifacts = new HashSet<Artifact>();
220
221 for ( Dependency dependency : dependencies )
222 {
223 VersionRange vr = VersionRange.createFromVersion( dependency.getVersion() );
224
225 Artifact artifact =
226 factory.createDependencyArtifact( dependency.getGroupId(), dependency.getArtifactId(), vr,
227 dependency.getType(), dependency.getClassifier(),
228 dependency.getScope() );
229 if ( snapshotsOnly && !artifact.isSnapshot() )
230 {
231 continue;
232 }
233 dependencyArtifacts.add( artifact );
234 }
235
236 if ( actTransitively )
237 {
238 try
239 {
240 ArtifactResolutionResult result;
241
242 if ( snapshotsOnly )
243 {
244 result = resolver.resolveTransitively( dependencyArtifacts, project.getArtifact(), localRepository,
245 remoteRepositories, source, new ArtifactFilter()
246 {
247 public boolean include( Artifact artifact )
248 {
249 return artifact.isSnapshot();
250 }
251 } );
252 }
253 else
254 {
255 result =
256 resolver.resolveTransitively( dependencyArtifacts, project.getArtifact(), remoteRepositories,
257 localRepository, source );
258 }
259
260 artifactMap = ArtifactUtils.artifactMapByVersionlessId( result.getArtifacts() );
261 }
262 catch ( ArtifactResolutionException e )
263 {
264 verbose( "Skipping: " + e.getArtifactId() + ". It cannot be resolved." );
265 }
266 catch ( ArtifactNotFoundException e )
267 {
268 verbose( "Skipping: " + e.getArtifactId() + ". It cannot be resolved." );
269 }
270 }
271 else
272 {
273 artifactMap = new HashMap<String, Artifact>();
274 for ( Artifact artifact : dependencyArtifacts )
275 {
276 try
277 {
278 resolver.resolve( artifact, remoteRepositories, localRepository );
279
280 artifactMap.put( ArtifactUtils.versionlessKey( artifact ), artifact );
281 }
282 catch ( ArtifactResolutionException e )
283 {
284 verbose( "Skipping: " + e.getArtifactId() + ". It cannot be resolved." );
285 }
286 catch ( ArtifactNotFoundException e )
287 {
288 verbose( "Skipping: " + e.getArtifactId() + ". It cannot be resolved." );
289 }
290 }
291 }
292
293 return artifactMap;
294 }
295
296 private void verbose( String message )
297 {
298 if ( verbose || getLog().isDebugEnabled() )
299 {
300 getLog().info( message );
301 }
302 }
303
304 private void refreshDependenciesForProject( MavenProject project, List<String> exclusionPatterns )
305 throws ArtifactResolutionException, MojoFailureException
306 {
307 Map<String, Artifact> deps = createArtifactMap( project );
308
309 if ( deps.isEmpty() )
310 {
311 getLog().info( "Nothing to do for project: " + project.getId() );
312 return;
313 }
314
315 if ( !exclusionPatterns.isEmpty() )
316 {
317 for ( String excludedKey : exclusionPatterns )
318 {
319 if ( GROUP_ID_FUZZINESS.equals( resolutionFuzziness ) )
320 {
321 verbose( "Excluding groupId: " + excludedKey + " from refresh operation for project: "
322 + project.getId() );
323
324 for ( Iterator<Map.Entry<String, Artifact>> deps_it = deps.entrySet().iterator();
325 deps_it.hasNext(); )
326 {
327 Map.Entry<String, Artifact> dependency = deps_it.next();
328
329 Artifact artifact = dependency.getValue();
330
331 if ( artifact.getGroupId().equals( excludedKey ) )
332 {
333 deps_it.remove();
334 }
335 }
336 }
337 else
338 {
339 verbose( "Excluding: " + excludedKey + " from refresh operation for project: " + project.getId() );
340
341 deps.remove( excludedKey );
342 }
343 }
344 }
345
346 verbose( "Processing dependencies for project: " + project.getId() );
347
348 List<Artifact> missingArtifacts = new ArrayList<Artifact>();
349 for ( Map.Entry<String, Artifact> entry : deps.entrySet() )
350 {
351 Artifact artifact = entry.getValue();
352
353 verbose( "Processing artifact: " + artifact.getId() );
354
355 File deleteTarget = findDeleteTarget( artifact );
356
357 verbose( "Deleting: " + deleteTarget );
358
359 if ( deleteTarget.isDirectory() )
360 {
361 try
362 {
363 FileUtils.deleteDirectory( deleteTarget );
364 }
365 catch ( IOException e )
366 {
367 throw new MojoFailureException( this, "Cannot delete dependency from the local repository: "
368 + artifact.getId(), "Failed to delete: " + deleteTarget );
369 }
370 }
371 else
372 {
373 deleteTarget.delete();
374 }
375
376 if ( reResolve )
377 {
378 verbose( "Re-resolving." );
379
380 artifact.setResolved( false );
381
382 try
383 {
384 resolver.resolveAlways( artifact, project.getRemoteArtifactRepositories(), localRepository );
385 }
386 catch ( ArtifactResolutionException e )
387 {
388 getLog().debug( e.getMessage() );
389 missingArtifacts.add( artifact );
390 }
391 catch ( ArtifactNotFoundException e )
392 {
393 getLog().debug( e.getMessage() );
394 missingArtifacts.add( artifact );
395 }
396 }
397 }
398
399 if ( missingArtifacts.size() > 0 )
400 {
401 String message = "required artifacts missing:\n";
402 for ( Artifact missingArtifact : missingArtifacts )
403 {
404 message += " " + missingArtifact.getId() + "\n";
405 }
406 message += "\nfor the artifact:";
407
408 throw new ArtifactResolutionException( message, project.getArtifact(),
409 project.getRemoteArtifactRepositories() );
410 }
411
412 }
413
414 private File findDeleteTarget( Artifact artifact )
415 {
416 File deleteTarget = artifact.getFile();
417
418 if ( GROUP_ID_FUZZINESS.equals( resolutionFuzziness ) )
419 {
420
421 deleteTarget = deleteTarget.getParentFile().getParentFile();
422
423
424 deleteTarget = deleteTarget.getParentFile();
425
426 String[] path = localRepository.pathOf( artifact ).split( "\\/" );
427
428
429
430
431 int groupParts = path.length - 4;
432
433 File parent = deleteTarget.getParentFile();
434 int count = 0;
435 while ( count++ < groupParts )
436 {
437
438
439
440
441
442 if ( parent.list().length < 2 )
443 {
444 deleteTarget = parent;
445
446
447 parent = deleteTarget.getParentFile();
448 }
449 else
450 {
451
452
453 break;
454 }
455 }
456
457 }
458 else if ( ARTIFACT_ID_FUZZINESS.equals( resolutionFuzziness ) )
459 {
460
461 deleteTarget = deleteTarget.getParentFile().getParentFile();
462 }
463 else if ( VERSION_FUZZINESS.equals( resolutionFuzziness ) )
464 {
465
466 deleteTarget = deleteTarget.getParentFile();
467 }
468
469
470 return deleteTarget;
471 }
472
473 }