mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[git] IDEA-103211 Support urls of different nature for a single remote
* GitHandler: set up both SSH and HTTP authentication environments for any remote command without analyzing urls. * Let specify several urls to the GitHandler, and do it for pull, push, fetch, and ls-remote commands * Modify Git interface for some commands to accept GitRemote instead of remoteName + remoteUrl, but still keep the previous signature in some cases where GitRemote object doesn't exist yet (e.g. in clone).
This commit is contained in:
+1
-1
@@ -402,7 +402,7 @@ public class CloudGitDeploymentRuntime extends CloudDeploymentRuntime {
|
||||
protected void push(@NotNull CloudGitApplication application, @NotNull GitRepository repository, @NotNull String remote)
|
||||
throws ServerRuntimeException {
|
||||
GitCommandResult gitPushResult
|
||||
= getGit().push(repository, remote, application.getGitUrl(), "master:master", createGitLineHandlerListener());
|
||||
= getGit().push(repository, remote, application.getGitUrl(), "master:master", false, createGitLineHandlerListener());
|
||||
checkGitResult(gitPushResult);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import git4idea.repo.GitRepository;
|
||||
import git4idea.repo.GitRepositoryManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class GitPull extends GitMergeAction {
|
||||
@@ -49,17 +50,16 @@ public class GitPull extends GitMergeAction {
|
||||
GitRepository repository = repositoryManager.getRepositoryForRoot(dialog.gitRoot());
|
||||
assert repository != null : "Repository can't be null for root " + dialog.gitRoot();
|
||||
String remoteOrUrl = dialog.getRemote();
|
||||
|
||||
GitRemote remote = GitUtil.findRemoteByName(repository, remoteOrUrl);
|
||||
final String url = (remote == null) ? remoteOrUrl : remote.getFirstUrl();
|
||||
if (url == null) {
|
||||
if (remoteOrUrl == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
GitRemote remote = GitUtil.findRemoteByName(repository, remoteOrUrl);
|
||||
final List<String> urls = remote == null ? Collections.singletonList(remoteOrUrl) : remote.getUrls();
|
||||
Computable<GitLineHandler> handlerProvider = new Computable<GitLineHandler>() {
|
||||
@Override
|
||||
public GitLineHandler compute() {
|
||||
return dialog.makeHandler(url);
|
||||
return dialog.makeHandler(urls);
|
||||
}
|
||||
};
|
||||
return new DialogState(dialog.gitRoot(), GitBundle.message("pulling.title", dialog.getRemote()), handlerProvider);
|
||||
|
||||
@@ -157,18 +157,12 @@ class GitDeleteRemoteBranchOperation extends GitBranchOperation {
|
||||
return GitCommandResult.error(error);
|
||||
}
|
||||
|
||||
String remoteUrl = remote.getFirstUrl();
|
||||
if (remoteUrl == null) {
|
||||
LOG.warn("No urls are defined for remote: " + remote);
|
||||
return GitCommandResult.error("There is no urls defined for remote " + remote.getName());
|
||||
}
|
||||
return pushDeletionNatively(repository, remoteName, remoteUrl, branchName);
|
||||
return pushDeletionNatively(repository, remote, branchName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private GitCommandResult pushDeletionNatively(@NotNull GitRepository repository, @NotNull String remoteName, @NotNull String url,
|
||||
@NotNull String branchName) {
|
||||
return myGit.push(repository, remoteName, url,":" + branchName);
|
||||
private GitCommandResult pushDeletionNatively(@NotNull GitRepository repository, @NotNull GitRemote remote, @NotNull String branchName) {
|
||||
return myGit.push(repository, remote, ":" + branchName, false, false, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -20,8 +20,6 @@ import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import git4idea.GitCommit;
|
||||
import git4idea.GitLocalBranch;
|
||||
import git4idea.GitRemoteBranch;
|
||||
import git4idea.repo.GitRemote;
|
||||
import git4idea.repo.GitRepository;
|
||||
import git4idea.reset.GitResetMode;
|
||||
@@ -106,14 +104,10 @@ public interface Git {
|
||||
GitCommandResult push(@NotNull GitRepository repository, @NotNull String remote, @Nullable String url, @NotNull String spec,
|
||||
boolean updateTracking, @NotNull GitLineHandlerListener... listeners);
|
||||
|
||||
@NotNull
|
||||
GitCommandResult push(@NotNull GitRepository repository, @NotNull String remote, @Nullable String url, @NotNull String spec,
|
||||
@NotNull GitLineHandlerListener... listeners);
|
||||
|
||||
@NotNull
|
||||
GitCommandResult push(@NotNull GitRepository repository,
|
||||
@NotNull GitLocalBranch source,
|
||||
@NotNull GitRemoteBranch target,
|
||||
@NotNull GitRemote remote,
|
||||
@NotNull String spec,
|
||||
boolean force,
|
||||
boolean updateTracking,
|
||||
@Nullable String tagMode,
|
||||
@@ -143,8 +137,10 @@ public interface Git {
|
||||
List<GitCommit> history(@NotNull GitRepository repository, @NotNull String range);
|
||||
|
||||
@NotNull
|
||||
GitCommandResult fetch(@NotNull GitRepository repository, @NotNull String url, @NotNull String remote,
|
||||
@NotNull List<GitLineHandlerListener> listeners, String... params);
|
||||
GitCommandResult fetch(@NotNull GitRepository repository,
|
||||
@NotNull GitRemote remote,
|
||||
@NotNull List<GitLineHandlerListener> listeners,
|
||||
String... params);
|
||||
|
||||
@NotNull
|
||||
GitCommandResult addRemote(@NotNull GitRepository repository, @NotNull String name, @NotNull String url);
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -36,6 +37,7 @@ import com.intellij.util.EnvironmentUtil;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import com.intellij.util.net.HttpConfigurable;
|
||||
import com.intellij.util.net.IdeaWideProxySelector;
|
||||
@@ -52,11 +54,14 @@ import org.jetbrains.git4idea.ssh.GitSSHHandler;
|
||||
import org.jetbrains.git4idea.ssh.GitXmlRpcSshService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
/**
|
||||
* A handler for git commands
|
||||
*/
|
||||
@@ -81,7 +86,8 @@ public abstract class GitHandler {
|
||||
private final File myWorkingDirectory;
|
||||
|
||||
private boolean myEnvironmentCleanedUp = true; // the flag indicating that environment has been cleaned up, by default is true because there is nothing to clean
|
||||
private int myHandlerNo;
|
||||
private int mySshHandler;
|
||||
private int myHttpHandler;
|
||||
private Processor<OutputStream> myInputProcessor; // The processor for stdin
|
||||
|
||||
// if true process might be cancelled
|
||||
@@ -110,7 +116,7 @@ public abstract class GitHandler {
|
||||
|
||||
private long myStartTime; // git execution start timestamp
|
||||
private static final long LONG_TIME = 10 * 1000;
|
||||
@Nullable private String myUrl;
|
||||
@Nullable private Collection<String> myUrls;
|
||||
private boolean myHttpAuthFailed;
|
||||
|
||||
|
||||
@@ -234,13 +240,16 @@ public abstract class GitHandler {
|
||||
return file;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
public void setUrl(@NotNull String url) {
|
||||
myUrl = url;
|
||||
setUrls(singletonList(url));
|
||||
}
|
||||
|
||||
public void setUrls(@NotNull Collection<String> urls) {
|
||||
myUrls = urls;
|
||||
}
|
||||
|
||||
protected boolean isRemote() {
|
||||
return myUrl != null;
|
||||
return myUrls != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -435,46 +444,12 @@ public abstract class GitHandler {
|
||||
}
|
||||
|
||||
// setup environment
|
||||
GitRemoteProtocol remoteProtocol = GitRemoteProtocol.fromUrl(myUrl);
|
||||
if (remoteProtocol == GitRemoteProtocol.SSH && myProjectSettings.isIdeaSsh()) {
|
||||
GitXmlRpcSshService ssh = ServiceManager.getService(GitXmlRpcSshService.class);
|
||||
myEnv.put(GitSSHHandler.GIT_SSH_ENV, ssh.getScriptPath().getPath());
|
||||
myHandlerNo = ssh.registerHandler(new GitSSHGUIHandler(myProject));
|
||||
myEnvironmentCleanedUp = false;
|
||||
myEnv.put(GitSSHHandler.SSH_HANDLER_ENV, Integer.toString(myHandlerNo));
|
||||
int port = ssh.getXmlRcpPort();
|
||||
myEnv.put(GitSSHHandler.SSH_PORT_ENV, Integer.toString(port));
|
||||
LOG.debug(String.format("handler=%s, port=%s", myHandlerNo, port));
|
||||
|
||||
final HttpConfigurable httpConfigurable = HttpConfigurable.getInstance();
|
||||
boolean useHttpProxy = httpConfigurable.USE_HTTP_PROXY && !isSshUrlExcluded(httpConfigurable, myUrl);
|
||||
myEnv.put(GitSSHHandler.SSH_USE_PROXY_ENV, String.valueOf(useHttpProxy));
|
||||
|
||||
if (useHttpProxy) {
|
||||
myEnv.put(GitSSHHandler.SSH_PROXY_HOST_ENV, StringUtil.notNullize(httpConfigurable.PROXY_HOST));
|
||||
myEnv.put(GitSSHHandler.SSH_PROXY_PORT_ENV, String.valueOf(httpConfigurable.PROXY_PORT));
|
||||
boolean proxyAuthentication = httpConfigurable.PROXY_AUTHENTICATION;
|
||||
myEnv.put(GitSSHHandler.SSH_PROXY_AUTHENTICATION_ENV, String.valueOf(proxyAuthentication));
|
||||
|
||||
if (proxyAuthentication) {
|
||||
myEnv.put(GitSSHHandler.SSH_PROXY_USER_ENV, StringUtil.notNullize(httpConfigurable.PROXY_LOGIN));
|
||||
myEnv.put(GitSSHHandler.SSH_PROXY_PASSWORD_ENV, StringUtil.notNullize(httpConfigurable.getPlainProxyPassword()));
|
||||
}
|
||||
if (isRemote()) {
|
||||
setupHttpAuthenticator();
|
||||
if (myProjectSettings.isIdeaSsh()) {
|
||||
setupSshAuthenticator();
|
||||
}
|
||||
}
|
||||
else if (remoteProtocol == GitRemoteProtocol.HTTP) {
|
||||
GitHttpAuthService service = ServiceManager.getService(GitHttpAuthService.class);
|
||||
myEnv.put(GitAskPassXmlRpcHandler.GIT_ASK_PASS_ENV, service.getScriptPath().getPath());
|
||||
assert myUrl != null : "myUrl can't be null here";
|
||||
GitHttpAuthenticator httpAuthenticator = service.createAuthenticator(myProject, myCommand, myUrl);
|
||||
myHandlerNo = service.registerHandler(httpAuthenticator);
|
||||
myEnvironmentCleanedUp = false;
|
||||
myEnv.put(GitAskPassXmlRpcHandler.GIT_ASK_PASS_HANDLER_ENV, Integer.toString(myHandlerNo));
|
||||
int port = service.getXmlRcpPort();
|
||||
myEnv.put(GitAskPassXmlRpcHandler.GIT_ASK_PASS_PORT_ENV, Integer.toString(port));
|
||||
LOG.debug(String.format("handler=%s, port=%s", myHandlerNo, port));
|
||||
addAuthListener(httpAuthenticator);
|
||||
}
|
||||
myCommandLine.getEnvironment().clear();
|
||||
myCommandLine.getEnvironment().putAll(myEnv);
|
||||
// start process
|
||||
@@ -493,9 +468,54 @@ public abstract class GitHandler {
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean isSshUrlExcluded(@NotNull HttpConfigurable httpConfigurable, @NotNull String url) {
|
||||
String host = URLUtil.parseHostFromSshUrl(url);
|
||||
return ((IdeaWideProxySelector)httpConfigurable.getOnlyBySettingsSelector()).isProxyException(host);
|
||||
private void setupHttpAuthenticator() throws IOException {
|
||||
GitHttpAuthService service = ServiceManager.getService(GitHttpAuthService.class);
|
||||
myEnv.put(GitAskPassXmlRpcHandler.GIT_ASK_PASS_ENV, service.getScriptPath().getPath());
|
||||
GitHttpAuthenticator httpAuthenticator = service.createAuthenticator(myProject, myCommand, ObjectUtils.assertNotNull(myUrls));
|
||||
myHttpHandler = service.registerHandler(httpAuthenticator);
|
||||
myEnvironmentCleanedUp = false;
|
||||
myEnv.put(GitAskPassXmlRpcHandler.GIT_ASK_PASS_HANDLER_ENV, Integer.toString(myHttpHandler));
|
||||
int port = service.getXmlRcpPort();
|
||||
myEnv.put(GitAskPassXmlRpcHandler.GIT_ASK_PASS_PORT_ENV, Integer.toString(port));
|
||||
LOG.debug(String.format("handler=%s, port=%s", myHttpHandler, port));
|
||||
addAuthListener(httpAuthenticator);
|
||||
}
|
||||
|
||||
private void setupSshAuthenticator() throws IOException {
|
||||
GitXmlRpcSshService ssh = ServiceManager.getService(GitXmlRpcSshService.class);
|
||||
myEnv.put(GitSSHHandler.GIT_SSH_ENV, ssh.getScriptPath().getPath());
|
||||
mySshHandler = ssh.registerHandler(new GitSSHGUIHandler(myProject));
|
||||
myEnvironmentCleanedUp = false;
|
||||
myEnv.put(GitSSHHandler.SSH_HANDLER_ENV, Integer.toString(mySshHandler));
|
||||
int port = ssh.getXmlRcpPort();
|
||||
myEnv.put(GitSSHHandler.SSH_PORT_ENV, Integer.toString(port));
|
||||
LOG.debug(String.format("handler=%s, port=%s", mySshHandler, port));
|
||||
|
||||
final HttpConfigurable httpConfigurable = HttpConfigurable.getInstance();
|
||||
boolean useHttpProxy = httpConfigurable.USE_HTTP_PROXY && !isSshUrlExcluded(httpConfigurable, ObjectUtils.assertNotNull(myUrls));
|
||||
myEnv.put(GitSSHHandler.SSH_USE_PROXY_ENV, String.valueOf(useHttpProxy));
|
||||
|
||||
if (useHttpProxy) {
|
||||
myEnv.put(GitSSHHandler.SSH_PROXY_HOST_ENV, StringUtil.notNullize(httpConfigurable.PROXY_HOST));
|
||||
myEnv.put(GitSSHHandler.SSH_PROXY_PORT_ENV, String.valueOf(httpConfigurable.PROXY_PORT));
|
||||
boolean proxyAuthentication = httpConfigurable.PROXY_AUTHENTICATION;
|
||||
myEnv.put(GitSSHHandler.SSH_PROXY_AUTHENTICATION_ENV, String.valueOf(proxyAuthentication));
|
||||
|
||||
if (proxyAuthentication) {
|
||||
myEnv.put(GitSSHHandler.SSH_PROXY_USER_ENV, StringUtil.notNullize(httpConfigurable.PROXY_LOGIN));
|
||||
myEnv.put(GitSSHHandler.SSH_PROXY_PASSWORD_ENV, StringUtil.notNullize(httpConfigurable.getPlainProxyPassword()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean isSshUrlExcluded(@NotNull final HttpConfigurable httpConfigurable, @NotNull Collection<String> urls) {
|
||||
return ContainerUtil.exists(urls, new Condition<String>() {
|
||||
@Override
|
||||
public boolean value(String url) {
|
||||
String host = URLUtil.parseHostFromSshUrl(url);
|
||||
return ((IdeaWideProxySelector)httpConfigurable.getOnlyBySettingsSelector()).isProxyException(host);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addAuthListener(@NotNull final GitHttpAuthenticator authenticator) {
|
||||
@@ -586,17 +606,11 @@ public abstract class GitHandler {
|
||||
if (myEnvironmentCleanedUp) {
|
||||
return;
|
||||
}
|
||||
GitRemoteProtocol remoteProtocol = GitRemoteProtocol.fromUrl(myUrl);
|
||||
if (remoteProtocol == GitRemoteProtocol.SSH) {
|
||||
GitXmlRpcSshService ssh = ServiceManager.getService(GitXmlRpcSshService.class);
|
||||
myEnvironmentCleanedUp = true;
|
||||
ssh.unregisterHandler(myHandlerNo);
|
||||
}
|
||||
else if (remoteProtocol == GitRemoteProtocol.HTTP) {
|
||||
GitHttpAuthService service = ServiceManager.getService(GitHttpAuthService.class);
|
||||
myEnvironmentCleanedUp = true;
|
||||
service.unregisterHandler(myHandlerNo);
|
||||
if (isRemote()) {
|
||||
ServiceManager.getService(GitXmlRpcSshService.class).unregisterHandler(mySshHandler);
|
||||
ServiceManager.getService(GitHttpAuthService.class).unregisterHandler(myHttpHandler);
|
||||
}
|
||||
myEnvironmentCleanedUp = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,6 +22,8 @@ import org.jetbrains.git4idea.http.GitAskPassXmlRpcHandler;
|
||||
import org.jetbrains.git4idea.ssh.GitXmlRpcHandlerService;
|
||||
import org.jetbrains.git4idea.util.ScriptGenerator;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Provides the authentication mechanism for Git HTTP connections.
|
||||
*/
|
||||
@@ -45,7 +47,9 @@ public abstract class GitHttpAuthService extends GitXmlRpcHandlerService<GitHttp
|
||||
* Creates new {@link GitHttpAuthenticator} that will be requested to handle username and password requests from Git.
|
||||
*/
|
||||
@NotNull
|
||||
public abstract GitHttpAuthenticator createAuthenticator(@NotNull Project project, @NotNull GitCommand command, @NotNull String url);
|
||||
public abstract GitHttpAuthenticator createAuthenticator(@NotNull Project project,
|
||||
@NotNull GitCommand command,
|
||||
@NotNull Collection<String> urls);
|
||||
|
||||
/**
|
||||
* Internal handler implementation class, it is made public to be accessible via XML RPC.
|
||||
|
||||
@@ -18,6 +18,8 @@ package git4idea.commands;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
@@ -25,8 +27,8 @@ class GitHttpAuthServiceImpl extends GitHttpAuthService {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public GitHttpAuthenticator createAuthenticator(@NotNull Project project, @NotNull GitCommand command, @NotNull String url) {
|
||||
return new GitHttpGuiAuthenticator(project, command, url);
|
||||
public GitHttpAuthenticator createAuthenticator(@NotNull Project project, @NotNull GitCommand command, @NotNull Collection<String> urls) {
|
||||
return new GitHttpGuiAuthenticator(project, command, urls);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -57,9 +58,9 @@ class GitHttpGuiAuthenticator implements GitHttpAuthenticator {
|
||||
private static final Logger LOG = Logger.getInstance(GitHttpGuiAuthenticator.class);
|
||||
private static final Class<GitHttpAuthenticator> PASS_REQUESTER = GitHttpAuthenticator.class;
|
||||
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final String myTitle;
|
||||
@NotNull private final String myUrlFromCommand;
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final String myTitle;
|
||||
@NotNull private final Collection<String> myUrlsFromCommand;
|
||||
|
||||
@Nullable private String myPassword;
|
||||
@Nullable private String myPasswordKey;
|
||||
@@ -69,10 +70,10 @@ class GitHttpGuiAuthenticator implements GitHttpAuthenticator {
|
||||
@Nullable private GitHttpAuthDataProvider myDataProvider;
|
||||
private boolean myWasCancelled;
|
||||
|
||||
GitHttpGuiAuthenticator(@NotNull Project project, @NotNull GitCommand command, @NotNull String url) {
|
||||
GitHttpGuiAuthenticator(@NotNull Project project, @NotNull GitCommand command, @NotNull Collection<String> url) {
|
||||
myProject = project;
|
||||
myTitle = "Git " + StringUtil.capitalize(command.name());
|
||||
myUrlFromCommand = url;
|
||||
myUrlsFromCommand = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -195,18 +196,25 @@ class GitHttpGuiAuthenticator implements GitHttpAuthenticator {
|
||||
if (StringUtil.isEmptyOrSpaces(url)) {
|
||||
// if Git doesn't specify the URL in the username/password query, we use the url from the Git command
|
||||
// We only take the host, to avoid entering the same password for different repositories on the same host.
|
||||
return adjustHttpUrl(getHost(myUrlFromCommand));
|
||||
return adjustHttpUrl(getHost(myUrlsFromCommand));
|
||||
}
|
||||
return adjustHttpUrl(url);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getHost(@NotNull String url) {
|
||||
Couple<String> split = UriUtil.splitScheme(url);
|
||||
String scheme = split.getFirst();
|
||||
String urlItself = split.getSecond();
|
||||
int pathStart = urlItself.indexOf("/");
|
||||
return scheme + URLUtil.SCHEME_SEPARATOR + urlItself.substring(0, pathStart);
|
||||
private static String getHost(@NotNull Collection<String> urls) {
|
||||
String host = "unknown";
|
||||
for (String url : urls) {
|
||||
Couple<String> split = UriUtil.splitScheme(url);
|
||||
String scheme = split.getFirst();
|
||||
String urlItself = split.getSecond();
|
||||
int pathStart = urlItself.indexOf("/");
|
||||
host = scheme + URLUtil.SCHEME_SEPARATOR + urlItself.substring(0, pathStart);
|
||||
if (scheme.startsWith("http")) {
|
||||
return host;
|
||||
}
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,6 +39,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static java.util.Collections.singleton;
|
||||
|
||||
/**
|
||||
* Easy-to-use wrapper of common native Git commands.
|
||||
* Most of them return result as {@link GitCommandResult}.
|
||||
@@ -374,29 +376,47 @@ public class GitImpl implements Git {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public GitCommandResult push(@NotNull GitRepository repository, @NotNull String remote, @Nullable String url, @NotNull String spec,
|
||||
boolean updateTracking, @NotNull GitLineHandlerListener... listeners) {
|
||||
return doPush(repository, remote, url, spec, false, updateTracking, null, listeners);
|
||||
public GitCommandResult push(@NotNull GitRepository repository,
|
||||
@NotNull String remote,
|
||||
@Nullable String url,
|
||||
@NotNull String spec,
|
||||
boolean updateTracking,
|
||||
@NotNull GitLineHandlerListener... listeners) {
|
||||
return doPush(repository, remote, singleton(url), spec, false, updateTracking, null, listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public GitCommandResult push(@NotNull GitRepository repository,
|
||||
@NotNull GitRemote remote,
|
||||
@NotNull String spec,
|
||||
boolean force,
|
||||
boolean updateTracking,
|
||||
@Nullable String tagMode,
|
||||
GitLineHandlerListener... listeners) {
|
||||
return doPush(repository, remote.getName(), remote.getPushUrls(), spec, force, updateTracking, tagMode, listeners);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private GitCommandResult doPush(@NotNull final GitRepository repository, @NotNull final String remote, @Nullable final String url,
|
||||
@NotNull final String spec, final boolean force, final boolean updateTracking,
|
||||
@Nullable final String tagMode,
|
||||
@NotNull final GitLineHandlerListener... listeners) {
|
||||
private GitCommandResult doPush(@NotNull final GitRepository repository,
|
||||
@NotNull final String remoteName,
|
||||
@NotNull final Collection<String> remoteUrls,
|
||||
@NotNull final String spec,
|
||||
final boolean force,
|
||||
final boolean updateTracking,
|
||||
@Nullable final String tagMode,
|
||||
@NotNull final GitLineHandlerListener... listeners) {
|
||||
return runCommand(new Computable<GitLineHandler>() {
|
||||
@Override
|
||||
public GitLineHandler compute() {
|
||||
final GitLineHandler h = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.PUSH);
|
||||
if (url != null) {
|
||||
h.setUrl(url);
|
||||
}
|
||||
h.setUrls(remoteUrls);
|
||||
h.setSilent(false);
|
||||
h.setStdoutSuppressed(false);
|
||||
addListeners(h, listeners);
|
||||
h.addProgressParameter();
|
||||
h.addParameters("--porcelain");
|
||||
h.addParameters(remote);
|
||||
h.addParameters(remoteName);
|
||||
h.addParameters(spec);
|
||||
if (updateTracking) {
|
||||
h.addParameters("--set-upstream");
|
||||
@@ -412,31 +432,6 @@ public class GitImpl implements Git {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public GitCommandResult push(@NotNull GitRepository repository, @NotNull String remote, @Nullable String url, @NotNull String spec,
|
||||
@NotNull GitLineHandlerListener... listeners) {
|
||||
return push(repository, remote, url, spec, false, listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public GitCommandResult push(@NotNull GitRepository repository, @NotNull GitLocalBranch source, @NotNull GitRemoteBranch target,
|
||||
boolean force, boolean updateTracking, @Nullable String tagMode, GitLineHandlerListener... listeners) {
|
||||
GitRemote remote = target.getRemote();
|
||||
Collection<String> pushUrls = remote.getPushUrls(); // TODO handle the case with multiple pushurls with different protocols
|
||||
String url;
|
||||
if (pushUrls.isEmpty()) {
|
||||
LOG.error("No urls or pushUrls are defined for " + remote);
|
||||
url = null;
|
||||
}
|
||||
else {
|
||||
url = pushUrls.iterator().next();
|
||||
}
|
||||
String spec = source.getFullName() + ":" + target.getNameForRemoteOperations();
|
||||
return doPush(repository, remote.getName(), url, spec, force, updateTracking, tagMode, listeners);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult show(@NotNull GitRepository repository, @NotNull String... params) {
|
||||
@@ -476,16 +471,18 @@ public class GitImpl implements Git {
|
||||
*/
|
||||
@Override
|
||||
@NotNull
|
||||
public GitCommandResult fetch(@NotNull final GitRepository repository, @NotNull final String url, @NotNull final String remote,
|
||||
@NotNull final List<GitLineHandlerListener> listeners, final String... params) {
|
||||
public GitCommandResult fetch(@NotNull final GitRepository repository,
|
||||
@NotNull final GitRemote remote,
|
||||
@NotNull final List<GitLineHandlerListener> listeners,
|
||||
final String... params) {
|
||||
return runCommand(new Computable<GitLineHandler>() {
|
||||
@Override
|
||||
public GitLineHandler compute() {
|
||||
final GitLineHandler h = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.FETCH);
|
||||
h.setSilent(false);
|
||||
h.setStdoutSuppressed(false);
|
||||
h.setUrl(url);
|
||||
h.addParameters(remote);
|
||||
h.setUrls(remote.getUrls());
|
||||
h.addParameters(remote.getName());
|
||||
h.addParameters(params);
|
||||
h.addProgressParameter();
|
||||
GitVcs vcs = GitVcs.getInstance(repository.getProject());
|
||||
@@ -511,7 +508,7 @@ public class GitImpl implements Git {
|
||||
public GitCommandResult lsRemote(@NotNull final Project project,
|
||||
@NotNull final File workingDir,
|
||||
@NotNull final String url) {
|
||||
return doLsRemote(project, workingDir, url, url);
|
||||
return doLsRemote(project, workingDir, url, singleton(url));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -520,27 +517,22 @@ public class GitImpl implements Git {
|
||||
@NotNull VirtualFile workingDir,
|
||||
@NotNull GitRemote remote,
|
||||
String... additionalParameters) {
|
||||
return doLsRemote(project, VfsUtilCore.virtualToIoFile(workingDir), remote.getName(), remote.getFirstUrl(), additionalParameters);
|
||||
return doLsRemote(project, VfsUtilCore.virtualToIoFile(workingDir), remote.getName(), remote.getUrls(), additionalParameters);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private GitCommandResult doLsRemote(@NotNull final Project project,
|
||||
@NotNull final File workingDir,
|
||||
@NotNull final String remoteId,
|
||||
@Nullable final String authenticationUrl,
|
||||
final String... additionalParameters) {
|
||||
private static GitCommandResult doLsRemote(@NotNull final Project project,
|
||||
@NotNull final File workingDir,
|
||||
@NotNull final String remoteId,
|
||||
@NotNull final Collection<String> authenticationUrls,
|
||||
final String... additionalParameters) {
|
||||
return run(new Computable<GitLineHandler>() {
|
||||
@Override
|
||||
public GitLineHandler compute() {
|
||||
GitLineHandler h = new GitLineHandler(project, workingDir, GitCommand.LS_REMOTE);
|
||||
h.addParameters(additionalParameters);
|
||||
h.addParameters(remoteId);
|
||||
if (authenticationUrl != null) {
|
||||
h.setUrl(authenticationUrl);
|
||||
}
|
||||
else {
|
||||
LOG.error("No valid URLs for remote " + remoteId);
|
||||
}
|
||||
h.setUrls(authenticationUrls);
|
||||
return h;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package git4idea.commands;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
public enum GitRemoteProtocol {
|
||||
GIT,
|
||||
SSH,
|
||||
HTTP;
|
||||
|
||||
@Nullable
|
||||
public static GitRemoteProtocol fromUrl(@Nullable String url) {
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
url = url.toLowerCase();
|
||||
if (url.startsWith("http")) {
|
||||
return HTTP;
|
||||
}
|
||||
if (url.startsWith("git://")) { // "://" are there not to mix with scp-like syntax used for SSH: git@host.com/path/to.git
|
||||
return GIT;
|
||||
}
|
||||
return SSH;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -178,11 +178,11 @@ public class GitPullDialog extends DialogWrapper {
|
||||
setOKActionEnabled(myBranchChooser.getMarkedElements().size() != 0);
|
||||
}
|
||||
|
||||
public GitLineHandler makeHandler(@NotNull String url) {
|
||||
public GitLineHandler makeHandler(@NotNull List<String> urls) {
|
||||
GitLineHandler h = new GitLineHandler(myProject, gitRoot(), GitCommand.PULL);
|
||||
// ignore merge failure for the pull
|
||||
h.ignoreErrorCode(1);
|
||||
h.setUrl(url);
|
||||
h.setUrls(urls);
|
||||
h.addProgressParameter();
|
||||
h.addParameters("--no-stat");
|
||||
if (myNoCommitCheckBox.isSelected()) {
|
||||
|
||||
@@ -368,7 +368,9 @@ public class GitPushOperation {
|
||||
GitLineHandlerListener progressListener = GitStandardProgressAnalyzer.createListener(myProgressIndicator);
|
||||
boolean setUpstream = pushSpec.getTarget().isNewBranchCreated() && !branchTrackingInfoIsSet(repository, sourceBranch);
|
||||
String tagMode = myTagMode == null ? null : myTagMode.getArgument();
|
||||
GitCommandResult res = myGit.push(repository, sourceBranch, targetBranch, myForce, setUpstream, tagMode, progressListener);
|
||||
|
||||
String spec = sourceBranch.getFullName() + ":" + targetBranch.getNameForRemoteOperations();
|
||||
GitCommandResult res = myGit.push(repository, targetBranch.getRemote(), spec, myForce, setUpstream, tagMode, progressListener);
|
||||
return new ResultWithOutput(res);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,11 +102,7 @@ public class GitFetcher {
|
||||
if (remote == null) {
|
||||
return logError("Couldn't find remote with the name " + remoteName, null);
|
||||
}
|
||||
String url = remote.getFirstUrl();
|
||||
if (url == null) {
|
||||
return logError("URL is null for remote " + remote.getName(), null);
|
||||
}
|
||||
return fetchRemote(repository, remote, url, branch);
|
||||
return fetchRemote(repository, remote, branch);
|
||||
}
|
||||
|
||||
private static GitFetchResult logError(@NotNull String message, @Nullable String additionalInfo) {
|
||||
@@ -123,16 +119,14 @@ public class GitFetcher {
|
||||
}
|
||||
|
||||
GitRemote remote = fetchParams.getRemote();
|
||||
String url = fetchParams.getUrl();
|
||||
return fetchRemote(repository, remote, url, null);
|
||||
return fetchRemote(repository, remote, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private GitFetchResult fetchRemote(@NotNull GitRepository repository,
|
||||
@NotNull GitRemote remote,
|
||||
@NotNull String url,
|
||||
@Nullable String branch) {
|
||||
return fetchNatively(repository, remote, url, branch);
|
||||
return fetchNatively(repository, remote, branch);
|
||||
}
|
||||
|
||||
// leaving this unused method, because the wanted behavior can change again
|
||||
@@ -146,8 +140,7 @@ public class GitFetcher {
|
||||
|
||||
GitRemote remote = fetchParams.getRemote();
|
||||
String remoteBranch = fetchParams.getRemoteBranch().getNameForRemoteOperations();
|
||||
String url = fetchParams.getUrl();
|
||||
return fetchNatively(repository, remote, url, remoteBranch);
|
||||
return fetchNatively(repository, remote, remoteBranch);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -167,14 +160,7 @@ public class GitFetcher {
|
||||
}
|
||||
|
||||
GitRemote remote = trackInfo.getRemote();
|
||||
String url = remote.getFirstUrl();
|
||||
if (url == null) {
|
||||
String message = "URL is null for remote " + remote.getName();
|
||||
LOG.error(message);
|
||||
return new FetchParams(GitFetchResult.error(new Exception(message)));
|
||||
}
|
||||
|
||||
return new FetchParams(remote, trackInfo.getRemoteBranch(), url);
|
||||
return new FetchParams(remote, trackInfo.getRemoteBranch());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -185,7 +171,7 @@ public class GitFetcher {
|
||||
LOG.error("URL is null for remote " + remote.getName());
|
||||
continue;
|
||||
}
|
||||
GitFetchResult res = fetchNatively(repository, remote, url, null);
|
||||
GitFetchResult res = fetchNatively(repository, remote, null);
|
||||
res.addPruneInfo(fetchResult.getPrunedRefs());
|
||||
fetchResult = res;
|
||||
if (!fetchResult.isSuccess()) {
|
||||
@@ -196,16 +182,15 @@ public class GitFetcher {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static GitFetchResult fetchNatively(@NotNull GitRepository repository, @NotNull GitRemote remote, @NotNull String url,
|
||||
@Nullable String branch) {
|
||||
private static GitFetchResult fetchNatively(@NotNull GitRepository repository, @NotNull GitRemote remote, @Nullable String branch) {
|
||||
Git git = ServiceManager.getService(Git.class);
|
||||
String[] additionalParams = branch != null ?
|
||||
new String[]{ getFetchSpecForBranch(branch, remote.getName()) } :
|
||||
ArrayUtil.EMPTY_STRING_ARRAY;
|
||||
|
||||
GitFetchPruneDetector pruneDetector = new GitFetchPruneDetector();
|
||||
GitCommandResult result =
|
||||
git.fetch(repository, url, remote.getName(), Collections.<GitLineHandlerListener>singletonList(pruneDetector), additionalParams);
|
||||
GitCommandResult result = git.fetch(repository, remote,
|
||||
Collections.<GitLineHandlerListener>singletonList(pruneDetector), additionalParams);
|
||||
|
||||
GitFetchResult fetchResult;
|
||||
if (result.success()) {
|
||||
@@ -347,16 +332,14 @@ public class GitFetcher {
|
||||
private GitRemote myRemote;
|
||||
private GitRemoteBranch myRemoteBranch;
|
||||
private GitFetchResult myError;
|
||||
private String myUrl;
|
||||
|
||||
FetchParams(GitFetchResult error) {
|
||||
myError = error;
|
||||
}
|
||||
|
||||
FetchParams(GitRemote remote, GitRemoteBranch remoteBranch, String url) {
|
||||
FetchParams(GitRemote remote, GitRemoteBranch remoteBranch) {
|
||||
myRemote = remote;
|
||||
myRemoteBranch = remoteBranch;
|
||||
myUrl = url;
|
||||
}
|
||||
|
||||
boolean isError() {
|
||||
@@ -374,9 +357,5 @@ public class GitFetcher {
|
||||
public GitRemoteBranch getRemoteBranch() {
|
||||
return myRemoteBranch;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,11 @@ import com.intellij.dvcs.push.PushSpec;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import git4idea.GitLocalBranch;
|
||||
import git4idea.GitRemoteBranch;
|
||||
import git4idea.commands.Git;
|
||||
import git4idea.commands.GitCommandResult;
|
||||
import git4idea.commands.GitImpl;
|
||||
import git4idea.commands.GitLineHandlerListener;
|
||||
import git4idea.repo.GitRemote;
|
||||
import git4idea.repo.GitRepository;
|
||||
import git4idea.test.GitTestUtil;
|
||||
import git4idea.update.GitUpdateResult;
|
||||
@@ -80,20 +79,20 @@ public class GitPushOperationMultiRepoTest extends GitPushOperationBaseTest {
|
||||
private static class FailingPushGit extends GitImpl {
|
||||
private Condition<GitRepository> myPushShouldFail;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@NotNull
|
||||
public GitCommandResult push(@NotNull GitRepository repository,
|
||||
@NotNull GitLocalBranch source,
|
||||
@NotNull GitRemoteBranch target,
|
||||
@NotNull GitRemote remote,
|
||||
@NotNull String spec,
|
||||
boolean force,
|
||||
boolean updateTracking,
|
||||
@Nullable String tagMode,
|
||||
GitLineHandlerListener... listeners) {
|
||||
if (myPushShouldFail.value(repository)) {
|
||||
return new GitCommandResult(false, 128, Collections.singletonList("Failed to push to " + target.getName()),
|
||||
return new GitCommandResult(false, 128, Collections.singletonList("Failed to push to " + remote.getName()),
|
||||
Collections.<String>emptyList(), null);
|
||||
}
|
||||
return super.push(repository, source, target, force, updateTracking, tagMode, listeners);
|
||||
return super.push(repository, remote, spec, force, updateTracking, tagMode, listeners);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +122,7 @@ public class GitPushOperationMultiRepoTest extends GitPushOperationBaseTest {
|
||||
GitPushRepoResult result2 = result.getResults().get(myCommunity);
|
||||
|
||||
assertResult(GitPushRepoResult.Type.ERROR, -1, "master", "origin/master", null, result1);
|
||||
assertEquals("Error text is incorrect", "Failed to push to origin/master", result1.getError());
|
||||
assertEquals("Error text is incorrect", "Failed to push to origin", result1.getError());
|
||||
assertResult(GitPushRepoResult.Type.SUCCESS, 1, "master", "origin/master", null, result2);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ import git4idea.commands.GitHttpAuthService;
|
||||
import git4idea.commands.GitHttpAuthenticator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
@@ -30,23 +32,21 @@ public class GitHttpAuthTestService extends GitHttpAuthService {
|
||||
@NotNull
|
||||
@Override
|
||||
public String askPassword(@NotNull String url) {
|
||||
throw new IllegalStateException("Authenticator was not registered");
|
||||
return "";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String askUsername(@NotNull String url) {
|
||||
throw new IllegalStateException("Authenticator was not registered");
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAuthData() {
|
||||
throw new IllegalStateException("Authenticator was not registered");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forgetPassword() {
|
||||
throw new IllegalStateException("Authenticator was not registered");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,7 +59,7 @@ public class GitHttpAuthTestService extends GitHttpAuthService {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitHttpAuthenticator createAuthenticator(@NotNull Project project, @NotNull GitCommand command, @NotNull String url) {
|
||||
public GitHttpAuthenticator createAuthenticator(@NotNull Project project, @NotNull GitCommand command, @NotNull Collection<String> urls) {
|
||||
return myAuthenticator;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ public abstract class GithubCreatePullRequestTestBase extends GithubTest {
|
||||
protected void deleteRemoteBranch() {
|
||||
GitRepository repository = GithubUtil.getGitRepository(myProject, myProjectRoot);
|
||||
if (repository != null) {
|
||||
ServiceManager.getService(Git.class).push(repository, "origin", PROJECT_URL, ":" + BRANCH_NAME);
|
||||
ServiceManager.getService(Git.class).push(repository, "origin", PROJECT_URL, ":" + BRANCH_NAME, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user