Skip to content

Commit

Permalink
Prepare for git client plugin 2.0.0 coexistence
Browse files Browse the repository at this point in the history
The git client plugin 2.0.0 release will switch from delivering JGit 3
to JGit 4.  JGit 4 requires Java 7 and provides Closeable implementations
of its methods that open external resources (like files).  JGit 4 removes
certain methods (like release()) because they are superseded by the JGit
4 Closeable implementation.

The gerrit trigger plugin depends on the git client plugin implementation
of JGit.  It correctly assumes the JGit provided by the git client plugin
is JGit 3.  If no changes are made to the plugins which depend on the
JGit provided by the git client plugin, those plugins will be broken by
the upgrade from JGit 3 to JGit 4.  They will report NoSuchMethodError
exceptions at run time or may report LinkageError exceptions during
class loading on some JVM implementations.

This change adapts the plugin to run with either git client plugin 1.x
(JGit 3) to git client plugin 2.x (JGit 4).

This is a temporary change until the plugin depends on git client
plugin 2.0.  Once it depends on git client plugin 2.0 (and JDK 7),
this change can be reverted.

Uses reflection to find the close method of RevWalk if needed.
When RevWalk and TreeWalk from JGit 3 are loaded, their release()
methods are called.  When RevWalk and TreeWalk from JGit 4 are loaded,
their close() methods are called.
  • Loading branch information
MarkEWaite committed Aug 14, 2016
1 parent 19fcdcc commit f3c16fc
Showing 1 changed file with 53 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,14 @@
import org.kohsuke.stapler.DataBoundConstructor;
import org.eclipse.jgit.lib.ObjectId;

import edu.umd.cs.findbugs.annotations.NonNull;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.sonyericsson.hudson.plugins.gerrit.trigger.Messages;

Expand Down Expand Up @@ -149,6 +154,51 @@ public Build prevBuildForChangelog(String singleBranch, BuildData data, GitClien
}
}

/**
* Close walk through method name found by reflection.
* @param walk the RevWalk object to be closed
*/
private static void closeByReflection(@NonNull RevWalk walk) {
java.lang.reflect.Method closeMethod;
try {
closeMethod = walk.getClass().getDeclaredMethod("close");
} catch (NoSuchMethodException ex) {
LOGGER.log(Level.SEVERE, "Exception finding walker close method: {0}", ex);
return;
} catch (SecurityException ex) {
LOGGER.log(Level.SEVERE, "Exception finding walker close method: {0}", ex);
return;
}
try {
closeMethod.invoke(walk);
} catch (IllegalAccessException ex) {
LOGGER.log(Level.SEVERE, "Exception calling walker close method: {0}", ex);
} catch (IllegalArgumentException ex) {
LOGGER.log(Level.SEVERE, "Exception calling walker close method: {0}", ex);
} catch (InvocationTargetException ex) {
LOGGER.log(Level.SEVERE, "Exception calling walker close method: {0}", ex);
}
}

/**
* Call release method on walk. JGit 3 uses release(), JGit 4 uses close() to
* release resources.
*
* This method should be removed once the code depends on git client 2.0.0.
* @param walk object whose close or release method will be called
* @throws IOException on IO error
*/
private static void releaseOrClose(RevWalk walk) throws IOException {
if (walk == null) {
return;
}
try {
walk.release(); // JGit 3
} catch (NoSuchMethodError noMethod) {
closeByReflection(walk);
}
}

//CS IGNORE RedundantThrows FOR NEXT 30 LINES. REASON: Informative, and could happen.
/**
* Gets the top parent of the given revision.
Expand Down Expand Up @@ -181,9 +231,7 @@ public ObjectId invoke(Repository repository, VirtualChannel virtualChannel)
} catch (Exception e) {
throw new GitException("Failed to find parent id. ", e);
} finally {
if (walk != null) {
walk.release();
}
releaseOrClose(walk);
}
return result;
}
Expand Down Expand Up @@ -227,4 +275,6 @@ public String invoke(Run<?, ?> build, VirtualChannel channel) {
return null;
}
}

private static final Logger LOGGER = Logger.getLogger(GerritTriggerBuildChooser.class.getName());
}

0 comments on commit f3c16fc

Please sign in to comment.