001 /* 002 * #%L 003 * License Maven Plugin 004 * 005 * $Id: AddThirdPartyMojo.java 14420 2011-08-11 10:00:24Z tchemit $ 006 * $HeadURL: http://svn.codehaus.org/mojo/tags/license-maven-plugin-1.0/src/main/java/org/codehaus/mojo/license/AddThirdPartyMojo.java $ 007 * %% 008 * Copyright (C) 2008 - 2011 CodeLutin, Codehaus, Tony Chemit 009 * %% 010 * This program is free software: you can redistribute it and/or modify 011 * it under the terms of the GNU Lesser General Public License as 012 * published by the Free Software Foundation, either version 3 of the 013 * License, or (at your option) any later version. 014 * 015 * This program is distributed in the hope that it will be useful, 016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 018 * GNU General Lesser Public License for more details. 019 * 020 * You should have received a copy of the GNU General Lesser Public 021 * License along with this program. If not, see 022 * <http://www.gnu.org/licenses/lgpl-3.0.html>. 023 * #L% 024 */ 025 026 package org.codehaus.mojo.license; 027 028 import java.io.File; 029 import java.io.FileOutputStream; 030 import java.io.IOException; 031 import java.util.ArrayList; 032 import java.util.Collection; 033 import java.util.List; 034 import java.util.Map; 035 import java.util.SortedMap; 036 import java.util.SortedSet; 037 038 import org.apache.commons.collections.CollectionUtils; 039 import org.apache.commons.collections.MapUtils; 040 import org.apache.maven.artifact.repository.ArtifactRepository; 041 import org.apache.maven.plugin.MojoFailureException; 042 import org.apache.maven.plugin.logging.Log; 043 import org.apache.maven.project.MavenProject; 044 import org.apache.maven.project.ProjectBuildingException; 045 import org.codehaus.mojo.license.model.LicenseMap; 046 047 /** 048 * Goal to generate the third-party license file. 049 * <p/> 050 * This file contains a list of the dependencies and their licenses. Each dependency and it's license is displayed on a 051 * single line in the format <br/> 052 * 053 * <pre> 054 * (<license-name>) <project-name> <groupId>:<artifactId>:<version> - <project-url> 055 * </pre> 056 * 057 * It will also copy it in the class-path (says add the generated directory as a resource of the build). 058 * 059 * @author tchemit <chemit@codelutin.com> 060 * @goal add-third-party 061 * @phase generate-resources 062 * @requiresDependencyResolution test 063 * @requiresProject true 064 * @since 1.0 065 */ 066 public class AddThirdPartyMojo extends AbstractAddThirdPartyMojo implements MavenProjectDependenciesConfigurator { 067 068 /** 069 * Local Repository. 070 * 071 * @parameter expression="${localRepository}" 072 * @required 073 * @readonly 074 * @since 1.0.0 075 */ 076 protected ArtifactRepository localRepository; 077 078 /** 079 * Remote repositories used for the project. 080 * 081 * @parameter expression="${project.remoteArtifactRepositories}" 082 * @required 083 * @readonly 084 * @since 1.0.0 085 */ 086 protected List remoteRepositories; 087 088 /** 089 * Deploy the third party missing file in maven repository. 090 * 091 * @parameter expression="${license.deployMissingFile}" default-value="true" 092 * @since 1.0 093 */ 094 protected boolean deployMissingFile; 095 096 /** 097 * Load from repositories third party missing files. 098 * 099 * @parameter expression="${license.useRepositoryMissingFiles}" default-value="true" 100 * @since 1.0 101 */ 102 protected boolean useRepositoryMissingFiles; 103 104 /** 105 * dependencies tool. 106 * 107 * @component 108 * @readonly 109 * @since 1.0 110 */ 111 private DependenciesTool dependenciesTool; 112 113 /** 114 * Controls if THIRD-PARTY.properties gets created or not 115 * 116 * @parameter expression="${license.doGenerateMissing}" default-value="false" 117 */ 118 private boolean doGenerateMissing; 119 120 @Override 121 protected boolean checkPackaging() { 122 return rejectPackaging("pom"); 123 } 124 125 @Override 126 protected SortedMap<String, MavenProject> loadDependencies() { 127 return dependenciesTool.loadProjectDependencies(getProject(), this, localRepository, remoteRepositories, 128 getArtifactCache()); 129 } 130 131 @Override 132 protected SortedProperties createUnsafeMapping() throws ProjectBuildingException, IOException, 133 ThirdPartyToolException { 134 135 SortedProperties unsafeMappings = getThridPartyTool().loadUnsafeMapping(getLicenseMap(), getArtifactCache(), 136 getEncoding(), getMissingFile()); 137 138 SortedSet<MavenProject> unsafeDependencies = getUnsafeDependencies(); 139 140 if (CollectionUtils.isNotEmpty(unsafeDependencies)) { 141 142 // there is some unresolved license 143 144 if (isUseRepositoryMissingFiles()) { 145 146 // try to load missing third party files from dependencies 147 148 Collection<MavenProject> projects = new ArrayList<MavenProject>(getProjectDependencies().values()); 149 projects.remove(getProject()); 150 projects.removeAll(unsafeDependencies); 151 152 SortedProperties resolvedUnsafeMapping = getThridPartyTool().loadThirdPartyDescriptorsForUnsafeMapping( 153 getEncoding(), projects, unsafeDependencies, getLicenseMap(), localRepository, 154 remoteRepositories); 155 156 // push back resolved unsafe mappings 157 unsafeMappings.putAll(resolvedUnsafeMapping); 158 159 } 160 } 161 if (isVerbose()) { 162 getLog().info("found " + unsafeMappings.size() + " unsafe mappings"); 163 } 164 165 // compute if missing file should be (re)-generate 166 boolean generateMissingfile = doGenerateMissing 167 && computeDoGenerateMissingFile(unsafeMappings, unsafeDependencies); 168 169 setDoGenerateMissing(generateMissingfile); 170 171 if (generateMissingfile && isVerbose()) { 172 StringBuilder sb = new StringBuilder(); 173 sb.append("Will use from missing file "); 174 sb.append(unsafeMappings.size()); 175 sb.append(" dependencies :"); 176 for (Map.Entry<Object, Object> entry : unsafeMappings.entrySet()) { 177 String id = (String) entry.getKey(); 178 String license = (String) entry.getValue(); 179 sb.append("\n - ").append(id).append(" - ").append(license); 180 } 181 getLog().info(sb.toString()); 182 } else { 183 if (isUseMissingFile() && !unsafeMappings.isEmpty()) { 184 getLog().debug("Missing file " + getMissingFile() + " is up-to-date."); 185 } 186 } 187 return unsafeMappings; 188 } 189 190 /** 191 * @param unsafeMappings 192 * the unsafe mapping coming from the missing file 193 * @param unsafeDependencies 194 * the unsafe dependencies from the project 195 * @return {@code true} if missing ifle should be (re-)generated, {@code false} otherwise 196 * @throws IOException 197 * if any IO problem 198 * @since 1.0 199 */ 200 protected boolean computeDoGenerateMissingFile(SortedProperties unsafeMappings, 201 SortedSet<MavenProject> unsafeDependencies) throws IOException { 202 203 if (!isUseMissingFile()) { 204 205 // never use the missing file 206 return false; 207 } 208 209 if (isForce()) { 210 211 // the mapping for missing file is not empty, regenerate it 212 return !CollectionUtils.isEmpty(unsafeMappings.keySet()); 213 } 214 215 if (!CollectionUtils.isEmpty(unsafeDependencies)) { 216 217 // there is some unsafe dependencies from the project, must 218 // regenerate missing file 219 return true; 220 } 221 222 File missingFile = getMissingFile(); 223 224 if (!missingFile.exists()) { 225 226 // the missing file does not exists, this happens when 227 // using remote missing file from dependencies 228 return true; 229 } 230 231 // check if the missing file has changed 232 SortedProperties oldUnsafeMappings = new SortedProperties(getEncoding()); 233 oldUnsafeMappings.load(missingFile); 234 return !unsafeMappings.equals(oldUnsafeMappings); 235 } 236 237 @Override 238 protected boolean checkSkip() { 239 if (!isDoGenerate() && !isDoGenerateBundle() && !isDoGenerateMissing()) { 240 241 getLog().info("All files are up to date, skip goal execution."); 242 return false; 243 } 244 return true; 245 } 246 247 @Override 248 protected void doAction() throws Exception { 249 boolean unsafe = checkUnsafeDependencies(); 250 251 writeThirdPartyFile(); 252 253 if (isDoGenerateMissing()) { 254 255 writeMissingFile(); 256 } 257 258 if (unsafe && isFailIfWarning()) { 259 throw new MojoFailureException("There is some dependencies with no license, please fill the file " 260 + getMissingFile()); 261 } 262 263 if (!unsafe && isUseMissingFile() && MapUtils.isEmpty(getUnsafeMappings()) && getMissingFile().exists()) { 264 265 // there is no missing dependencies, but still a missing file, delete it 266 getLog().debug("There is no dependency to put in missing file, delete it at " + getMissingFile()); 267 FileUtil.deleteFile(getMissingFile()); 268 } 269 270 if (!unsafe && isDeployMissingFile() && MapUtils.isNotEmpty(getUnsafeMappings())) { 271 272 // can deploy missing file 273 File file = getMissingFile(); 274 275 getLog().debug("Will deploy third party file from " + file); 276 getThridPartyTool().attachThirdPartyDescriptor(getProject(), file); 277 } 278 279 addResourceDir(getOutputDirectory(), "**/*.txt"); 280 } 281 282 protected void writeMissingFile() throws IOException { 283 284 Log log = getLog(); 285 LicenseMap licenseMap = getLicenseMap(); 286 File file = getMissingFile(); 287 288 FileUtil.createDirectoryIfNecessary(file.getParentFile()); 289 log.info("Regenerate missing license file " + file); 290 291 FileOutputStream writer = new FileOutputStream(file); 292 try { 293 StringBuilder sb = new StringBuilder(" Generated by " + getClass().getName()); 294 List<String> licenses = new ArrayList<String>(licenseMap.keySet()); 295 licenses.remove(LicenseMap.getUnknownLicenseMessage()); 296 if (!licenses.isEmpty()) { 297 sb.append("\n-------------------------------------------------------------------------------"); 298 sb.append("\n Already used licenses in project :"); 299 for (String license : licenses) { 300 sb.append("\n - ").append(license); 301 } 302 } 303 sb.append("\n-------------------------------------------------------------------------------"); 304 sb.append("\n Please fill the missing licenses for dependencies :\n\n"); 305 getUnsafeMappings().store(writer, sb.toString()); 306 } finally { 307 writer.close(); 308 } 309 } 310 311 public boolean isDoGenerateMissing() { 312 return doGenerateMissing; 313 } 314 315 public void setDoGenerateMissing(boolean doGenerateMissing) { 316 this.doGenerateMissing = doGenerateMissing; 317 } 318 319 public ArtifactRepository getLocalRepository() { 320 return localRepository; 321 } 322 323 public List getRemoteRepositories() { 324 return remoteRepositories; 325 } 326 327 /** 328 * {@inheritDoc} 329 */ 330 @Override 331 public boolean isIncludeTransitiveDependencies() { 332 return includeTransitiveDependencies; 333 } 334 335 // /** 336 // * {@inheritDoc} 337 // */ 338 // public List<String> getExcludedScopes() 339 // { 340 // return Arrays.asList( Artifact.SCOPE_SYSTEM ); 341 // } 342 343 public boolean isDeployMissingFile() { 344 return deployMissingFile; 345 } 346 347 public boolean isUseRepositoryMissingFiles() { 348 return useRepositoryMissingFiles; 349 } 350 351 }