From abf420302bb03b119c19ddf29ef0c968f77c318d Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Tue, 24 Oct 2017 23:13:37 +0200 Subject: [PATCH 1/2] Reintroduce protected method which removal broke EMF Compare So far we follow OSGi semantic versioning [1] which says the following: "A change in the second (minor) part of the version signals that the change is backward compatible with consumers of the API package but not with the providers of that API. That is, when the API package goes from version 1.5 to 1.6 it is no longer compatible with a provider of that API but consumers of that API are backward compatible with that API package." The change Ib5fbf17bdaf727bc5d0e106ce88f2620d9f87a6f broke EMF Compare which subclasses ResolveMerger since we added a new parameter to the protected ResolveMerger.processEntry() method. According to the above cited OSGi semantic versioning this is ok, implementers should expect that they break on minor version changes of the API they implement. This change reintroduces the old processEntry() method in order to help avoid breakage for existing EMF Compare versions which expect breakage also for the implementer case only for major version change (in this case from JGit 4.x to 5.x). [1] http://www.osgi.org/wp-content/uploads/SemanticVersioning1.pdf See: https://dev.eclipse.org/mhonarc/lists/jgit-dev/msg03431.html Change-Id: I48ba4308dee73925fa32d6c2fd6b5fd89632c571 Signed-off-by: Matthias Sohn --- org.eclipse.jgit/.settings/.api_filters | 12 ++++ .../org/eclipse/jgit/merge/ResolveMerger.java | 56 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index 034b20f90..20d08c3a0 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -35,6 +35,18 @@ + + + + + + + + + + + + diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java index 92c2bb35a..23fdc35bd 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -444,6 +444,62 @@ public class ResolveMerger extends ThreeWayMerger { return newEntry; } + /** + * Processes one path and tries to merge taking git attributes in account. + * This method will do all trivial (not content) merges and will also detect + * if a merge will fail. The merge will fail when one of the following is + * true + *
    + *
  • the index entry does not match the entry in ours. When merging one + * branch into the current HEAD, ours will point to HEAD and theirs will + * point to the other branch. It is assumed that the index matches the HEAD + * because it will only not match HEAD if it was populated before the merge + * operation. But the merge commit should not accidentally contain + * modifications done before the merge. Check the git read-tree documentation for further explanations.
  • + *
  • A conflict was detected and the working-tree file is dirty. When a + * conflict is detected the content-merge algorithm will try to write a + * merged version into the working-tree. If the file is dirty we would + * override unsaved data.
  • + *
