diff --git a/maven-repository-reports-standard/pom.xml b/maven-repository-reports-standard/pom.xml index 792359141..bbead04d7 100755 --- a/maven-repository-reports-standard/pom.xml +++ b/maven-repository-reports-standard/pom.xml @@ -61,5 +61,9 @@ org.apache.maven.repository maven-repository-utils + + org.apache.maven.repository + maven-repository-indexer + diff --git a/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/DuplicateArtifactFileReportProcessor.java b/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/DuplicateArtifactFileReportProcessor.java new file mode 100644 index 000000000..598531fbd --- /dev/null +++ b/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/DuplicateArtifactFileReportProcessor.java @@ -0,0 +1,170 @@ +package org.apache.maven.repository.reporting; + +/* + * Copyright 2005-2006 The Apache Software Foundation. + * + * 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. + */ + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.model.Model; +import org.apache.maven.repository.digest.DefaultDigester; +import org.apache.maven.repository.digest.Digester; +import org.apache.maven.repository.indexing.DefaultRepositoryIndexingFactory; +import org.apache.maven.repository.indexing.RepositoryIndex; +import org.apache.maven.repository.indexing.RepositoryIndexException; +import org.apache.maven.repository.indexing.RepositoryIndexSearchException; +import org.apache.maven.repository.indexing.RepositoryIndexSearchLayer; +import org.apache.maven.repository.indexing.RepositoryIndexingFactory; +import org.apache.maven.repository.indexing.SearchResult; +import org.apache.maven.repository.indexing.query.Query; +import org.apache.maven.repository.indexing.query.SinglePhraseQuery; + +import java.io.File; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.Iterator; +import java.util.List; + +/** + * Validates an artifact file for duplicates within the same groupId based from what's available in a RepositoryIndex + * + * @author Edwin Punzalan + */ +public class DuplicateArtifactFileReportProcessor + implements ArtifactReportProcessor +{ + private Digester digester; + + private RepositoryIndexingFactory indexFactory; + + //@todo configurable? + private String algorithm = RepositoryIndex.FLD_MD5; + + private RepositoryIndexSearchLayer searchLayer; + + //@todo must be injected + private ArtifactFactory artifactFactory; + + public void processArtifact( Model model, Artifact artifact, ArtifactReporter reporter, + ArtifactRepository repository ) + throws ReportProcessorException + { + if ( artifact.getFile() != null ) + { + //@todo remove hard-coded value; current value enables tests to pass + String indexPath = new File( "target/.index" ).getAbsolutePath(); + + //@todo may be injected? + if ( digester == null ) + { + digester = new DefaultDigester(); + } + + //@todo may be injected? + if ( indexFactory == null ) + { + indexFactory = new DefaultRepositoryIndexingFactory(); + } + + RepositoryIndex index; + try + { + index = indexFactory.createArtifactRepositoryIndex( indexPath, repository ); + } + catch ( RepositoryIndexException e ) + { + throw new ReportProcessorException( "Unable to create RepositoryIndex instance", e ); + } + + if ( searchLayer == null ) + { + searchLayer = new RepositoryIndexSearchLayer( index, artifactFactory ); + } + + String checksum; + try + { + checksum = digester.createChecksum( artifact.getFile(), algorithm ); + } + catch ( IOException e ) + { + throw new ReportProcessorException( "Failed to generate checksum", e ); + } + catch ( NoSuchAlgorithmException e ) + { + throw new ReportProcessorException( "Failed to generate checksum", e ); + } + + Query query = new SinglePhraseQuery( algorithm, checksum.trim() ); + + try + { + List results = searchLayer.searchAdvanced( query ); + + if ( results.isEmpty() ) + { + reporter.addSuccess( artifact ); + } + else + { + String id = artifact.getId(); + + boolean hasDuplicates = false; + for ( Iterator hits = results.iterator(); hits.hasNext(); ) + { + SearchResult result = (SearchResult) hits.next(); + Artifact artifactMatch = result.getArtifact(); + + //make sure it is not the same artifact + if ( !id.equals( artifactMatch.getId() ) ) + { + //report only duplicates from the same groupId + String groupId = artifact.getGroupId(); + if ( groupId.equals( artifactMatch.getGroupId() ) ) + { + hasDuplicates = true; + reporter.addFailure( artifact, "Found duplicate for " + artifactMatch.getId() ); + } + } + } + + if ( !hasDuplicates ) + { + reporter.addSuccess( artifact ); + } + } + } + catch ( RepositoryIndexSearchException e ) + { + throw new ReportProcessorException( "Failed to search in index", e ); + } + } + else + { + reporter.addWarning( artifact, "Artifact file is null" ); + } + } + + public ArtifactFactory getArtifactFactory() + { + return artifactFactory; + } + + public void setArtifactFactory( ArtifactFactory artifactFactory ) + { + this.artifactFactory = artifactFactory; + } +} diff --git a/maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/DuplicateArtifactFileReportProcessorTest.java b/maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/DuplicateArtifactFileReportProcessorTest.java new file mode 100644 index 000000000..70d617263 --- /dev/null +++ b/maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/DuplicateArtifactFileReportProcessorTest.java @@ -0,0 +1,127 @@ +package org.apache.maven.repository.reporting; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.model.Model; +import org.apache.maven.repository.digest.DefaultDigester; +import org.apache.maven.repository.indexing.ArtifactRepositoryIndex; +import org.codehaus.plexus.util.FileUtils; + +import java.io.File; + +/** + * @author Edwin Punzalan + */ +public class DuplicateArtifactFileReportProcessorTest + extends AbstractRepositoryReportsTestCase +{ + private MockArtifactReporter reporter; + + private Artifact artifact; + + private Model model; + + private DuplicateArtifactFileReportProcessor processor; + + private ArtifactFactory artifactFactory; + + private String indexPath = new File( "target/.index" ).getAbsolutePath(); + + protected void setUp() + throws Exception + { + super.setUp(); + artifactFactory = (ArtifactFactory) lookup( ArtifactFactory.class.getName() ); + reporter = new MockArtifactReporter(); + artifact = createArtifact( "groupId", "artifactId", "1.0-alpha-1", "1.0-alpha-1", "jar" ); + model = new Model(); + processor = new DuplicateArtifactFileReportProcessor(); + processor.setArtifactFactory( artifactFactory ); + + ArtifactRepositoryIndex index = new ArtifactRepositoryIndex( indexPath, repository, new DefaultDigester() ); + index.indexArtifact( artifact ); + index.optimize(); + index.close(); + } + + protected void tearDown() + throws Exception + { + FileUtils.deleteDirectory( indexPath ); + + processor = null; + model = null; + artifact = null; + reporter = null; + super.tearDown(); + } + + public void testNullArtifactFile() + throws Exception + { + artifact.setFile( null ); + + processor.processArtifact( model, artifact, reporter, repository ); + + assertEquals( "Check no successes", 0, reporter.getSuccesses() ); + assertEquals( "Check warnings", 1, reporter.getWarnings() ); + assertEquals( "Check no failures", 0, reporter.getFailures() ); + } + + public void testSuccessOnAlreadyIndexedArtifact() + throws Exception + { + processor.processArtifact( model, artifact, reporter, repository ); + + assertEquals( "Check no successes", 1, reporter.getSuccesses() ); + assertEquals( "Check warnings", 0, reporter.getWarnings() ); + assertEquals( "Check no failures", 0, reporter.getFailures() ); + } + + public void testSuccessOnDifferentGroupId() + throws Exception + { + artifact.setGroupId( "different.groupId" ); + processor.processArtifact( model, artifact, reporter, repository ); + + assertEquals( "Check no successes", 1, reporter.getSuccesses() ); + assertEquals( "Check warnings", 0, reporter.getWarnings() ); + assertEquals( "Check no failures", 0, reporter.getFailures() ); + } + + public void testSuccessOnNewArtifact() + throws Exception + { + Artifact newArtifact = createArtifact( "groupId", "artifactId", "1.0-alpha-1", "1.0-alpha-1", "pom" ); + + processor.processArtifact( model, newArtifact, reporter, repository ); + + assertEquals( "Check no successes", 1, reporter.getSuccesses() ); + assertEquals( "Check warnings", 0, reporter.getWarnings() ); + assertEquals( "Check no failures", 0, reporter.getFailures() ); + } + + public void testFailure() + throws Exception + { + Artifact duplicate = createArtifact( artifact.getGroupId(), "snapshot-artifact", "1.0-alpha-1-SNAPSHOT", + artifact.getVersion(), artifact.getType() ); + duplicate.setFile( artifact.getFile() ); + + processor.processArtifact( model, duplicate, reporter, repository ); + + assertEquals( "Check no successes", 0, reporter.getSuccesses() ); + assertEquals( "Check warnings", 0, reporter.getWarnings() ); + assertEquals( "Check no failures", 1, reporter.getFailures() ); + } + + private Artifact createArtifact( String groupId, String artifactId, String baseVersion, String version, + String type ) + { + Artifact artifact = artifactFactory.createArtifact( groupId, artifactId, version, null, type ); + artifact.setBaseVersion( baseVersion ); + artifact.setRepository( repository ); + artifact.setFile( new File( repository.getBasedir(), repository.pathOf( artifact ) ) ); + return artifact; + } +}