diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java index 349f68ae987b..ae717723db89 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java @@ -47,12 +47,7 @@ import com.intellij.util.containers.Convertor; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.messages.Topic; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.provider.HgCachingCommitedChangesProvider; -import org.zmlx.hg4idea.provider.HgChangeProvider; -import org.zmlx.hg4idea.provider.HgDiffProvider; -import org.zmlx.hg4idea.provider.HgHistoryProvider; -import org.zmlx.hg4idea.provider.HgMergeProvider; -import org.zmlx.hg4idea.provider.HgRollbackEnvironment; +import org.zmlx.hg4idea.provider.*; import org.zmlx.hg4idea.provider.annotate.HgAnnotationProvider; import org.zmlx.hg4idea.provider.commit.HgCheckinEnvironment; import org.zmlx.hg4idea.provider.update.HgIntegrateEnvironment; @@ -136,6 +131,10 @@ public class HgVcs extends AbstractVcs { return new HgProjectConfigurable(projectSettings); } + public HgProjectSettings getProjectSettings() { + return projectSettings; + } + @Override public ChangeProvider getChangeProvider() { return changeProvider; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java index bbbd4e8e8ad1..266d457f085c 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java @@ -16,6 +16,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import org.apache.commons.lang.StringUtils; +import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgRevisionNumber; import java.nio.charset.Charset; @@ -33,8 +34,8 @@ public abstract class HgChangesetsCommand { private static final String SEPARATOR_STRING = "\u0017"; //ascii: end of transmission block - private final Project project; - private final String command; + protected final Project project; + protected final String command; public HgChangesetsCommand(Project project, String command) { this.project = project; @@ -46,9 +47,6 @@ public abstract class HgChangesetsCommand { } protected List getRevisions(VirtualFile repo) { - HgCommandService commandService = HgCommandService.getInstance(project); - - List args = new ArrayList(Arrays.asList( "--template", "{rev}|{node|short}|{author}|{desc|firstline}" + SEPARATOR_STRING, @@ -57,13 +55,7 @@ public abstract class HgChangesetsCommand { addArguments(args); - HgCommandResult result; - if (isAuthenticationNeeded()) { - String repositoryURL = new HgShowConfigCommand(project).getDefaultPath(repo); - result = new HgCommandAuthenticator().executeCommandAndAuthenticateIfNecessary(project, repo, repositoryURL, command, args, args.size()-1); - } else { - result = commandService.execute(repo, HgCommandService.DEFAULT_OPTIONS, command, args, Charset.defaultCharset(), isSilentCommand()); - } + HgCommandResult result = executeCommand(repo, args); if (result == null) { return Collections.emptyList(); @@ -89,14 +81,12 @@ public abstract class HgChangesetsCommand { return revisions; } - protected boolean isSilentCommand() { - return false; + @Nullable + protected HgCommandResult executeCommand(VirtualFile repo, List args) { + return HgCommandService.getInstance(project).execute(repo, HgCommandService.DEFAULT_OPTIONS, command, args, Charset.defaultCharset(), isSilentCommand()); } - /** - * Return false for local operations, true - for remote, which may require authenticate on the server. - */ - protected boolean isAuthenticationNeeded() { + protected boolean isSilentCommand() { return false; } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommandAuthenticator.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommandAuthenticator.java index f6f81c10520b..5007815066f6 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommandAuthenticator.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommandAuthenticator.java @@ -33,6 +33,7 @@ import java.net.URISyntaxException; import java.util.List; import java.util.Map; +import static org.zmlx.hg4idea.command.HgErrorUtil.isAbort; import static org.zmlx.hg4idea.command.HgErrorUtil.isAuthorizationError; /** @@ -67,23 +68,27 @@ class HgCommandAuthenticator { HgUrl hgUrl = new HgUrl(remoteRepository); if (hgUrl.supportsAuthentication()) { final GetPasswordRunnable runnable = new GetPasswordRunnable(project, hgUrl); - // first time try to get info from password safe if it's there, or show auth dialog if not - result = tryToAuthenticate(project, localRepository, hgUrl, runnable, command, arguments, urlArgumentPosition); - if (!isAuthorizationError(result)) { - saveCredentials(project, runnable); - } else { - // then twice request auth info from user - runnable.setForceShowDialog(true); - for (int i = 0; i < 2; i++) { - result = tryToAuthenticate(project, localRepository, hgUrl, runnable, command, arguments, urlArgumentPosition); - if (!isAuthorizationError(result)) { - saveCredentials(project, runnable); + for (int i = 0; i < 3; i++) { + if (i == 1) { + runnable.setForceShowDialog(true); // first time try to get info from password safe if it's there, next time don't even try, + // because it means that the saved data didn't pass the authentication + } + result = tryToAuthenticate(project, localRepository, hgUrl, runnable, command, arguments, urlArgumentPosition); + if (result == HgCommandResult.CANCELLED) { + return result; + } + if (isAbort(result)) { + if (isAuthorizationError(result)) { + continue; + } else { return result; } } - HgUtil.notifyError(project, "Authentication failed", "Authentication to " + remoteRepository + " failed"); + saveCredentials(project, runnable); return result; } + HgUtil.notifyError(project, "Authentication failed", "Authentication to " + remoteRepository + " failed"); + return result; } else { HgUtil.notifyError(project, "Authentication error", "Authentication was requested, but " + hgUrl.getScheme() + " doesn't support it."); } @@ -106,6 +111,8 @@ class HgCommandAuthenticator { if (runnable.isOk()) { hgUrl.setUsername(runnable.getUserName()); hgUrl.setPassword(String.valueOf(runnable.getPassword())); + } else { + return HgCommandResult.CANCELLED; } arguments.set(urlArgumentPosition, hgUrl.asString()); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommandResult.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommandResult.java index 8c5988fc3e3a..8057b46f08f1 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommandResult.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommandResult.java @@ -20,7 +20,8 @@ import java.util.List; public final class HgCommandResult { - static final HgCommandResult EMPTY = new HgCommandResult(new StringWriter(), new StringWriter(), 0); + public static final HgCommandResult EMPTY = new HgCommandResult(new StringWriter(), new StringWriter(), 0); + public static final HgCommandResult CANCELLED = new HgCommandResult(new StringWriter(), new StringWriter(), 1); private final StringWriter out; private final StringWriter err; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgIncomingCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgIncomingCommand.java index 8470e5f3424f..b905c3459071 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgIncomingCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgIncomingCommand.java @@ -14,26 +14,10 @@ package org.zmlx.hg4idea.command; import com.intellij.openapi.project.Project; -import java.util.List; - -public class HgIncomingCommand extends HgChangesetsCommand { +public class HgIncomingCommand extends HgRemoteChangesetsCommand { public HgIncomingCommand(Project project) { super(project, "incoming"); } - @Override - protected void addArguments(List args) { - args.add("--newest-first"); - } - - @Override - protected boolean isSilentCommand() { - return true; - } - - @Override - protected boolean isAuthenticationNeeded() { - return true; - } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java index 0304578f9c76..a14eb43e2cac 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java @@ -14,26 +14,10 @@ package org.zmlx.hg4idea.command; import com.intellij.openapi.project.Project; -import java.util.List; - -public class HgOutgoingCommand extends HgChangesetsCommand { +public class HgOutgoingCommand extends HgRemoteChangesetsCommand { public HgOutgoingCommand(Project project) { super(project, "outgoing"); } - @Override - protected void addArguments(List args) { - args.add("--newest-first"); - } - - @Override - protected boolean isSilentCommand() { - return true; - } - - @Override - protected boolean isAuthenticationNeeded() { - return true; - } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java new file mode 100644 index 000000000000..5166952b3166 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2011 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 org.zmlx.hg4idea.command; + +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationListener; +import com.intellij.notification.NotificationType; +import com.intellij.notification.Notifications; +import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.zmlx.hg4idea.HgProjectSettings; +import org.zmlx.hg4idea.HgVcs; + +import javax.swing.event.HyperlinkEvent; +import java.util.List; + +/** + * Common ancestor for HgIncomingCommand and HgOutgoingCommand - changeset commands which need connection to the server. + * @author Kirill Likhodedov + */ +public abstract class HgRemoteChangesetsCommand extends HgChangesetsCommand { + public HgRemoteChangesetsCommand(Project project, String command) { + super(project, command); + } + + @Override + protected void addArguments(List args) { + args.add("--newest-first"); + } + + @Override + protected boolean isSilentCommand() { + return true; + } + + @Override + protected HgCommandResult executeCommand(VirtualFile repo, List args) { + String repositoryURL = new HgShowConfigCommand(project).getDefaultPath(repo); + HgCommandResult result = new HgCommandAuthenticator().executeCommandAndAuthenticateIfNecessary(project, repo, repositoryURL, command, args, args.size()-1); + if (result == HgCommandResult.CANCELLED) { + final HgVcs vcs = HgVcs.getInstance(project); + Notifications.Bus.notify(new Notification(HgVcs.NOTIFICATION_GROUP_ID, "Checking for incoming/outgoing changes disabled", + "Authentication is required to check incoming/outgoing changes in " + repositoryURL + + "
You may enable checking for changes in the Settings." + , NotificationType.ERROR, new NotificationListener() { + @Override + public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { + ShowSettingsUtil.getInstance().showSettingsDialog(project, vcs.getConfigurable()); + } + }), project); + final HgProjectSettings projectSettings = vcs.getProjectSettings(); + projectSettings.setCheckIncoming(false); + projectSettings.setCheckOutgoing(false); + } + return result; + } + +}