+ * + * @param base + * the common base for ours and theirs + * @param ours + * the ours side of the merge. When merging a branch into the + * HEAD ours will point to HEAD + * @param theirs + * the theirs side of the merge. When merging a branch into the + * current HEAD theirs will point to the branch which is merged + * into HEAD. + * @param index + * the index entry + * @param work + * the file in the working tree + * @param ignoreConflicts + * see + * {@link ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)} + * @return false if the merge will fail because the index entry + * didn't match ours or the working-dir file was dirty and a + * conflict occurred + * @throws MissingObjectException + * @throws IncorrectObjectTypeException + * @throws CorruptObjectException + * @throws IOException + * @since 3.5 + * @deprecated + */ + @Deprecated + protected boolean processEntry(CanonicalTreeParser base, + CanonicalTreeParser ours, CanonicalTreeParser theirs, + DirCacheBuildIterator index, WorkingTreeIterator work, + boolean ignoreConflicts) throws MissingObjectException, + IncorrectObjectTypeException, CorruptObjectException, IOException { + return processEntry(base, ours, theirs, index, work, ignoreConflicts, + null); + } + /** * Processes one path and tries to merge taking git attributes in account. * This method will do all trivial (not content) merges and will also detect From f67af4e16b3adc0d2c14fa5e2fdc594975e7fe40 Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Tue, 7 Nov 2017 08:19:56 +0100 Subject: [PATCH 2/2] Work around a Jsch bug: ensure the user name is set from URI JSch unconditionally overrides the user name given in the connection URI by the one found in ~/.ssh/config (if that does specify one for the used host). If the SSH config file has a different user name, we'll end up using the wrong name, which typically results in an authentication failure or in Eclipse/EGit asking for a password for the wrong user. Unfortunately there is no way to prevent or circumvent this Jsch behavior up front; it occurs already in the Session constructor at com.jcraft.jsch.Session() and the Session.applyConfig() method. And while there is a Session.setUserName() that would enable us to correct this, that latter method has package visibility only. So resort to reflection to invoke that setUserName() method to ensure that Jsch uses the user name from the URI, if there is one. Bug: 526778 Change-Id: Ia327099b5210a037380b2750a7fd76ff25c41a5a Signed-off-by: Thomas Wolf --- .../eclipse/jgit/internal/JGitText.properties | 1 + .../org/eclipse/jgit/internal/JGitText.java | 1 + .../transport/JschConfigSessionFactory.java | 34 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index 0b9a24779..6e8002ae2 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -608,6 +608,7 @@ sourceIsNotAWildcard=Source is not a wildcard. sourceRefDoesntResolveToAnyObject=Source ref {0} doesn''t resolve to any object. sourceRefNotSpecifiedForRefspec=Source ref not specified for refspec: {0} squashCommitNotUpdatingHEAD=Squash commit -- not updating HEAD +sshUserNameError=Jsch error: failed to set SSH user name correctly to ''{0}''; using ''{1}'' picked up from SSH config file. sslFailureExceptionMessage=Secure connection to {0} could not be stablished because of SSL problems sslFailureInfo=A secure connection to {0}\ncould not be established because the server''s certificate could not be validated. sslFailureCause=SSL reported: {0} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index 4225dba09..0e1a4f3ac 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -667,6 +667,7 @@ public class JGitText extends TranslationBundle { /***/ public String sourceRefDoesntResolveToAnyObject; /***/ public String sourceRefNotSpecifiedForRefspec; /***/ public String squashCommitNotUpdatingHEAD; + /***/ public String sshUserNameError; /***/ public String sslFailureExceptionMessage; /***/ public String sslFailureInfo; /***/ public String sslFailureCause; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java index 7fe9066a3..eadfd69b5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java @@ -53,14 +53,19 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.net.ConnectException; import java.net.UnknownHostException; +import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.util.FS; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; @@ -80,6 +85,10 @@ import com.jcraft.jsch.UserInfo; * to supply appropriate {@link UserInfo} to the session. */ public abstract class JschConfigSessionFactory extends SshSessionFactory { + + private static final Logger LOG = LoggerFactory + .getLogger(JschConfigSessionFactory.class); + private final Map byIdentityFile = new HashMap<>(); private JSch defaultJSch; @@ -177,6 +186,9 @@ public abstract class JschConfigSessionFactory extends SshSessionFactory { FS fs, String user, final String pass, String host, int port, final OpenSshConfig.Host hc) throws JSchException { final Session session = createSession(hc, user, host, port, fs); + // Jsch will have overridden the explicit user by the one from the SSH + // config file... + setUserName(session, user); // We retry already in getSession() method. JSch must not retry // on its own. session.setConfig("MaxAuthTries", "1"); //$NON-NLS-1$ //$NON-NLS-2$ @@ -199,6 +211,28 @@ public abstract class JschConfigSessionFactory extends SshSessionFactory { return session; } + private void setUserName(Session session, String userName) { + // Jsch 0.1.54 picks up the user name from the ssh config, even if an + // explicit user name was given! We must correct that if ~/.ssh/config + // has a different user name. + if (userName == null || userName.isEmpty() + || userName.equals(session.getUserName())) { + return; + } + try { + Class[] parameterTypes = { String.class }; + Method method = Session.class.getDeclaredMethod("setUserName", //$NON-NLS-1$ + parameterTypes); + method.setAccessible(true); + method.invoke(session, userName); + } catch (NullPointerException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException + | NoSuchMethodException | SecurityException e) { + LOG.error(MessageFormat.format(JGitText.get().sshUserNameError, + userName, session.getUserName()), e); + } + } + /** * Create a new remote session for the requested address. *