/*
* #%L
* License Maven Plugin
*
* $Id$
* $HeadURL$
* %%
* Copyright (C) 2008 - 2011 CodeLutin, Codehaus, Tony Chemit
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.codehaus.mojo.license;
import org.apache.commons.collections.CollectionUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
/**
* Goal to generate the third-party license file.
* <p/>
* This file contains a list of the dependencies and their licenses. Each dependency and it's
* license is displayed on a single line in the format <br/>
* <pre>
* (<license-name>) <project-name> <groupId>:<artifactId>:<version> - <project-url>
* </pre>
* It will also copy it in the class-path (says add the generated directory as
* a resource of the build).
*
* @author tchemit <chemit@codelutin.com>
* @goal add-third-party
* @phase generate-resources
* @requiresDependencyResolution test
* @requiresProject true
* @since 1.0
*/
public class AddThirdPartyMojo
extends AbstractAddThirdPartyMojo
implements MavenProjectDependenciesLoader
{
/**
* Local Repository.
*
* @parameter expression="${localRepository}"
* @required
* @readonly
* @since 1.0.0
*/
protected ArtifactRepository localRepository;
/**
* Remote repositories used for the project.
*
* @parameter expression="${project.remoteArtifactRepositories}"
* @required
* @readonly
* @since 1.0.0
*/
protected List<?> remoteRepositories;
/**
* Maven Project Builder component.
*
* @component
* @required
* @readonly
* @since 1.0.0
*/
protected MavenProjectBuilder mavenProjectBuilder;
private boolean doGenerateMissing;
@Override
protected boolean checkPackaging()
{
return rejectPackaging( "pom" );
}
@Override
protected SortedMap<String, MavenProject> loadDependencies()
{
return ArtifactHelper.loadProjectDependencies( this, getLog(), getArtifactCache() );
}
@Override
protected SortedProperties createUnsafeMapping()
throws ProjectBuildingException, IOException
{
SortedProperties unsafeMappings =
getLicenseMap().loadUnsafeMapping( getArtifactCache(), getEncoding(), getMissingFile() );
SortedSet<MavenProject> unsafeDependencies = getUnsafeDependencies();
if ( isVerbose() )
{
getLog().info( "found " + unsafeMappings.size() + " unsafe mappings" );
}
// compute if missing file should be (re)-generate
boolean generateMissingfile = computeDoGenerateMissingFile( unsafeMappings, unsafeDependencies );
setDoGenerateMissing( generateMissingfile );
if ( generateMissingfile && isVerbose() )
{
StringBuilder sb = new StringBuilder();
sb.append( "Will use from missing file " );
sb.append( unsafeMappings.size() );
sb.append( " dependencies :" );
for ( Map.Entry<Object, Object> entry : unsafeMappings.entrySet() )
{
String id = (String) entry.getKey();
String license = (String) entry.getValue();
sb.append( "\n - " ).append( id ).append( " - " ).append( license );
}
getLog().info( sb.toString() );
}
else
{
if ( isUseMissingFile() && !unsafeMappings.isEmpty() )
{
getLog().info( "Missing file " + getMissingFile() + " is up-to-date." );
}
}
return unsafeMappings;
}
/**
* @param unsafeMappings the unsafe mapping coming from the missing file
* @param unsafeDependencies the unsafe dependencies from the project
* @return {@code true} if missing ifle should be (re-)generated, {@code false} otherwise
* @throws IOException if any IO problem
* @since 1.0
*/
protected boolean computeDoGenerateMissingFile( SortedProperties unsafeMappings,
SortedSet<MavenProject> unsafeDependencies )
throws IOException
{
if ( !isUseMissingFile() )
{
// never use the missing file
return false;
}
if ( isForce() )
{
// the mapping fro missing file is not empty, regenerate it
return !CollectionUtils.isEmpty( unsafeMappings.keySet() );
}
else
{
if ( !CollectionUtils.isEmpty( unsafeDependencies ) )
{
// there is some unsafe dependencies from the project, must
// regenerate missing file
return true;
}
// check if the missing file has changed
SortedProperties oldUnsafeMappings = new SortedProperties( getEncoding() );
oldUnsafeMappings.load( getMissingFile() );
return !unsafeMappings.equals( oldUnsafeMappings );
}
}
@Override
protected boolean checkSkip()
{
if ( !isDoGenerate() && !isDoGenerateBundle() && !isDoGenerateMissing() )
{
getLog().info( "All files are up to date, skip goal execution." );
return false;
}
return true;
}
@Override
protected void doAction()
throws Exception
{
boolean unsafe = checkUnsafeDependencies();
writeThirdPartyFile();
if ( isDoGenerateMissing() )
{
writeMissingFile();
}
if ( unsafe && isFailIfWarning() )
{
throw new MojoFailureException(
"There is some dependencies with no license, please fill the file " + getMissingFile() );
}
addResourceDir( getOutputDirectory(), "**/*.txt" );
}
protected void writeMissingFile()
throws IOException
{
Log log = getLog();
LicenseMap licenseMap = getLicenseMap();
File file = getMissingFile();
FileUtil.createDirectoryIfNecessary( file.getParentFile() );
log.info( "Regenerate missing license file " + file );
FileOutputStream writer = new FileOutputStream( file );
try
{
StringBuilder sb = new StringBuilder( " Generated by " + getClass().getName() );
List<String> licenses = new ArrayList<String>( licenseMap.keySet() );
licenses.remove( LicenseMap.getUnknownLicenseMessage() );
if ( !licenses.isEmpty() )
{
sb.append( "\n-------------------------------------------------------------------------------" );
sb.append( "\n Already used licenses in project :" );
for ( String license : licenses )
{
sb.append( "\n - " ).append( license );
}
}
sb.append( "\n-------------------------------------------------------------------------------" );
sb.append( "\n Please fill the missing licenses for dependencies :\n\n" );
getUnsafeMappings().store( writer, sb.toString() );
}
finally
{
writer.close();
}
}
public boolean isDoGenerateMissing()
{
return doGenerateMissing;
}
public void setDoGenerateMissing( boolean doGenerateMissing )
{
this.doGenerateMissing = doGenerateMissing;
}
public ArtifactRepository getLocalRepository()
{
return localRepository;
}
public List<?> getRemoteRepositories()
{
return remoteRepositories;
}
public MavenProjectBuilder getMavenProjectBuilder()
{
return mavenProjectBuilder;
}
public boolean isIncludeTransitiveDependencies()
{
return includeTransitiveDependencies;
}
public List<String> getExcludeScopes()
{
return Arrays.asList( Artifact.SCOPE_SYSTEM );
}
}