diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f37ebb --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/xmvn-3.0.0.tar.xz diff --git a/.xmvn.metadata b/.xmvn.metadata new file mode 100644 index 0000000..ebb0607 --- /dev/null +++ b/.xmvn.metadata @@ -0,0 +1 @@ +d887a65c5649459f513dd70c688b080e47afc691 SOURCES/xmvn-3.0.0.tar.xz diff --git a/SOURCES/0001-Don-t-use-JAXB-for-converting-bytes-to-hex-string.patch b/SOURCES/0001-Don-t-use-JAXB-for-converting-bytes-to-hex-string.patch new file mode 100644 index 0000000..415ee9a --- /dev/null +++ b/SOURCES/0001-Don-t-use-JAXB-for-converting-bytes-to-hex-string.patch @@ -0,0 +1,58 @@ +From 336cbdc97f3c7055ebdf858141bfc160fd4d412b Mon Sep 17 00:00:00 2001 +From: Mikolaj Izdebski +Date: Fri, 8 Dec 2017 18:00:54 +0100 +Subject: [PATCH] Don't use JAXB for converting bytes to hex string + +--- + .../java/org/fedoraproject/xmvn/resolver/impl/CacheManager.java | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/xmvn-core/src/main/java/org/fedoraproject/xmvn/resolver/impl/CacheManager.java b/xmvn-core/src/main/java/org/fedoraproject/xmvn/resolver/impl/CacheManager.java +index 1d6c193b..0902aa88 100644 +--- a/xmvn-core/src/main/java/org/fedoraproject/xmvn/resolver/impl/CacheManager.java ++++ b/xmvn-core/src/main/java/org/fedoraproject/xmvn/resolver/impl/CacheManager.java +@@ -16,14 +16,13 @@ + package org.fedoraproject.xmvn.resolver.impl; + + import java.io.IOException; ++import java.math.BigInteger; + import java.nio.file.Files; + import java.nio.file.Path; + import java.nio.file.Paths; + import java.security.MessageDigest; + import java.security.NoSuchAlgorithmException; + +-import javax.xml.bind.annotation.adapters.HexBinaryAdapter; +- + /** + * @author Mikolaj Izdebski + */ +@@ -31,8 +30,6 @@ class CacheManager + { + private static final String DIGEST_ALGORITHM = "SHA-1"; + +- private final HexBinaryAdapter hexAdapter; +- + private final MessageDigest digest; + + private static volatile Path cacheHome; +@@ -41,7 +38,6 @@ class CacheManager + { + try + { +- hexAdapter = new HexBinaryAdapter(); + digest = MessageDigest.getInstance( DIGEST_ALGORITHM ); + } + catch ( NoSuchAlgorithmException e ) +@@ -53,7 +49,7 @@ class CacheManager + private String hash( Path path ) + throws IOException + { +- return hexAdapter.marshal( digest.digest( Files.readAllBytes( path ) ) ); ++ return new BigInteger( 1, digest.digest( Files.readAllBytes( path ) ) ).setBit( 160 ).toString( 16 ).substring( 1 ).toUpperCase(); + } + + private static Path getPathDefault( String key, Object defaultValue ) +-- +2.14.3 + diff --git a/SOURCES/0001-Fix-configuration-of-aliased-plugins.patch b/SOURCES/0001-Fix-configuration-of-aliased-plugins.patch new file mode 100644 index 0000000..9208c31 --- /dev/null +++ b/SOURCES/0001-Fix-configuration-of-aliased-plugins.patch @@ -0,0 +1,76 @@ +From 46ad87218f0be4a4b7e292a1c8b5d5dbce48ae63 Mon Sep 17 00:00:00 2001 +From: Mikolaj Izdebski +Date: Fri, 16 Mar 2018 11:10:35 +0100 +Subject: [PATCH] Fix configuration of aliased plugins + +Normally Maven tries to look up plugin configuration using plugin +coordinates taken from plugin descriptor. This works with pure Maven +as plugin descriptor always matches reference in POM. +However in XMvn they can differ when plugin artifact is resolved +throug artifact alias, so XMvn should force use of coordinates +specified in in POM. +--- + .../aether/XMvnMojoExecutionConfigurator.java | 51 ++++++++++++++++++++++ + 1 file changed, 51 insertions(+) + create mode 100644 xmvn-connector-aether/src/main/java/org/fedoraproject/xmvn/connector/aether/XMvnMojoExecutionConfigurator.java + +diff --git a/xmvn-connector-aether/src/main/java/org/fedoraproject/xmvn/connector/aether/XMvnMojoExecutionConfigurator.java b/xmvn-connector-aether/src/main/java/org/fedoraproject/xmvn/connector/aether/XMvnMojoExecutionConfigurator.java +new file mode 100644 +index 00000000..72e38b37 +--- /dev/null ++++ b/xmvn-connector-aether/src/main/java/org/fedoraproject/xmvn/connector/aether/XMvnMojoExecutionConfigurator.java +@@ -0,0 +1,51 @@ ++/*- ++ * Copyright (c) 2018 Red Hat, Inc. ++ * ++ * Licensed 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.fedoraproject.xmvn.connector.aether; ++ ++import org.apache.maven.lifecycle.MojoExecutionConfigurator; ++import org.apache.maven.lifecycle.internal.DefaultMojoExecutionConfigurator; ++import org.apache.maven.plugin.MojoExecution; ++import org.apache.maven.plugin.descriptor.PluginDescriptor; ++import org.apache.maven.project.MavenProject; ++import org.codehaus.plexus.component.annotations.Component; ++ ++/** ++ * @author Mikolaj Izdebski ++ */ ++@Component( role = MojoExecutionConfigurator.class ) ++public class XMvnMojoExecutionConfigurator ++ extends DefaultMojoExecutionConfigurator ++{ ++ @Override ++ public void configure( MavenProject project, MojoExecution execution, boolean allowPluginLevelConfig ) ++ { ++ PluginDescriptor originalPluginDescriptor = execution.getMojoDescriptor().getPluginDescriptor(); ++ ++ PluginDescriptor aliasedPluginDescriptor = originalPluginDescriptor.clone(); ++ aliasedPluginDescriptor.setGroupId( execution.getPlugin().getGroupId() ); ++ aliasedPluginDescriptor.setArtifactId( execution.getPlugin().getArtifactId() ); ++ ++ try ++ { ++ execution.getMojoDescriptor().setPluginDescriptor( aliasedPluginDescriptor ); ++ super.configure( project, execution, allowPluginLevelConfig ); ++ } ++ finally ++ { ++ execution.getMojoDescriptor().setPluginDescriptor( originalPluginDescriptor ); ++ } ++ } ++} +-- +2.14.3 + diff --git a/SOURCES/0001-Fix-installer-plugin-loading.patch b/SOURCES/0001-Fix-installer-plugin-loading.patch new file mode 100644 index 0000000..2acf3fd --- /dev/null +++ b/SOURCES/0001-Fix-installer-plugin-loading.patch @@ -0,0 +1,403 @@ +From 0fd7b0d19bd96456292585e883e3ba2ebbaf579b Mon Sep 17 00:00:00 2001 +From: Mikolaj Izdebski +Date: Wed, 21 Jun 2017 10:21:10 +0200 +Subject: [PATCH] Fix installer plugin loading + +--- + .../install/impl/ArtifactInstallerFactory.java | 97 ++++++-- + .../tools/install/impl/IsolatedClassRealm.java | 245 +++++++++++++++++++++ + 2 files changed, 320 insertions(+), 22 deletions(-) + create mode 100644 xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/IsolatedClassRealm.java + +diff --git a/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/ArtifactInstallerFactory.java b/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/ArtifactInstallerFactory.java +index 7a80571..e6a9a2d 100644 +--- a/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/ArtifactInstallerFactory.java ++++ b/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/ArtifactInstallerFactory.java +@@ -15,8 +15,17 @@ + */ + package org.fedoraproject.xmvn.tools.install.impl; + ++import java.io.BufferedReader; ++import java.io.IOException; ++import java.io.InputStream; ++import java.io.InputStreamReader; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.nio.file.Paths; + import java.util.Arrays; +-import java.util.Collection; ++import java.util.LinkedHashMap; ++import java.util.List; ++import java.util.Map; + import java.util.Properties; + + import org.slf4j.Logger; +@@ -35,49 +44,93 @@ class ArtifactInstallerFactory + + private final ArtifactInstaller defaultArtifactInstaller; + +- private final ArtifactInstaller eclipseArtifactInstaller; ++ private final IsolatedClassRealm pluginRealm; + +- private static ArtifactInstaller loadPlugin( String className ) ++ private final Map cachedPluginsByType = new LinkedHashMap<>(); ++ ++ private final Map cachedPluginsByImplClass = new LinkedHashMap<>(); ++ ++ private ArtifactInstaller tryLoadPlugin( String type ) + { ++ if ( cachedPluginsByType.containsKey( type ) ) ++ return cachedPluginsByType.get( type ); ++ + try + { +- return (ArtifactInstaller) ArtifactInstallerFactory.class.getClassLoader().loadClass( className ).newInstance(); ++ String resourceName = ArtifactInstaller.class.getCanonicalName() + "/" + type; ++ InputStream resourceStream = pluginRealm != null ? pluginRealm.getResourceAsStream( resourceName ) : null; ++ if ( resourceStream == null ) ++ { ++ logger.debug( "No XMvn Installer plugin found for packaging type {}", type ); ++ cachedPluginsByType.put( type, null ); ++ return null; ++ } ++ ++ String pluginImplClass; ++ try ( BufferedReader resourceReader = new BufferedReader( new InputStreamReader( resourceStream ) ) ) ++ { ++ pluginImplClass = resourceReader.readLine(); ++ } ++ ++ ArtifactInstaller pluggedInInstaller = cachedPluginsByImplClass.get( pluginImplClass ); ++ if ( pluggedInInstaller == null ) ++ { ++ pluggedInInstaller = (ArtifactInstaller) pluginRealm.loadClass( pluginImplClass ).newInstance(); ++ cachedPluginsByImplClass.put( pluginImplClass, pluggedInInstaller ); ++ } ++ ++ cachedPluginsByType.put( type, pluggedInInstaller ); ++ return pluggedInInstaller; + } +- catch ( ReflectiveOperationException e ) ++ catch ( IOException | ReflectiveOperationException e ) + { +- return null; ++ throw new RuntimeException( "Unable to load XMvn Installer plugin for packaging type " + type, e ); + } + } + + public ArtifactInstallerFactory( Configurator configurator ) + { + defaultArtifactInstaller = new DefaultArtifactInstaller( configurator ); +- // FIXME Don't hardcode plugin class name +- eclipseArtifactInstaller = loadPlugin( "org.fedoraproject.p2.xmvn.EclipseArtifactInstaller" ); ++ ++ Path pluginDir = Paths.get( "/usr/share/xmvn/lib/installer" ); ++ if ( Files.isDirectory( pluginDir ) ) ++ { ++ ClassLoader parentClassLoader = ArtifactInstallerFactory.class.getClassLoader(); ++ pluginRealm = new IsolatedClassRealm( parentClassLoader ); ++ pluginRealm.addJarDirectory( pluginDir ); ++ PLUGIN_IMPORTS.forEach( pluginRealm::importPackage ); ++ } ++ else ++ { ++ pluginRealm = null; ++ } + } + + /** +- * List of Tycho pacgkaging types. ++ * List of packages imported from XMvn Installer class loader to plug-in realms. + */ +- private static final Collection ECLIPSE_PACKAGING_TYPES = Arrays.asList( "eclipse-plugin", // +- "eclipse-test-plugin", // +- "eclipse-feature", // +- "eclipse-repository", // +- "eclipse-application", // +- "eclipse-update-site", // +- "eclipse-target-definition" ); ++ private static final List PLUGIN_IMPORTS = Arrays.asList( // XMvn API ++ "org.fedoraproject.xmvn.artifact", // ++ "org.fedoraproject.xmvn.config", // ++ "org.fedoraproject.xmvn.deployer", // ++ "org.fedoraproject.xmvn.locator", // ++ "org.fedoraproject.xmvn.metadata", // ++ "org.fedoraproject.xmvn.resolver", // ++ // XMvn Installer SPI ++ "org.fedoraproject.xmvn.tools.install", // ++ // SLF4J API ++ "org.slf4j" // ++ ); + + @SuppressWarnings( "unused" ) + public ArtifactInstaller getInstallerFor( Artifact artifact, Properties properties ) + { + String type = properties.getProperty( "type" ); +- if ( type != null && ECLIPSE_PACKAGING_TYPES.contains( type ) ) ++ if ( type != null ) + { +- if ( eclipseArtifactInstaller != null ) +- return eclipseArtifactInstaller; +- +- logger.error( "Unable to load XMvn P2 plugin, Eclipse artifact installation will be impossible" ); +- throw new RuntimeException( "Unable to load XMvn P2 plugin" ); ++ ArtifactInstaller pluggedInInstaller = tryLoadPlugin( type ); ++ if ( pluggedInInstaller != null ) ++ return pluggedInInstaller; + } + + return defaultArtifactInstaller; +diff --git a/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/IsolatedClassRealm.java b/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/IsolatedClassRealm.java +new file mode 100644 +index 0000000..3324604 +--- /dev/null ++++ b/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/IsolatedClassRealm.java +@@ -0,0 +1,245 @@ ++/*- ++ * Copyright (c) 2014-2017 Red Hat, Inc. ++ * ++ * Licensed 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.fedoraproject.xmvn.tools.install.impl; ++ ++import java.io.IOException; ++import java.net.MalformedURLException; ++import java.net.URL; ++import java.net.URLClassLoader; ++import java.nio.file.DirectoryStream; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.util.Collection; ++import java.util.Collections; ++import java.util.Enumeration; ++import java.util.HashSet; ++import java.util.LinkedHashSet; ++import java.util.Set; ++ ++/** ++ * A generic, isolated class loader. ++ *

++ * This class loader has its own classpath, separate from the primary Java classpath. It has a parent class loader, to ++ * which it delegates loading a set of imported classes. All other classes are loaded from its own classpath. ++ * ++ * @author Mikolaj Izdebski ++ */ ++class IsolatedClassRealm ++ extends URLClassLoader ++{ ++ static ++ { ++ registerAsParallelCapable(); ++ } ++ ++ private final ClassLoader parent; ++ ++ private final Set imports = new HashSet<>(); ++ ++ private final Set importsAll = new HashSet<>(); ++ ++ public IsolatedClassRealm( ClassLoader parent ) ++ { ++ super( new URL[0], null ); ++ this.parent = parent; ++ } ++ ++ public void addJar( Path jar ) ++ { ++ try ++ { ++ addURL( jar.toUri().toURL() ); ++ } ++ catch ( MalformedURLException e ) ++ { ++ throw new RuntimeException( e ); ++ } ++ } ++ ++ public void addJarDirectory( Path dir ) ++ { ++ try ( DirectoryStream stream = Files.newDirectoryStream( dir, "*.jar" ) ) ++ { ++ for ( Path path : stream ) ++ { ++ addJar( path ); ++ } ++ } ++ catch ( IOException e ) ++ { ++ throw new RuntimeException( e ); ++ } ++ } ++ ++ public void importPackage( String packageName ) ++ { ++ imports.add( packageName ); ++ } ++ ++ public void importAllPackages( String packageName ) ++ { ++ importsAll.add( packageName ); ++ } ++ ++ boolean isImported( String name ) ++ { ++ int index = name.lastIndexOf( '/' ); ++ ++ if ( index >= 0 ) ++ { ++ name = name.replace( '/', '.' ); ++ } ++ else ++ { ++ index = Math.max( name.lastIndexOf( '.' ), 0 ); ++ } ++ ++ String namespace = name.substring( 0, index ); ++ ++ if ( imports.contains( namespace ) ) ++ return true; ++ ++ while ( !namespace.isEmpty() ) ++ { ++ if ( importsAll.contains( namespace ) ) ++ return true; ++ ++ namespace = namespace.substring( 0, Math.max( namespace.lastIndexOf( '.' ), 0 ) ); ++ } ++ ++ return false; ++ } ++ ++ @Override ++ public Class loadClass( String name ) ++ throws ClassNotFoundException ++ { ++ return loadClass( name, false ); ++ } ++ ++ @Override ++ protected Class loadClass( String name, boolean resolve ) ++ throws ClassNotFoundException ++ { ++ if ( isImported( name ) ) ++ { ++ try ++ { ++ return parent.loadClass( name ); ++ } ++ catch ( ClassNotFoundException e ) ++ { ++ } ++ } ++ ++ try ++ { ++ return super.loadClass( name, resolve ); ++ } ++ catch ( ClassNotFoundException e ) ++ { ++ } ++ ++ synchronized ( getClassLoadingLock( name ) ) ++ { ++ Class clazz = findLoadedClass( name ); ++ if ( clazz != null ) ++ { ++ return clazz; ++ } ++ ++ try ++ { ++ return super.findClass( name ); ++ } ++ catch ( ClassNotFoundException e ) ++ { ++ } ++ } ++ ++ throw new ClassNotFoundException( name ); ++ } ++ ++ @Override ++ protected Class findClass( String name ) ++ throws ClassNotFoundException ++ { ++ throw new ClassNotFoundException( name ); ++ } ++ ++ @Override ++ public URL getResource( String name ) ++ { ++ if ( isImported( name ) ) ++ { ++ URL resource = parent.getResource( name ); ++ if ( resource != null ) ++ { ++ return resource; ++ } ++ } ++ ++ URL resource = super.getResource( name ); ++ if ( resource != null ) ++ { ++ return resource; ++ } ++ ++ resource = super.findResource( name ); ++ if ( resource != null ) ++ { ++ return resource; ++ } ++ ++ return null; ++ } ++ ++ @Override ++ public Enumeration getResources( String name ) ++ throws IOException ++ { ++ Collection resources = new LinkedHashSet<>(); ++ ++ if ( isImported( name ) ) ++ { ++ try ++ { ++ resources.addAll( Collections.list( parent.getResources( name ) ) ); ++ } ++ catch ( IOException e ) ++ { ++ } ++ } ++ ++ try ++ { ++ resources.addAll( Collections.list( super.getResources( name ) ) ); ++ } ++ catch ( IOException e ) ++ { ++ } ++ ++ try ++ { ++ resources.addAll( Collections.list( super.findResources( name ) ) ); ++ } ++ catch ( IOException e ) ++ { ++ } ++ ++ return Collections.enumeration( resources ); ++ } ++} +-- +2.9.3 + diff --git a/SOURCES/0001-Port-to-Gradle-4.2.patch b/SOURCES/0001-Port-to-Gradle-4.2.patch new file mode 100644 index 0000000..0e2a2f8 --- /dev/null +++ b/SOURCES/0001-Port-to-Gradle-4.2.patch @@ -0,0 +1,568 @@ +From 34b37637bd469621bb3eadfdf5fb856a806722df Mon Sep 17 00:00:00 2001 +From: Michael Simacek +Date: Mon, 2 Oct 2017 12:01:09 +0300 +Subject: [PATCH] Port to Gradle 4.2 + +--- + libs/gradle-core-api/pom.xml | 32 ++++++ + libs/gradle-logging/pom.xml | 32 ++++++ + libs/gradle-model-core/pom.xml | 32 ++++++ + libs/pom.xml | 3 + + xmvn-connector-gradle/pom.xml | 15 +++ + .../xmvn/connector/gradle/GradleResolver.java | 119 ++++++++++++++------- + .../xmvn/connector/gradle/XMvnGradlePlugin.java | 16 +-- + .../xmvn/connector/gradle/XMvnInstallTask.java | 22 +++- + xmvn-parent/pom.xml | 17 ++- + 9 files changed, 235 insertions(+), 53 deletions(-) + create mode 100644 libs/gradle-core-api/pom.xml + create mode 100644 libs/gradle-logging/pom.xml + create mode 100644 libs/gradle-model-core/pom.xml + +diff --git a/libs/gradle-core-api/pom.xml b/libs/gradle-core-api/pom.xml +new file mode 100644 +index 00000000..7b3d68d5 +--- /dev/null ++++ b/libs/gradle-core-api/pom.xml +@@ -0,0 +1,32 @@ ++ ++ ++ ++ 4.0.0 ++ ++ org.fedoraproject.xmvn ++ libs ++ 3.0.0 ++ .. ++ ++ org.gradle ++ gradle-core-api ++ ${gradleVersion} ++ Gradle core API module ++ +diff --git a/libs/gradle-logging/pom.xml b/libs/gradle-logging/pom.xml +new file mode 100644 +index 00000000..d2dec7c1 +--- /dev/null ++++ b/libs/gradle-logging/pom.xml +@@ -0,0 +1,32 @@ ++ ++ ++ ++ 4.0.0 ++ ++ org.fedoraproject.xmvn ++ libs ++ 3.0.0 ++ .. ++ ++ org.gradle ++ gradle-logging ++ ${gradleVersion} ++ Gradle logging module ++ +diff --git a/libs/gradle-model-core/pom.xml b/libs/gradle-model-core/pom.xml +new file mode 100644 +index 00000000..f841b960 +--- /dev/null ++++ b/libs/gradle-model-core/pom.xml +@@ -0,0 +1,32 @@ ++ ++ ++ ++ 4.0.0 ++ ++ org.fedoraproject.xmvn ++ libs ++ 3.0.0 ++ .. ++ ++ org.gradle ++ gradle-model-core ++ ${gradleVersion} ++ Gradle model-core module ++ +diff --git a/libs/pom.xml b/libs/pom.xml +index 2b31c5d0..fc29e359 100644 +--- a/libs/pom.xml ++++ b/libs/pom.xml +@@ -37,8 +37,11 @@ + gradle-base-services + gradle-base-services-groovy + gradle-core ++ gradle-core-api ++ gradle-model-core + gradle-dependency-management + gradle-resources ++ gradle-logging + + + +diff --git a/xmvn-connector-gradle/pom.xml b/xmvn-connector-gradle/pom.xml +index b433e5dd..f18a285e 100644 +--- a/xmvn-connector-gradle/pom.xml ++++ b/xmvn-connector-gradle/pom.xml +@@ -54,11 +54,21 @@ + + + org.gradle ++ gradle-core-api ++ provided ++ ++ ++ org.gradle + gradle-core + provided + + + org.gradle ++ gradle-model-core ++ provided ++ ++ ++ org.gradle + gradle-dependency-management + provided + +@@ -68,6 +78,11 @@ + provided + + ++ org.gradle ++ gradle-logging ++ provided ++ ++ + org.apache.ivy + ivy + provided +diff --git a/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/GradleResolver.java b/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/GradleResolver.java +index a81c5bc0..6305aa86 100644 +--- a/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/GradleResolver.java ++++ b/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/GradleResolver.java +@@ -18,41 +18,47 @@ package org.fedoraproject.xmvn.connector.gradle; + import java.nio.file.Path; + import java.util.Collections; + import java.util.LinkedHashSet; ++import java.util.Map; + import java.util.Set; + ++import org.gradle.api.artifacts.ComponentMetadataSupplier; + import org.gradle.api.artifacts.ModuleVersionIdentifier; ++import org.gradle.api.artifacts.component.ComponentArtifactIdentifier; + import org.gradle.api.artifacts.component.ModuleComponentIdentifier; ++import org.gradle.api.internal.artifacts.ImmutableModuleIdentifierFactory; + import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ConfiguredModuleComponentRepository; + import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ModuleComponentRepositoryAccess; + import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.DescriptorParseContext; +-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.GradlePomModuleDescriptorParser; + import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.MetaDataParser; +-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.DefaultVersionComparator; +-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.DefaultVersionSelectorScheme; ++import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvableArtifact; + import org.gradle.api.internal.artifacts.repositories.AbstractArtifactRepository; + import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository; ++import org.gradle.api.internal.artifacts.repositories.resolver.MetadataFetchingCost; + import org.gradle.api.internal.component.ArtifactType; +-import org.gradle.internal.component.external.model.DefaultMavenModuleResolveMetaData; +-import org.gradle.internal.component.external.model.DefaultModuleComponentArtifactMetaData; +-import org.gradle.internal.component.external.model.ModuleComponentResolveMetaData; +-import org.gradle.internal.component.external.model.MutableModuleComponentResolveMetaData; +-import org.gradle.internal.component.model.ComponentArtifactMetaData; ++import org.gradle.internal.component.external.model.DefaultModuleComponentArtifactMetadata; ++import org.gradle.internal.component.external.model.DefaultMutableMavenModuleResolveMetadata; ++import org.gradle.internal.component.external.model.FixedComponentArtifacts; ++import org.gradle.internal.component.external.model.ModuleComponentArtifactMetadata; ++import org.gradle.internal.component.external.model.ModuleComponentResolveMetadata; ++import org.gradle.internal.component.external.model.MutableMavenModuleResolveMetadata; ++import org.gradle.internal.component.external.model.MutableModuleComponentResolveMetadata; ++import org.gradle.internal.component.model.ComponentArtifactMetadata; + import org.gradle.internal.component.model.ComponentOverrideMetadata; +-import org.gradle.internal.component.model.ComponentResolveMetaData; +-import org.gradle.internal.component.model.ComponentUsage; ++import org.gradle.internal.component.model.ComponentResolveMetadata; + import org.gradle.internal.component.model.DefaultIvyArtifactName; +-import org.gradle.internal.component.model.DependencyMetaData; ++import org.gradle.internal.component.model.DependencyMetadata; + import org.gradle.internal.component.model.IvyArtifactName; + import org.gradle.internal.component.model.ModuleSource; + import org.gradle.internal.resolve.ArtifactResolveException; + import org.gradle.internal.resolve.ModuleVersionResolveException; + import org.gradle.internal.resolve.result.BuildableArtifactResolveResult; + import org.gradle.internal.resolve.result.BuildableArtifactSetResolveResult; ++import org.gradle.internal.resolve.result.BuildableComponentArtifactsResolveResult; + import org.gradle.internal.resolve.result.BuildableModuleComponentMetaDataResolveResult; + import org.gradle.internal.resolve.result.BuildableModuleVersionListingResolveResult; +-import org.gradle.internal.resource.local.DefaultLocallyAvailableExternalResource; +-import org.gradle.internal.resource.local.DefaultLocallyAvailableResource; ++import org.gradle.internal.resource.local.FileResourceRepository; + import org.gradle.internal.resource.local.LocallyAvailableExternalResource; ++import org.gradle.internal.resource.metadata.DefaultExternalResourceMetaData; + import org.slf4j.Logger; + import org.slf4j.LoggerFactory; + +@@ -72,6 +78,21 @@ public class GradleResolver + implements ResolutionAwareRepository, ConfiguredModuleComponentRepository, ModuleComponentRepositoryAccess, + DescriptorParseContext + { ++ public GradleResolver( MetaDataParser pomParser, ++ ImmutableModuleIdentifierFactory moduleIdentifierFactory, ++ FileResourceRepository fileRepository ) ++ { ++ this.pomParser = pomParser; ++ this.moduleIdentifierFactory = moduleIdentifierFactory; ++ this.fileRepository = fileRepository; ++ } ++ ++ private MetaDataParser pomParser; ++ ++ private ImmutableModuleIdentifierFactory moduleIdentifierFactory; ++ ++ private FileResourceRepository fileRepository; ++ + private final Logger logger = LoggerFactory.getLogger( GradleResolver.class ); + + static class LazyLocatorProvider +@@ -135,17 +156,17 @@ public class GradleResolver + } + + @Override +- public void listModuleVersions( DependencyMetaData arg0, BuildableModuleVersionListingResolveResult arg1 ) ++ public void listModuleVersions( DependencyMetadata arg0, BuildableModuleVersionListingResolveResult arg1 ) + { + logger.debug( "listModuleVersions() called, but it is NOT IMPLEMENTED" ); + } + + @Override +- public void resolveArtifact( ComponentArtifactMetaData artifact, ModuleSource module, ++ public void resolveArtifact( ComponentArtifactMetadata artifact, ModuleSource module, + BuildableArtifactResolveResult result ) + { + ModuleVersionIdentifier moduleId = +- ( (DefaultModuleComponentArtifactMetaData) artifact ).toArtifactIdentifier().getModuleVersionIdentifier(); ++ ( (DefaultModuleComponentArtifactMetadata) artifact ).toArtifactIdentifier().getModuleVersionIdentifier(); + String groupId = moduleId.getGroup(); + String artifactId = artifact.getName().getName(); + String extension = artifact.getName().getExtension(); +@@ -180,11 +201,9 @@ public class GradleResolver + { + logger.debug( "Found Maven POM: {}", pomPath ); + +- MetaDataParser parser = +- new GradlePomModuleDescriptorParser( new DefaultVersionSelectorScheme( new DefaultVersionComparator() ) ); +- MutableModuleComponentResolveMetaData metaData = parser.parseMetaData( this, pomPath.toFile() ); ++ MutableModuleComponentResolveMetadata metaData = pomParser.parseMetaData( this, pomPath.toFile() ); + +- result.resolved( metaData ); ++ result.resolved( metaData.asImmutable() ); + return; + } + else +@@ -204,9 +223,11 @@ public class GradleResolver + if ( path != null ) + { + logger.debug( "Artifact {} found, returning minimal model", artifact3 ); +- MutableModuleComponentResolveMetaData metaData = +- new DefaultMavenModuleResolveMetaData( id, request.getArtifacts() ); +- result.resolved( metaData ); ++ ModuleVersionIdentifier mvi = ++ moduleIdentifierFactory.moduleWithVersion( id.getGroup(), id.getModule(), id.getVersion() ); ++ MutableModuleComponentResolveMetadata metaData = ++ new DefaultMutableMavenModuleResolveMetadata( mvi, id, request.getArtifacts() ); ++ result.resolved( metaData.asImmutable() ); + return; + } + } +@@ -224,24 +245,15 @@ public class GradleResolver + + if ( artifactSet.isEmpty() ) + { +- artifactSet.add( new DefaultIvyArtifactName( id.getModule(), "jar", "jar", +- Collections.emptyMap() ) ); ++ artifactSet.add( new DefaultIvyArtifactName( id.getModule(), "jar", "jar", null ) ); + } + + return artifactSet; + } + + @Override +- public void resolveModuleArtifacts( ComponentResolveMetaData component, ComponentUsage usage, +- BuildableArtifactSetResolveResult result ) +- { +- result.resolved( Collections.singleton( ( (ModuleComponentResolveMetaData) component ).artifact( "jar", "jar", +- null ) ) ); +- } +- +- @Override +- public void resolveModuleArtifacts( ComponentResolveMetaData component, ArtifactType type, +- BuildableArtifactSetResolveResult result ) ++ public void resolveArtifactsWithType( ComponentResolveMetadata component, ArtifactType type, ++ BuildableArtifactSetResolveResult result ) + { + if ( type != ArtifactType.MAVEN_POM ) + { +@@ -250,15 +262,22 @@ public class GradleResolver + return; + } + +- ModuleComponentResolveMetaData metaData = (ModuleComponentResolveMetaData) component; +- ModuleComponentIdentifier id = metaData.getComponentId(); ++ ModuleComponentIdentifier id = (ModuleComponentIdentifier) component.getComponentId(); + DefaultIvyArtifactName name = new DefaultIvyArtifactName( id.getModule(), "pom", "pom" ); +- DefaultModuleComponentArtifactMetaData resolvedMetaData = +- new DefaultModuleComponentArtifactMetaData( id, name ); ++ DefaultModuleComponentArtifactMetadata resolvedMetaData = ++ new DefaultModuleComponentArtifactMetadata( id, name ); + result.resolved( Collections.singleton( resolvedMetaData ) ); + } + + @Override ++ public void resolveArtifacts( ComponentResolveMetadata component, BuildableComponentArtifactsResolveResult result ) ++ { ++ ModuleComponentArtifactMetadata artifact = ++ ( (ModuleComponentResolveMetadata) component ).artifact( "jar", "jar", null ); ++ result.resolved( new FixedComponentArtifacts( Collections.singleton( artifact ) ) ); ++ } ++ ++ @Override + public LocallyAvailableExternalResource getMetaDataArtifact( ModuleComponentIdentifier id, ArtifactType type ) + { + Path pomPath = resolve( new DefaultArtifact( id.getGroup(), id.getModule(), "pom", id.getVersion() ) ); +@@ -266,7 +285,25 @@ public class GradleResolver + if ( pomPath == null ) + return null; + +- return new DefaultLocallyAvailableExternalResource( pomPath.toUri(), +- new DefaultLocallyAvailableResource( pomPath.toFile() ) ); ++ DefaultExternalResourceMetaData metadata = new DefaultExternalResourceMetaData( pomPath.toUri(), 0, 0 ); ++ return fileRepository.resource( pomPath.toFile(), pomPath.toUri(), metadata ); ++ } ++ ++ @Override ++ public ComponentMetadataSupplier createMetadataSupplier() ++ { ++ return null; ++ } ++ ++ @Override ++ public Map getArtifactCache() ++ { ++ return Collections.emptyMap(); ++ } ++ ++ @Override ++ public MetadataFetchingCost estimateMetadataFetchingCost( ModuleComponentIdentifier arg0 ) ++ { ++ return MetadataFetchingCost.CHEAP; + } + } +diff --git a/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/XMvnGradlePlugin.java b/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/XMvnGradlePlugin.java +index 2646f098..c3250e3c 100644 +--- a/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/XMvnGradlePlugin.java ++++ b/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/XMvnGradlePlugin.java +@@ -15,9 +15,11 @@ + */ + package org.fedoraproject.xmvn.connector.gradle; + ++import groovy.lang.Closure; ++import groovy.lang.GroovyShell; + import org.gradle.api.Plugin; + import org.gradle.api.Task; +-import org.gradle.api.artifacts.repositories.ArtifactRepository; ++import org.gradle.api.artifacts.dsl.RepositoryHandler; + import org.gradle.api.invocation.Gradle; + + /** +@@ -26,15 +28,17 @@ import org.gradle.api.invocation.Gradle; + public class XMvnGradlePlugin + implements Plugin + { ++ private void configureRepositories( RepositoryHandler repositories ) ++ { ++ repositories.configure( (Closure) new GroovyShell().evaluate( "{ it -> xmvn() }" ) ); ++ } ++ + @Override + public void apply( Gradle gradle ) + { +- ArtifactRepository repo = new GradleResolver(); +- repo.setName( "xmvn" ); +- + gradle.allprojects( project -> { +- project.getRepositories().addFirst( repo ); +- project.getBuildscript().getRepositories().addFirst( repo ); ++ configureRepositories( project.getRepositories() ); ++ configureRepositories( project.getBuildscript().getRepositories() ); + + Task upload = project.getTasks().create( "xmvnInstall", XMvnInstallTask.class ); + upload.setDescription( "Installs all artifacts through XMvn" ); +diff --git a/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/XMvnInstallTask.java b/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/XMvnInstallTask.java +index 196f4a5b..07905f1f 100644 +--- a/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/XMvnInstallTask.java ++++ b/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/XMvnInstallTask.java +@@ -17,6 +17,7 @@ package org.fedoraproject.xmvn.connector.gradle; + + import java.nio.file.Files; + import java.util.Collections; ++import java.util.HashSet; + import java.util.List; + import java.util.Set; + import java.util.stream.Collectors; +@@ -32,7 +33,7 @@ import org.gradle.api.artifacts.PublishArtifact; + import org.gradle.api.artifacts.PublishException; + import org.gradle.api.component.SoftwareComponent; + import org.gradle.api.internal.component.SoftwareComponentInternal; +-import org.gradle.api.internal.component.Usage; ++import org.gradle.api.internal.component.UsageContext; + import org.gradle.api.tasks.TaskAction; + + import org.fedoraproject.xmvn.artifact.Artifact; +@@ -83,7 +84,7 @@ class XMvnInstallTask + Project dependencyProject = projectDependency.getDependencyProject(); + Stream components = dependencyProject.getComponents().stream(); + Stream internalComponents = components.map( c -> (SoftwareComponentInternal) c ); +- Stream usages = internalComponents.flatMap( ic -> ic.getUsages().stream() ); ++ Stream usages = internalComponents.flatMap( ic -> ic.getUsages().stream() ); + Stream publishArtifacts = usages.flatMap( usage -> usage.getArtifacts().stream() ); + Stream artifacts = publishArtifacts.map( pa -> getPublishArtifact( dependencyProject, pa ) ); + return artifacts.collect( Collectors.toList() ); +@@ -144,7 +145,13 @@ class XMvnInstallTask + } + } + +- DeploymentResult result = getDeployer().deploy( request ); ++ DeploymentResult result; ++ ++ // prevent parallel access to installation plan ++ synchronized ( XMvnInstallTask.class ) ++ { ++ result = getDeployer().deploy( request ); ++ } + + if ( result.getException() != null ) + { +@@ -155,17 +162,22 @@ class XMvnInstallTask + @TaskAction + protected void deployProject() + { ++ Set seenArtifacts = new HashSet<>(); ++ + for ( SoftwareComponent component : getProject().getComponents() ) + { + SoftwareComponentInternal internalComponent = (SoftwareComponentInternal) component; + +- for ( Usage usage : internalComponent.getUsages() ) ++ for ( UsageContext usage : internalComponent.getUsages() ) + { + Set dependencies = usage.getDependencies(); + + for ( PublishArtifact artifact : usage.getArtifacts() ) + { +- deploy( artifact, dependencies ); ++ if ( seenArtifacts.add( artifact ) ) ++ { ++ deploy( artifact, dependencies ); ++ } + } + } + } +diff --git a/xmvn-parent/pom.xml b/xmvn-parent/pom.xml +index 661cc24d..7e7a6d94 100644 +--- a/xmvn-parent/pom.xml ++++ b/xmvn-parent/pom.xml +@@ -84,7 +84,7 @@ + 1 + 2.4.0 + 1.64 +- 2.13-rc-1 ++ 4.2.1 + 2.4.10 + 2.2 + 1.0.3 +@@ -278,11 +278,21 @@ + + + org.gradle ++ gradle-core-api ++ ${gradleVersion} ++ ++ ++ org.gradle + gradle-core + ${gradleVersion} + + + org.gradle ++ gradle-model-core ++ ${gradleVersion} ++ ++ ++ org.gradle + gradle-dependency-management + ${gradleVersion} + +@@ -292,6 +302,11 @@ + ${gradleVersion} + + ++ org.gradle ++ gradle-logging ++ ${gradleVersion} ++ ++ + org.codehaus.groovy + groovy-all + ${groovyVersion} +-- +2.13.6 + diff --git a/SOURCES/0001-Port-to-Gradle-4.3.1.patch b/SOURCES/0001-Port-to-Gradle-4.3.1.patch new file mode 100644 index 0000000..efc5531 --- /dev/null +++ b/SOURCES/0001-Port-to-Gradle-4.3.1.patch @@ -0,0 +1,62 @@ +From cd6cf796f7c2230c940f95f46dc905a25152c486 Mon Sep 17 00:00:00 2001 +From: Michael Simacek +Date: Fri, 10 Nov 2017 15:13:45 +0200 +Subject: [PATCH] Port to Gradle 4.3.1 + +--- + .../java/org/fedoraproject/xmvn/connector/gradle/GradleResolver.java | 2 +- + .../java/org/fedoraproject/xmvn/connector/gradle/XMvnInstallTask.java | 4 ++-- + xmvn-parent/pom.xml | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/GradleResolver.java b/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/GradleResolver.java +index 6305aa86..9e1a247a 100644 +--- a/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/GradleResolver.java ++++ b/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/GradleResolver.java +@@ -226,7 +226,7 @@ public class GradleResolver + ModuleVersionIdentifier mvi = + moduleIdentifierFactory.moduleWithVersion( id.getGroup(), id.getModule(), id.getVersion() ); + MutableModuleComponentResolveMetadata metaData = +- new DefaultMutableMavenModuleResolveMetadata( mvi, id, request.getArtifacts() ); ++ DefaultMutableMavenModuleResolveMetadata.missing( mvi, id ); + result.resolved( metaData.asImmutable() ); + return; + } +diff --git a/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/XMvnInstallTask.java b/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/XMvnInstallTask.java +index 07905f1f..d220e266 100644 +--- a/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/XMvnInstallTask.java ++++ b/xmvn-connector-gradle/src/main/java/org/fedoraproject/xmvn/connector/gradle/XMvnInstallTask.java +@@ -116,7 +116,7 @@ class XMvnInstallTask + } ).collect( Collectors.toList() ); + } + +- private void deploy( PublishArtifact gradleArtifact, Set dependencies ) ++ private void deploy( PublishArtifact gradleArtifact, Set dependencies ) + { + DeploymentRequest request = new DeploymentRequest(); + +@@ -170,7 +170,7 @@ class XMvnInstallTask + + for ( UsageContext usage : internalComponent.getUsages() ) + { +- Set dependencies = usage.getDependencies(); ++ Set dependencies = usage.getDependencies(); + + for ( PublishArtifact artifact : usage.getArtifacts() ) + { +diff --git a/xmvn-parent/pom.xml b/xmvn-parent/pom.xml +index 7e7a6d94..910e27b6 100644 +--- a/xmvn-parent/pom.xml ++++ b/xmvn-parent/pom.xml +@@ -84,7 +84,7 @@ + 1 + 2.4.0 + 1.64 +- 4.2.1 ++ 4.3.1 + 2.4.10 + 2.2 + 1.0.3 +-- +2.13.6 + diff --git a/SOURCES/0001-Support-setting-Xdoclint-none-in-m-javadoc-p-3.0.0.patch b/SOURCES/0001-Support-setting-Xdoclint-none-in-m-javadoc-p-3.0.0.patch new file mode 100644 index 0000000..c483cf4 --- /dev/null +++ b/SOURCES/0001-Support-setting-Xdoclint-none-in-m-javadoc-p-3.0.0.patch @@ -0,0 +1,30 @@ +From 9aa9c66be355d95e2c532bbdfdc98bdbba9b6606 Mon Sep 17 00:00:00 2001 +From: Michael Simacek +Date: Thu, 7 Dec 2017 15:50:52 +0200 +Subject: [PATCH] Support setting "-Xdoclint:none" in m-javadoc-p >= 3.0.0 + +maven-javadoc-plugin 3.0.0 replaced `additionalparam` string property +with `additionalOptions` list property. +See: https://issues.apache.org/jira/browse/MJAVADOC-368 +--- + .../fedoraproject/xmvn/connector/aether/XMvnMojoExecutionListener.java | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/xmvn-connector-aether/src/main/java/org/fedoraproject/xmvn/connector/aether/XMvnMojoExecutionListener.java b/xmvn-connector-aether/src/main/java/org/fedoraproject/xmvn/connector/aether/XMvnMojoExecutionListener.java +index 5f9b5dd4..bb066638 100644 +--- a/xmvn-connector-aether/src/main/java/org/fedoraproject/xmvn/connector/aether/XMvnMojoExecutionListener.java ++++ b/xmvn-connector-aether/src/main/java/org/fedoraproject/xmvn/connector/aether/XMvnMojoExecutionListener.java +@@ -267,7 +267,10 @@ public class XMvnMojoExecutionListener + // Disable doclint + if ( JAVADOC_AGGREGATE.equals( execution ) ) + { ++ // maven-javadoc-plugin < 3.0.0 + trySetBeanProperty( mojo, "additionalparam", "-Xdoclint:none" ); ++ // maven-javadoc-plugin >= 3.0.0 ++ trySetBeanProperty( mojo, "additionalOptions", new String[] { "-Xdoclint:none" } ); + } + else if ( XMVN_BUILDDEP.equals( execution ) ) + { +-- +2.14.3 + diff --git a/SOURCES/0001-Use-apache-commons-compress-for-manifest-injection-a.patch b/SOURCES/0001-Use-apache-commons-compress-for-manifest-injection-a.patch new file mode 100644 index 0000000..ff552e8 --- /dev/null +++ b/SOURCES/0001-Use-apache-commons-compress-for-manifest-injection-a.patch @@ -0,0 +1,593 @@ +From 4e1e7377d6318d2bd7dd8620269e172a704650e2 Mon Sep 17 00:00:00 2001 +From: Michael Simacek +Date: Mon, 16 Apr 2018 15:29:50 +0200 +Subject: [PATCH] Use apache-commons-compress for manifest injection and native + code detection + +--- + xmvn-parent/pom.xml | 8 +- + xmvn-tools/xmvn-install/pom.xml | 4 + + .../fedoraproject/xmvn/tools/install/JarUtils.java | 176 +++++++++------------ + .../xmvn/tools/install/impl/JarUtilsTest.java | 55 +++++++ + .../src/test/resources/recompression-size.jar | Bin 0 -> 4376 bytes + xmvn.spec | 3 +- + 6 files changed, 140 insertions(+), 106 deletions(-) + create mode 100644 xmvn-tools/xmvn-install/src/test/resources/recompression-size.jar + +diff --git a/xmvn-parent/pom.xml b/xmvn-parent/pom.xml +index df6af7fb..f6465d90 100644 +--- a/xmvn-parent/pom.xml ++++ b/xmvn-parent/pom.xml +@@ -92,6 +92,7 @@ + 3.0.24 + 3.5 + 1.7.25 ++ 1.16.1 + + + 1.3.2.GA +@@ -102,7 +103,7 @@ + 3.6.1 + 3.0.0 + 2.8.2 +- 3.4 ++ 3.5 + 1.6 + 2.5.2 + 0.7.9 +@@ -321,6 +322,11 @@ + plexus-container-default + ${plexusVersion} + ++ ++ org.apache.commons ++ commons-compress ++ ${commonsCompressVersion} ++ + + + +diff --git a/xmvn-tools/xmvn-install/pom.xml b/xmvn-tools/xmvn-install/pom.xml +index 66ac01d7..fbb36a68 100644 +--- a/xmvn-tools/xmvn-install/pom.xml ++++ b/xmvn-tools/xmvn-install/pom.xml +@@ -61,5 +61,9 @@ + org.ow2.asm + asm + ++ ++ org.apache.commons ++ commons-compress ++ + + +diff --git a/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/JarUtils.java b/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/JarUtils.java +index 98d3a57e..5cb62b0f 100644 +--- a/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/JarUtils.java ++++ b/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/JarUtils.java +@@ -16,19 +16,16 @@ + package org.fedoraproject.xmvn.tools.install; + + import java.io.IOException; +-import java.lang.reflect.Field; ++import java.io.InputStream; + import java.nio.file.Files; + import java.nio.file.Path; +-import java.util.Collection; ++import java.util.Enumeration; + import java.util.jar.Attributes; +-import java.util.jar.JarEntry; +-import java.util.jar.JarInputStream; +-import java.util.jar.JarOutputStream; + import java.util.jar.Manifest; +-import java.util.zip.ZipEntry; +-import java.util.zip.ZipInputStream; +-import java.util.zip.ZipOutputStream; + ++import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; ++import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; ++import org.apache.commons.compress.archivers.zip.ZipFile; + import org.objectweb.asm.ClassReader; + import org.objectweb.asm.ClassVisitor; + import org.objectweb.asm.MethodVisitor; +@@ -43,6 +40,8 @@ import org.fedoraproject.xmvn.artifact.Artifact; + */ + public final class JarUtils + { ++ private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF"; ++ + private static final Logger LOGGER = LoggerFactory.getLogger( JarUtils.class ); + + // From /usr/include/linux/elf.h +@@ -67,28 +66,33 @@ public final class JarUtils + * + * @return {@code true} if native code was found inside given JAR + */ +- public static boolean containsNativeCode( Path jar ) ++ public static boolean containsNativeCode( Path jarPath ) + { +- try ( ZipInputStream jis = new ZipInputStream( Files.newInputStream( jar ) ) ) ++ try ( ZipFile jar = new ZipFile( jarPath.toFile() ) ) + { +- ZipEntry ent; +- while ( ( ent = jis.getNextEntry() ) != null ) ++ Enumeration entries = jar.getEntries(); ++ while ( entries.hasMoreElements() ) + { +- if ( ent.isDirectory() ) ++ ZipArchiveEntry entry = entries.nextElement(); ++ if ( entry.isDirectory() ) + continue; +- if ( jis.read() == ELFMAG0 && jis.read() == ELFMAG1 && jis.read() == ELFMAG2 && jis.read() == ELFMAG3 ) ++ try ( InputStream jis = jar.getInputStream( entry ) ) + { +- LOGGER.debug( "Native code found inside {}: {}", jar, ent.getName() ); +- return true; ++ if ( jis.read() == ELFMAG0 && jis.read() == ELFMAG1 && jis.read() == ELFMAG2 ++ && jis.read() == ELFMAG3 ) ++ { ++ LOGGER.debug( "Native code found inside {}: {}", jarPath, entry.getName() ); ++ return true; ++ } + } + } + +- LOGGER.trace( "Native code not found inside {}", jar ); ++ LOGGER.trace( "Native code not found inside {}", jarPath ); + return false; + } + catch ( IOException e ) + { +- LOGGER.debug( "I/O exception caught when trying to determine whether JAR contains native code: {}", jar, ++ LOGGER.debug( "I/O exception caught when trying to determine whether JAR contains native code: {}", jarPath, + e ); + return false; + } +@@ -122,40 +126,47 @@ public final class JarUtils + * + * @return {@code true} given JAR as found inside to use native code + */ +- public static boolean usesNativeCode( Path jar ) ++ public static boolean usesNativeCode( Path jarPath ) + { +- try ( ZipInputStream jis = new ZipInputStream( Files.newInputStream( jar ) ) ) ++ try ( ZipFile jar = new ZipFile( jarPath.toFile() ) ) + { +- ZipEntry ent; +- while ( ( ent = jis.getNextEntry() ) != null ) ++ Enumeration entries = jar.getEntries(); ++ while ( entries.hasMoreElements() ) + { +- final String entryName = ent.getName(); +- if ( ent.isDirectory() || !entryName.endsWith( ".class" ) ) ++ ZipArchiveEntry entry = entries.nextElement(); ++ final String entryName = entry.getName(); ++ if ( entry.isDirectory() || !entryName.endsWith( ".class" ) ) + continue; + +- new ClassReader( jis ).accept( new ClassVisitor( Opcodes.ASM4 ) ++ try ( InputStream jis = jar.getInputStream( entry ) ) + { +- @Override +- public MethodVisitor visitMethod( int flags, String name, String desc, String sig, String[] exc ) ++ new ClassReader( jis ).accept( new ClassVisitor( Opcodes.ASM4 ) + { +- if ( ( flags & Opcodes.ACC_NATIVE ) != 0 ) +- throw new NativeMethodFound( entryName, name, sig ); ++ @Override ++ public MethodVisitor visitMethod( int flags, String name, String desc, String sig, ++ String[] exc ) ++ { ++ if ( ( flags & Opcodes.ACC_NATIVE ) != 0 ) ++ throw new NativeMethodFound( entryName, name, sig ); + +- return super.visitMethod( flags, name, desc, sig, exc ); +- } +- }, ClassReader.SKIP_CODE ); ++ return super.visitMethod( flags, name, desc, sig, exc ); ++ } ++ }, ClassReader.SKIP_CODE ); ++ } + } + + return false; + } + catch ( NativeMethodFound e ) + { +- LOGGER.debug( "Native method {}({}) found in {}: {}", e.methodName, e.methodSignature, jar, e.className ); ++ LOGGER.debug( "Native method {}({}) found in {}: {}", e.methodName, e.methodSignature, jarPath, ++ e.className ); + return true; + } + catch ( IOException e ) + { +- LOGGER.debug( "I/O exception caught when trying to determine whether JAR uses native code: {}", jar, e ); ++ LOGGER.debug( "I/O exception caught when trying to determine whether JAR uses native code: {}", jarPath, ++ e ); + return false; + } + catch ( RuntimeException e ) +@@ -178,29 +189,13 @@ public final class JarUtils + } + } + +- /** +- * OpenJDK has a sanity check that prevents adding duplicate entries to ZIP streams. The problem is that some of +- * JARs we try to inject manifests to (especially the ones created by Gradle) already contain duplicate entries, so +- * manifest injection would always fail for them with "ZipException: duplicate entry". +- *

+- * This function tries to work around this OpenJDK sanity check, effectively allowing creating ZIP files with +- * duplicated entries. It should be called on particular ZIP output stream before adding each duplicate entry. +- * +- * @param zipOutputStream ZIP stream to hack +- */ +- private static void openJdkAvoidDuplicateEntryHack( ZipOutputStream zipOutputStream ) ++ private static void updateManifest( Artifact artifact, Manifest mf ) + { +- try +- { +- Field namesField = ZipOutputStream.class.getDeclaredField( "names" ); +- namesField.setAccessible( true ); +- Collection names = (Collection) namesField.get( zipOutputStream ); +- names.clear(); +- } +- catch ( ReflectiveOperationException e ) +- { +- // This hack relies on OpenJDK internals and therefore is not guaranteed to work. Ignore failures. +- } ++ putAttribute( mf, Artifact.MF_KEY_GROUPID, artifact.getGroupId(), null ); ++ putAttribute( mf, Artifact.MF_KEY_ARTIFACTID, artifact.getArtifactId(), null ); ++ putAttribute( mf, Artifact.MF_KEY_EXTENSION, artifact.getExtension(), Artifact.DEFAULT_EXTENSION ); ++ putAttribute( mf, Artifact.MF_KEY_CLASSIFIER, artifact.getClassifier(), "" ); ++ putAttribute( mf, Artifact.MF_KEY_VERSION, artifact.getVersion(), Artifact.DEFAULT_VERSION ); + } + + /** +@@ -213,65 +208,38 @@ public final class JarUtils + public static void injectManifest( Path targetJar, Artifact artifact ) + { + LOGGER.trace( "Trying to inject manifest to {}", artifact ); +- Manifest mf = null; + try + { +- try ( JarInputStream jis = new JarInputStream( Files.newInputStream( targetJar ) ) ) ++ try ( ZipFile jar = new ZipFile( targetJar.toFile() ) ) + { +- mf = jis.getManifest(); +- if ( mf == null ) ++ ZipArchiveEntry manifestEntry = jar.getEntry( MANIFEST_PATH ); ++ if ( manifestEntry != null ) + { +- // getManifest sometimes doesn't find the manifest, try finding it as plain entry +- ZipEntry ent; +- while ( ( ent = jis.getNextEntry() ) != null ) ++ Manifest mf = new Manifest( jar.getInputStream( manifestEntry ) ); ++ updateManifest( artifact, mf ); ++ Files.delete( targetJar ); ++ try ( ZipArchiveOutputStream os = new ZipArchiveOutputStream( targetJar.toFile() ) ) + { +- if ( ent.getName().equalsIgnoreCase( "META-INF/MANIFEST.MF" ) ) +- { +- mf = new Manifest( jis ); +- break; +- } ++ // write manifest ++ ZipArchiveEntry newManifestEntry = new ZipArchiveEntry( MANIFEST_PATH ); ++ os.putArchiveEntry( newManifestEntry ); ++ mf.write( os ); ++ os.closeArchiveEntry(); ++ // copy the rest of content ++ jar.copyRawEntries( os, entry -> !entry.equals( manifestEntry ) ); + } +- } +- } +- +- if ( mf == null ) +- { +- LOGGER.trace( "Manifest injection skipped: no pre-existing manifest found to update" ); +- return; +- } +- +- putAttribute( mf, Artifact.MF_KEY_GROUPID, artifact.getGroupId(), null ); +- putAttribute( mf, Artifact.MF_KEY_ARTIFACTID, artifact.getArtifactId(), null ); +- putAttribute( mf, Artifact.MF_KEY_EXTENSION, artifact.getExtension(), Artifact.DEFAULT_EXTENSION ); +- putAttribute( mf, Artifact.MF_KEY_CLASSIFIER, artifact.getClassifier(), "" ); +- putAttribute( mf, Artifact.MF_KEY_VERSION, artifact.getVersion(), Artifact.DEFAULT_VERSION ); +- +- try ( JarInputStream jis = new JarInputStream( Files.newInputStream( targetJar ) ) ) +- { +- +- targetJar = targetJar.toRealPath(); +- Files.delete( targetJar ); +- try ( JarOutputStream jos = new JarOutputStream( Files.newOutputStream( targetJar ), mf ) ) +- { +- byte[] buf = new byte[512]; +- JarEntry entry; +- while ( ( entry = jis.getNextJarEntry() ) != null ) ++ catch ( IOException e ) + { +- openJdkAvoidDuplicateEntryHack( jos ); +- jos.putNextEntry( entry ); +- +- int sz; +- while ( ( sz = jis.read( buf ) ) > 0 ) +- jos.write( buf, 0, sz ); ++ // Re-throw exceptions that occur when processing JAR file after reading header and manifest. ++ throw new RuntimeException( e ); + } ++ LOGGER.trace( "Manifest injected successfully" ); + } +- catch ( IOException e ) ++ else + { +- // Re-throw exceptions that occur when processing JAR file after reading header and manifest. +- throw new RuntimeException( e ); ++ LOGGER.trace( "Manifest injection skipped: no pre-existing manifest found to update" ); ++ return; + } +- +- LOGGER.trace( "Manifest injected successfully" ); + } + } + catch ( IOException e ) +diff --git a/xmvn-tools/xmvn-install/src/test/java/org/fedoraproject/xmvn/tools/install/impl/JarUtilsTest.java b/xmvn-tools/xmvn-install/src/test/java/org/fedoraproject/xmvn/tools/install/impl/JarUtilsTest.java +index 3ec10cfa..98945a64 100644 +--- a/xmvn-tools/xmvn-install/src/test/java/org/fedoraproject/xmvn/tools/install/impl/JarUtilsTest.java ++++ b/xmvn-tools/xmvn-install/src/test/java/org/fedoraproject/xmvn/tools/install/impl/JarUtilsTest.java +@@ -19,11 +19,13 @@ import static org.junit.Assert.assertEquals; + import static org.junit.Assert.assertFalse; + import static org.junit.Assert.assertNotNull; + import static org.junit.Assert.assertTrue; ++import static org.junit.Assume.assumeTrue; + + import java.nio.file.Files; + import java.nio.file.Path; + import java.nio.file.Paths; + import java.nio.file.StandardCopyOption; ++import java.nio.file.attribute.PosixFilePermission; + import java.util.Arrays; + import java.util.jar.Attributes; + import java.util.jar.JarInputStream; +@@ -116,6 +118,38 @@ public class JarUtilsTest + } + } + ++ /** ++ * Regression test for a jar which contains an entry that can recompress with a different size, which caused a ++ * mismatch in sizes. ++ * ++ * @throws Exception ++ */ ++ @Test ++ public void testManifestInjectionRecompressionCausesSizeMismatch() ++ throws Exception ++ { ++ Path testResource = Paths.get( "src/test/resources/recompression-size.jar" ); ++ Path testJar = workDir.resolve( "manifest.jar" ); ++ Files.copy( testResource, testJar, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING ); ++ ++ Artifact artifact = ++ new DefaultArtifact( "org.eclipse.osgi", "osgi.compatibility.state", "1.1.0.v20180409-1212" ); ++ JarUtils.injectManifest( testJar, artifact ); ++ ++ try ( JarInputStream jis = new JarInputStream( Files.newInputStream( testJar ) ) ) ++ { ++ Manifest mf = jis.getManifest(); ++ assertNotNull( mf ); ++ ++ Attributes attr = mf.getMainAttributes(); ++ assertNotNull( attr ); ++ ++ assertEquals( "org.eclipse.osgi", attr.getValue( "JavaPackages-GroupId" ) ); ++ assertEquals( "osgi.compatibility.state", attr.getValue( "JavaPackages-ArtifactId" ) ); ++ assertEquals( "1.1.0.v20180409-1212", attr.getValue( "JavaPackages-Version" ) ); ++ } ++ } ++ + /** + * Test JAR if manifest injection works as expected when some artifact fields have default values. + * +@@ -148,6 +182,27 @@ public class JarUtilsTest + } + } + ++ /** ++ * Test JAR if manifest injection preserves sane file perms. ++ * ++ * @throws Exception ++ */ ++ @Test ++ public void testManifestInjectionSanePermissions() ++ throws Exception ++ { ++ Path testResource = Paths.get( "src/test/resources/example.jar" ); ++ Path testJar = workDir.resolve( "manifest.jar" ); ++ Files.copy( testResource, testJar, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING ); ++ ++ assumeTrue( "sane umask", Files.getPosixFilePermissions( testJar ).contains( PosixFilePermission.OTHERS_READ ) ); ++ ++ Artifact artifact = new DefaultArtifact( "org.apache.maven", "maven-model", "xsd", "model", "2.2.1" ); ++ JarUtils.injectManifest( testJar, artifact ); ++ ++ assertTrue( Files.getPosixFilePermissions( testJar ).contains( PosixFilePermission.OTHERS_READ ) ); ++ } ++ + /** + * Test if native code detection works as expected. + * +diff --git a/xmvn-tools/xmvn-install/src/test/resources/recompression-size.jar b/xmvn-tools/xmvn-install/src/test/resources/recompression-size.jar +new file mode 100644 +index 00000000..976481ea +--- /dev/null ++++ b/xmvn-tools/xmvn-install/src/test/resources/recompression-size.jar +@@ -0,0 +1,145 @@ ++PK ++