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