diff --git a/src/main/java/org/apache/maven/plugins/antrun/AntRunMojo.java b/src/main/java/org/apache/maven/plugins/antrun/AntRunMojo.java index 5ff1844..20f9a77 100644 --- a/src/main/java/org/apache/maven/plugins/antrun/AntRunMojo.java +++ b/src/main/java/org/apache/maven/plugins/antrun/AntRunMojo.java @@ -429,11 +429,7 @@ public void copyProperties(MavenProject mavenProject, Project antProject) { // Add properties for dependency artifacts Set depArtifacts = mavenProject.getArtifacts(); - for (Artifact artifact : depArtifacts) { - String propName = artifact.getDependencyConflictId(); - - antProject.setProperty(propertyPrefix + propName, artifact.getFile().getPath()); - } + setDependencyFileProperties(depArtifacts, antProject); // Add a property containing the list of versions for the mapper StringBuilder versionsBuffer = new StringBuilder(); @@ -443,6 +439,37 @@ public void copyProperties(MavenProject mavenProject, Project antProject) { antProject.setProperty(versionsPropertyName, versionsBuffer.toString()); } + /** + * Registers one ${propertyPrefix}${dependencyConflictId} property per dependency, + * holding the path to that dependency's artifact file. + *

+ * An artifact's file may be null when it was never resolved, for instance under + * partial or offline resolution. Such dependencies are skipped with a warning naming them, + * rather than aborting the build: the property is simply absent, so a build that never + * references it still runs. + * + * @param depArtifacts the project's dependency artifacts, may be null + * @param antProject the Ant project to set properties on, not null + */ + void setDependencyFileProperties(Set depArtifacts, Project antProject) { + if (depArtifacts == null) { + return; + } + + for (Artifact artifact : depArtifacts) { + String propName = artifact.getDependencyConflictId(); + + File artifactFile = artifact.getFile(); + if (artifactFile == null) { + getLog().warn("Not setting property \"" + propertyPrefix + propName + "\": dependency " + + artifact.getId() + " has no resolved artifact file."); + continue; + } + + antProject.setProperty(propertyPrefix + propName, artifactFile.getPath()); + } + } + /** * Copy properties from the Ant project to the Maven project. * diff --git a/src/test/java/org/apache/maven/plugins/antrun/AntRunMojoDependencyPropertiesTest.java b/src/test/java/org/apache/maven/plugins/antrun/AntRunMojoDependencyPropertiesTest.java new file mode 100644 index 0000000..53b2ba8 --- /dev/null +++ b/src/test/java/org/apache/maven/plugins/antrun/AntRunMojoDependencyPropertiesTest.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.maven.plugins.antrun; + +import java.io.File; +import java.lang.reflect.Field; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.DefaultArtifact; +import org.apache.maven.artifact.handler.DefaultArtifactHandler; +import org.apache.maven.artifact.versioning.VersionRange; +import org.apache.tools.ant.Project; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * A dependency whose artifact was never resolved has a null file. Registering the + * per-dependency path properties must not fall over on it. + */ +class AntRunMojoDependencyPropertiesTest { + + /** + * execute() defaults propertyPrefix to "" before any of this runs; a directly + * constructed mojo has not been through that, so mirror it here. + */ + private static AntRunMojo mojoWithEmptyPrefix() throws Exception { + AntRunMojo mojo = new AntRunMojo(null); + Field prefix = AntRunMojo.class.getDeclaredField("propertyPrefix"); + prefix.setAccessible(true); + prefix.set(mojo, ""); + return mojo; + } + + private static Artifact artifact(String artifactId, File file) { + Artifact artifact = new DefaultArtifact( + "org.example", + artifactId, + VersionRange.createFromVersion("1.0"), + "compile", + "jar", + null, + new DefaultArtifactHandler("jar")); + artifact.setFile(file); + return artifact; + } + + @Test + void unresolvedDependencyIsSkippedInsteadOfThrowing() throws Exception { + Set artifacts = new LinkedHashSet<>(); + artifacts.add(artifact("unresolved", null)); + + Project antProject = new Project(); + AntRunMojo mojo = mojoWithEmptyPrefix(); + + assertDoesNotThrow(() -> mojo.setDependencyFileProperties(artifacts, antProject)); + assertNull( + antProject.getProperty("org.example:unresolved:jar"), + "no path property should be set for a dependency with no artifact file"); + } + + @Test + void resolvedDependenciesStillGetTheirPathProperty() throws Exception { + File resolved = new File("target", "resolved-1.0.jar"); + + Set artifacts = new LinkedHashSet<>(); + artifacts.add(artifact("unresolved", null)); + artifacts.add(artifact("resolved", resolved)); + + Project antProject = new Project(); + AntRunMojo mojo = mojoWithEmptyPrefix(); + + mojo.setDependencyFileProperties(artifacts, antProject); + + // The unresolved artifact is listed first, so this also proves one bad + // dependency no longer prevents the rest from being registered. + assertEquals( + resolved.getPath(), + antProject.getProperty("org.example:resolved:jar"), + "resolved dependencies must still get their path property"); + } + + @Test + void nullArtifactSetIsTolerated() throws Exception { + Project antProject = new Project(); + AntRunMojo mojo = mojoWithEmptyPrefix(); + + assertDoesNotThrow(() -> mojo.setDependencyFileProperties(null, antProject)); + } +}