diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2022-01-13 11:57:54 +0100 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2022-01-13 11:57:54 +0100 |
commit | cfdd42d95c39a064abaacd659bf0e09a206aa818 (patch) | |
tree | 9b2ce2906151eae5a4a1118a04b94660ecaec20c /config-model | |
parent | d4c30771a13f9f3df9edf234fe324ca4dad8b3cb (diff) |
Warn on deprecated Maven artifacts in pom.xml
Also change deprecated bundle logic to use regex matcher for Java package name.
Diffstat (limited to 'config-model')
4 files changed, 133 insertions, 17 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/BundleValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/BundleValidator.java index 04d4ac35e6a..d89d2f166cd 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/BundleValidator.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/BundleValidator.java @@ -10,8 +10,17 @@ import com.yahoo.config.application.api.DeployLogger; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.path.Path; import com.yahoo.vespa.model.VespaModel; - +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; import java.io.IOException; +import java.io.StringReader; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -20,12 +29,15 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.function.Predicate; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; import java.util.logging.Level; +import java.util.regex.Pattern; +import java.util.stream.Collectors; /** * A validator for bundles. Uses BND library for some of the validation. @@ -61,6 +73,8 @@ public class BundleValidator extends Validator { throw new IllegalArgumentException("Non-existing or invalid manifest in " + filename); } validateManifest(deployLogger, filename, manifest); + getPomXmlContent(deployLogger, jarFile) + .ifPresent(pomXml -> validatePomXml(deployLogger, filename, pomXml)); } private void validateManifest(DeployLogger deployLogger, String filename, Manifest mf) { @@ -92,18 +106,20 @@ public class BundleValidator extends Validator { private static void validateImportedPackages(DeployLogger deployLogger, String filename, Manifest manifest) { Domain osgiHeaders = Domain.domain(manifest); Parameters importPackage = osgiHeaders.getImportPackage(); - Map<DeprecatedArtifact, List<String>> deprecatedPackagesInUse = new HashMap<>(); + Map<DeprecatedProvidedBundle, List<String>> deprecatedPackagesInUse = new HashMap<>(); importPackage.forEach((packageName, attrs) -> { VersionRange versionRange = attrs.getVersion() != null ? VersionRange.parseOSGiVersionRange(attrs.getVersion()) : null; - for (DeprecatedArtifact deprecatedArtifact : DeprecatedArtifact.values()) { - if (deprecatedArtifact.javaPackages.contains(packageName) - && (versionRange == null || deprecatedArtifact.versionDiscriminator.test(versionRange))) { - deprecatedPackagesInUse.computeIfAbsent(deprecatedArtifact, __ -> new ArrayList<>()) - .add(packageName); + for (DeprecatedProvidedBundle deprecatedBundle : DeprecatedProvidedBundle.values()) { + for (Predicate<String> matcher : deprecatedBundle.javaPackageMatchers) { + if (matcher.test(packageName) + && (versionRange == null || deprecatedBundle.versionDiscriminator.test(versionRange))) { + deprecatedPackagesInUse.computeIfAbsent(deprecatedBundle, __ -> new ArrayList<>()) + .add(packageName); + } } } }); @@ -117,27 +133,91 @@ public class BundleValidator extends Validator { }); } - private enum DeprecatedArtifact { + private static final Pattern POM_FILE_LOCATION = Pattern.compile("META-INF/maven/.+?/.+?/pom.xml"); + + private Optional<String> getPomXmlContent(DeployLogger deployLogger, JarFile jarFile) { + return jarFile.stream() + .filter(f -> POM_FILE_LOCATION.matcher(f.getName()).matches()) + .findFirst() + .map(f -> { + try { + return new String(jarFile.getInputStream(f).readAllBytes()); + } catch (IOException e) { + deployLogger.log(Level.INFO, + String.format("Unable to read '%s' from '%s'", f.getName(), jarFile.getName())); + return null; + } + }); + } + + private void validatePomXml(DeployLogger deployLogger, String jarFilename, String pomXmlContent) { + try { + Document pom = DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder() + .parse(new InputSource(new StringReader(pomXmlContent))); + NodeList dependencies = (NodeList) XPathFactory.newDefaultInstance().newXPath() + .compile("/project/dependencies/dependency") + .evaluate(pom, XPathConstants.NODESET); + for (int i = 0; i < dependencies.getLength(); i++) { + Element dependency = (Element) dependencies.item(i); + String groupId = dependency.getElementsByTagName("groupId").item(0).getTextContent(); + String artifactId = dependency.getElementsByTagName("artifactId").item(0).getTextContent(); + for (DeprecatedMavenArtifact deprecatedArtifact : DeprecatedMavenArtifact.values()) { + if (groupId.equals(deprecatedArtifact.groupId) && artifactId.equals(deprecatedArtifact.artifactId)) { + deployLogger.logApplicationPackage(Level.WARNING, + String.format("For pom.xml in '%s': \n" + + "The dependency %s:%s is listed below dependencies. \n" + + "%s", + jarFilename, groupId, artifactId, deprecatedArtifact.description)); + } + } + } + } catch (ParserConfigurationException e) { + throw new RuntimeException(e); + } catch (Exception e) { + deployLogger.log(Level.INFO, String.format("Unable to parse pom.xml from %s", jarFilename)); + } + } + + private enum DeprecatedMavenArtifact { + VESPA_HTTP_CLIENT_EXTENSION("com.yahoo.vespa", "vespa-http-client-extensions", + "The 'vespa-http-client-extensions' artifact will be removed in Vespa 8. " + + "Programmatic use can be safely removed from system/staging tests. " + + "See internal Vespa 8 release notes for details."); + + final String groupId; + final String artifactId; + final String description; + + DeprecatedMavenArtifact(String groupId, String artifactId, String description) { + this.groupId = groupId; + this.artifactId = artifactId; + this.description = description; + } + } + + private enum DeprecatedProvidedBundle { ORG_JSON("org.json:json", "The org.json library will no longer provided by jdisc runtime on Vespa 8. " + "See https://docs.vespa.ai/en/vespa8-release-notes.html#container-runtime.", - Set.of("org.json")); + Set.of("org\\.json")); final String name; - final Collection<String> javaPackages; + final Collection<Predicate<String>> javaPackageMatchers; final Predicate<VersionRange> versionDiscriminator; final String description; - DeprecatedArtifact(String name, String description, Collection<String> javaPackages) { - this(name, description, __ -> true, javaPackages); + DeprecatedProvidedBundle(String name, String description, Collection<String> javaPackagePatterns) { + this(name, description, __ -> true, javaPackagePatterns); } - DeprecatedArtifact(String name, - String description, - Predicate<VersionRange> versionDiscriminator, - Collection<String> javaPackages) { + DeprecatedProvidedBundle(String name, + String description, + Predicate<VersionRange> versionDiscriminator, + Collection<String> javaPackagePatterns) { this.name = name; - this.javaPackages = javaPackages; + this.javaPackageMatchers = javaPackagePatterns.stream() + .map(s -> Pattern.compile(s).asMatchPredicate()) + .collect(Collectors.toList()); this.versionDiscriminator = versionDiscriminator; this.description = description; } diff --git a/config-model/src/test/cfg/application/validation/testjars/pom-xml-warnings/META-INF/MANIFEST.MF b/config-model/src/test/cfg/application/validation/testjars/pom-xml-warnings/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..1f88a5e6477 --- /dev/null +++ b/config-model/src/test/cfg/application/validation/testjars/pom-xml-warnings/META-INF/MANIFEST.MF @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +Created-By: 1.6.0_20 (Apple Inc.) +Bundle-ManifestVersion: 2 +Bundle-Name: mybundle +Bundle-SymbolicName: mybundle +Bundle-Version: 0 + diff --git a/config-model/src/test/cfg/application/validation/testjars/pom-xml-warnings/META-INF/maven/com.yahoo.test/mybundle/pom.xml b/config-model/src/test/cfg/application/validation/testjars/pom-xml-warnings/META-INF/maven/com.yahoo.test/mybundle/pom.xml new file mode 100644 index 00000000000..1d28f307824 --- /dev/null +++ b/config-model/src/test/cfg/application/validation/testjars/pom-xml-warnings/META-INF/maven/com.yahoo.test/mybundle/pom.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>com.yahoo.test</groupId> + <artifactId>mybundle</artifactId> + <packaging>container-plugin</packaging> + <version>1.0.0</version> + <dependencies> + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>vespa-http-client-extensions</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project>
\ No newline at end of file diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/BundleValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/BundleValidatorTest.java index ae508c6a388..5532a2d1e3a 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/BundleValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/BundleValidatorTest.java @@ -69,6 +69,20 @@ public class BundleValidatorTest { "The org.json library will no longer provided by jdisc runtime on Vespa 8. See https://docs.vespa.ai/en/vespa8-release-notes.html#container-runtime."); } + @Test + public void outputs_deploy_warning_on_deprecated_dependency() throws IOException { + StringBuffer buffer = new StringBuffer(); + DeployLogger logger = createDeployLogger(buffer); + BundleValidator validator = new BundleValidator(); + JarFile jarFile = createTemporaryJarFile("pom-xml-warnings"); + validator.validateJarFile(logger, jarFile); + assertThat(buffer.toString()) + .contains("For pom.xml in 'pom-xml-warnings.jar': \n" + + "The dependency com.yahoo.vespa:vespa-http-client-extensions is listed below dependencies. \n" + + "The 'vespa-http-client-extensions' artifact will be removed in Vespa 8. " + + "Programmatic use can be safely removed from system/staging tests. See internal Vespa 8 release notes for details."); + } + private JarFile createTemporaryJarFile(String testArtifact) throws IOException { Path jarFile = tempDir.newFile(testArtifact + ".jar").toPath(); Path artifactDirectory = Paths.get("src/test/cfg/application/validation/testjars/" + testArtifact); |