Skip to content

Commit

Permalink
Add a javadoc dependency injector
Browse files Browse the repository at this point in the history
When using the javadoc goal to aggregate documentation using configured
source directories there is the problem that also a reference to
projects that are mentioned in the source directories is required.

This adds a new (configurable) injector that adds the projects mentioned
as the source as dependencies of the project.
  • Loading branch information
laeubi committed Nov 12, 2023
1 parent bce5c53 commit c5e6f22
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,41 @@

public final class MavenDependencyInjector {

/**
* Injects a set of additional project dependencies into an existing maven project.
*
* @param project
* @param dependencyProjects
*/
public static void injectMavenProjectDependencies(MavenProject project, Iterable<MavenProject> dependencyProjects) {
Model model = project.getModel();
Set<String> existingDependencies = model.getDependencies().stream().map(MavenDependencyInjector::getProjectKey)
.collect(Collectors.toCollection(HashSet::new));
for (MavenProject dependencyProject : dependencyProjects) {
if (dependencyProject == project) {
continue;
}
Dependency dependency = new Dependency();
dependency.setArtifactId(dependencyProject.getArtifactId());
dependency.setGroupId(dependencyProject.getGroupId());
dependency.setVersion(dependencyProject.getVersion());
String packaging = dependencyProject.getPackaging();
dependency.setType(packaging);
dependency.setScope(Artifact.SCOPE_COMPILE);
dependency.setOptional(false);
if (existingDependencies.add(getProjectKey(dependency))) {
model.addDependency(dependency);
}
}
}

private static String getProjectKey(Dependency dependency) {

return dependency.getGroupId() + ":" + dependency.getArtifactId() + ":"
+ Objects.requireNonNullElse(dependency.getType(), "jar") + ":" + dependency.getVersion() + ":"
+ Objects.requireNonNullElse(dependency.getClassifier(), "");
}

/**
* Injects the dependencies of a project (as determined by the p2 dependency resolver) back into
* the Maven model.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
Expand All @@ -41,11 +40,8 @@

import org.apache.maven.AbstractMavenLifecycleParticipant;
import org.apache.maven.MavenExecutionException;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.io.ModelWriter;
import org.apache.maven.project.MavenProject;
Expand Down Expand Up @@ -158,28 +154,13 @@ public void afterProjectsRead(MavenSession session) throws MavenExecutionExcepti
//do not inject additional dependencies for non Tycho managed projects!
continue;
}
Model model = project.getModel();
Set<String> existingDependencies = model.getDependencies().stream()
.map(TychoMavenLifecycleParticipant::getKey)
.collect(Collectors.toCollection(HashSet::new));
Collection<MavenProject> dependencyProjects = closure.getDependencyProjects(project);
for (MavenProject dependencyProject : dependencyProjects) {
Dependency dependency = new Dependency();
dependency.setArtifactId(dependencyProject.getArtifactId());
dependency.setGroupId(dependencyProject.getGroupId());
dependency.setVersion(dependencyProject.getVersion());
String packaging = dependencyProject.getPackaging();
dependency.setType(packaging);
dependency.setScope(Artifact.SCOPE_COMPILE);
dependency.setOptional(false);
if (existingDependencies.add(getKey(dependency))) {
model.addDependency(dependency);
}
}
MavenDependencyInjector.injectMavenProjectDependencies(project, dependencyProjects);
if (DUMP_DATA) {
try {
Set<MavenProject> visited = new HashSet<>();
modelWriter.write(new File(project.getBasedir(), "pom-model.xml"), Map.of(), model);
modelWriter.write(new File(project.getBasedir(), "pom-model.xml"), Map.of(),
project.getModel());
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(new File(project.getBasedir(), "requirements.txt"))))) {
writer.write(project.getId() + ":\r\n");
Expand Down Expand Up @@ -223,13 +204,6 @@ private void dumpProjectRequirements(MavenProject project, BufferedWriter writer
}
}

private static String getKey(Dependency dependency) {

return dependency.getGroupId() + ":" + dependency.getArtifactId() + ":"
+ Objects.requireNonNullElse(dependency.getType(), "jar") + ":" + dependency.getVersion() + ":"
+ Objects.requireNonNullElse(dependency.getClassifier(), "");
}

@Override
public void afterSessionEnd(MavenSession session) throws MavenExecutionException {
buildListeners.notifyBuildEnd(session);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright (c) 2023 Christoph Läubrich and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.extras.docbundle;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
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;

/**
* This mojo is only there
*/
@Mojo(name = "configure-document-bundle-plugin", defaultPhase = LifecyclePhase.INITIALIZE, requiresDependencyResolution = ResolutionScope.NONE, threadSafe = true)
public class ConfigureMojo extends AbstractMojo {

/**
* name of the parameter to inject javadoc source dependencies
*/
public static final String PARAM_INJECT_JAVADOC_DEPENDENCIES = "injectJavadocDependencies";
@Parameter(name = PARAM_INJECT_JAVADOC_DEPENDENCIES)
private boolean dummyBoolean;

@Override
public void execute() throws MojoExecutionException, MojoFailureException {
throw new MojoFailureException("This mojo is not intended to be ever called");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright (c) 2023 Christoph Läubrich and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.extras.docbundle;

import java.io.File;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import org.apache.maven.execution.MavenSession;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.eclipse.tycho.build.BuildListener;
import org.eclipse.tycho.core.maven.MavenDependencyInjector;
import org.eclipse.tycho.helper.PluginConfigurationHelper;
import org.eclipse.tycho.helper.PluginConfigurationHelper.Configuration;
import org.eclipse.tycho.helper.ProjectHelper;

@Component(role = BuildListener.class, hint = "javadoc")
public class JavadocBuildListener implements BuildListener {

private static final String JAVADOC_GOAL = "javadoc";
private static final String ARTIFACT_ID = "maven-javadoc-plugin";
private static final String GROUP_ID = "org.apache.maven.plugins";

@Requirement
private ProjectHelper projectHelper;

@Requirement
private PluginConfigurationHelper configurationHelper;

@Override
public void buildStarted(MavenSession session) {
List<MavenProject> projects = session.getProjects();
for (MavenProject project : projects) {
if (isJavadocProject(project, session)) {
Configuration configuration = configurationHelper.getConfiguration(GROUP_ID, ARTIFACT_ID, JAVADOC_GOAL,
project, session);
List<MavenProject> additionalProjects = configuration.getString("sourcepath").stream()
.flatMap(sourcepath -> {
return Arrays.stream(sourcepath.split(";|:"));
}).map(s -> s.strip()).map(s -> new File(project.getBasedir(), s).toPath().normalize())
.map(sourcePath -> getProject(sourcePath, projects)).filter(Objects::nonNull).distinct()
.toList();
MavenDependencyInjector.injectMavenProjectDependencies(project, additionalProjects);
}
}

}

private MavenProject getProject(Path sourcePath, List<MavenProject> projects) {
MavenProject match = null;
int matchNameCount = -1;
for (MavenProject mavenProject : projects) {
Path basePath = mavenProject.getBasedir().toPath();
if (sourcePath.startsWith(basePath)) {
int nameCount = basePath.getNameCount();
if (match == null || nameCount > matchNameCount) {
match = mavenProject;
matchNameCount = nameCount;
}
}
}
return match;
}

private boolean isJavadocProject(MavenProject project, MavenSession mavenSession) {
if (projectHelper.hasPluginExecution(GROUP_ID, ARTIFACT_ID, JAVADOC_GOAL, project, mavenSession)) {
Configuration configuration = configurationHelper.getConfiguration(ConfigureMojo.class, project,
mavenSession);
return configuration.getBoolean(ConfigureMojo.PARAM_INJECT_JAVADOC_DEPENDENCIES).orElse(false);
}
return false;
}

@Override
public void buildEnded(MavenSession session) {
// nothing to do...
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.LegacySupport;
import org.apache.maven.plugin.Mojo;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.util.InterpolationFilterReader;
Expand Down Expand Up @@ -58,7 +60,26 @@ public Configuration getConfiguration(Xpp3Dom configuration) {
return new Configuration(configuration);
}

public Configuration getConfiguration(String pluginGroupId, String pluginArtifactId, String goal,
MavenProject project, MavenSession mavenSession) {
return new Configuration(
projectHelper.getPluginConfiguration(pluginGroupId, pluginArtifactId, goal, project, mavenSession));
}

public <M extends Mojo> Configuration getConfiguration(Class<M> mojo) {
MavenSession currentSession = legacySupport.getSession();
if (currentSession == null) {
return getConfiguration((Xpp3Dom) null);
}
MavenProject currentProject = currentSession.getCurrentProject();
if (currentProject == null) {
return getConfiguration((Xpp3Dom) null);
}
return getConfiguration(mojo, currentProject, currentSession);
}

public <M extends Mojo> Configuration getConfiguration(Class<M> mojo, MavenProject project,
MavenSession mavenSession) {
URL resource = mojo.getResource("/META-INF/maven/plugin.xml");
if (resource == null) {
throw new IllegalStateException("can't find plugin descriptor of mojo " + mojo.getName());
Expand All @@ -77,7 +98,7 @@ public <M extends Mojo> Configuration getConfiguration(Class<M> mojo) {
for (MojoDescriptor mojoDescriptor : pluginDescriptor.getMojos()) {
if (mojo.getName().equals(mojoDescriptor.getImplementation())) {
Xpp3Dom configuration = projectHelper.getPluginConfiguration(pluginDescriptor.getGroupId(),
pluginDescriptor.getArtifactId(), mojoDescriptor.getGoal());
pluginDescriptor.getArtifactId(), mojoDescriptor.getGoal(), project, mavenSession);
return getConfiguration(configuration);

}
Expand Down Expand Up @@ -132,6 +153,11 @@ public <E extends Enum<E>> Optional<E> getEnum(String name, Class<E> type) {
});
}

@Override
public String toString() {
return configuration == null ? "-empty configuration-" : String.valueOf(configuration);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public List<Plugin> getPlugins(MavenProject project, MavenSession mavenSession)
* @param goal
* @param project
* @param mavenSession
* @return <code>true</code> if an execution was found or <code>false</code> otherwhise.
* @return <code>true</code> if an execution was found or <code>false</code> otherwise.
*/
public boolean hasPluginExecution(String pluginGroupId, String pluginArtifactId, String goal, MavenProject project,
MavenSession mavenSession) {
Expand Down Expand Up @@ -127,11 +127,14 @@ public Xpp3Dom getPluginConfiguration(String pluginGroupId, String pluginArtifac
if (goal == null) {
return getDom(plugin.getConfiguration());
}
//first check for goal specific configuration
for (PluginExecution execution : plugin.getExecutions()) {
if (execution.getGoals().contains(goal)) {
return getDom(execution.getConfiguration());
}
}
//get plugin config
return getDom(plugin.getConfiguration());
}
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import org.eclipse.tycho.versions.pom.PomFile;
import org.osgi.framework.Version;

@Component(role = BuildListener.class)
@Component(role = BuildListener.class, hint = "version-bump")
public class VersionBumpBuildListener implements BuildListener {

@Requirement
Expand Down Expand Up @@ -79,10 +79,10 @@ public void buildEnded(MavenSession session) {
String newVersion = suggestedVersion.map(String::valueOf)
.orElseGet(() -> Versions.incrementVersion(currentVersion,
VersionBumpMojo.getIncrement(session, project, projectHelper)));
boolean isSnapshot = currentVersion.endsWith(TychoConstants.SUFFIX_SNAPSHOT);
if (isSnapshot) {
newVersion += TychoConstants.SUFFIX_SNAPSHOT;
}
boolean isSnapshot = currentVersion.endsWith(TychoConstants.SUFFIX_SNAPSHOT);
if (isSnapshot) {
newVersion += TychoConstants.SUFFIX_SNAPSHOT;
}
logger.info(project.getId() + " requires a version bump from " + currentVersion + " => "
+ newVersion);
engine.setProjects(metadataReader.getProjects());
Expand Down

0 comments on commit c5e6f22

Please sign in to comment.