[git] Detect remote protocol from the url

* Clone, fetch and ls-remote are trivial: just pass the url parameter.
* Pull: modify the method signature, since it can return pull or merge
  handler depending on the situation. For merge url is not needed.
* Standard Push (GitPusher):
  - simplify the logic by taking the first url
    instead of iterating over all of them,
    because we don't support pushing to several urls very well anyway.
  - report error if there are no push urls: GitPusher shouldn't be
    called in this case at all.
* Push when remote branch is deleted (GitDeleteRemoteBranchOperation):
  same as for the standard push: take the first url,
  report error if there are no urls defined for the remote.
This commit is contained in:
Kirill Likhodedov
2013-03-09 20:49:03 +04:00
parent b2b8f2f957
commit 553d2bd55c
13 changed files with 68 additions and 47 deletions
@@ -92,9 +92,9 @@ public class GitPull extends GitRepositoryAction {
if (!fetchSuccessful) {
return;
}
handlerReference.set(dialog.pullOrMergeHandler(false));
handlerReference.set(dialog.pullOrMergeHandler(null));
} else {
handlerReference.set(dialog.pullOrMergeHandler(true));
handlerReference.set(dialog.pullOrMergeHandler(url));
}
@@ -45,7 +45,7 @@ import static com.intellij.openapi.util.text.StringUtil.pluralize;
*/
abstract class GitBranchOperation {
private static final Logger LOG = Logger.getInstance(GitBranchOperation.class);
protected static final Logger LOG = Logger.getInstance(GitBranchOperation.class);
@NotNull protected final Project myProject;
@NotNull protected final GitPlatformFacade myFacade;
@@ -152,24 +152,31 @@ class GitDeleteRemoteBranchOperation extends GitBranchOperation {
private GitCommandResult pushDeletion(@NotNull GitRepository repository, @NotNull String remoteName, @NotNull String branchName) {
GitRemote remote = getRemoteByName(repository, remoteName);
if (remote == null) {
return pushDeletionNatively(repository, remoteName, branchName);
String error = "Couldn't find remote by name: " + remoteName;
LOG.error(error);
return GitCommandResult.error(error);
}
String remoteUrl = remote.getFirstUrl();
if (remoteUrl != null && GitHttpAdapter.shouldUseJGit(remoteUrl)) {
if (remoteUrl == null) {
LOG.warn("No urls are defined for remote: " + remote);
return GitCommandResult.error("There is no urls defined for remote " + remote.getName());
}
if (GitHttpAdapter.shouldUseJGit(remoteUrl)) {
String fullBranchName = branchName.startsWith(GitBranch.REFS_HEADS_PREFIX) ? branchName : GitBranch.REFS_HEADS_PREFIX + branchName;
String spec = ":" + fullBranchName;
GitSimplePushResult simplePushResult = GitHttpAdapter.push(repository, remote.getName(), remoteUrl, spec);
return convertSimplePushResultToCommandResult(simplePushResult);
}
else {
return pushDeletionNatively(repository, remoteName, branchName);
return pushDeletionNatively(repository, remoteName, remoteUrl, branchName);
}
}
@NotNull
private GitCommandResult pushDeletionNatively(@NotNull GitRepository repository, @NotNull String remoteName, @NotNull String branchName) {
return myGit.push(repository, remoteName, ":" + branchName);
private GitCommandResult pushDeletionNatively(@NotNull GitRepository repository, @NotNull String remoteName, @NotNull String url,
@NotNull String branchName) {
return myGit.push(repository, remoteName, url,":" + branchName);
}
@NotNull
@@ -164,7 +164,7 @@ public class GitCloneDialog extends DialogWrapper {
*/
private boolean test(String url) {
final GitLineHandlerPasswordRequestAware handler = new GitLineHandlerPasswordRequestAware(myProject, new File("."), GitCommand.LS_REMOTE);
handler.setRemoteProtocol(GitRemoteProtocol.SSH);
handler.setRemoteProtocol(url);
handler.addParameters(url, "master");
GitTask task = new GitTask(myProject, handler, GitBundle.message("clone.testing", url));
GitTaskResult result = task.executeModal();
@@ -92,11 +92,11 @@ public interface Git {
GitCommandResult tip(@NotNull GitRepository repository, @NotNull String branchName);
@NotNull
GitCommandResult push(@NotNull GitRepository repository, @NotNull String remote, @NotNull String spec,
GitCommandResult push(@NotNull GitRepository repository, @NotNull String remote, @NotNull String url, @NotNull String spec,
@NotNull GitLineHandlerListener... listeners);
@NotNull
GitCommandResult push(@NotNull GitRepository repository, @NotNull GitPushSpec pushSpec,
GitCommandResult push(@NotNull GitRepository repository, @NotNull GitPushSpec spec, @NotNull String url,
@NotNull GitLineHandlerListener... listeners);
@NotNull
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -80,4 +81,8 @@ public class GitCommandResult {
return myException;
}
@NotNull
public static GitCommandResult error(@NotNull String error) {
return new GitCommandResult(false, 1, Collections.singletonList(error), Collections.<String>emptyList(), null);
}
}
@@ -217,8 +217,8 @@ public abstract class GitHandler {
return file;
}
public void setRemoteProtocol(@NotNull GitRemoteProtocol remoteProtocol) {
myRemoteProtocol = remoteProtocol;
public void setRemoteProtocol(@NotNull String url) {
myRemoteProtocol = GitRemoteProtocol.fromUrl(url);
}
protected boolean isRemote() {
@@ -132,7 +132,7 @@ public class GitImpl implements Git {
public GitCommandResult clone(@NotNull Project project, @NotNull File parentDirectory, @NotNull String url,
@NotNull String clonedDirectoryName, @NotNull GitLineHandlerListener... listeners) {
GitLineHandlerPasswordRequestAware handler = new GitLineHandlerPasswordRequestAware(project, parentDirectory, GitCommand.CLONE);
handler.setRemoteProtocol(GitRemoteProtocol.SSH);
handler.setRemoteProtocol(url);
handler.addParameters("--progress");
handler.addParameters(url);
handler.addParameters(clonedDirectoryName);
@@ -356,11 +356,11 @@ public class GitImpl implements Git {
@Override
@NotNull
public GitCommandResult push(@NotNull GitRepository repository, @NotNull String remote, @NotNull String spec,
@NotNull GitLineHandlerListener... listeners) {
public GitCommandResult push(@NotNull GitRepository repository, @NotNull String remote, @NotNull String url, @NotNull String spec,
@NotNull GitLineHandlerListener... listeners) {
final GitLineHandlerPasswordRequestAware h = new GitLineHandlerPasswordRequestAware(repository.getProject(), repository.getRoot(),
GitCommand.PUSH);
h.setRemoteProtocol(GitRemoteProtocol.SSH);
h.setRemoteProtocol(url);
h.setSilent(false);
addListeners(h, listeners);
h.addProgressParameter();
@@ -371,12 +371,12 @@ public class GitImpl implements Git {
@Override
@NotNull
public GitCommandResult push(@NotNull GitRepository repository, @NotNull GitPushSpec pushSpec,
@NotNull GitLineHandlerListener... listeners) {
public GitCommandResult push(@NotNull GitRepository repository, @NotNull GitPushSpec pushSpec, @NotNull String url,
@NotNull GitLineHandlerListener... listeners) {
GitRemote remote = pushSpec.getRemote();
GitBranch remoteBranch = pushSpec.getDest();
String destination = remoteBranch.getName().replaceFirst(remote.getName() + "/", "");
return push(repository, remote.getName(), pushSpec.getSource().getName() + ":" + destination, listeners);
return push(repository, remote.getName(), url, pushSpec.getSource().getName() + ":" + destination, listeners);
}
@NotNull
@@ -15,11 +15,26 @@
*/
package git4idea.commands;
import org.jetbrains.annotations.NotNull;
/**
* @author Kirill Likhodedov
*/
public enum GitRemoteProtocol {
GIT,
SSH,
HTTP
HTTP;
@NotNull
public static GitRemoteProtocol fromUrl(@NotNull String url) {
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;
}
}
@@ -27,7 +27,6 @@ import git4idea.GitRemoteBranch;
import git4idea.GitUtil;
import git4idea.commands.GitCommand;
import git4idea.commands.GitLineHandler;
import git4idea.commands.GitRemoteProtocol;
import git4idea.i18n.GitBundle;
import git4idea.repo.GitBranchTrackInfo;
import git4idea.repo.GitRemote;
@@ -154,12 +153,13 @@ public class GitPullDialog extends DialogWrapper {
/**
* @return a pull handler configured according to dialog options
*/
public GitLineHandler pullOrMergeHandler(boolean pull) {
public GitLineHandler pullOrMergeHandler(@Nullable String url) {
boolean pull = url != null;
GitLineHandler h = new GitLineHandler(myProject, gitRoot(), pull ? GitCommand.PULL : GitCommand.MERGE);
// ignore merge failure for the pull
h.ignoreErrorCode(1);
if (pull) {
h.setRemoteProtocol(GitRemoteProtocol.SSH);
h.setRemoteProtocol(url);
h.addProgressParameter();
}
h.addParameters("--no-stat");
@@ -318,21 +318,18 @@ public final class GitPusher {
}
GitRemote remote = pushSpec.getRemote();
String httpUrl = null;
for (String pushUrl : remote.getPushUrls()) {
if (GitHttpAdapter.shouldUseJGit(pushUrl)) {
httpUrl = pushUrl;
break; // TODO support http and ssh urls in one origin
}
Collection<String> pushUrls = remote.getPushUrls();
if (pushUrls.isEmpty()) {
LOG.error("No urls or pushUrls are defined for " + remote);
return GitSimplePushResult.error("There are no URLs defined for remote " + remote.getName());
}
String url = pushUrls.iterator().next();
GitSimplePushResult pushResult;
boolean pushOverHttp = httpUrl != null;
if (pushOverHttp) {
pushResult = GitHttpAdapter.push(repository, remote.getName(), httpUrl, formPushSpec(pushSpec, remote));
if (GitHttpAdapter.shouldUseJGit(url)) {
pushResult = GitHttpAdapter.push(repository, remote.getName(), url, formPushSpec(pushSpec, remote));
}
else {
pushResult = pushNatively(repository, pushSpec);
pushResult = pushNatively(repository, pushSpec, url);
}
if (pushResult.getType() == GitSimplePushResult.Type.SUCCESS) {
@@ -396,10 +393,10 @@ public final class GitPusher {
}
@NotNull
private GitSimplePushResult pushNatively(GitRepository repository, GitPushSpec pushSpec) {
private GitSimplePushResult pushNatively(GitRepository repository, GitPushSpec pushSpec, @NotNull String url) {
GitPushRejectedDetector rejectedDetector = new GitPushRejectedDetector();
GitLineHandlerListener progressListener = GitStandardProgressAnalyzer.createListener(myProgressIndicator);
GitCommandResult res = myGit.push(repository, pushSpec, rejectedDetector, progressListener);
GitCommandResult res = myGit.push(repository, pushSpec, url, rejectedDetector, progressListener);
if (rejectedDetector.rejected()) {
Collection<String> rejectedBranches = rejectedDetector.getRejectedBranches();
return GitSimplePushResult.reject(rejectedBranches);
@@ -132,7 +132,7 @@ public class GitFetcher {
if (GitHttpAdapter.shouldUseJGit(url)) {
return GitHttpAdapter.fetch(repository, remote, url, null);
}
return fetchNatively(repository.getRoot(), remote, null);
return fetchNatively(repository.getRoot(), remote, url, null);
}
// leaving this unused method, because the wanted behavior can change again
@@ -150,7 +150,7 @@ public class GitFetcher {
if (GitHttpAdapter.shouldUseJGit(url)) {
return GitHttpAdapter.fetch(repository, remote, url, remoteBranch);
}
return fetchNatively(repository.getRoot(), remote, remoteBranch);
return fetchNatively(repository.getRoot(), remote, url, remoteBranch);
}
@NotNull
@@ -198,7 +198,7 @@ public class GitFetcher {
}
}
else {
GitFetchResult res = fetchNatively(repository.getRoot(), remote, null);
GitFetchResult res = fetchNatively(repository.getRoot(), remote, url, null);
res.addPruneInfo(fetchResult.getPrunedRefs());
fetchResult = res;
if (!fetchResult.isSuccess()) {
@@ -209,9 +209,9 @@ public class GitFetcher {
return fetchResult;
}
private GitFetchResult fetchNatively(@NotNull VirtualFile root, @NotNull GitRemote remote, @Nullable String branch) {
private GitFetchResult fetchNatively(@NotNull VirtualFile root, @NotNull GitRemote remote, @NotNull String url, @Nullable String branch) {
final GitLineHandlerPasswordRequestAware h = new GitLineHandlerPasswordRequestAware(myProject, root, GitCommand.FETCH);
h.setRemoteProtocol(GitRemoteProtocol.SSH);
h.setRemoteProtocol(url);
h.addProgressParameter();
if (GitVersionSpecialty.SUPPORTS_FETCH_PRUNE.existsIn(myVcs.getVersion())) {
h.addParameters("--prune");
@@ -190,9 +190,7 @@ public class GitTestImpl implements Git {
@NotNull
@Override
public GitCommandResult push(@NotNull GitRepository repository,
@NotNull String remote,
@NotNull String spec,
public GitCommandResult push(@NotNull GitRepository repository, @NotNull String remote, @NotNull String url, @NotNull String spec,
@NotNull GitLineHandlerListener... listeners) {
throw new UnsupportedOperationException();
}
@@ -200,8 +198,7 @@ public class GitTestImpl implements Git {
@NotNull
@Override
public GitCommandResult push(@NotNull GitRepository repository,
@NotNull GitPushSpec pushSpec,
@NotNull GitLineHandlerListener... listeners) {
@NotNull GitPushSpec spec, @NotNull String url, @NotNull GitLineHandlerListener... listeners) {
throw new UnsupportedOperationException();
}