[xmvn/jenkins] Add patch for injecting Javapackages manifests

Mikolaj Izdebski mizdebsk at fedoraproject.org
Thu May 29 18:00:27 UTC 2014


commit 72f8dc26498d03f4e60612fcb1823ddb38518466
Author: Mikolaj Izdebski <mizdebsk at redhat.com>
Date:   Thu May 29 19:58:42 2014 +0200

    Add patch for injecting Javapackages manifests

 ...x-JAR-post-processing-during-installation.patch |  212 ++++++++++++++++++++
 build.bash                                         |    2 +-
 xmvn.spec                                          |   13 +-
 3 files changed, 225 insertions(+), 2 deletions(-)
---
diff --git a/0001-Fix-JAR-post-processing-during-installation.patch b/0001-Fix-JAR-post-processing-during-installation.patch
new file mode 100644
index 0000000..91a5d8b
--- /dev/null
+++ b/0001-Fix-JAR-post-processing-during-installation.patch
@@ -0,0 +1,212 @@
+From de2dd29f853fdb39ec5916a6c388f81ced4b61a5 Mon Sep 17 00:00:00 2001
+From: Mikolaj Izdebski <mizdebsk at redhat.com>
+Date: Thu, 29 May 2014 18:18:30 +0200
+Subject: [PATCH] Fix JAR post-processing during installation
+
+This improves native code detection and Javapackages manifest
+injection.
+---
+ .../install/impl/DefaultArtifactInstaller.java     |  5 ++
+ .../xmvn/tools/install/impl/JarUtils.java          | 78 ++++++++++++++++++----
+ 2 files changed, 70 insertions(+), 13 deletions(-)
+
+diff --git a/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/DefaultArtifactInstaller.java b/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/DefaultArtifactInstaller.java
+index d973447..38a5eab 100644
+--- a/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/DefaultArtifactInstaller.java
++++ b/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/DefaultArtifactInstaller.java
+@@ -16,6 +16,7 @@
+ package org.fedoraproject.xmvn.tools.install.impl;
+ 
+ import static org.fedoraproject.xmvn.tools.install.impl.JarUtils.containsNativeCode;
++import static org.fedoraproject.xmvn.tools.install.impl.JarUtils.injectManifest;
+ import static org.fedoraproject.xmvn.tools.install.impl.JarUtils.usesNativeCode;
+ 
+ import java.nio.file.Path;
+@@ -65,10 +66,14 @@ public class DefaultArtifactInstaller
+             new DefaultArtifact( am.getGroupId(), am.getArtifactId(), am.getExtension(), am.getClassifier(),
+                                  am.getVersion() );
+ 
++        // Handle native JARs/WARs etc
+         Path artifactPath = Paths.get( am.getPath() );
+         if ( usesNativeCode( artifactPath ) || containsNativeCode( artifactPath ) )
+             am.getProperties().setProperty( "native", "true" );
+ 
++        // Inject Javapackages manifests
++        injectManifest( artifactPath, artifact );
++
+         Map<String, String> properties = new LinkedHashMap<>();
+         for ( String name : am.getProperties().stringPropertyNames() )
+             properties.put( name, am.getProperties().getProperty( name ) );
+diff --git a/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/JarUtils.java b/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/JarUtils.java
+index 0ba8920..5dd09ea 100644
+--- a/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/JarUtils.java
++++ b/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/JarUtils.java
+@@ -30,17 +30,22 @@ import org.objectweb.asm.ClassReader;
+ import org.objectweb.asm.ClassVisitor;
+ import org.objectweb.asm.MethodVisitor;
+ import org.objectweb.asm.Opcodes;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
+ 
+ import org.fedoraproject.xmvn.artifact.Artifact;
+ import org.fedoraproject.xmvn.utils.ArtifactUtils;
++import org.fedoraproject.xmvn.utils.FileUtils;
+ 
+ /**
+  * @author Mikolaj Izdebski
+  */
+ class JarUtils
+ {
++    private static final Logger logger = LoggerFactory.getLogger( JarUtils.class );
++
+     /**
+-     * Heuristically try to determine whether given JAR (or WAR, EAR, ...) file contains native (architecture-dependant)
++     * Heuristically try to determine whether given JAR (or WAR, EAR, ...) file contains native (architecture-dependent)
+      * code.
+      * <p>
+      * Currently this code only checks only for ELF binaries, but that behavior can change in future.
+@@ -63,19 +68,43 @@ class JarUtils
+                 if ( ent.isDirectory() )
+                     continue;
+                 if ( jis.read() == ELFMAG0 && jis.read() == ELFMAG1 && jis.read() == ELFMAG2 && jis.read() == ELFMAG3 )
++                {
++                    logger.debug( "Native code found inside {}: {}", jar, ent.getName() );
+                     return true;
++                }
+             }
+ 
++            logger.trace( "Native code not found inside {}", jar );
+             return false;
+         }
+         catch ( IOException e )
+         {
++            logger.debug( "I/O exception caught when trying to determine whether JAR contains native code: {}", jar, e );
+             return false;
+         }
+     }
+ 
++    static class NativeMethodFound
++        extends RuntimeException
++    {
++        private static final long serialVersionUID = 1;
++
++        final String className;
++
++        final String methodName;
++
++        final String methodSignature;
++
++        NativeMethodFound( String className, String methodName, String methodSignature )
++        {
++            this.className = className;
++            this.methodName = methodName;
++            this.methodSignature = methodSignature;
++        }
++    }
++
+     /**
+-     * Heuristically try to determine whether given JAR (or WAR, EAR, ...) file is using native (architecture-dependant)
++     * Heuristically try to determine whether given JAR (or WAR, EAR, ...) file is using native (architecture-dependent)
+      * code.
+      * <p>
+      * Currently this code only checks if any class file declares Java native methods, but that behavior can change in
+@@ -90,29 +119,33 @@ class JarUtils
+             ZipEntry ent;
+             while ( ( ent = jis.getNextEntry() ) != null )
+             {
+-                if ( ent.isDirectory() || !ent.getName().endsWith( ".class" ) )
++                final String entryName = ent.getName();
++                if ( ent.isDirectory() || !entryName.endsWith( ".class" ) )
+                     continue;
+ 
+-                final boolean[] usesNativeCode = new boolean[1];
+-
+-                new ClassReader( jis ).accept( new ClassVisitor( Opcodes.ASM4 )
++                new ClassReader( jis ).accept( new ClassVisitor( Opcodes.ASM5 )
+                 {
+                     @Override
+                     public MethodVisitor visitMethod( int flags, String name, String desc, String sig, String[] exc )
+                     {
+-                        usesNativeCode[0] = ( flags & Opcodes.ACC_NATIVE ) != 0;
++                        if ( ( flags & Opcodes.ACC_NATIVE ) != 0 )
++                            throw new NativeMethodFound( entryName, name, sig );
++
+                         return super.visitMethod( flags, name, desc, sig, exc );
+                     }
+                 }, ClassReader.SKIP_CODE );
+-
+-                if ( usesNativeCode[0] )
+-                    return true;
+             }
+ 
+             return false;
+         }
++        catch ( NativeMethodFound e )
++        {
++            logger.debug( "Native method {}({}) found in {}: {}", e.methodName, e.methodSignature, jar, e.className );
++            return true;
++        }
+         catch ( IOException e )
+         {
++            logger.debug( "I/O exception caught when trying to determine whether JAR uses native code: {}", jar, e );
+             return false;
+         }
+     }
+@@ -123,6 +156,11 @@ class JarUtils
+         {
+             Attributes attributes = manifest.getMainAttributes();
+             attributes.putValue( key, value );
++            logger.trace( "Injected field {}: {}", key, value );
++        }
++        else
++        {
++            logger.trace( "Not injecting field {} (it has default value \"{}\")", key, defaultValue );
+         }
+     }
+ 
+@@ -132,18 +170,21 @@ class JarUtils
+      * 
+      * @param targetJar
+      * @param artifact
+-     * @throws IOException
+      */
+     public static void injectManifest( Path targetJar, Artifact artifact )
+-        throws IOException
+     {
+-        targetJar = targetJar.toRealPath();
++        logger.trace( "Trying to inject manifest to {}", artifact );
++
++        targetJar = FileUtils.followSymlink( targetJar );
+ 
+         try (JarInputStream jis = new JarInputStream( Files.newInputStream( targetJar ) ))
+         {
+             Manifest mf = jis.getManifest();
+             if ( mf == null )
++            {
++                logger.trace( "Manifest injection skipped: no pre-existing manifest found to update" );
+                 return;
++            }
+ 
+             putAttribute( mf, ArtifactUtils.MF_KEY_GROUPID, artifact.getGroupId(), null );
+             putAttribute( mf, ArtifactUtils.MF_KEY_ARTIFACTID, artifact.getArtifactId(), null );
+@@ -166,6 +207,17 @@ class JarUtils
+                         jos.write( buf, 0, sz );
+                 }
+             }
++            catch ( IOException e )
++            {
++                // 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 )
++        {
++            logger.debug( "I/O exception caught when trying to read JAR: {}", targetJar );
+         }
+     }
+ }
+-- 
+1.9.0
+
diff --git a/build.bash b/build.bash
index a473faf..bed8e81 100644
--- a/build.bash
+++ b/build.bash
@@ -23,7 +23,7 @@ rpmbuild -bs --clean --define "_topdir `pwd`" --define "_sourcedir `pwd`" xmvn.s
 rm -Rf ${resultdir}/*
 # print root.log and build.log in case of failure
 trap "cat ${resultdir}/root.log | tail -30; cat ${resultdir}/build.log || :" 0
-mock -r fedora-rawhide-x86_64 SRPMS/*.src.rpm
+mock -D 'jenkins 1' -r fedora-rawhide-x86_64 SRPMS/*.src.rpm
 
 # remove unneeded stuff
 rm -f xmvn-*.tar.xz
diff --git a/xmvn.spec b/xmvn.spec
index cc5afc6..9143cd8 100644
--- a/xmvn.spec
+++ b/xmvn.spec
@@ -1,6 +1,6 @@
 Name:           xmvn
 Version:        2.0.0
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        Local Extensions for Apache Maven
 License:        ASL 2.0
 URL:            http://mizdebsk.fedorapeople.org/xmvn
@@ -8,6 +8,8 @@ BuildArch:      noarch
 
 Source0:        https://fedorahosted.org/released/%{name}/%{name}-%{version}.tar.xz
 
+Patch0001:      0001-Fix-JAR-post-processing-during-installation.patch
+
 BuildRequires:  maven >= 3.2.1-3
 BuildRequires:  maven-local
 BuildRequires:  beust-jcommander
@@ -134,6 +136,12 @@ This package provides %{summary}.
 %prep
 %setup -q
 
+# Skip patch application on Jenkins - it is supposed to always use the
+# latest vanilla upstream snapshot.
+%if !0%{?jenkins}
+%patch0001 -p1
+%endif
+
 %mvn_package :xmvn __noinstall
 
 # In XMvn 2.x xmvn-connector was renamed to xmvn-connector-aether
@@ -280,6 +288,9 @@ end
 %doc LICENSE NOTICE
 
 %changelog
+* Thu May 29 2014 Mikolaj Izdebski <mizdebsk at redhat.com> - 2.0.0-2
+- Add patch for injecting Javapackages manifests
+
 * Thu May 29 2014 Mikolaj Izdebski <mizdebsk at redhat.com> - 2.0.0-1
 - Update to upstream version 2.0.0
 


More information about the scm-commits mailing list