[java-identity-provider] 03/07: JPAR-175 Add back trace from WAR content to provoking artifact in pom.
Rod Widdowson
rdw at steadingsoftware.com
Tue Jun 22 09:23:52 UTC 2021
This is an automated email from the git hooks/post-receive script.
rdw pushed a commit to branch main
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=3c90e2ff1c046f8ef76f934c16316d8ffeed5532
commit 3c90e2ff1c046f8ef76f934c16316d8ffeed5532
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Thu Jun 17 14:30:30 2021 +0100
JPAR-175 Add back trace from WAR content to provoking artifact in pom.
https://issues.shibboleth.net/jira/browse/JPAR-175
---
.../idp/dependencies/DependencyTest.java | 243 ++++++++++++++++++---
.../net/shibboleth/idp/dependencies/ParsedPom.java | 59 +++--
2 files changed, 257 insertions(+), 45 deletions(-)
diff --git a/idp-installer/src/test/java/net/shibboleth/idp/dependencies/DependencyTest.java b/idp-installer/src/test/java/net/shibboleth/idp/dependencies/DependencyTest.java
index 60dd0d87d..9eeb2ec38 100644
--- a/idp-installer/src/test/java/net/shibboleth/idp/dependencies/DependencyTest.java
+++ b/idp-installer/src/test/java/net/shibboleth/idp/dependencies/DependencyTest.java
@@ -18,11 +18,13 @@
package net.shibboleth.idp.dependencies;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.io.BufferedOutputStream;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
@@ -32,23 +34,26 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
import org.apache.maven.shared.invoker.DefaultInvocationRequest;
import org.apache.maven.shared.invoker.DefaultInvoker;
import org.apache.maven.shared.invoker.InvocationRequest;
import org.apache.maven.shared.invoker.Invoker;
import org.apache.maven.shared.invoker.MavenInvocationException;
-import org.junit.AfterClass;
import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import net.shibboleth.idp.dependencies.ParsedPom.PomArtifact;
import net.shibboleth.idp.installer.plugin.impl.PluginInstallerSupport;
+import net.shibboleth.utilities.java.support.collection.Pair;
import net.shibboleth.utilities.java.support.xml.ParserPool;
import net.shibboleth.utilities.java.support.xml.XMLParserException;
@@ -58,7 +63,7 @@ import net.shibboleth.utilities.java.support.xml.XMLParserException;
public class DependencyTest extends OpenSAMLInitBaseTestCase {
/** Set this up if you want to run the tests from eclipse. */
- private static String LOCAL_MAVEN_HOME = null;
+ private static String LOCAL_MAVEN_HOME = "C:/Program Files (x86)/apache-maven-3.6.1";
/** Parse for us to use. */
private ParserPool parserPool;
@@ -77,6 +82,8 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
private PrintWriter report;
+ private PomArtifact parentArtefact;
+
/** We have as an assumption that the CWD is idp-installer. Test this.
* @throws IOException
@@ -128,15 +135,23 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
}
workingDir = Files.createTempDirectory("dependencyTest");
parserPool = XMLObjectProviderRegistrySupport.getParserPool();
- final ParsedPom idpParent = new ParsedPom(parserPool, Path.of("../idp-parent/pom.xml"), true);
+ ParsedPom idpParent = new ParsedPom(parserPool, Path.of("../idp-parent/pom.xml"), null);
idpArtefact = idpParent.getOurInfo();
- assertNotNull(idpParent.getParent());
- final Path parentPath = downloadPom(idpParent.getParent());
- final ParsedPom projectParent = new ParsedPom(parserPool, parentPath, false);
+ parentArtefact = idpParent.getParent();
+ assertNotNull(parentArtefact);
+ final Path parentPath = downloadPom(parentArtefact);
+ final ParsedPom projectParent = new ParsedPom(parserPool, parentPath, new Properties());
+ idpParent = new ParsedPom(parserPool, Path.of("../idp-parent/pom.xml"), projectParent.getProperties());
dependencies.addAll(projectParent.getCompileDependencies());
+ dependencies.addAll(idpParent.getCompileDependencies());
for (final PomArtifact bom : projectParent.getBomDependencies()) {
final Path bomPath = downloadPom(bom);
- final ParsedPom bomContents = new ParsedPom(parserPool, bomPath, false);
+ final ParsedPom bomContents = new ParsedPom(parserPool, bomPath, projectParent.getProperties());
+ dependencies.addAll(bomContents.getCompileDependencies());
+ }
+ for (final PomArtifact bom : idpParent.getBomDependencies()) {
+ final Path bomPath = downloadPom(bom);
+ final ParsedPom bomContents = new ParsedPom(parserPool, bomPath, projectParent.getProperties());
dependencies.addAll(bomContents.getCompileDependencies());
}
final File out = new File("target/dependencyReport.txt");
@@ -150,9 +165,10 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
}
/** The guts of the first test. Are all the files what we expected?
- * @throws IOException
+ * @throws IOException if the file doesn't exist
+ * @throws MavenInvocationException if we fail to download a pom or a dependency
*/
- @Test public void testDependencies() throws IOException {
+ @Test public void testDependencies() throws IOException, MavenInvocationException {
if (!mavenAvailable) {
return;
}
@@ -162,54 +178,215 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
int wrongVersion = 0;
int found = 0;
int nonUsed = 0;
- int dupNames = Files.list(lib).mapToInt(e -> addName(names, lib.relativize(e).toString())).sum();
+ int dupNames = 0;
+ Files.list(lib).forEach(e -> addName(names, lib.relativize(e).toString()));
report.format("WAR CONTENTS\n=== ========\n");
Collections.sort(dependencies);
+ // ArtifactId->(Ver->[source, source])
+ final Map<String, Map<String, Set<String>>> dependencySource = new HashMap<>();
+ PomArtifact last = null;
for (PomArtifact artifact : dependencies) {
final String id = artifact.getArtifactId();
final String ver = artifact.getVersion();
- final String version = names.get(id);
- if (version == null) {
+ final String version = names.remove(id);
+ if (artifact.equals(last)) {
+ report.format("%-22s\t: %-12s\tDUPLICATE artifact\n", id, ver);
+ dupNames++;
+ } else if (version == null) {
report.format("%-22s\t: %-12s\tNOT found in war\n", id, ver);
nonUsed++;
} else if (version.equals(ver)) {
report.format("%-22s\t: %-12s\tFound in war\n", id, ver);
found++;
+ analyzeChild(dependencySource, artifact);
} else {
report.format("%-22s\t: %-12s\tVERSION MISMATCH - found %s\n", id, ver, version);
+ analyzeChild(dependencySource, artifact);
wrongVersion++;
}
+ last = artifact;
}
if (dupNames != 0) {
report.format("\n%d Duplicate names\n", dupNames);
}
- report.format("\n%d dependencies, %d found, %d not found %d mismatched", dependencies.size(), found, nonUsed, wrongVersion);
+ report.format("\n%d dependencies, %d found, %d not found, %d mismatched\n\nDependency Sources\n", dependencies.size(), found, nonUsed, wrongVersion);
+
+ final List<String> contributedDeps = new ArrayList<>(names.keySet());
+ Collections.sort(contributedDeps);
+ int noSource = 0, verMismatch = 0;
+
+ for (final String dependency: contributedDeps) {
+ final Map<String, Set<String>> map = dependencySource.get(dependency);
+ final String version = names.get(dependency);
+ if (map == null) {
+ if (!dependency.startsWith("idp-")) {
+ report.format("%-35s\t: %-12s\tNo source artefact found\n", dependency, version);
+ noSource++;
+ }
+ } else {
+ final Set<String> sources = map.remove(version);
+ if (sources == null) {
+ report.format("%-35s\t: %-12s\tNO Dependency contributes this version\n", dependency, version);
+ verMismatch ++;
+ } else {
+ List<String> vers = new ArrayList<>(sources);
+ Collections.sort(vers);
+ report.format("%-35s\t: %-12s\tContributed by %s\n", dependency, version, String.join(", ", vers));
+ }
+ final List<String> versions = new ArrayList<>(map.keySet());
+ Collections.sort(versions);
+ for (final String ver:versions) {
+ List<String> vers = new ArrayList<>(map.get(ver));
+ Collections.sort(vers);
+ report.format("%-22s\t: %-12s\tContributed by %s\n", " ", ver, String.join(" ", vers));
+ }
+ }
+ }
+ report.format("%d Version mismatches, %d lost artifacts", verMismatch, noSource);
report.flush();
report.close();
assertEquals(wrongVersion, 0, "Mismatched version");
assertEquals(dupNames, 0, "Multiple similarly named jars");
}
-
+
+ /** Given an artifact do an "mvn dependency:copy-dependencies" on it.
+ * Then analyse the output file into the map. The dependency name
+ * yields a map. Looking this up with a version yields a set of the sources.
+ * @param dependencySource where to accumulate the results
+ * @param artifact what to start with.
+ * @throws MavenInvocationException if maven fails.
+ * @throws IOException if a file doesbn't exist.
+ */
+ private void analyzeChild(final Map<String, Map<String, Set<String>>> dependencySource,
+ final PomArtifact artifact) throws MavenInvocationException, IOException {
+ final File pomFile = outputPom(artifact);
+ final String artifactName = artifact.getArtifactId()+"-"+artifact.getVersion();
+ final Path outputDir = workingDir.resolve(artifactName);
+
+ final Properties props = new Properties(2);
+ props.setProperty("includeScope","runtime");
+ props.setProperty("outputDirectory", outputDir.toString());
+ InvocationRequest request = new DefaultInvocationRequest().setProperties(props).setPomFile(pomFile).setGoals( Arrays.asList( "dependency:copy-dependencies" ) );
+
+ Invoker invoker = new DefaultInvoker();
+ invoker.execute( request );
+ Files.list(outputDir).forEach(e -> addDep(dependencySource, outputDir.relativize(e).toString(), artifact));
+ }
+
+ /** Add the artifact as a source of this file.
+ * @param dependencySources where to accumulate the answers
+ * @param dep the file name of the dependency which was down-loaded
+ * @param artifact the artifact which provoked the download
+ */
+ private void addDep(final Map<String, Map<String, Set<String>>> dependencySources,
+ final String dep,
+ final PomArtifact artifact) {
+ final Pair<String,String> depId = splitFileName(dep);
+
+ if (artifact.getArtifactId().equals(depId.getFirst()) && artifact.getVersion().equals(depId.getSecond())) {
+ // it's us. Not interesting
+ return;
+ }
+
+ // for each version, what contributed this dependency
+ Map<String, Set<String>> depEntry = dependencySources.get(depId.getFirst());
+ if (depEntry == null) {
+ depEntry = new HashMap<>();
+ dependencySources.put(depId.getFirst(), depEntry);
+ }
+ Set<String> provider = depEntry.get(depId.getSecond());
+ if (provider == null) {
+ provider = new HashSet<>();
+ depEntry.put(depId.getSecond(), provider);
+ }
+ provider.add(artifact.getArtifactId()+"-"+artifact.getVersion());
+ }
+
+ /** Create a pom file which has one dependency - this artifact.
+ * @param artifact the artifact.
+ * @return the file.
+ * @throws FileNotFoundException
+ */
+ private File outputPom(PomArtifact artifact) throws FileNotFoundException {
+ final File file = workingDir.resolve(new StringBuilder(artifact.getArtifactId())
+ .append("-")
+ .append(artifact.getVersion())
+ .append(".xml").
+ toString()).toFile();
+ final FileOutputStream outStream = new FileOutputStream(file);
+ final PrintWriter pom = new PrintWriter(new BufferedOutputStream(outStream));
+ pom.format("<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+ + " xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n"
+ + " <modelVersion>4.0.0</modelVersion>\n"
+ + "\n"
+ + " <parent>\n"
+ + " <groupId>%s</groupId>\n"
+ + " <artifactId>%s</artifactId>\n"
+ + " <version>%s</version>\n"
+ + " </parent>\n"
+ + "\n", parentArtefact.getGroupId(), parentArtefact.getArtifactId(), parentArtefact.getVersion());
+ pom.format(" <groupId>shibboleth.net.dependency</groupId>\n"
+ + " <version>0.0.1</version>\n"
+ + " <name>Shibboleth Dependency</name>\n"
+ + " <artifactId>idp-dep-%s</artifactId>\n"
+ + " <packaging>jar</packaging>\n\n", artifact.getArtifactId());
+ pom.format(" <dependencies>\n"
+ + " <dependency>\n"
+ + " <groupId>%s</groupId><artifactId>%s</artifactId><version>%s</version>\n"
+ + " </dependency>\n"
+ + " </dependencies>\n\n", artifact.getGroupId(),artifact.getArtifactId(), artifact.getVersion());
+ pom.format(" <repositories>\n"
+ + " <repository>\n"
+ + " <id>shib-release</id>\n"
+ + " <url>https://build.shibboleth.net/nexus/content/groups/public</url>\n"
+ + " <snapshots>\n"
+ + " <enabled>false</enabled>\n"
+ + " </snapshots>\n"
+ + " </repository>\n"
+ + " <repository>\n"
+ + " <id>shib-snapshot</id>\n"
+ + " <url>https://build.shibboleth.net/nexus/content/repositories/snapshots</url>\n"
+ + " <releases>\n"
+ + " <enabled>false</enabled>\n"
+ + " </releases>\n"
+ + " </repository>\n"
+ + " </repositories>\n"
+ + "</project>\n");
+ pom.flush();
+ pom.close();
+ return file;
+ }
+
+ /** Split the file name into the artifact (first) and version (second).
+ * @param inName the file name
+ * @return a pair.
+ */
+ private Pair<String, String> splitFileName(final String inName) {
+ final String name;
+ if (inName.endsWith(".jar")) {
+ name = inName.substring(0, inName.length()-4);
+ } else {
+ name = inName;
+ }
+ final int last;
+ if (name.endsWith("-SNAPSHOT")) {
+ last = name.substring(0, name.length()-9).lastIndexOf("-");
+ } else {
+ last = name.lastIndexOf("-");
+ }
+ final String base = name.substring(0, last);
+ String versionExtension = name.substring(last+1);
+ return new Pair<>(base, versionExtension);
+ }
+
/** Trivial accumulator to pull a name in the lib directory apart and insert it into the map.
* @param names The map to accumulate into
* @param jarPath the file we are looking at.
- * @return 1 if here was a previous entry.
*/
- private int addName(Map<String, String> names, String jarPath) {
- final int last = jarPath.lastIndexOf("-");
- final String base = jarPath.substring(0, last);
- String versionExtension = jarPath.substring(last+1);
- final String oldVersion;
- if (versionExtension.endsWith(".jar")) {
- versionExtension = versionExtension.substring(0, versionExtension.length()-4);
- }
- oldVersion = names.put(base, versionExtension);
- if (oldVersion == null) {
- return 0;
- }
- report.format("%-22s\t: Duplicate version %-12s\t& %s\n", base, versionExtension, oldVersion);
- return 1;
+ private void addName(Map<String, String> names, String jarPath) {
+ final Pair<String, String> nm = splitFileName(jarPath);
+ names.put(nm.getFirst(), nm.getSecond());
}
/** tell maven to download the artifact and returns it's path.
@@ -218,6 +395,8 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
* @throws MavenInvocationException
*/
private Path downloadPom(final PomArtifact artifact) throws MavenInvocationException {
+ final Path output = workingDir.resolve(artifact.getArtifactId() + ".pom");
+ assertFalse(Files.exists(output));
final String fullArtifactName = new StringBuilder(artifact.getGroupId())
.append(':')
.append(artifact.getArtifactId())
@@ -226,15 +405,17 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
.append(":pom")
.toString();
- final Properties props = new Properties(2);
+ final Properties props = new Properties(3);
props.setProperty("artifact",fullArtifactName);
+ props.setProperty("mdep.stripVersion","true");
props.setProperty("outputDirectory", workingDir.toString());
InvocationRequest request = new DefaultInvocationRequest().setProperties(props).setGoals( Arrays.asList( "dependency:copy" ) );
Invoker invoker = new DefaultInvoker();
invoker.execute( request );
+ assertTrue(Files.exists(output));
- return workingDir.resolve(artifact.getArtifactId() + "-" + artifact.getVersion() + ".pom");
+ return output;
}
}
diff --git a/idp-installer/src/test/java/net/shibboleth/idp/dependencies/ParsedPom.java b/idp-installer/src/test/java/net/shibboleth/idp/dependencies/ParsedPom.java
index b5a3cc420..ed7fb9ede 100644
--- a/idp-installer/src/test/java/net/shibboleth/idp/dependencies/ParsedPom.java
+++ b/idp-installer/src/test/java/net/shibboleth/idp/dependencies/ParsedPom.java
@@ -63,19 +63,23 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
/** Us. */
private final PomArtifact us;
-
+
/**
* Constructor.
*
- * @param parsers a short vut to let us parse XML
+ * @param parsers a short-cut to let us parse XML
* @param pom the {@link Path} to the pom.
- * @param parentOnly Do we just want the parent (and our) info
+ * @param parentPomProperties if present it is properties from the parent (which might be empty), if null we are *only*
+ * looking for the parent pom coordinates.
* @throws IOException from parsing
* @throws FileNotFoundException if the file doesn't exist
* @throws XMLParserException from parsing
*/
- public ParsedPom(final ParserPool parsers, final Path pom, final boolean parentOnly)
+ public ParsedPom(@Nonnull final ParserPool parsers,
+ @Nonnull final Path pom,
+ @Nullable final Properties parentPomProperties)
throws FileNotFoundException, IOException, XMLParserException {
+
Document document;
try (final InputStream stream = new BufferedInputStream(new FileInputStream(pom.toFile()))) {
document = parsers.parse(stream);
@@ -92,9 +96,13 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
us = new PomArtifact(el, parent);
- if (parentOnly) {
+ if (parentPomProperties == null) {
return;
}
+ for (final Object p:parentPomProperties.keySet()) {
+ String pName = (String) p;
+ properties.setProperty(pName, parentPomProperties.getProperty(pName));
+ }
final List<Element> props = ElementSupport.getChildElementsByTagName(el, "properties");
if (!props.isEmpty()) {
parseProperties(props.get(0));
@@ -154,7 +162,6 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
}
}
-
/**
* @param item
*/
@@ -167,7 +174,6 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
}
}
-
/**
* @param item
*/
@@ -181,21 +187,21 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
public List<PomArtifact> getCompileDependencies() {
return compileDependencies;
}
-
+
/**
* @return Returns the bomDependencies.
*/
public List<PomArtifact> getBomDependencies() {
return bomDependencies;
}
-
+
/** Return our artifactInformation.
* @return us.
*/
public PomArtifact getOurInfo() {
return us;
}
-
+
/**
* @return Returns the parent.
*/
@@ -203,6 +209,13 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
return parent;
}
+ /**
+ * @return Returns the properties.
+ */
+ public Properties getProperties() {
+ return properties;
+ }
+
/** Encapsulation of a <dependency> element. */
public class PomArtifact implements Comparable<PomArtifact>{
@@ -216,7 +229,7 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
@Nonnull private final String version;
/** <exclusions>. */
- @Nonnull private final Set<Pair<String, String>> exclusion = new HashSet<>();
+ @Nonnull private final Set<Pair<String, String>> exclusions = new HashSet<>();
/**
* Constructor.
@@ -269,7 +282,7 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
els = ElementSupport.getChildElementsByTagName(e, "artifactId");
Constraint.isGreaterThan(0, els.size(), "<artifactId> should exist in exclusion");
final String art = getElementContent(els.get(0));
- exclusion.add(new Pair<>(grp, art));
+ exclusions.add(new Pair<>(grp, art));
}
}
}
@@ -280,14 +293,14 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
public String getGroupId() {
return groupId;
}
-
+
/**
* @return Returns the artifactId.
*/
public String getArtifactId() {
return artifactId;
}
-
+
/**
* @return Returns the version.
*/
@@ -295,9 +308,27 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
return version;
}
+ /**
+ * @return Returns the exclusions.
+ */
+ public Set<Pair<String, String>> getExclusions() {
+ return exclusions;
+ }
+
/** {@inheritDoc} */
public int compareTo(final PomArtifact o) {
return getArtifactId().compareTo(o.getArtifactId());
}
+
+ /** {@inheritDoc} */
+ public boolean equals(final Object obj) {
+ if (obj != null && obj instanceof PomArtifact ) {
+ final PomArtifact him = (PomArtifact) obj;
+ return him.getArtifactId().equals(getArtifactId()) &&
+ him.getGroupId().equals(getGroupId()) &&
+ him.getVersion().equals(getVersion());
+ }
+ return false;
+ }
}
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list