1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codehaus.mojo.license;
17
18 import org.apache.maven.artifact.Artifact;
19 import org.apache.maven.artifact.repository.ArtifactRepository;
20 import org.apache.maven.model.License;
21 import org.apache.maven.plugin.AbstractMojo;
22 import org.apache.maven.plugin.MojoExecutionException;
23 import org.apache.maven.project.MavenProject;
24 import org.codehaus.mojo.license.model.ProjectLicenseInfo;
25
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.FileNotFoundException;
29 import java.io.IOException;
30 import java.net.MalformedURLException;
31 import java.net.URL;
32 import java.util.*;
33
34
35
36
37
38
39
40
41
42
43
44
45 public class DownloadLicensesMojo
46 extends AbstractMojo
47 implements MavenProjectDependenciesConfigurator
48 {
49
50
51
52
53
54
55
56
57 private MavenProject project;
58
59
60
61
62
63
64
65
66 private ArtifactRepository localRepository;
67
68
69
70
71
72
73
74
75 private List remoteRepositories;
76
77
78
79
80
81
82
83 private File licensesConfigFile;
84
85
86
87
88
89
90
91 private File licensesOutputDirectory;
92
93
94
95
96
97
98
99 private File licensesOutputFile;
100
101
102
103
104
105
106
107 private String excludedScopes;
108
109
110
111
112
113
114
115 private String includedScopes;
116
117
118
119
120
121
122
123 private boolean offline;
124
125
126
127
128
129
130
131 private boolean quiet;
132
133
134
135
136
137
138
139 private boolean includeTransitiveDependencies;
140
141
142
143
144
145
146
147
148 private DependenciesTool dependenciesTool;
149
150
151
152
153
154 private Set<String> downloadedLicenseURLs = new HashSet<String>();
155
156
157
158
159 public void execute()
160 throws MojoExecutionException
161 {
162
163 if ( offline )
164 {
165
166 getLog().warn( "Offline flag is on, download-licenses goal is skip." );
167 return;
168 }
169 initDirectories();
170
171 Map<String, ProjectLicenseInfo> configuredDepLicensesMap = new HashMap<String, ProjectLicenseInfo>();
172
173
174 if ( licensesOutputFile.exists() )
175 {
176 loadLicenseInfo( configuredDepLicensesMap, licensesOutputFile, true );
177 }
178
179
180 if ( licensesConfigFile.exists() )
181 {
182 loadLicenseInfo( configuredDepLicensesMap, licensesConfigFile, false );
183 }
184
185 SortedMap<String, MavenProject> dependencies =
186 dependenciesTool.loadProjectDependencies( project, this, localRepository, remoteRepositories, null );
187
188
189 List<ProjectLicenseInfo> depProjectLicenses = new ArrayList<ProjectLicenseInfo>();
190
191 for ( MavenProject project : dependencies.values() )
192 {
193 Artifact artifact = project.getArtifact();
194 getLog().debug( "Checking licenses for project " + artifact );
195 String artifactProjectId = getArtifactProjectId( artifact );
196 ProjectLicenseInfo depProject;
197 if ( configuredDepLicensesMap.containsKey( artifactProjectId ) )
198 {
199 depProject = configuredDepLicensesMap.get( artifactProjectId );
200 depProject.setVersion( artifact.getVersion() );
201 }
202 else
203 {
204 depProject = createDependencyProject( project );
205 }
206 downloadLicenses( depProject );
207 depProjectLicenses.add( depProject );
208 }
209
210 try
211 {
212 LicenseSummaryWriter.writeLicenseSummary( depProjectLicenses, licensesOutputFile );
213 }
214 catch ( Exception e )
215 {
216 throw new MojoExecutionException( "Unable to write license summary file: " + licensesOutputFile, e );
217 }
218
219 }
220
221 private void initDirectories()
222 throws MojoExecutionException
223 {
224 try
225 {
226 FileUtil.createDirectoryIfNecessary( licensesOutputDirectory );
227
228 FileUtil.createDirectoryIfNecessary( licensesOutputFile.getParentFile() );
229 }
230 catch ( IOException e )
231 {
232 throw new MojoExecutionException( "Unable to create a directory...", e );
233 }
234 }
235
236
237
238
239
240
241
242
243
244
245 private void loadLicenseInfo( Map<String, ProjectLicenseInfo> configuredDepLicensesMap, File licenseConfigFile,
246 boolean previouslyDownloaded )
247 throws MojoExecutionException
248 {
249 FileInputStream fis = null;
250 try
251 {
252 fis = new FileInputStream( licenseConfigFile );
253 List<ProjectLicenseInfo> licensesList = LicenseSummaryReader.parseLicenseSummary( fis );
254 for ( ProjectLicenseInfo dep : licensesList )
255 {
256 configuredDepLicensesMap.put( dep.getId(), dep );
257 if ( previouslyDownloaded )
258 {
259 for ( License license : dep.getLicenses() )
260 {
261
262 downloadedLicenseURLs.add( license.getUrl() );
263 }
264 }
265 }
266 }
267 catch ( Exception e )
268 {
269 throw new MojoExecutionException( "Unable to parse license summary output file: " + licenseConfigFile, e );
270 }
271 finally
272 {
273 FileUtil.tryClose( fis );
274 }
275 }
276
277
278
279
280
281
282
283 public String getArtifactProjectId( Artifact artifact )
284 {
285 return artifact.getGroupId() + ":" + artifact.getArtifactId();
286 }
287
288
289
290
291
292
293
294 public ProjectLicenseInfo createDependencyProject( MavenProject depMavenProject )
295 {
296 ProjectLicenseInfo dependencyProject =
297 new ProjectLicenseInfo( depMavenProject.getGroupId(), depMavenProject.getArtifactId(),
298 depMavenProject.getVersion() );
299 List<?> licenses = depMavenProject.getLicenses();
300 for ( Object license : licenses )
301 {
302 dependencyProject.addLicense( (License) license );
303 }
304 return dependencyProject;
305 }
306
307
308
309
310
311
312
313
314
315 private String getLicenseFileName( License license )
316 throws MalformedURLException
317 {
318 URL licenseUrl = new URL( license.getUrl() );
319 File licenseUrlFile = new File( licenseUrl.getPath() );
320 String licenseFileName = licenseUrlFile.getName();
321
322 if ( license.getName() != null )
323 {
324 licenseFileName = license.getName() + " - " + licenseUrlFile.getName();
325 }
326
327
328 final String DEFAULT_EXTENSION = ".txt";
329 int extensionIndex = licenseFileName.lastIndexOf( "." );
330 if ( extensionIndex == -1 || extensionIndex > ( licenseFileName.length() - 3 ) )
331 {
332
333 licenseFileName = licenseFileName + DEFAULT_EXTENSION;
334 }
335
336
337 licenseFileName = licenseFileName.toLowerCase();
338
339 return licenseFileName;
340 }
341
342
343
344
345
346
347 private void downloadLicenses( ProjectLicenseInfo depProject )
348 {
349 getLog().debug( "Downloading license(s) for project " + depProject );
350
351 List<License> licenses = depProject.getLicenses();
352
353 if ( depProject.getLicenses() == null || depProject.getLicenses().isEmpty() )
354 {
355 if ( !quiet )
356 {
357 getLog().warn( "No license information available for: " + depProject );
358 }
359 return;
360 }
361
362 for ( License license : licenses )
363 {
364 try
365 {
366 String licenseFileName = getLicenseFileName( license );
367
368 File licenseOutputFile = new File( licensesOutputDirectory, licenseFileName );
369 if ( licenseOutputFile.exists() )
370 {
371 continue;
372 }
373
374 if ( !downloadedLicenseURLs.contains( license.getUrl() ) )
375 {
376 LicenseDownloader.downloadLicense( license.getUrl(), licenseOutputFile );
377 downloadedLicenseURLs.add( license.getUrl() );
378 }
379 }
380 catch ( MalformedURLException e )
381 {
382 if ( !quiet )
383 {
384 getLog().warn( "POM for dependency " + depProject.toString() + " has an invalid license URL: " +
385 license.getUrl() );
386 }
387 }
388 catch ( FileNotFoundException e )
389 {
390 if ( !quiet )
391 {
392 getLog().warn( "POM for dependency " + depProject.toString() +
393 " has a license URL that returns file not found: " + license.getUrl() );
394 }
395 }
396 catch ( IOException e )
397 {
398 getLog().warn( "Unable to retrieve license for dependency: " + depProject.toString() );
399 getLog().warn( license.getUrl() );
400 getLog().warn( e.getMessage() );
401 }
402
403 }
404
405 }
406
407 public MavenProject getProject()
408 {
409 return project;
410 }
411
412 public ArtifactRepository getLocalRepository()
413 {
414 return localRepository;
415 }
416
417 public List getRemoteRepositories()
418 {
419 return remoteRepositories;
420 }
421
422
423
424
425 public boolean isIncludeTransitiveDependencies()
426 {
427 return includeTransitiveDependencies;
428 }
429
430
431
432
433 public List<String> getExcludedScopes()
434 {
435 String[] split = excludedScopes == null ? new String[0] : excludedScopes.split( "," );
436 return Arrays.asList( split );
437 }
438
439 public void setExcludedScopes( String excludedScopes )
440 {
441 this.excludedScopes = excludedScopes;
442 }
443
444
445
446
447 public List<String> getIncludedScopes()
448 {
449 String[] split = includedScopes == null ? new String[0] : includedScopes.split( "," );
450 return Arrays.asList( split );
451 }
452
453 public void setIncludedScopes( String includedScopes )
454 {
455 this.includedScopes = includedScopes;
456 }
457
458
459
460
461
462
463 public String getIncludedArtifacts()
464 {
465 return null;
466 }
467
468
469
470
471
472
473 public String getIncludedGroups()
474 {
475 return null;
476 }
477
478
479
480
481
482
483 public String getExcludedGroups()
484 {
485 return null;
486 }
487
488
489
490
491
492
493 public String getExcludedArtifacts()
494 {
495 return null;
496 }
497
498
499
500
501 public boolean isVerbose()
502 {
503 return getLog().isDebugEnabled();
504 }
505 }