diff options
author | Harald Musum <musum@verizonmedia.com> | 2019-10-23 17:56:58 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-23 17:56:58 +0200 |
commit | 850d23293609c4ced8d1200a1d35346ec342b6e2 (patch) | |
tree | d5a11a849895958f78bea7a87c910b22968fdfe0 | |
parent | 300b49a158de311733cdc2e397d0e05208c3a9cf (diff) | |
parent | 8ea607e6a3b637fdcd9e5f8d3914bb3c66e360c3 (diff) |
Merge pull request #11070 from vespa-engine/gjoranv/artifact-version-for-exports5
Gjoranv/artifact version for exports5
21 files changed, 539 insertions, 142 deletions
diff --git a/bundle-plugin-test/integration-test/pom.xml b/bundle-plugin-test/integration-test/pom.xml new file mode 100644 index 00000000000..42d3b0e4d62 --- /dev/null +++ b/bundle-plugin-test/integration-test/pom.xml @@ -0,0 +1,92 @@ +<?xml version="1.0"?> +<!-- Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> +<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> + <parent> + <groupId>com.yahoo.vespa.bundle-plugin</groupId> + <artifactId>bundle-plugin-test</artifactId> + <version>7-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <artifactId>integration-test</artifactId> + <version>7-SNAPSHOT</version> + <packaging>jar</packaging> + + <dependencies> + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>config</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>vespajlib</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-artifact</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>com.yahoo.vespa.bundle-plugin</groupId> + <artifactId>main</artifactId> + <classifier>bundle</classifier> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.yahoo.vespa.bundle-plugin</groupId> + <artifactId>artifact-version-for-exports</artifactId> + <classifier>bundle</classifier> + <version>${project.version}</version> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <redirectTestOutputToFile>${test.hide}</redirectTestOutputToFile> + <systemPropertyVariables> + <test.bundle.path>${project.build.directory}/dependency</test.bundle.path> + </systemPropertyVariables> + <trimStackTrace>false</trimStackTrace> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy-dependencies</id> + <phase>process-test-classes</phase> + <goals> + <goal>copy-dependencies</goal> + </goals> + <configuration> + <includeScope>compile</includeScope> + <excludeTransitive>true</excludeTransitive> + <stripVersion>true</stripVersion> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + </plugin> + </plugins> + </build> +</project> diff --git a/bundle-plugin-test/src/test/java/com/yahoo/BundleIT.java b/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/BundleTest.java index 932b78a5c8d..a46abce1dff 100644 --- a/bundle-plugin-test/src/test/java/com/yahoo/BundleIT.java +++ b/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/BundleTest.java @@ -1,24 +1,29 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo; +package com.yahoo.container.plugin; import com.yahoo.osgi.maven.ProjectBundleClassPaths; import com.yahoo.vespa.config.VespaVersion; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import java.io.File; -import java.io.FilenameFilter; import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collection; +import java.util.Enumeration; import java.util.jar.Attributes; +import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; +import java.util.regex.Pattern; import java.util.zip.ZipEntry; import static com.yahoo.osgi.maven.ProjectBundleClassPaths.CLASSPATH_MAPPINGS_FILENAME; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.anyOf; import static org.hamcrest.CoreMatchers.containsString; @@ -26,21 +31,29 @@ import static org.hamcrest.CoreMatchers.endsWith; import static org.hamcrest.CoreMatchers.hasItems; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; /** * Verifies the bundle jar file built and its manifest. + * * @author Tony Vaagenes */ -public class BundleIT { +public class BundleTest { + static final String TEST_BUNDLE_PATH = System.getProperty("test.bundle.path", ".") + "/"; + + // If bundle-plugin-test is compiled in a mvn command that also built dependencies, e.g. jrt, + // the artifact is jrt.jar, otherwise the installed and versioned artifact + // is used: jrt-7-SNAPSHOT.jar or e.g. jrt-7.123.45.jar. + private static String snapshotOrVersionOrNone = "(-\\d+((-SNAPSHOT)|((\\.\\d+(\\.\\d+)?)?))?)?\\.jar"; + private JarFile jarFile; private Attributes mainAttributes; @Before public void setup() { try { - File componentJar = findBundleJar(); + File componentJar = findBundleJar("main"); jarFile = new JarFile(componentJar); Manifest manifest = jarFile.getManifest(); mainAttributes = manifest.getMainAttributes(); @@ -49,19 +62,13 @@ public class BundleIT { } } - private File findBundleJar() { - File[] componentFile = new File("target").listFiles(new FilenameFilter() { - @Override - public boolean accept(File file, String fileName) { - return fileName.endsWith("-deploy.jar") || fileName.endsWith("-jar-with-dependencies.jar"); - } - }); - - if (componentFile.length != 1) { - throw new RuntimeException("Failed finding component jar file"); + static File findBundleJar(String bundleName) { + Path bundlePath = Paths.get(TEST_BUNDLE_PATH, bundleName + "-bundle.jar"); + if (! Files.exists(bundlePath)) { + throw new RuntimeException("Failed finding component jar file: " + bundlePath); } - return componentFile[0]; + return bundlePath.toFile(); } @Test @@ -75,7 +82,7 @@ public class BundleIT { @Test public void require_that_bundle_symbolic_name_matches_pom_artifactId() { - assertThat(mainAttributes.getValue("Bundle-SymbolicName"), is("bundle-plugin-test")); + assertThat(mainAttributes.getValue("Bundle-SymbolicName"), is("main")); } @Test @@ -115,23 +122,28 @@ public class BundleIT { public void require_that_manifest_contains_bundle_class_path() { String bundleClassPath = mainAttributes.getValue("Bundle-ClassPath"); assertThat(bundleClassPath, containsString(".,")); - // If bundle-plugin-test is compiled in a mvn command that also built jrt, - // the jrt artifact is jrt.jar, otherwise the installed and versioned artifact - // is used: jrt-7-SNAPSHOT.jar. - assertThat(bundleClassPath, anyOf( - containsString("dependencies/jrt-7-SNAPSHOT.jar"), - containsString("dependencies/jrt.jar"))); + + Pattern jrtPattern = Pattern.compile("dependencies/jrt" + snapshotOrVersionOrNone); + assertTrue("Bundle class path did not contain jrt.", jrtPattern.matcher(bundleClassPath).find()); } @Test public void require_that_component_jar_file_contains_compile_artifacts() { - ZipEntry versionedEntry = jarFile.getEntry("dependencies/jrt-7-SNAPSHOT.jar"); - ZipEntry unversionedEntry = jarFile.getEntry("dependencies/jrt.jar"); - if (versionedEntry == null) { - assertNotNull(unversionedEntry); - } else { - assertNull(unversionedEntry); + String depJrt = "dependencies/jrt"; + Pattern jrtPattern = Pattern.compile(depJrt + snapshotOrVersionOrNone); + ZipEntry jrtEntry = null; + + Enumeration<JarEntry> entries = jarFile.entries(); + while (entries.hasMoreElements()) { + var e = entries.nextElement(); + if (e.getName().startsWith(depJrt)) { + if (jrtPattern.matcher(e.getName()).matches()) { + jrtEntry = e; + break; + } + } } + assertNotNull("Component jar file did not contain jrt dependency.", jrtEntry); } @@ -141,17 +153,25 @@ public class BundleIT { assertThat(webInfUrl, containsString("/WEB-INF/web.xml")); } + // TODO Vespa 8: Remove, the classpath mappings file is only needed for jersey resources to work in the application test framework. + // When this test is removed, also remove the maven-resources-plugin from the 'main' test bundle's pom. + @Rule + public TemporaryFolder tempFolder = new TemporaryFolder(); @SuppressWarnings("unchecked") @Test - public void bundle_class_path_mappings_are_generated() throws URISyntaxException, IOException { - URL mappingsUrl = getClass().getResource("/" + CLASSPATH_MAPPINGS_FILENAME); + public void bundle_class_path_mappings_are_generated() throws Exception { + ZipEntry classpathMappingsEntry = jarFile.getEntry(CLASSPATH_MAPPINGS_FILENAME); + assertNotNull( - "Could not find " + CLASSPATH_MAPPINGS_FILENAME + " in the test output directory", - mappingsUrl); + "Could not find " + CLASSPATH_MAPPINGS_FILENAME + " in the test bundle", + classpathMappingsEntry); + + Path mappingsFile = tempFolder.newFile(CLASSPATH_MAPPINGS_FILENAME).toPath(); + Files.copy(jarFile.getInputStream(classpathMappingsEntry), mappingsFile, REPLACE_EXISTING); - ProjectBundleClassPaths bundleClassPaths = ProjectBundleClassPaths.load(Paths.get(mappingsUrl.toURI())); + ProjectBundleClassPaths bundleClassPaths = ProjectBundleClassPaths.load(mappingsFile); - assertThat(bundleClassPaths.mainBundle.bundleSymbolicName, is("bundle-plugin-test")); + assertThat(bundleClassPaths.mainBundle.bundleSymbolicName, is("main")); Collection<String> mainBundleClassPaths = bundleClassPaths.mainBundle.classPathElements; @@ -159,7 +179,7 @@ public class BundleIT { hasItems( endsWith("target/classes"), anyOf( - allOf(containsString("jrt"), containsString(".jar"), containsString("m2/repository")), - containsString("jrt/target/jrt.jar")))); + allOf(containsString("/jrt-"), containsString(".jar")), + containsString("/jrt.jar")))); } } diff --git a/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/ExportPackageVersionTest.java b/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/ExportPackageVersionTest.java new file mode 100644 index 00000000000..66f36e32f39 --- /dev/null +++ b/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/ExportPackageVersionTest.java @@ -0,0 +1,72 @@ +// Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.plugin; + +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.util.jar.Attributes; +import java.util.jar.JarFile; + +import static com.yahoo.container.plugin.BundleTest.findBundleJar; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertThat; + +/** + * Verifies that the 'useArtifactVersionForExportPackages' setting for the bundle-plugin works as intended. + * + * @author gjoranv + */ +public class ExportPackageVersionTest { + + private static Attributes mainAttributes; + private static String bundleVersion; + + @BeforeClass + public static void setup() { + try { + File componentJar = findBundleJar("artifact-version-for-exports"); + mainAttributes = new JarFile(componentJar).getManifest().getMainAttributes(); + bundleVersion = mainAttributes.getValue("Bundle-Version"); + + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Test + public void artifact_version_without_qualifier_is_used_as_export_version() { + // Bundle-Version is artifact version without qualifier + String expectedExport = "ai.vespa.noversion;version=" + bundleVersion; + + String exportPackage = mainAttributes.getValue("Export-Package"); + assertThat(exportPackage, containsString(expectedExport)); + + // Verify that there is no qualifier + assertThat(exportPackage, not(containsString(expectedExport + "."))); + } + + @Test + public void explicit_version_in_ExportPackage_annotation_overrides_artifact_version() { + String exportPackage = mainAttributes.getValue("Export-Package"); + assertThat(exportPackage, containsString("ai.vespa.explicitversion;version=2.4.6.RELEASE")); + } + + @Test + public void artifact_version_of_dependency_is_used_as_export_version_for_package_in_compile_scoped_dependency() { + String exportPackage = mainAttributes.getValue("Export-Package"); + + // TODO: This test should have checked for a fixed version of the dependency bundle, different than the main bundle version. + // See comment in the dependency bundle's pom.xml for why this is not the case. + assertThat(exportPackage, containsString("ai.vespa.noversion_dep;version=" + bundleVersion)); + } + + @Test + public void explicit_version_in_ExportPackage_annotation_overrides_artifact_version_of_compile_scoped_dependency() { + String exportPackage = mainAttributes.getValue("Export-Package"); + assertThat(exportPackage, containsString("ai.vespa.explicitversion_dep;version=3.6.9.RELEASE")); + } + +} diff --git a/bundle-plugin-test/pom.xml b/bundle-plugin-test/pom.xml index 3ba9bf7b4b6..b27f6edc5f8 100644 --- a/bundle-plugin-test/pom.xml +++ b/bundle-plugin-test/pom.xml @@ -11,80 +11,12 @@ <version>7-SNAPSHOT</version> <relativePath>../parent/pom.xml</relativePath> </parent> - <groupId>com.yahoo.vespa</groupId> + <groupId>com.yahoo.vespa.bundle-plugin</groupId> <artifactId>bundle-plugin-test</artifactId> <version>7-SNAPSHOT</version> - <packaging>container-plugin</packaging> - <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>com.yahoo.vespa</groupId> - <artifactId>container-dev</artifactId> - <version>${project.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>com.yahoo.vespa</groupId> - <artifactId>vespajlib</artifactId> - <version>${project.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.json</groupId> - <artifactId>json</artifactId> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>com.yahoo.vespa</groupId> - <artifactId>jrt</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <!-- Added to verify that module-info.class can be handled by bundle-plugin without throwing an exception. --> - <groupId>javax.xml.bind</groupId> - <artifactId>jaxb-api</artifactId> - <version>2.3.0</version> - </dependency> - </dependencies> - <build> - <plugins> - <plugin> - <groupId>com.yahoo.vespa</groupId> - <artifactId>bundle-plugin</artifactId> - <version>${project.version}</version> - <extensions>true</extensions> - <configuration> - <Import-Package> - manualImport.withoutVersion, - manualImport.withVersion;version="12.3.4", - multiple.packages.with.the.same.version1;multiple.packages.with.the.same.version2;version="[1,2)" - </Import-Package> - <WebInfUrl>/WEB-INF/web.xml</WebInfUrl> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-failsafe-plugin</artifactId> - <version>2.9</version> - <executions> - <execution> - <id>integration-test</id> - <goals> - <goal>integration-test</goal> - </goals> - </execution> - <execution> - <id>verify</id> - <goals> - <goal>verify</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> + <packaging>pom</packaging> + <modules> + <module>integration-test</module> + <module>test-bundles</module> + </modules> </project> diff --git a/bundle-plugin-test/test-bundles/artifact-version-for-exports-dep/pom.xml b/bundle-plugin-test/test-bundles/artifact-version-for-exports-dep/pom.xml new file mode 100644 index 00000000000..34b250ae927 --- /dev/null +++ b/bundle-plugin-test/test-bundles/artifact-version-for-exports-dep/pom.xml @@ -0,0 +1,37 @@ +<?xml version="1.0"?> +<!-- Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> +<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> + <parent> + <groupId>com.yahoo.vespa.bundle-plugin</groupId> + <artifactId>test-bundles</artifactId> + <version>7-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <artifactId>artifact-version-for-exports-dep</artifactId> + <!-- TODO: Should use a fixed version different than the dependent bundle. + But version is set to the release version by build scripts before building. + Then, the dependent bundle will not find the artifact. Skipping this step for a sub-module seems + impossible with the maven-versions-plugin, and cumbersome with factorylib. --> + <version>7-SNAPSHOT</version> + <packaging>container-plugin</packaging> + <dependencies> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>com.yahoo.vespa</groupId> + <artifactId>bundle-plugin</artifactId> + <version>${project.version}</version> + <extensions>true</extensions> + <configuration> + <useArtifactVersionForExportPackages>true</useArtifactVersionForExportPackages> + <configGenVersion>${project.version}</configGenVersion> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/bundle-plugin-test/test-bundles/artifact-version-for-exports-dep/src/main/java/ai/vespa/explicitversion_dep/package-info.java b/bundle-plugin-test/test-bundles/artifact-version-for-exports-dep/src/main/java/ai/vespa/explicitversion_dep/package-info.java new file mode 100644 index 00000000000..3eea8b11f1e --- /dev/null +++ b/bundle-plugin-test/test-bundles/artifact-version-for-exports-dep/src/main/java/ai/vespa/explicitversion_dep/package-info.java @@ -0,0 +1,6 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +@ExportPackage(version = @Version(major = 3, minor = 6, micro = 9, qualifier = "RELEASE")) +package ai.vespa.explicitversion_dep; + +import com.yahoo.osgi.annotation.ExportPackage; +import com.yahoo.osgi.annotation.Version; diff --git a/bundle-plugin-test/test-bundles/artifact-version-for-exports-dep/src/main/java/ai/vespa/noversion_dep/package-info.java b/bundle-plugin-test/test-bundles/artifact-version-for-exports-dep/src/main/java/ai/vespa/noversion_dep/package-info.java new file mode 100644 index 00000000000..794e177f7e7 --- /dev/null +++ b/bundle-plugin-test/test-bundles/artifact-version-for-exports-dep/src/main/java/ai/vespa/noversion_dep/package-info.java @@ -0,0 +1,5 @@ +// Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +@ExportPackage +package ai.vespa.noversion_dep; + +import com.yahoo.osgi.annotation.ExportPackage; diff --git a/bundle-plugin-test/test-bundles/artifact-version-for-exports/pom.xml b/bundle-plugin-test/test-bundles/artifact-version-for-exports/pom.xml new file mode 100644 index 00000000000..619189cd874 --- /dev/null +++ b/bundle-plugin-test/test-bundles/artifact-version-for-exports/pom.xml @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<!-- Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> +<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> + <parent> + <groupId>com.yahoo.vespa.bundle-plugin</groupId> + <artifactId>test-bundles</artifactId> + <version>7-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <artifactId>artifact-version-for-exports</artifactId> + <version>7-SNAPSHOT</version> + <packaging>container-plugin</packaging> + <dependencies> + <dependency> + <groupId>com.yahoo.vespa.bundle-plugin</groupId> + <artifactId>artifact-version-for-exports-dep</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>com.yahoo.vespa</groupId> + <artifactId>bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <useArtifactVersionForExportPackages>true</useArtifactVersionForExportPackages> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/bundle-plugin-test/test-bundles/artifact-version-for-exports/src/main/java/ai/vespa/explicitversion/package-info.java b/bundle-plugin-test/test-bundles/artifact-version-for-exports/src/main/java/ai/vespa/explicitversion/package-info.java new file mode 100644 index 00000000000..96cf6a3bf85 --- /dev/null +++ b/bundle-plugin-test/test-bundles/artifact-version-for-exports/src/main/java/ai/vespa/explicitversion/package-info.java @@ -0,0 +1,6 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +@ExportPackage(version = @Version(major = 2, minor = 4, micro = 6, qualifier = "RELEASE")) +package ai.vespa.explicitversion; + +import com.yahoo.osgi.annotation.ExportPackage; +import com.yahoo.osgi.annotation.Version; diff --git a/bundle-plugin-test/test-bundles/artifact-version-for-exports/src/main/java/ai/vespa/noversion/package-info.java b/bundle-plugin-test/test-bundles/artifact-version-for-exports/src/main/java/ai/vespa/noversion/package-info.java new file mode 100644 index 00000000000..e7e11e39889 --- /dev/null +++ b/bundle-plugin-test/test-bundles/artifact-version-for-exports/src/main/java/ai/vespa/noversion/package-info.java @@ -0,0 +1,5 @@ +// Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +@ExportPackage +package ai.vespa.noversion; + +import com.yahoo.osgi.annotation.ExportPackage; diff --git a/bundle-plugin-test/test-bundles/main/pom.xml b/bundle-plugin-test/test-bundles/main/pom.xml new file mode 100644 index 00000000000..c9c9ea270eb --- /dev/null +++ b/bundle-plugin-test/test-bundles/main/pom.xml @@ -0,0 +1,78 @@ +<?xml version="1.0"?> +<!-- Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> +<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> + <parent> + <groupId>com.yahoo.vespa.bundle-plugin</groupId> + <artifactId>test-bundles</artifactId> + <version>7-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <artifactId>main</artifactId> + <version>7-SNAPSHOT</version> + <packaging>container-plugin</packaging> + <dependencies> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>jrt</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <!-- Added to verify that module-info.class can be handled by bundle-plugin without throwing an exception. --> + <groupId>javax.xml.bind</groupId> + <artifactId>jaxb-api</artifactId> + <version>2.3.0</version> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>com.yahoo.vespa</groupId> + <artifactId>bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <Import-Package> + manualImport.withoutVersion, + manualImport.withVersion;version="12.3.4", + multiple.packages.with.the.same.version1;multiple.packages.with.the.same.version2;version="[1,2)" + </Import-Package> + <WebInfUrl>/WEB-INF/web.xml</WebInfUrl> + </configuration> + </plugin> + <plugin> + <!-- Trick to copy bundle-plugin.bundle-classpath-mappings.json from target/test-classes to target/classes --> + <artifactId>maven-resources-plugin</artifactId> + <executions> + <execution> + <id>copy-bundle-classpath-mappings-from-test-to-main</id> + <!-- NOTE: Must be done after generating classpath-mappings and before assembling the bundle (see the test-bundles pom) --> + <phase>process-test-sources</phase> + <goals> + <goal>copy-resources</goal> + </goals> + <configuration> + <outputDirectory>${project.build.outputDirectory}</outputDirectory> + <overwrite>true</overwrite> + <resources> + <resource> + <directory>${project.build.testOutputDirectory}</directory> + <includes> + <include>bundle-plugin.bundle-classpath-mappings.json</include> + </includes> + </resource> + </resources> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/bundle-plugin-test/src/main/java/InDefaultPackage.java b/bundle-plugin-test/test-bundles/main/src/main/java/InDefaultPackage.java index a650916d653..a650916d653 100644 --- a/bundle-plugin-test/src/main/java/InDefaultPackage.java +++ b/bundle-plugin-test/test-bundles/main/src/main/java/InDefaultPackage.java diff --git a/bundle-plugin-test/src/main/java/com/yahoo/test/SimpleSearcher.java b/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/SimpleSearcher.java index dddca3f4d59..dddca3f4d59 100644 --- a/bundle-plugin-test/src/main/java/com/yahoo/test/SimpleSearcher.java +++ b/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/SimpleSearcher.java diff --git a/bundle-plugin-test/src/main/java/com/yahoo/test/SimpleSearcher2.java b/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/SimpleSearcher2.java index 3220171de13..3220171de13 100644 --- a/bundle-plugin-test/src/main/java/com/yahoo/test/SimpleSearcher2.java +++ b/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/SimpleSearcher2.java diff --git a/bundle-plugin-test/src/main/java/com/yahoo/test/package-info.java b/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/package-info.java index 5774fc8d5f2..5774fc8d5f2 100644 --- a/bundle-plugin-test/src/main/java/com/yahoo/test/package-info.java +++ b/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/package-info.java diff --git a/bundle-plugin-test/src/main/resources/configdefinitions/test.def b/bundle-plugin-test/test-bundles/main/src/main/resources/configdefinitions/test.def index b4ba9ec518a..b4ba9ec518a 100644 --- a/bundle-plugin-test/src/main/resources/configdefinitions/test.def +++ b/bundle-plugin-test/test-bundles/main/src/main/resources/configdefinitions/test.def diff --git a/bundle-plugin-test/test-bundles/pom.xml b/bundle-plugin-test/test-bundles/pom.xml new file mode 100644 index 00000000000..712ccb5542e --- /dev/null +++ b/bundle-plugin-test/test-bundles/pom.xml @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!-- Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> +<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> + <parent> + <groupId>com.yahoo.vespa.bundle-plugin</groupId> + <artifactId>bundle-plugin-test</artifactId> + <version>7-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <artifactId>test-bundles</artifactId> + <version>7-SNAPSHOT</version> + <packaging>pom</packaging> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + </plugin> + </plugins> + <pluginManagement> + <plugins> + <plugin> + <!-- Trick to package bundles before test phase to allow running 'mvn test' --> + <groupId>com.yahoo.vespa</groupId> + <artifactId>bundle-plugin</artifactId> + <version>${project.version}</version> + <executions> + <execution> + <id>generate-classpath-mappings</id> + <phase>generate-test-sources</phase> + <goals> + <goal>generate-bundle-classpath-mappings</goal> + </goals> + </execution> + <execution> + <id>package-test-bundles</id> + <!-- Must be done after generating classpath-mappings and copying it in the 'main' bundle. --> + <phase>test-compile</phase> + <goals> + <goal>generate-osgi-manifest</goal> + <goal>assemble-container-plugin</goal> + </goals> + </execution> + </executions> + <configuration> + <!-- Make the integration-test module use the bundle jars instead of the ordinary artifacts. --> + <AttachBundle>true</AttachBundle> + </configuration> + </plugin> + </plugins> + </pluginManagement> + </build> + <modules> + <module>artifact-version-for-exports</module> + <module>artifact-version-for-exports-dep</module> + <module>main</module> + </modules> + + <dependencies> + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>container-dev</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> + + <properties> + <maven.javadoc.skip>true</maven.javadoc.skip> + </properties> +</project> diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/Analyze.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/Analyze.java index 13a306a0c1c..d586f324f77 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/Analyze.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/Analyze.java @@ -1,17 +1,18 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.plugin.classanalysis; +import org.apache.maven.artifact.versioning.ArtifactVersion; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Optional; -import static com.yahoo.container.plugin.util.IO.withFileInputStream; /** * Main entry point for class analysis @@ -21,16 +22,20 @@ import static com.yahoo.container.plugin.util.IO.withFileInputStream; */ public class Analyze { public static ClassFileMetaData analyzeClass(File classFile) { + return analyzeClass(classFile, null); + } + + public static ClassFileMetaData analyzeClass(File classFile, ArtifactVersion artifactVersion) { try { - return withFileInputStream(classFile, Analyze::analyzeClass); - } catch (RuntimeException e) { + return analyzeClass(new FileInputStream(classFile), artifactVersion); + } catch (Exception e) { throw new RuntimeException("An error occurred when analyzing " + classFile.getPath(), e); } } - public static ClassFileMetaData analyzeClass(InputStream inputStream) { + public static ClassFileMetaData analyzeClass(InputStream inputStream, ArtifactVersion artifactVersion) { try { - AnalyzeClassVisitor visitor = new AnalyzeClassVisitor(); + AnalyzeClassVisitor visitor = new AnalyzeClassVisitor(artifactVersion); new ClassReader(inputStream).accept(visitor, ClassReader.SKIP_DEBUG); return visitor.result(); } catch (IOException e) { diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassVisitor.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassVisitor.java index 0225c43e4b8..e37a9caa7cc 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassVisitor.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassVisitor.java @@ -3,6 +3,7 @@ package com.yahoo.container.plugin.classanalysis; import com.yahoo.osgi.annotation.ExportPackage; import com.yahoo.osgi.annotation.Version; +import org.apache.maven.artifact.versioning.ArtifactVersion; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassVisitor; @@ -27,8 +28,11 @@ class AnalyzeClassVisitor extends ClassVisitor implements ImportCollector { private Set<String> imports = new HashSet<>(); private Optional<ExportPackageAnnotation> exportPackageAnnotation = Optional.empty(); - AnalyzeClassVisitor() { + private final Optional<ArtifactVersion> defaultExportPackageVersion; + + AnalyzeClassVisitor(ArtifactVersion defaultExportPackageVersion) { super(Opcodes.ASM7); + this.defaultExportPackageVersion = Optional.ofNullable(defaultExportPackageVersion); } @Override @@ -99,9 +103,14 @@ class AnalyzeClassVisitor extends ClassVisitor implements ImportCollector { private AnnotationVisitor visitExportPackage() { return new AnnotationVisitor(Opcodes.ASM7) { - private int major = defaultVersionValue("major"); - private int minor = defaultVersionValue("minor"); - private int micro = defaultVersionValue("micro"); + private int major = defaultExportPackageVersion.map(ArtifactVersion::getMajorVersion) + .orElse(defaultVersionValue("major")); + private int minor = defaultExportPackageVersion.map(ArtifactVersion::getMinorVersion) + .orElse(defaultVersionValue("minor")); + private int micro = defaultExportPackageVersion.map(ArtifactVersion::getIncrementalVersion) + .orElse(defaultVersionValue("micro")); + + // Default qualifier is the empty string. private String qualifier = defaultVersionValue("qualifier"); @Override diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java index c23e55a9eec..11a82ab7443 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java @@ -14,6 +14,8 @@ import com.yahoo.container.plugin.osgi.ImportPackages.Import; import com.yahoo.container.plugin.util.Strings; import org.apache.commons.lang3.tuple.Pair; import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Mojo; @@ -44,8 +46,7 @@ import static com.yahoo.container.plugin.osgi.ExportPackages.exportsByPackageNam import static com.yahoo.container.plugin.osgi.ImportPackages.calculateImports; import static com.yahoo.container.plugin.util.Files.allDescendantFiles; import static com.yahoo.container.plugin.util.IO.withFileOutputStream; -import static com.yahoo.container.plugin.util.JarFiles.withInputStream; -import static com.yahoo.container.plugin.util.JarFiles.withJarFile; + /** * @author Tony Vaagenes @@ -57,6 +58,15 @@ public class GenerateOsgiManifestMojo extends AbstractMojo { @Parameter(defaultValue = "${project}") private MavenProject project = null; + /** + * If set to true, the artifact's version is used as default package version for ExportPackages. + * Packages from included (compile scoped) artifacts will use the version for their own artifact. + * If the package is exported with an explicit version in package-info.java, that version will be + * used regardless of this parameter. + */ + @Parameter(alias = "UseArtifactVersionForExportPackages", defaultValue = "false") + private boolean useArtifactVersionForExportPackages; + @Parameter private String discApplicationClass = null; @@ -215,8 +225,11 @@ public class GenerateOsgiManifestMojo extends AbstractMojo { Map<String, Optional<String>> manualImports, Collection<Import> imports, PackageTally pluginPackageTally) { Map<String, String> ret = new HashMap<>(); String importPackage = Stream.concat(manualImports.entrySet().stream().map(e -> asOsgiImport(e.getKey(), e.getValue())), - imports.stream().map(Import::asOsgiImport)).sorted().collect(Collectors.joining(",")); - String exportPackage = osgiExportPackages(pluginPackageTally.exportedPackages()).stream().sorted().collect(Collectors.joining(",")); + imports.stream().map(Import::asOsgiImport)).sorted() + .collect(Collectors.joining(",")); + + String exportPackage = osgiExportPackages(pluginPackageTally.exportedPackages()).stream().sorted() + .collect(Collectors.joining(",")); for (Pair<String, String> element : Arrays.asList(// Pair.of("Created-By", "vespa container maven plugin"), // @@ -301,34 +314,47 @@ public class GenerateOsgiManifestMojo extends AbstractMojo { artifact.getId(), artifact.getType()))); } + private ArtifactVersion artifactVersionOrNull(String version) { + return useArtifactVersionForExportPackages ? new DefaultArtifactVersion(version) : null; + } + private PackageTally getProjectClassesTally() { File outputDirectory = new File(project.getBuild().getOutputDirectory()); - List<ClassFileMetaData> analyzedClasses = allDescendantFiles(outputDirectory).filter(file -> file.getName().endsWith(".class")) - .map(Analyze::analyzeClass).collect(Collectors.toList()); + List<ClassFileMetaData> analyzedClasses = allDescendantFiles(outputDirectory) + .filter(file -> file.getName().endsWith(".class")) + .map(classFile -> Analyze.analyzeClass(classFile, artifactVersionOrNull(bundleVersion))) + .collect(Collectors.toList()); return PackageTally.fromAnalyzedClassFiles(analyzedClasses); } - private static PackageTally definedPackages(Collection<Artifact> jarArtifacts) { - return PackageTally.combine(jarArtifacts.stream().map(ja -> withJarFile(ja.getFile(), GenerateOsgiManifestMojo::definedPackages)) - .collect(Collectors.toList())); + private PackageTally definedPackages(Collection<Artifact> jarArtifacts) { + List<PackageTally> tallies = new ArrayList<>(); + for (var artifact : jarArtifacts) { + try { + tallies.add(definedPackages(new JarFile(artifact.getFile()), artifactVersionOrNull(artifact.getVersion()))); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return PackageTally.combine(tallies); } - private static PackageTally definedPackages(JarFile jarFile) throws MojoExecutionException { + private static PackageTally definedPackages(JarFile jarFile, ArtifactVersion version) throws MojoExecutionException { List<ClassFileMetaData> analyzedClasses = new ArrayList<>(); for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements();) { JarEntry entry = entries.nextElement(); if (! entry.isDirectory() && entry.getName().endsWith(".class")) { - analyzedClasses.add(analyzeClass(jarFile, entry)); + analyzedClasses.add(analyzeClass(jarFile, entry, version)); } } return PackageTally.fromAnalyzedClassFiles(analyzedClasses); } - private static ClassFileMetaData analyzeClass(JarFile jarFile, JarEntry entry) throws MojoExecutionException { + private static ClassFileMetaData analyzeClass(JarFile jarFile, JarEntry entry, ArtifactVersion version) throws MojoExecutionException { try { - return withInputStream(jarFile, entry, Analyze::analyzeClass); + return Analyze.analyzeClass(jarFile.getInputStream(entry), version); } catch (Exception e) { throw new MojoExecutionException( String.format("While analyzing the class '%s' in jar file '%s'", entry.getName(), jarFile.getName()), e); diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/util/IO.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/util/IO.java index a1e313b920b..654fb700a43 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/util/IO.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/util/IO.java @@ -13,13 +13,6 @@ import java.io.OutputStream; * @author ollivir */ public class IO { - public static <T> T withFileInputStream(File file, ThrowingFunction<FileInputStream, T> f) { - try (FileInputStream fis = new FileInputStream(file)) { - return f.apply(fis); - } catch (Exception e) { - throw new RuntimeException(e); - } - } /** * Creates a new file and all its parent directories, and provides a file output stream to the file. |