>();
+ ApplicationManager.getApplication().invokeAndWait(new Runnable() {
+ @Override public void run() {
+ filePaths.set(selectFilePathsToDelete(filesToConfirmDeletion));
+ }
+ }, indicator.getModalityState());
+ if (filePaths.get() != null) {
+ filesToDelete.addAll(filePaths.get());
+ }
+ }
+ }
+
+ if (!filesToDelete.isEmpty()) {
+ performDeletion(filesToDelete);
}
}
- }
+ }.queue();
+ }
- if (!filesToDelete.isEmpty()) {
- performDeletion(filesToDelete);
+ /**
+ * Newly added files (which were added to the repo but never committed) should be removed from the VCS,
+ * but without user confirmation.
+ * NB: we don't use {@link #needConfirmDeletion(com.intellij.openapi.vfs.VirtualFile)},
+ * because it is executed in EDT, while we need to access hg log, which should be done in background. Starting a Task.Modal for
+ * each file is ineffective, so we start it once (in {@link #executeDelete()} for all files.
localRevisions = logCommand.execute(hgFile, -1, true);
+
+ // file is newly added, if it doesn't have a history or if the last history action was deleting this file.
+ return localRevisions != null && !localRevisions.isEmpty() && !localRevisions.get(0).getDeletedFiles().contains(hgFile.getRelativePath());
}
/**
@@ -211,30 +238,22 @@ public class HgVFSListener extends VcsVFSListener {
@Override
protected void performDeletion( final List filesToDelete) {
- (new Task.ConditionalModal(myProject,
- HgVcsMessages.message("hg4idea.remove.progress"),
- false,
- VcsConfiguration.getInstance(myProject).getAddRemoveOption()) {
- @Override public void run( @NotNull ProgressIndicator aProgressIndicator ) {
- final ArrayList deletes = new ArrayList();
- for (FilePath file : filesToDelete) {
- if (file.isDirectory()) {
- continue;
- }
-
- deletes.add(new HgFile(VcsUtil.getVcsRootFor(myProject, file), file));
- }
-
- if (!deletes.isEmpty()) {
- new HgRemoveCommand(myProject).execute(deletes);
- }
-
- for (HgFile file : deletes) {
- dirtyScopeManager.fileDirty(file.toFilePath());
- }
+ final ArrayList deletes = new ArrayList();
+ for (FilePath file : filesToDelete) {
+ if (file.isDirectory()) {
+ continue;
}
- }).queue();
+ deletes.add(new HgFile(VcsUtil.getVcsRootFor(myProject, file), file));
+ }
+
+ if (!deletes.isEmpty()) {
+ new HgRemoveCommand(myProject).execute(deletes);
+ }
+
+ for (HgFile file : deletes) {
+ dirtyScopeManager.fileDirty(file.toFilePath());
+ }
}
@Override
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java
index 6aff4dfc7c5e..bf1551d06c6c 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java
@@ -14,6 +14,8 @@ package org.zmlx.hg4idea;
import com.intellij.concurrency.JobScheduler;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ApplicationNamesInfo;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.impl.patch.formove.FilePathComparator;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.fileEditor.FileEditorManagerAdapter;
@@ -46,6 +48,7 @@ import com.intellij.util.containers.ComparatorDelegate;
import com.intellij.util.containers.Convertor;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.messages.Topic;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.provider.*;
import org.zmlx.hg4idea.provider.annotate.HgAnnotationProvider;
@@ -72,6 +75,7 @@ public class HgVcs extends AbstractVcs {
private static final Icon INCOMING_ICON = IconLoader.getIcon("/actions/moveDown.png");
private static final Icon OUTGOING_ICON = IconLoader.getIcon("/actions/moveUp.png");
+ private static final Logger LOG = Logger.getInstance(HgVcs.class);
public static final String VCS_NAME = "hg4idea";
public static final String NOTIFICATION_GROUP_ID = "Mercurial";
@@ -102,6 +106,7 @@ public class HgVcs extends AbstractVcs {
private final HgMergeProvider myMergeProvider;
private HgExecutableValidator myExecutableValidator;
private final Object myExecutableValidatorLock = new Object();
+ private File myPromptHooksExtensionFile;
public HgVcs(Project project,
HgGlobalSettings globalSettings, HgProjectSettings projectSettings,
@@ -236,12 +241,27 @@ public class HgVcs extends AbstractVcs {
return HgUtil.getNearestHgRoot(dir) != null;
}
+ /**
+ * @return the prompthooks.py extension used for capturing prompts from Mercurial and requesting IDEA's user about authentication.
+ */
+ public @NotNull File getPromptHooksExtensionFile() {
+ if (myPromptHooksExtensionFile == null) {
+ // check that hooks are available
+ myPromptHooksExtensionFile = HgUtil.getTemporaryPythonFile("prompthooks");
+ if (myPromptHooksExtensionFile == null || !myPromptHooksExtensionFile.exists()) {
+ LOG.error("prompthooks.py Mercurial extension is not found. Please reinstall " + ApplicationNamesInfo.getInstance().getProductName());
+ }
+ }
+ return myPromptHooksExtensionFile;
+ }
+
@Override
public void activate() {
// validate hg executable on start
if (!ApplicationManager.getApplication().isUnitTestMode()) {
getExecutableValidator().checkExecutableAndShowDialogIfNeeded();
}
+
// status bar
StatusBar statusBar = WindowManager.getInstance().getStatusBar(myProject);
if (statusBar != null) {
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java
index d0aad5f6ba27..5a08c2c6122e 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java
@@ -22,7 +22,7 @@ import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.HgUtil;
import org.zmlx.hg4idea.HgVcs;
-import org.zmlx.hg4idea.command.HgCommandException;
+import org.zmlx.hg4idea.execution.HgCommandException;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java
index 65c83aaa04a9..21b977587f73 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java
@@ -15,7 +15,7 @@ package org.zmlx.hg4idea.action;
import com.intellij.openapi.project.Project;
import com.intellij.vcsUtil.VcsUtil;
import org.apache.commons.lang.StringUtils;
-import org.zmlx.hg4idea.command.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgCommandResult;
import java.util.List;
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java
index af560c5fce2d..af702917e2e1 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java
@@ -14,9 +14,11 @@ package org.zmlx.hg4idea.action;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.command.HgTagCreateCommand;
-import org.zmlx.hg4idea.command.HgCommandException;
-import org.zmlx.hg4idea.command.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgCommandException;
+import org.zmlx.hg4idea.execution.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgCommandResultHandler;
import org.zmlx.hg4idea.ui.HgTagDialog;
import java.util.Collection;
@@ -44,10 +46,12 @@ public class HgCreateTagAction extends HgAbstractGlobalAction {
}
public void execute() throws HgCommandException {
- HgCommandResult result =
- new HgTagCreateCommand(project, dialog.getRepository(), dialog.getTagName()).execute();
-
- new HgCommandResultNotifier(project).process(result);
+ new HgTagCreateCommand(project, dialog.getRepository(), dialog.getTagName()).execute(new HgCommandResultHandler() {
+ @Override
+ public void process(@Nullable HgCommandResult result) {
+ new HgCommandResultNotifier(project).process(result);
+ }
+ });
}
};
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java
index de16ba14e30f..e745a7b0085e 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java
@@ -5,7 +5,6 @@ import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
-import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
@@ -13,6 +12,7 @@ import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsDirectoryMapping;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.Consumer;
import org.zmlx.hg4idea.HgUtil;
import org.zmlx.hg4idea.HgVcs;
import org.zmlx.hg4idea.HgVcsMessages;
@@ -53,6 +53,7 @@ public class HgInit extends DumbAwareAction {
// check if the selected folder is not yet under mercurial and provide some options in that case
final VirtualFile vcsRoot = HgUtil.getNearestHgRoot(selectedRoot);
VirtualFile mapRoot = selectedRoot;
+ boolean needToCreateRepo = false;
if (vcsRoot != null) {
final HgInitAlreadyUnderHgDialog dialog = new HgInitAlreadyUnderHgDialog(myProject,
selectedRoot.getPresentableUrl(), vcsRoot.getPresentableUrl());
@@ -64,18 +65,23 @@ public class HgInit extends DumbAwareAction {
if (dialog.getAnswer() == HgInitAlreadyUnderHgDialog.Answer.USE_PARENT_REPO) {
mapRoot = vcsRoot;
} else if (dialog.getAnswer() == HgInitAlreadyUnderHgDialog.Answer.CREATE_REPO_HERE) {
- if (!createRepository(selectedRoot)) {
- return;
- }
+ needToCreateRepo = true;
}
} else { // no parent repository => creating the repository here.
- if (!createRepository(selectedRoot)){
- return;
- }
+ needToCreateRepo = true;
}
- // update vcs directory mappings if new repository was created inside the current project directory
- if (myProject != null && (! myProject.isDefault()) && myProject.getBaseDir() != null && VfsUtil.isAncestor(myProject.getBaseDir(), mapRoot, false)) {
+ if (needToCreateRepo) {
+ createRepository(selectedRoot, mapRoot);
+ } else {
+ updateDirectoryMappings(mapRoot);
+ }
+ }
+
+ // update vcs directory mappings if new repository was created inside the current project directory
+ private void updateDirectoryMappings(VirtualFile mapRoot) {
+ if (myProject != null && (! myProject.isDefault()) && myProject.getBaseDir() != null && VfsUtil
+ .isAncestor(myProject.getBaseDir(), mapRoot, false)) {
mapRoot.refresh(false, false);
final String path = mapRoot.equals(myProject.getBaseDir()) ? "" : mapRoot.getPath();
final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject);
@@ -103,14 +109,24 @@ public class HgInit extends DumbAwareAction {
}
}
- private boolean createRepository(VirtualFile selectedRoot) {
- final boolean succeeded = (new HgInitCommand(myProject)).execute(selectedRoot);
- Notifications.Bus.notify(new Notification(HgVcs.NOTIFICATION_GROUP_ID,
- HgVcsMessages.message(succeeded ? "hg4idea.init.created.notification.title" : "hg4idea.init.error.title"),
- HgVcsMessages.message(succeeded ? "hg4idea.init.created.notification.description" : "hg4idea.init.error.description",
- selectedRoot.getPresentableUrl()),
- succeeded ? NotificationType.INFORMATION : NotificationType.ERROR), myProject.isDefault() ? null : myProject);
- return succeeded;
+ private void createRepository(final VirtualFile selectedRoot, final VirtualFile mapRoot) {
+ new HgInitCommand(myProject).execute(selectedRoot, new Consumer() {
+ @Override
+ public void consume(Boolean succeeded) {
+ if (succeeded) {
+ updateDirectoryMappings(mapRoot);
+ }
+ Notifications.Bus.notify(new Notification(HgVcs.NOTIFICATION_GROUP_ID,
+ HgVcsMessages.message(
+ succeeded ? "hg4idea.init.created.notification.title" : "hg4idea.init.error.title"),
+ HgVcsMessages.message(succeeded
+ ? "hg4idea.init.created.notification.description"
+ : "hg4idea.init.error.description",
+ selectedRoot.getPresentableUrl()),
+ succeeded ? NotificationType.INFORMATION : NotificationType.ERROR),
+ myProject.isDefault() ? null : myProject);
+ }
+ });
}
-}
+}
\ No newline at end of file
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMqRebaseAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMqRebaseAction.java
index 279d68b7b01e..82b398ca8483 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMqRebaseAction.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMqRebaseAction.java
@@ -15,8 +15,11 @@ package org.zmlx.hg4idea.action;
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.HgFile;
import org.zmlx.hg4idea.command.*;
+import org.zmlx.hg4idea.execution.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgCommandResultHandler;
import org.zmlx.hg4idea.provider.update.HgConflictResolver;
import org.zmlx.hg4idea.ui.HgPullDialog;
@@ -57,23 +60,29 @@ public class HgMqRebaseAction extends HgAbstractGlobalAction {
pullCommand.setSource(dialog.getSource());
pullCommand.setRebase(true);
pullCommand.setUpdate(false);
- new HgCommandResultNotifier(project).process(pullCommand.execute());
- String currentBranch = new HgTagBranchCommand(project, repository).getCurrentBranch();
- if (StringUtils.isBlank(currentBranch)) {
- return;
- }
+ pullCommand.execute(new HgCommandResultHandler() {
+ @Override
+ public void process(@Nullable HgCommandResult result) {
+ new HgCommandResultNotifier(project).process(result);
- new HgConflictResolver(project).resolve(repository);
+ String currentBranch = new HgTagBranchCommand(project, repository).getCurrentBranch();
+ if (StringUtils.isBlank(currentBranch)) {
+ return;
+ }
- HgResolveCommand resolveCommand = new HgResolveCommand(project);
- Map status = resolveCommand.list(repository);
+ new HgConflictResolver(project).resolve(repository);
- if (status.containsValue(HgResolveStatusEnum.UNRESOLVED)) {
- return;
- }
+ HgResolveCommand resolveCommand = new HgResolveCommand(project);
+ Map status = resolveCommand.getListSynchronously(repository);
- new HgRebaseCommand(project, repository).continueRebase();
+ if (status.containsValue(HgResolveStatusEnum.UNRESOLVED)) {
+ return;
+ }
+
+ new HgRebaseCommand(project, repository).continueRebase();
+ }
+ });
}
};
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java
index 982e6b0451b7..15d705be9c6c 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java
@@ -14,8 +14,10 @@ package org.zmlx.hg4idea.action;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.command.HgPullCommand;
-import org.zmlx.hg4idea.command.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgCommandResultHandler;
import org.zmlx.hg4idea.ui.HgPullDialog;
import java.util.Collection;
@@ -49,8 +51,12 @@ public class HgPullAction extends HgAbstractGlobalAction {
command.setSource(dialog.getSource());
command.setRebase(false);
command.setUpdate(false);
- HgCommandResult result = command.execute();
- new HgCommandResultNotifier(project).process(result);
+ command.execute(new HgCommandResultHandler() {
+ @Override
+ public void process(@Nullable HgCommandResult result) {
+ new HgCommandResultNotifier(project).process(result);
+ }
+ });
}
};
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java
index 3436e733d853..838623bd2177 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java
@@ -14,7 +14,10 @@ package org.zmlx.hg4idea.action;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.command.HgPushCommand;
+import org.zmlx.hg4idea.execution.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgCommandResultHandler;
import org.zmlx.hg4idea.ui.HgPushDialog;
import java.util.Collection;
@@ -46,7 +49,12 @@ public class HgPushAction extends HgAbstractGlobalAction {
command.setRevision(dialog.getRevision());
command.setForce(dialog.isForce());
command.setBranch(dialog.getBranch());
- new HgCommandResultNotifier(project).process(command.execute());
+ command.execute(new HgCommandResultHandler() {
+ @Override
+ public void process(@Nullable HgCommandResult result) {
+ new HgCommandResultNotifier(project).process(result);
+ }
+ });
}
};
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgRunConflictResolverAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgRunConflictResolverAction.java
index 71d5bd095f61..7e6802a7c6a6 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgRunConflictResolverAction.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgRunConflictResolverAction.java
@@ -12,8 +12,11 @@
// limitations under the License.
package org.zmlx.hg4idea.action;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
import org.zmlx.hg4idea.provider.update.HgConflictResolver;
import org.zmlx.hg4idea.ui.HgRunConflictResolverDialog;
@@ -60,7 +63,12 @@ public class HgRunConflictResolverAction extends HgAbstractGlobalAction {
}
public void execute() {
- new HgConflictResolver(project).resolve(repository);
+ new Task.Modal(project, "Mercurial resolves conflicts", false) {
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ new HgConflictResolver(project).resolve(repository);
+ }
+ }.queue();
}
};
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgSwitchWorkingDirectoryAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgSwitchWorkingDirectoryAction.java
index 384194da9202..d9d18ff94490 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgSwitchWorkingDirectoryAction.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgSwitchWorkingDirectoryAction.java
@@ -12,11 +12,12 @@
// limitations under the License.
package org.zmlx.hg4idea.action;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.zmlx.hg4idea.HgVcs;
import org.zmlx.hg4idea.command.HgUpdateCommand;
-import org.zmlx.hg4idea.command.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgCommandResult;
import org.zmlx.hg4idea.ui.HgSwitchDialog;
import java.util.Collection;
@@ -44,7 +45,7 @@ public class HgSwitchWorkingDirectoryAction extends HgAbstractGlobalAction {
}
public void execute() {
- HgUpdateCommand command = new HgUpdateCommand(project, dialog.getRepository());
+ final HgUpdateCommand command = new HgUpdateCommand(project, dialog.getRepository());
command.setClean(dialog.isRemoveLocalChanges());
if (dialog.isRevisionSelected()) {
command.setRevision(dialog.getRevision());
@@ -56,10 +57,14 @@ public class HgSwitchWorkingDirectoryAction extends HgAbstractGlobalAction {
command.setRevision(dialog.getTag().getName());
}
- HgCommandResult result = command.execute();
- new HgCommandResultNotifier(project).process(result);
-
- project.getMessageBus().syncPublisher(HgVcs.BRANCH_TOPIC).update(project);
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ HgCommandResult result = command.execute();
+ new HgCommandResultNotifier(project).process(result);
+ project.getMessageBus().syncPublisher(HgVcs.BRANCH_TOPIC).update(project);
+ }
+ });
}
};
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java
index 680c7f129c87..7025c7f68227 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java
@@ -17,6 +17,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.zmlx.hg4idea.HgFile;
import org.zmlx.hg4idea.HgUtil;
+import org.zmlx.hg4idea.execution.HgCommandExecutor;
import java.util.Arrays;
import java.util.Collection;
@@ -48,7 +49,7 @@ public class HgAddCommand {
*/
public void execute(@NotNull Collection hgFiles) {
for(Map.Entry> entry : HgUtil.getRelativePathsByRepository(hgFiles).entrySet()) {
- HgCommandService.getInstance(myProject).execute(entry.getKey(), "add", entry.getValue());
+ new HgCommandExecutor(myProject).executeInCurrentThread(entry.getKey(), "add", entry.getValue());
}
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAnnotateCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAnnotateCommand.java
index 07d2c81835b5..257367f385f3 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAnnotateCommand.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAnnotateCommand.java
@@ -15,6 +15,8 @@ package org.zmlx.hg4idea.command;
import com.intellij.openapi.project.Project;
import org.zmlx.hg4idea.HgFile;
import org.zmlx.hg4idea.HgRevisionNumber;
+import org.zmlx.hg4idea.execution.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgCommandExecutor;
import org.zmlx.hg4idea.provider.annotate.HgAnnotationLine;
import org.jetbrains.annotations.NotNull;
@@ -44,10 +46,8 @@ public class HgAnnotateCommand {
}
public List execute(@NotNull HgFile hgFile) {
- HgCommandService service = HgCommandService.getInstance(project);
- HgCommandResult result = service.execute(
- hgFile.getRepo(), "annotate", Arrays.asList("-cqnudl", hgFile.getRelativePath())
- );
+ HgCommandExecutor executor = new HgCommandExecutor(project);
+ HgCommandResult result = executor.executeInCurrentThread(hgFile.getRepo(), "annotate", Arrays.asList("-cqnudl", hgFile.getRelativePath()));
List annotations = new ArrayList();
for (String line : result.getOutputLines()) {
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCatCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCatCommand.java
index 6beb6ef187d4..6b02f52a3d1c 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCatCommand.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCatCommand.java
@@ -17,6 +17,8 @@ import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.HgFile;
import org.zmlx.hg4idea.HgRevisionNumber;
+import org.zmlx.hg4idea.execution.HgCommandExecutor;
+import org.zmlx.hg4idea.execution.HgCommandResult;
import java.nio.charset.Charset;
import java.util.Collections;
@@ -34,8 +36,10 @@ public class HgCatCommand {
@Nullable
public String execute(HgFile hgFile, HgRevisionNumber vcsRevisionNumber, Charset charset) {
final List arguments = createArguments(vcsRevisionNumber, hgFile.getRelativePath());
- final HgCommandService service = HgCommandService.getInstance(myProject);
- final HgCommandResult result = service.execute(hgFile.getRepo(), Collections.emptyList(), "cat", arguments, charset, true);
+ final HgCommandExecutor executor = new HgCommandExecutor(myProject);
+ executor.setOptions(Collections.emptyList());
+ executor.setSilent(true);
+ final HgCommandResult result = executor.executeInCurrentThread(hgFile.getRepo(), "cat", arguments);
if (result == null) { // in case of error
return null;
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java
index 266d457f085c..261fdda52a77 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java
@@ -18,8 +18,9 @@ import com.intellij.openapi.vfs.VirtualFile;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.HgRevisionNumber;
+import org.zmlx.hg4idea.execution.HgCommandExecutor;
+import org.zmlx.hg4idea.execution.HgCommandResult;
-import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -83,7 +84,9 @@ public abstract class HgChangesetsCommand {
@Nullable
protected HgCommandResult executeCommand(VirtualFile repo, List args) {
- return HgCommandService.getInstance(project).execute(repo, HgCommandService.DEFAULT_OPTIONS, command, args, Charset.defaultCharset(), isSilentCommand());
+ final HgCommandExecutor executor = new HgCommandExecutor(project);
+ executor.setSilent(isSilentCommand());
+ return executor.executeInCurrentThread(repo, command, args);
}
protected boolean isSilentCommand() {
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCloneCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCloneCommand.java
index 1384ddc2f528..16df8fc6235c 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCloneCommand.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCloneCommand.java
@@ -2,11 +2,10 @@ package org.zmlx.hg4idea.command;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.Nullable;
+import org.zmlx.hg4idea.execution.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgCommandExecutor;
-import java.nio.charset.Charset;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedList;
import java.util.List;
public class HgCloneCommand {
@@ -14,7 +13,6 @@ public class HgCloneCommand {
private String repositoryURL;
private String directory;
- private final HgCommandAuthenticator authenticator = new HgCommandAuthenticator();
public HgCloneCommand(Project project) {
this.project = project;
@@ -33,6 +31,8 @@ public class HgCloneCommand {
final List arguments = new ArrayList(2);
arguments.add(repositoryURL);
arguments.add(directory);
- return authenticator.executeCommandAndAuthenticateIfNecessary(project, null, repositoryURL, "clone", arguments);
+ final HgCommandExecutor executor = new HgCommandExecutor(project);
+ executor.setShowOutput(true);
+ return executor.executeInCurrentThread(null, "clone", arguments);
}
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommandAuthenticator.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommandAuthenticator.java
deleted file mode 100644
index 5007815066f6..000000000000
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommandAuthenticator.java
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright 2008-2010 Victor Iacoban
-//
-// 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.ide.passwordSafe.PasswordSafe;
-import com.intellij.ide.passwordSafe.PasswordSafeException;
-import com.intellij.ide.passwordSafe.config.PasswordSafeSettings;
-import com.intellij.ide.passwordSafe.impl.PasswordSafeImpl;
-import com.intellij.ide.passwordSafe.impl.PasswordSafeProvider;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.ui.UIUtil;
-import com.intellij.vcsUtil.VcsUtil;
-import org.apache.commons.lang.StringUtils;
-import org.jetbrains.annotations.Nullable;
-import org.zmlx.hg4idea.HgGlobalSettings;
-import org.zmlx.hg4idea.HgUtil;
-import org.zmlx.hg4idea.HgVcs;
-import org.zmlx.hg4idea.ui.HgUsernamePasswordDialog;
-
-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;
-
-/**
- * Base class for any command interacting with a remote repository and which needs authentication.
- */
-class HgCommandAuthenticator {
-
- private static final Logger LOG = Logger.getInstance(HgCommandAuthenticator.class.getName());
-
- @Nullable
- protected HgCommandResult executeCommandAndAuthenticateIfNecessary(Project project, VirtualFile localRepository, String remoteRepository, String command, List arguments) {
- return executeCommandAndAuthenticateIfNecessary(project, localRepository, remoteRepository, command, arguments, 0);
- }
- /**
- * Tries to execute an hg command and analyzes the output.
- * If authentication is needed, watches to the PasswordSafe for the saved password. Otherwise asks the user.
- * Repeats it 3 times to give a chance to retry.
- * @param project
- * @param localRepository
- * @param remoteRepository
- * @param command
- * @param arguments
- * @param urlPosition
- * @return
- */
- @Nullable
- protected HgCommandResult executeCommandAndAuthenticateIfNecessary(Project project, VirtualFile localRepository, String remoteRepository, String command, List arguments, int urlArgumentPosition) {
- HgCommandResult result = HgCommandService.getInstance(project).execute(localRepository, command, arguments); // try to execute without authentication data
- if (isAuthorizationError(result)) {
- try {
- // get auth data from password safe of from user and inject to the url
- HgUrl hgUrl = new HgUrl(remoteRepository);
- if (hgUrl.supportsAuthentication()) {
- final GetPasswordRunnable runnable = new GetPasswordRunnable(project, hgUrl);
- 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;
- }
- }
- 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.");
- }
- } catch (URISyntaxException e) {
- VcsUtil.showErrorMessage(project, "Invalid repository: " + remoteRepository, "Error");
- }
- }
- return result;
- }
-
- /**
- * Shows the auth dialog if needed, fills authentication data to the given hgurl and returns the result of command execution.
- * NB: hgUrl is modified
- */
- @Nullable
- private static HgCommandResult tryToAuthenticate(Project project, VirtualFile localRepository, HgUrl hgUrl, GetPasswordRunnable runnable, String command, List arguments, int urlArgumentPosition) throws URISyntaxException {
- HgCommandService service = HgCommandService.getInstance(project);
-
- UIUtil.invokeAndWaitIfNeeded(runnable);
- if (runnable.isOk()) {
- hgUrl.setUsername(runnable.getUserName());
- hgUrl.setPassword(String.valueOf(runnable.getPassword()));
- } else {
- return HgCommandResult.CANCELLED;
- }
-
- arguments.set(urlArgumentPosition, hgUrl.asString());
- return service.execute(localRepository, command, arguments);
- }
-
- private static void saveCredentials(Project project, GetPasswordRunnable runnable) {
- final PasswordSafeImpl passwordSafe = (PasswordSafeImpl)PasswordSafe.getInstance();
- if (passwordSafe.getSettings().getProviderType().equals(PasswordSafeSettings.ProviderType.DO_NOT_STORE)) {
- return;
- }
- final String key = keyForUrlAndLogin(runnable.getURL(), runnable.getUserName());
-
- final PasswordSafeProvider provider = runnable.isRememberPassword() ? passwordSafe.getMasterKeyProvider() : passwordSafe.getMemoryProvider();
- try {
- provider.storePassword(project, HgCommandAuthenticator.class, key, runnable.getPassword());
- final HgVcs vcs = HgVcs.getInstance(project);
- if (vcs != null) {
- vcs.getGlobalSettings().addRememberedUrl(runnable.getURL(), runnable.getUserName());
- }
- } catch (PasswordSafeException e) {
- LOG.info("Couldn't store the password for key [" + key + "]", e);
- }
- }
-
- private static class GetPasswordRunnable implements Runnable {
-
- private final HgUrl hgUrl;
- private String userName;
- private String myPassword;
- private Project project;
- private boolean myForceShowDialog;
- private boolean ok = false;
- private static final Logger LOG = Logger.getInstance(GetPasswordRunnable.class.getName());
- private String myURL;
- private boolean myRememberPassword;
-
- public GetPasswordRunnable(Project project, HgUrl hgUrl) {
- this.hgUrl = hgUrl;
- this.project = project;
- }
-
- public void run() {
-
- // get the string representation of the url
- @Nullable String stringUrl = null;
- try {
- stringUrl = hgUrl.asString();
- }
- catch (URISyntaxException e) {
- LOG.warn("Couldn't parse hgUrl: [" + hgUrl + "]", e);
- }
-
- // find if we've already been here
- final HgVcs vcs = HgVcs.getInstance(project);
- if (vcs == null) { return; }
-
- final HgGlobalSettings hgGlobalSettings = vcs.getGlobalSettings();
- final Map> urls = hgGlobalSettings.getRememberedUrls();
- @Nullable List rememberedLoginsForUrl = urls.get(stringUrl);
-
- String login = hgUrl.getUsername();
- if (StringUtils.isBlank(login)) {
- // find the last used login
- if (rememberedLoginsForUrl != null && !rememberedLoginsForUrl.isEmpty()) {
- login = rememberedLoginsForUrl.get(0);
- }
- }
-
- String password = hgUrl.getPassword();
- if (StringUtils.isBlank(password) && stringUrl != null) {
- // if we've logged in with this login, search for password
- final String key = keyForUrlAndLogin(stringUrl, login);
- try {
- final PasswordSafeImpl passwordSafe = (PasswordSafeImpl)PasswordSafe.getInstance();
- password = passwordSafe.getMemoryProvider().getPassword(project, HgCommandAuthenticator.class, key);
- if (password == null && passwordSafe.getSettings().getProviderType().equals(PasswordSafeSettings.ProviderType.MASTER_PASSWORD)) {
- password = passwordSafe.getMasterKeyProvider().getPassword(project, HgCommandAuthenticator.class, key);
- }
- } catch (PasswordSafeException e) {
- LOG.info("Couldn't get password for key [" + key + "]", e);
- }
- }
-
- // don't show dialog if we can (not forced + both fields are known)
- if (!myForceShowDialog && !StringUtils.isBlank(password) && !StringUtils.isBlank(login)) {
- userName = login;
- myPassword = password;
- ok = true;
- return;
- }
-
- String url;
- try {
- url = hgUrl.asString(false);
- }
- catch (URISyntaxException e) {
- url = null;
- }
- final HgUsernamePasswordDialog dialog = new HgUsernamePasswordDialog(project, url, login, password);
- dialog.show();
- if (dialog.isOK()) {
- userName = dialog.getUsername();
- myPassword = dialog.getPassword();
- ok = true;
-
- myRememberPassword = dialog.isRememberPassword();
- if (stringUrl != null) {
- myURL = stringUrl;
- }
- }
- }
-
- public String getUserName() {
- return userName;
- }
-
- public String getPassword() {
- return myPassword;
- }
-
- public boolean isOk() {
- return ok;
- }
-
- public String getURL() {
- return myURL;
- }
-
- public void setForceShowDialog(boolean forceShowDialog) {
- myForceShowDialog = forceShowDialog;
- }
-
- public boolean isRememberPassword() {
- return myRememberPassword;
- }
- }
-
- private static String keyForUrlAndLogin(String stringUrl, String login) {
- return stringUrl + login;
- }
-
-}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java
index 07a3170242e8..c4ac4d2e3ea6 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java
@@ -22,6 +22,8 @@ import org.jetbrains.annotations.NotNull;
import org.zmlx.hg4idea.HgFile;
import org.zmlx.hg4idea.HgVcs;
import org.zmlx.hg4idea.HgVcsMessages;
+import org.zmlx.hg4idea.execution.HgCommandException;
+import org.zmlx.hg4idea.execution.HgCommandExecutor;
import java.io.BufferedWriter;
import java.io.File;
@@ -68,7 +70,7 @@ public class HgCommitCommand {
for (HgFile hgFile : files) {
parameters.add(hgFile.getRelativePath());
}
- ensureSuccess(HgCommandService.getInstance(project).execute(repo, "commit", parameters));
+ ensureSuccess(new HgCommandExecutor(project).executeInCurrentThread(repo, "commit", parameters));
project.getMessageBus().syncPublisher(HgVcs.REMOTE_TOPIC).update(project);
} catch (IOException e) {
LOG.info(e);
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCopyCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCopyCommand.java
index a99f63d1f073..7b2ed5b9c4a0 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCopyCommand.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCopyCommand.java
@@ -14,6 +14,7 @@ package org.zmlx.hg4idea.command;
import com.intellij.openapi.project.Project;
import org.zmlx.hg4idea.HgFile;
+import org.zmlx.hg4idea.execution.HgCommandExecutor;
import java.util.Arrays;
@@ -26,10 +27,9 @@ public class HgCopyCommand {
}
public void execute(HgFile source, HgFile target) {
- HgCommandService service = HgCommandService.getInstance(project);
+ HgCommandExecutor executor = new HgCommandExecutor(project);
if (source.getRepo().equals(target.getRepo())) {
- service.execute(source.getRepo(), "copy",
- Arrays.asList("--after", source.getRelativePath(), target.getRelativePath()));
+ executor.execute(source.getRepo(), "copy", Arrays.asList("--after", source.getRelativePath(), target.getRelativePath()), null);
}
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgIdentifyCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgIdentifyCommand.java
index dbc3d899cf79..fe65c06bd869 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgIdentifyCommand.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgIdentifyCommand.java
@@ -2,17 +2,15 @@ package org.zmlx.hg4idea.command;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.Nullable;
+import org.zmlx.hg4idea.execution.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgCommandExecutor;
-import java.nio.charset.Charset;
-import java.util.Collection;
-import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class HgIdentifyCommand {
private final Project project;
- private final HgCommandAuthenticator authenticator = new HgCommandAuthenticator();
private String source;
public HgIdentifyCommand(Project project) {
@@ -31,6 +29,8 @@ public class HgIdentifyCommand {
public HgCommandResult execute() {
final List