|
| 1 | +/* |
| 2 | + * SPDX-License-Identifier: Apache-2.0 |
| 3 | + * Copyright Red Hat Inc. and Hibernate Authors |
| 4 | + */ |
| 5 | +package org.hibernate.search.build.enforcer; |
| 6 | + |
| 7 | +import java.util.ArrayList; |
| 8 | +import java.util.List; |
| 9 | +import java.util.Set; |
| 10 | + |
| 11 | +import javax.inject.Inject; |
| 12 | +import javax.inject.Named; |
| 13 | + |
| 14 | +import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule; |
| 15 | +import org.apache.maven.enforcer.rule.api.EnforcerRuleException; |
| 16 | +import org.apache.maven.execution.MavenSession; |
| 17 | +import org.apache.maven.model.Dependency; |
| 18 | +import org.apache.maven.model.Plugin; |
| 19 | +import org.apache.maven.model.PluginExecution; |
| 20 | +import org.apache.maven.project.DefaultDependencyResolutionRequest; |
| 21 | +import org.apache.maven.project.DependencyResolutionException; |
| 22 | +import org.apache.maven.project.DependencyResolutionResult; |
| 23 | +import org.apache.maven.project.MavenProject; |
| 24 | +import org.apache.maven.project.ProjectDependenciesResolver; |
| 25 | +import org.codehaus.plexus.util.xml.Xpp3Dom; |
| 26 | +import org.eclipse.aether.util.filter.AndDependencyFilter; |
| 27 | +import org.eclipse.aether.util.filter.ExclusionsDependencyFilter; |
| 28 | +import org.eclipse.aether.util.filter.ScopeDependencyFilter; |
| 29 | + |
| 30 | +@Named("allLuceneNextDependenciesCopiedRule") // rule name - must start with lowercase character |
| 31 | +public class AllLuceneNextDependenciesCopiedRule extends AbstractEnforcerRule { |
| 32 | + |
| 33 | + private static final String DEPENDENCY_PLUGIN = "org.apache.maven.plugins:maven-dependency-plugin"; |
| 34 | + private static final String EXECUTION_COPY = "copy-dependencies-lucene-next"; |
| 35 | + private static final String LUCENE_NEXT_ARTIFACT_ID = "hibernate-search-backend-lucene-next"; |
| 36 | + // Inject needed Maven components |
| 37 | + @Inject |
| 38 | + private MavenSession session; |
| 39 | + |
| 40 | + @Inject |
| 41 | + private ProjectDependenciesResolver dependenciesResolver; |
| 42 | + |
| 43 | + /** |
| 44 | + * Rule parameter as list of items. |
| 45 | + */ |
| 46 | + private Set<Dependency> dependenciesToSkip; |
| 47 | + |
| 48 | + public void execute() throws EnforcerRuleException { |
| 49 | + Plugin plugin = session.getCurrentProject().getPlugin( DEPENDENCY_PLUGIN ); |
| 50 | + if ( plugin == null ) { |
| 51 | + throw new EnforcerRuleException( "Project %s:%s does not configure the Dependency plugin (%s)!" |
| 52 | + .formatted( session.getCurrentProject().getGroupId(), session.getCurrentProject().getArtifactId(), |
| 53 | + DEPENDENCY_PLUGIN |
| 54 | + ) ); |
| 55 | + } |
| 56 | + |
| 57 | + PluginExecution execution = plugin.getExecutionsAsMap().get( EXECUTION_COPY ); |
| 58 | + if ( execution == null ) { |
| 59 | + throw new EnforcerRuleException( "Project %s:%s does not configure the Dependency plugin (%s) execution \"%s\"!" |
| 60 | + .formatted( session.getCurrentProject().getGroupId(), session.getCurrentProject().getArtifactId(), |
| 61 | + DEPENDENCY_PLUGIN, EXECUTION_COPY |
| 62 | + ) ); |
| 63 | + } |
| 64 | + |
| 65 | + if ( execution.getConfiguration() instanceof Xpp3Dom configuration ) { |
| 66 | + Xpp3Dom artifactItems = configuration.getChild( "artifactItems" ); |
| 67 | + if ( artifactItems == null ) { |
| 68 | + throw new EnforcerRuleException( |
| 69 | + "Project %s:%s does not specify the Javadoc plugin (%s) execution \"%s\" sourcepath configuration attribute!" |
| 70 | + .formatted( session.getCurrentProject().getGroupId(), |
| 71 | + session.getCurrentProject().getArtifactId(), |
| 72 | + DEPENDENCY_PLUGIN, EXECUTION_COPY |
| 73 | + ) ); |
| 74 | + } |
| 75 | + |
| 76 | + MavenProject luceneNextProject = session.getAllProjects().stream() |
| 77 | + .filter( p -> "jar".equals( p.getPackaging() ) && LUCENE_NEXT_ARTIFACT_ID.equals( p.getArtifactId() ) ) |
| 78 | + .findFirst() |
| 79 | + .orElseThrow( |
| 80 | + () -> new EnforcerRuleException( "%s is not available, cannot determine required dependencies." |
| 81 | + .formatted( LUCENE_NEXT_ARTIFACT_ID ) ) ); |
| 82 | + |
| 83 | + List<org.eclipse.aether.graph.Dependency> dependencies = resolveDependencies( luceneNextProject ); |
| 84 | + List<Dependency> redundantDependencies = new ArrayList<>(); |
| 85 | + |
| 86 | + |
| 87 | + for ( Xpp3Dom artifact : artifactItems.getChildren() ) { |
| 88 | + if ( !dependencies |
| 89 | + .removeIf( dep -> dep.getArtifact().getGroupId().equals( artifact.getChild( "groupId" ).getValue() ) |
| 90 | + && dep.getArtifact().getArtifactId().equals( artifact.getChild( "artifactId" ).getValue() ) |
| 91 | + && dep.getArtifact().getVersion().equals( artifact.getChild( "version" ).getValue() ) ) ) { |
| 92 | + Dependency dependency = new Dependency(); |
| 93 | + dependency.setGroupId( artifact.getChild( "groupId" ).getValue() ); |
| 94 | + dependency.setArtifactId( artifact.getChild( "artifactId" ).getValue() ); |
| 95 | + dependency.setVersion( artifact.getChild( "version" ).getValue() ); |
| 96 | + redundantDependencies.add( dependency ); |
| 97 | + } |
| 98 | + } |
| 99 | + |
| 100 | + if ( !dependencies.isEmpty() ) { |
| 101 | + throw new EnforcerRuleException( |
| 102 | + "Some Lucene next backend dependencies are missing: %s".formatted( dependencies ) ); |
| 103 | + } |
| 104 | + if ( !redundantDependencies.isEmpty() ) { |
| 105 | + throw new EnforcerRuleException( |
| 106 | + "Some Lucene next backend dependencies are redundant: %s".formatted( redundantDependencies ) ); |
| 107 | + } |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + private List<org.eclipse.aether.graph.Dependency> resolveDependencies(MavenProject luceneNextProject) { |
| 112 | + try { |
| 113 | + DependencyResolutionResult result = dependenciesResolver |
| 114 | + .resolve( new DefaultDependencyResolutionRequest( luceneNextProject, session.getRepositorySession() ) |
| 115 | + .setResolutionFilter( |
| 116 | + new AndDependencyFilter( |
| 117 | + // we skip test dependencies |
| 118 | + new ScopeDependencyFilter( "test" ), |
| 119 | + // and the ones we explicitly asked to skip: |
| 120 | + new ExclusionsDependencyFilter( dependenciesToSkip.stream() |
| 121 | + .map( d -> d.getGroupId() + ":" + d.getArtifactId() ).toList() ) |
| 122 | + ) ) ); |
| 123 | + return result.getDependencies(); |
| 124 | + } |
| 125 | + catch (DependencyResolutionException e) { |
| 126 | + throw new RuntimeException( e ); |
| 127 | + } |
| 128 | + } |
| 129 | +} |
0 commit comments