Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Wolf2015-08-25 19:29:12 +0000
committerMatthias Sohn2015-08-28 14:21:30 +0000
commit3a6a38c067ef807fe3898367c891029cf3611e17 (patch)
tree0f72a014855348db8a8e16ed0f6da714e4f242c5
parent92de59d06e5eb67856257a3eafac2e83febbb916 (diff)
downloadegit-3a6a38c067ef807fe3898367c891029cf3611e17.tar.gz
egit-3a6a38c067ef807fe3898367c891029cf3611e17.tar.xz
egit-3a6a38c067ef807fe3898367c891029cf3611e17.zip
Auto-configure Gerrit after ssh clone
ConfigureGerritAfterCloneTask.isGerrit() only worked for HTTP(S) cloning in general; for ssh cloning it worked only for git.eclipse.org. Use the same approach as for HTTP also for SSH: invoke Gerrit's "gerrit version" SSH endpoint and see what we get. Bug: 474019 Change-Id: Ic97040add0e805f34ef00f194e2a34ad3011fdcf Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch> Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/op/ConfigureGerritAfterCloneTask.java100
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/AbstractGitCloneWizard.java24
2 files changed, 114 insertions, 10 deletions
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/op/ConfigureGerritAfterCloneTask.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/op/ConfigureGerritAfterCloneTask.java
index 0a76a58a0c..43723255d3 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/op/ConfigureGerritAfterCloneTask.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/op/ConfigureGerritAfterCloneTask.java
@@ -1,5 +1,6 @@
/*******************************************************************************
* Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com>
+ * Copyright (C) 2015, Thomas Wolf <thomas.wolf@paranor.ch>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,13 +9,16 @@
*******************************************************************************/
package org.eclipse.egit.core.op;
+import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
+import java.util.regex.Pattern;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
@@ -25,8 +29,14 @@ import org.eclipse.egit.core.op.CloneOperation.PostCloneTask;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.RemoteConfig;
+import org.eclipse.jgit.transport.RemoteSession;
+import org.eclipse.jgit.transport.SshSessionFactory;
import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.io.MessageWriter;
+import org.eclipse.jgit.util.io.StreamCopyThread;
/**
* Configure Gerrit if repository was cloned from a Gerrit server
@@ -45,6 +55,29 @@ public class ConfigureGerritAfterCloneTask implements PostCloneTask {
private static final String GERRIT_CONFIG_SERVER_VERSION_API = "/config/server/version"; //$NON-NLS-1$
+ private static final int GERRIT_SSHD_DEFAULT_PORT = 29418;
+
+ private static final String GERRIT_SSHD_VERSION_API = "gerrit version"; //$NON-NLS-1$
+
+ /**
+ * Pattern to match the sshd reply[1] against to determine whether it's a
+ * Gerrit.
+ * <p>
+ * [1]<a href=
+ * "https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/cmd-version.html">
+ * Gerrit 2.11 gerrit version ssh command</a>
+ * </p>
+ * <p>
+ * We match the whole reply from Gerrit's sshd (as opposed to a prefix match
+ * for "gerrit version") just in case a non-Gerrit has the great idea to
+ * return an error message like "gerrit version: unknown command" or some
+ * such on its stdout...
+ * </p>
+ */
+ private static final Pattern GERRIT_SSHD_REPLY = Pattern
+ .compile(GERRIT_SSHD_VERSION_API
+ + "\\s+(?:\\d+(?:\\.\\d+)+|.+-\\d+-g[0-9a-fA-F]{7})"); //$NON-NLS-1$
+
/**
* To prevent against Cross Site Script Inclusion (XSSI) attacks, the Gerrit
* JSON response body starts with a magic prefix line we can use as a second
@@ -61,6 +94,8 @@ public class ConfigureGerritAfterCloneTask implements PostCloneTask {
private final String remoteName;
+ private final CredentialsProvider credentialsProvider;
+
private int timeout;
/**
@@ -68,14 +103,19 @@ public class ConfigureGerritAfterCloneTask implements PostCloneTask {
* not null
* @param remoteName
* not null
+ * @param credentialsProvider
+ * {@link CredentialsProvider} to use for remote communication;
+ * if {@code null} auto-configuration for repositories cloned
+ * over ssh will work only for git.eclipse.org
* @param timeout
* timeout for remote communication in seconds
*/
public ConfigureGerritAfterCloneTask(String uri, String remoteName,
- int timeout) {
+ CredentialsProvider credentialsProvider, int timeout) {
this.uri = uri;
this.remoteName = remoteName;
this.timeout = timeout;
+ this.credentialsProvider = credentialsProvider;
}
public void execute(Repository repository, IProgressMonitor monitor)
@@ -121,7 +161,8 @@ public class ConfigureGerritAfterCloneTask implements PostCloneTask {
if (HTTPS.equals(s) && (u.getPort() == 443 || u.getPort() == -1)
&& path != null && path.startsWith(GERRIT_CONTEXT_ROOT)) {
return true;
- } else if (SSH.equals(s) && (u.getPort() == 29418)) {
+ } else
+ if (SSH.equals(s) && u.getPort() == GERRIT_SSHD_DEFAULT_PORT) {
return true;
}
}
@@ -178,6 +219,25 @@ public class ConfigureGerritAfterCloneTask implements PostCloneTask {
httpConnection.disconnect();
}
}
+ } else if (SSH.equals(s)) {
+ if (u.getPort() < 0 || u.getUser() == null
+ || credentialsProvider == null) {
+ return false;
+ }
+ URIish sshUri = u.setPath(""); //$NON-NLS-1$
+ try {
+ String result = runSshCommand(sshUri, credentialsProvider,
+ repo.getFS(), GERRIT_SSHD_VERSION_API);
+ return result != null
+ && GERRIT_SSHD_REPLY.matcher(result).matches();
+ } catch (IOException e) {
+ // Something went wrong with the connection or with the command
+ // execution. Maybe the server didn't recognize the command. Do
+ // the safe thing and claim it wasn't a Gerrit. In the worst
+ // case, the user may have to do the Gerrit config setup via
+ // the ConfigureGerritWizard.
+ return false;
+ }
}
return false;
}
@@ -213,4 +273,40 @@ public class ConfigureGerritAfterCloneTask implements PostCloneTask {
config.save();
}
+ private String runSshCommand(URIish sshUri, CredentialsProvider provider,
+ FS fs, String command) throws IOException {
+ RemoteSession session = null;
+ Process process = null;
+ StreamCopyThread errorThread = null;
+ try (MessageWriter stderr = new MessageWriter()) {
+ session = SshSessionFactory.getInstance().getSession(sshUri,
+ provider, fs, 1000 * timeout);
+ process = session.exec(command, 0);
+ errorThread = new StreamCopyThread(process.getErrorStream(),
+ stderr.getRawStream());
+ errorThread.start();
+ try (BufferedReader reader = new BufferedReader(
+ new InputStreamReader(process.getInputStream(),
+ Constants.CHARSET))) {
+ return reader.readLine();
+ }
+ } finally {
+ if (errorThread != null) {
+ try {
+ errorThread.halt();
+ } catch (InterruptedException e) {
+ // Stop waiting and return anyway.
+ } finally {
+ errorThread = null;
+ }
+ }
+ if (process != null) {
+ process.destroy();
+ }
+ if (session != null) {
+ SshSessionFactory.getInstance().releaseSession(session);
+ }
+ }
+ }
+
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/AbstractGitCloneWizard.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/AbstractGitCloneWizard.java
index b1c53431e5..49ff1d1777 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/AbstractGitCloneWizard.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/AbstractGitCloneWizard.java
@@ -61,6 +61,7 @@ import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.IWorkingSet;
@@ -245,17 +246,21 @@ public abstract class AbstractGitCloneWizard extends Wizard {
final CloneOperation op = new CloneOperation(uri, allSelected,
selectedBranches, workdir, ref != null ? ref.getName() : null,
remoteName, timeout);
- if (credentials != null)
- op.setCredentialsProvider(new EGitCredentialsProvider(
- credentials.getUser(), credentials.getPassword()));
- else
- op.setCredentialsProvider(new EGitCredentialsProvider());
+ CredentialsProvider credentialsProvider = null;
+ if (credentials != null) {
+ credentialsProvider = new EGitCredentialsProvider(
+ credentials.getUser(), credentials.getPassword());
+ } else {
+ credentialsProvider = new EGitCredentialsProvider();
+ }
+ op.setCredentialsProvider(credentialsProvider);
op.setCloneSubmodules(cloneDestination.isCloneSubmodules());
configureFetchSpec(op, gitRepositoryInfo, remoteName);
configurePush(op, gitRepositoryInfo, remoteName);
configureRepositoryConfig(op, gitRepositoryInfo);
- configureGerrit(op, gitRepositoryInfo, remoteName, timeout);
+ configureGerrit(op, gitRepositoryInfo, credentialsProvider, remoteName,
+ timeout);
if (cloneDestination.isImportProjects()) {
final IWorkingSet[] sets = cloneDestination.getWorkingSets();
@@ -349,9 +354,12 @@ public abstract class AbstractGitCloneWizard extends Wizard {
}
private void configureGerrit(CloneOperation op,
- GitRepositoryInfo gitRepositoryInfo, String remoteName, int timeout) {
+ GitRepositoryInfo gitRepositoryInfo,
+ CredentialsProvider credentialsProvider, String remoteName,
+ int timeout) {
ConfigureGerritAfterCloneTask task = new ConfigureGerritAfterCloneTask(
- gitRepositoryInfo.getCloneUri(), remoteName, timeout);
+ gitRepositoryInfo.getCloneUri(), remoteName,
+ credentialsProvider, timeout);
op.addPostCloneTask(task);
}

Back to the top