mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-64835 hg: support auth dialog cancellation
1. HgRemoteChangesetsCommand - common ancestor for HgIncoming/OutgoingCommand. All common functionality moved. 2. HgChangesetsCommand.executeCommand - override for remote commands. No more isAuthenticationNeeded(). 3. HgRemoteChangesetsCommand.executeCommand: if user cancelled the dialog, show notification and disable checkboxes for checking incoming/outgoing changes. 4. HgCommandAuthenticator: 3 attempts for authentication error; if other error - return; if auth passed - save credentials and return; if cancelled - return special HgCommandResult.CANCELLED (and show notification in the client - see #3). TODOs for disabling checkboxes: 1. Disable not for project, but for repository+project. 2. Expire the notification once the problem was fixed.
This commit is contained in:
@@ -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<CommittedChangeList> {
|
||||
return new HgProjectConfigurable(projectSettings);
|
||||
}
|
||||
|
||||
public HgProjectSettings getProjectSettings() {
|
||||
return projectSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChangeProvider getChangeProvider() {
|
||||
return changeProvider;
|
||||
|
||||
@@ -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<HgRevisionNumber> getRevisions(VirtualFile repo) {
|
||||
HgCommandService commandService = HgCommandService.getInstance(project);
|
||||
|
||||
|
||||
List<String> args = new ArrayList<String>(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<String> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<String> args) {
|
||||
args.add("--newest-first");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSilentCommand() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAuthenticationNeeded() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> args) {
|
||||
args.add("--newest-first");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSilentCommand() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAuthenticationNeeded() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> args) {
|
||||
args.add("--newest-first");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSilentCommand() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HgCommandResult executeCommand(VirtualFile repo, List<String> 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 +
|
||||
"<br/>You may enable checking for changes <a href='#'>in the Settings</a>."
|
||||
, 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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user