Add patch for injecting Javapackages manifests

This commit is contained in:
Mikolaj Izdebski 2014-05-29 19:58:42 +02:00
parent d842140da0
commit 72f8dc2649
3 changed files with 225 additions and 2 deletions

View File

@ -0,0 +1,212 @@
From de2dd29f853fdb39ec5916a6c388f81ced4b61a5 Mon Sep 17 00:00:00 2001
From: Mikolaj Izdebski <mizdebsk@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

View File

@ -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

View File

@ -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@redhat.com> - 2.0.0-2
- Add patch for injecting Javapackages manifests
* Thu May 29 2014 Mikolaj Izdebski <mizdebsk@redhat.com> - 2.0.0-1
- Update to upstream version 2.0.0