Skip to content
Permalink
Browse files

Prepare for git client plugin 2.0.0 coexistence

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.

Other plugins depend on the git client plugin implementation of JGit.
They currently (correctly) assume 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 shows how a plugin which depends on the JGit provided with the
git client plugin can be adapted 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 git plugin (and other plugins)
are updated to depend on git client plugin 2.0.  Once they depend on
git client plugin 2.0, this change can be reverted.

Uses reflection to find the close method of RevWalk and TreeWalk classes.
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.

Use release(), not dispose() when ending AbstractGitSCMSource.retrieve()

The javadoc for dispose() hints that release() is a superset.
Using release() is consistent with the rest of the code (and with most
git-client-plugin usages).
  • Loading branch information...
MarkEWaite committed Jul 26, 2016
1 parent b8e17c5 commit 71946a2896d3adcd1171ac59b7c45bacaf7a9c56
@@ -8,7 +8,6 @@
import hudson.plugins.git.Branch;
import hudson.plugins.git.BranchSpec;
import hudson.plugins.git.GitException;
import hudson.plugins.git.GitSCM;
import hudson.plugins.git.Revision;
import hudson.remoting.VirtualChannel;
import hudson.slaves.NodeProperty;
@@ -20,9 +19,12 @@
import org.jenkinsci.plugins.gitclient.GitClient;
import org.jenkinsci.plugins.gitclient.RepositoryCallback;

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

import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.*;
import java.util.logging.Level;
@@ -52,6 +54,46 @@ public static Node workspaceToNode(FilePath workspace) { // TODO https://trello.
return j;
}

private static void _close(@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
*/
private static void _release(RevWalk walk) throws IOException {
if (walk == null) {
return;
}
try {
walk.release(); // JGit 3
} catch (NoSuchMethodError noMethod) {
_close(walk);
}
}

/**
* Return a list of "Revisions" - where a revision knows about all the branch names that refer to
* a SHA1.
@@ -190,7 +232,7 @@ public Revision sortBranchesForRevision(Revision revision, List<BranchSpec> bran
}

} finally {
walk.release();
_release(walk);
}

if (log)
@@ -1,3 +1,4 @@

/*
* The MIT License
*
@@ -74,6 +75,7 @@

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
@@ -84,6 +86,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

@@ -183,6 +186,64 @@ protected SCMRevision retrieve(@NonNull SCMHead head, @NonNull TaskListener list
}
}

private static void _close(@NonNull Object 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
*/
private static void _release(TreeWalk walk) throws IOException {
if (walk == null) {
return;
}
try {
walk.release(); // JGit 3
} catch (NoSuchMethodError noMethod) {
_close(walk);
}
}

/**
* 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
*/
private void _release(RevWalk walk) {
if (walk == null) {
return;
}
try {
walk.release(); // JGit 3
} catch (NoSuchMethodError noMethod) {
_close(walk);
}
}

@NonNull
@Override
protected void retrieve(@NonNull final SCMHeadObserver observer,
@@ -250,9 +311,7 @@ public boolean exists(@NonNull String path) throws IOException {
try {
return tw != null;
} finally {
if (tw != null) {
tw.release();
}
_release(tw);
}
}
};
@@ -271,7 +330,7 @@ public boolean exists(@NonNull String path) throws IOException {
}
}
} finally {
walk.dispose();
_release(walk);
}

listener.getLogger().println("Done.");

0 comments on commit 71946a2

Please sign in to comment.
You can’t perform that action at this time.