net.nicoulaj.maven.plugins.checksum.mojo.DependenciesCheckMojo Maven / Gradle / Ivy
/*
* checksum-maven-plugin - http://checksum-maven-plugin.nicoulaj.net
* Copyright © 2010-2021 checksum-maven-plugin contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.nicoulaj.maven.plugins.checksum.mojo;
import net.nicoulaj.maven.plugins.checksum.digest.DigesterException;
import net.nicoulaj.maven.plugins.checksum.digest.DigesterFactory;
import net.nicoulaj.maven.plugins.checksum.digest.FileDigester;
import net.nicoulaj.maven.plugins.checksum.execution.ExecutionException;
import net.nicoulaj.maven.plugins.checksum.execution.target.CsvSummaryFileTarget;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.utils.io.FileUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
/**
* checks the summary file (csv) against the project dependencies.
*
* @author Gunnar Tjarks
* @since 1.8
* @version $Id: $Id
*/
@Mojo(
name = DependenciesCheckMojo.NAME,
defaultPhase = LifecyclePhase.VERIFY,
requiresProject = true,
inheritByDefault = false,
requiresDependencyResolution = ResolutionScope.RUNTIME,
threadSafe = true)
public class DependenciesCheckMojo extends AbstractMojo
{
/**
* The mojo name.
*/
public static final String NAME = "check";
/**
* The Maven project.
*/
@Parameter(property = "project", required = true, readonly = true)
protected MavenProject project;
/**
* The name of the summary file.
*/
@Parameter(property = "csvSummaryFile", defaultValue = "dependencies-checksums.csv")
protected String csvSummaryFile;
/**
* The dependency scopes to include.
*
* Allowed values are compile, test, runtime, provided and system.
All scopes are included by default.
*
*
Use the following syntax:
*
<scopes>
* <scope>compile<scope>
* <scope>runtime<scope>
* </scopes>
*
* @since 1.0
*/
@Parameter
protected List scopes;
/**
* The dependency types to include.
*
* All types are included by default.
*
*
* Use the following syntax:
*
* <types>
* <type>jar<type>
* <type>zip<type>
* </types>
*
*/
@Parameter
protected List types;
/**
* Transitive dependencies or direct dependencies only.
*/
@Parameter(property = "transitive", defaultValue = "false")
protected boolean transitive;
/**
* Flag used to suppress execution.
*/
@Parameter(property = "checksum.skip", defaultValue = "false")
protected boolean skip;
/**
* Flag used to allow execution for pom packaging.
*/
@Parameter(property = "checksum.pom.skip", defaultValue = "true")
protected boolean pomSkip;
/** {@inheritDoc} */
@Override
public void execute() throws MojoFailureException
{
if (skip)
{
getLog().info("Skipping checksum:check execution because property checksum.skip is set.");
}
else if (pomSkip && skipPackaging("pom"))
{
getLog().warn("The goal is skipped due to packaging '" + project.getPackaging() + "'. You can override this using checksum.pom.skip=false property.");
}
else
{
try
{
File summaryFile = FileUtils.resolveFile(new File(project.getBasedir().getAbsolutePath()),
csvSummaryFile);
// 1. read summeryFile
Map> summaryFileContent = readSummaryFile(summaryFile);
// 2. dependency check
checkDependencies(summaryFileContent);
}
catch (ExecutionException e)
{
getLog().error(e.getMessage());
throw new MojoFailureException(e.getMessage());
}
}
}
/**
* @param packagings the packagings to skip
* @return {@code true} if the project's packaging is in the given ones.
*/
private boolean skipPackaging(String... packagings)
{
String projectPackaging = project.getPackaging();
return Arrays.asList(packagings).contains(projectPackaging);
}
private void checkDependencies(Map> summaryFileContent)
throws ExecutionException
{
for ( Artifact artifact : getArtifactsToProcess() )
{
Map fileHashcodes = summaryFileContent.get(artifact.getFile().getName());
if (fileHashcodes == null)
{
throw new ExecutionException("Artifact " + artifact + " is not in summary file content!");
}
for ( Map.Entry fileHashcode : fileHashcodes.entrySet() )
{
process(fileHashcode.getKey(), artifact, fileHashcode.getValue());
}
}
}
private void process(String algorithm, Artifact artifact, String hash) throws ExecutionException
{
File file = artifact.getFile();
try
{
// Calculate the hash for the file/algo
FileDigester digester = DigesterFactory.getInstance().getFileDigester(algorithm);
String calculatedHash = digester.calculate(file);
if (!calculatedHash.equals(hash))
{
throw new ExecutionException("The dependency hash value '" + calculatedHash + "' of file '" + file
+ "' does not equal the hash value '" + hash
+ "' stored in the summary file!");
}
getLog().debug(artifact + " (" + file + ") - " + algorithm + " : " + calculatedHash + " = " + hash);
}
catch (NoSuchAlgorithmException e)
{
throw new ExecutionException("Unsupported algorithm " + algorithm + ".");
}
catch (DigesterException e)
{
throw new ExecutionException("Unable to calculate " + algorithm + " hash for " + file.getName() + ": "
+ e.getMessage());
}
}
private List getArtifactsToProcess()
{
List result = new LinkedList<>();
Set allProjectModules = new HashSet<>();
allModules(project, allProjectModules);
Set artifacts = transitive ? project.getArtifacts() : project.getDependencyArtifacts();
for ( Artifact artifact : artifacts )
{
if (!allProjectModules.contains(artifact) && (scopes == null || scopes.contains(artifact.getScope()))
&& (types == null || types.contains(artifact.getType())))
{
getLog().debug(String.format("check artifact %s", artifact));
result.add(artifact);
}
}
return result;
}
private void allModules(MavenProject mavenProject, Set result)
{
if (result.contains(mavenProject.getArtifact()))
{
return;
}
result.add(mavenProject.getArtifact());
List modules = new ArrayList<>();
if (mavenProject.hasParent())
{
modules.add(mavenProject.getParent());
}
List collectedProjects = mavenProject.getCollectedProjects();
if (collectedProjects != null)
{
modules.addAll(collectedProjects);
}
for ( MavenProject module : modules )
{
allModules(module, result);
}
}
/**
* Read the summary file
*
* @param outputFile the summary file
* @return the summary content (>)
* @throws ExecutionException if an error happens while running the execution.
*/
private Map> readSummaryFile(File outputFile) throws ExecutionException
{
List algorithms = new ArrayList<>();
Map> filesHashcodes = new HashMap<>();
try ( BufferedReader reader = new BufferedReader( new FileReader( outputFile ) ) )
{
String line;
while ( ( line = reader.readLine() ) != null )
{
// Read the CVS file header
if ( isFileHeader( line ) )
{
readFileHeader( line, algorithms );
}
else
{
// Read the dependencies checksums
readDependenciesChecksums( line, algorithms, filesHashcodes );
}
}
}
catch ( IOException e )
{
throw new ExecutionException( e.getMessage() );
}
return filesHashcodes;
}
private boolean isFileHeader(String line)
{
return line.startsWith(CsvSummaryFileTarget.CSV_COMMENT_MARKER + "File");
}
private void readFileHeader(String line, List algorithms)
{
// #File,sha1,md5,...
String[] split = line.split(CsvSummaryFileTarget.CSV_COLUMN_SEPARATOR);
algorithms.addAll( Arrays.asList( split ).subList( 1, split.length ) );
}
private void readDependenciesChecksums(String line,
List algorithms,
Map> filesHashcodes)
{
String[] split = line.split(CsvSummaryFileTarget.CSV_COLUMN_SEPARATOR);
String fileName = split[0];
Map fileHashcodes = new HashMap<>();
for ( int i = 1 ; i < split.length ; i++ )
{
fileHashcodes.put(algorithms.get(i - 1), split[i]);
}
filesHashcodes.put(fileName, fileHashcodes);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy