diff options
Diffstat (limited to 'plugins/hg4idea')
30 files changed, 663 insertions, 125 deletions
diff --git a/plugins/hg4idea/hg4idea.iml b/plugins/hg4idea/hg4idea.iml index 7f5074895e4f..93b5a5109bde 100644 --- a/plugins/hg4idea/hg4idea.iml +++ b/plugins/hg4idea/hg4idea.iml @@ -16,9 +16,10 @@ <orderEntry type="module" module-name="vcs-impl" /> <orderEntry type="module" module-name="platform-impl" /> <orderEntry type="library" name="Guava" level="project" /> - <orderEntry type="module" module-name="dvcs" /> + <orderEntry type="module" module-name="dvcs-impl" /> <orderEntry type="module" module-name="vcs-log-api" /> <orderEntry type="module" module-name="vcs-log-impl" /> + <orderEntry type="module" module-name="dvcs-api" /> </component> </module> diff --git a/plugins/hg4idea/src/META-INF/plugin.xml b/plugins/hg4idea/src/META-INF/plugin.xml index 9ccc175803f5..26b69326a703 100644 --- a/plugins/hg4idea/src/META-INF/plugin.xml +++ b/plugins/hg4idea/src/META-INF/plugin.xml @@ -21,6 +21,7 @@ <vcs name="hg4idea" vcsClass="org.zmlx.hg4idea.HgVcs" displayName="Mercurial" administrativeAreaName=".hg"/> <checkoutProvider implementation="org.zmlx.hg4idea.provider.HgCheckoutProvider"/> <vcsRootChecker implementation="org.zmlx.hg4idea.roots.HgRootChecker"/> + <pushSupport implementation="org.zmlx.hg4idea.push.HgPushSupport"/> <errorHandler implementation="com.intellij.diagnostic.ITNReporter"/> <vcsPopupProvider implementation="org.zmlx.hg4idea.provider.HgQuickListProvider"/> <logProvider implementation="org.zmlx.hg4idea.log.HgLogProvider"/> diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java index d38bc7bfc6a7..d6282ebe8786 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java @@ -29,7 +29,9 @@ import org.zmlx.hg4idea.util.HgUtil; import javax.swing.*; import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; abstract class HgAbstractGlobalAction extends AnAction { @@ -48,12 +50,17 @@ abstract class HgAbstractGlobalAction extends AnAction { if (project == null) { return; } - VirtualFile file = event.getData(CommonDataKeys.VIRTUAL_FILE); - HgRepositoryManager repositoryManager = HgUtil.getRepositoryManager(project); - HgRepository repo = file != null ? repositoryManager.getRepositoryForFile(file): HgUtil.getCurrentRepository(project); + VirtualFile[] files = event.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY); + final HgRepositoryManager repositoryManager = HgUtil.getRepositoryManager(project); List<HgRepository> repositories = repositoryManager.getRepositories(); if (!repositories.isEmpty()) { - execute(project, repositories, repo); + List<HgRepository> selectedRepositories = (files == null || files.length == 0) + ? + Collections.singletonList(HgUtil.getCurrentRepository(project)) + : HgActionUtil.collectRepositoriesFromFiles(repositoryManager, + Arrays.asList(files)); + + execute(project, repositories, selectedRepositories); } } @@ -66,7 +73,7 @@ abstract class HgAbstractGlobalAction extends AnAction { protected abstract void execute(@NotNull Project project, @NotNull Collection<HgRepository> repositories, - @Nullable HgRepository selectedRepo); + @NotNull List<HgRepository> selectedRepositories); public static void handleException(@Nullable Project project, @NotNull Exception e) { handleException(project, "Error", e); @@ -102,16 +109,4 @@ abstract class HgAbstractGlobalAction extends AnAction { return true; } - @Nullable - public static HgRepository getSelectedRepositoryFromEvent(AnActionEvent e) { - final DataContext dataContext = e.getDataContext(); - final Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null) { - return null; - } - VirtualFile file = e.getData(CommonDataKeys.VIRTUAL_FILE); - HgRepositoryManager repositoryManager = HgUtil.getRepositoryManager(project); - return file != null ? repositoryManager.getRepositoryForFile(file) : HgUtil.getCurrentRepository(project); - } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalSingleRepoAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalSingleRepoAction.java new file mode 100644 index 000000000000..bfb2d7715e68 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalSingleRepoAction.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2014 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.action; + +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.repo.HgRepository; + +import javax.swing.*; +import java.util.Collection; +import java.util.List; + +public abstract class HgAbstractGlobalSingleRepoAction extends HgAbstractGlobalAction { + + public HgAbstractGlobalSingleRepoAction(Icon icon) { + super(icon); + } + + public HgAbstractGlobalSingleRepoAction() { + super(); + } + + @Override + protected void execute(@NotNull Project project, + @NotNull Collection<HgRepository> repositories, + @NotNull List<HgRepository> selectedRepositories) { + execute(project, repositories, selectedRepositories.isEmpty() ? null : selectedRepositories.get(0)); + } + + protected abstract void execute(@NotNull Project project, + @NotNull Collection<HgRepository> repositories, + @Nullable HgRepository selectedRepo); +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgActionUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgActionUtil.java new file mode 100644 index 000000000000..6abebd587787 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgActionUtil.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2014 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.action; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import com.sun.istack.internal.NotNull; +import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.repo.HgRepository; +import org.zmlx.hg4idea.repo.HgRepositoryManager; +import org.zmlx.hg4idea.util.HgUtil; + +import java.util.Collection; +import java.util.List; + +public class HgActionUtil { + + @NotNull + public static List<HgRepository> collectRepositoriesFromFiles(@NotNull final HgRepositoryManager repositoryManager, + @NotNull Collection<VirtualFile> files) { + return ContainerUtil.mapNotNull(files, new Function<VirtualFile, HgRepository>() { + @Override + public HgRepository fun(VirtualFile file) { + return repositoryManager.getRepositoryForFile(file); + } + }); + } + + @Nullable + public static HgRepository getSelectedRepositoryFromEvent(AnActionEvent e) { + final DataContext dataContext = e.getDataContext(); + final Project project = CommonDataKeys.PROJECT.getData(dataContext); + if (project == null) { + return null; + } + VirtualFile file = e.getData(CommonDataKeys.VIRTUAL_FILE); + HgRepositoryManager repositoryManager = HgUtil.getRepositoryManager(project); + return file != null ? repositoryManager.getRepositoryForFile(file) : HgUtil.getCurrentRepository(project); + } +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java index b8a10ed92116..d799cde1705c 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java @@ -22,7 +22,7 @@ import org.zmlx.hg4idea.repo.HgRepository; import java.util.Collection; -public class HgBranchesAction extends HgAbstractGlobalAction { +public class HgBranchesAction extends HgAbstractGlobalSingleRepoAction { @Override protected void execute(@NotNull Project project, @NotNull Collection<HgRepository> repositories, @Nullable HgRepository selectedRepo) { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java index 5c97e3ca9f39..c8734e8109f4 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java @@ -25,7 +25,7 @@ import org.zmlx.hg4idea.util.HgErrorUtil; import java.util.Collection; -public class HgCreateTagAction extends HgAbstractGlobalAction { +public class HgCreateTagAction extends HgAbstractGlobalSingleRepoAction { public void execute(@NotNull final Project project, @NotNull Collection<HgRepository> repositories, diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMerge.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMerge.java index 1743e7e5b56e..45ff24e382ce 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMerge.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMerge.java @@ -33,7 +33,7 @@ import org.zmlx.hg4idea.ui.HgMergeDialog; import java.util.Collection; -public class HgMerge extends HgAbstractGlobalAction { +public class HgMerge extends HgAbstractGlobalSingleRepoAction { @Override public void execute(@NotNull final Project project, diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgProcessRebaseAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgProcessRebaseAction.java index 342369f0a9bb..84e9d5b1beaf 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgProcessRebaseAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgProcessRebaseAction.java @@ -18,10 +18,10 @@ package org.zmlx.hg4idea.action; import com.intellij.openapi.actionSystem.AnActionEvent; import org.zmlx.hg4idea.repo.HgRepository; -public abstract class HgProcessRebaseAction extends HgAbstractGlobalAction { +public abstract class HgProcessRebaseAction extends HgAbstractGlobalSingleRepoAction { protected static boolean isRebasing(AnActionEvent e) { - HgRepository repository = HgAbstractGlobalAction.getSelectedRepositoryFromEvent(e); + HgRepository repository = HgActionUtil.getSelectedRepositoryFromEvent(e); return repository != null && repository.getState() == HgRepository.State.REBASING; } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java index d5a934e1d86d..74beff13eb81 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java @@ -24,7 +24,7 @@ import org.zmlx.hg4idea.ui.HgPullDialog; import java.util.Collection; -public class HgPullAction extends HgAbstractGlobalAction { +public class HgPullAction extends HgAbstractGlobalSingleRepoAction { public HgPullAction() { super(AllIcons.Actions.CheckOut); } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java index 1b5704f1d0f4..232b2ef7fa73 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java @@ -12,14 +12,14 @@ // limitations under the License. package org.zmlx.hg4idea.action; +import com.intellij.dvcs.push.ui.VcsPushDialog; import com.intellij.icons.AllIcons; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgPusher; import org.zmlx.hg4idea.repo.HgRepository; import java.util.Collection; +import java.util.List; public class HgPushAction extends HgAbstractGlobalAction { public HgPushAction() { @@ -29,7 +29,7 @@ public class HgPushAction extends HgAbstractGlobalAction { @Override public void execute(@NotNull final Project project, @NotNull Collection<HgRepository> repositories, - @Nullable final HgRepository selectedRepo) { - new HgPusher(project).showDialogAndPush(repositories, selectedRepo); + @NotNull final List<HgRepository> selectedRepositories) { + new VcsPushDialog(project, selectedRepositories).show(); } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgRunConflictResolverAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgRunConflictResolverAction.java index 938413e95356..279747c5278b 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgRunConflictResolverAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgRunConflictResolverAction.java @@ -25,7 +25,7 @@ import org.zmlx.hg4idea.ui.HgRunConflictResolverDialog; import java.util.Collection; -public class HgRunConflictResolverAction extends HgAbstractGlobalAction { +public class HgRunConflictResolverAction extends HgAbstractGlobalSingleRepoAction { @Override public void execute(@NotNull final Project project, @NotNull Collection<HgRepository> repositories, @Nullable HgRepository selectedRepo) { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgUpdateToAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgUpdateToAction.java index 7e1025921234..415cd223bd1f 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgUpdateToAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgUpdateToAction.java @@ -29,7 +29,7 @@ import org.zmlx.hg4idea.util.HgErrorUtil; import java.util.Collection; -public class HgUpdateToAction extends HgAbstractGlobalAction { +public class HgUpdateToAction extends HgAbstractGlobalSingleRepoAction { @Override protected void execute(@NotNull Project project, @NotNull Collection<HgRepository> repositories, @Nullable HgRepository selectedRepo) { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgIdentifyCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgIdentifyCommand.java index c719d9174d39..4acbc1f72370 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgIdentifyCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgIdentifyCommand.java @@ -31,7 +31,7 @@ public class HgIdentifyCommand { public HgCommandResult execute(@NotNull ModalityState state) { final List<String> arguments = new LinkedList<String>(); arguments.add(source); - final HgRemoteCommandExecutor executor = new HgRemoteCommandExecutor(project, source, state); + final HgRemoteCommandExecutor executor = new HgRemoteCommandExecutor(project, source, state, false); executor.setSilent(true); return executor.executeInCurrentThread(null, "identify", arguments); } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java index 64f155064ead..578af65a6b56 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java @@ -12,11 +12,19 @@ // limitations under the License. package org.zmlx.hg4idea.command; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.execution.HgCommandResult; +import org.zmlx.hg4idea.execution.HgRemoteCommandExecutor; +import org.zmlx.hg4idea.log.HgHistoryUtil; import org.zmlx.hg4idea.util.HgUtil; +import java.util.LinkedList; +import java.util.List; + public class HgOutgoingCommand extends HgRemoteChangesetsCommand { public HgOutgoingCommand(Project project) { @@ -27,4 +35,23 @@ public class HgOutgoingCommand extends HgRemoteChangesetsCommand { protected String getRepositoryUrl(VirtualFile root) { return HgUtil.getRepositoryDefaultPushPath(project, root); } + + @Nullable + public HgCommandResult execute(@NotNull VirtualFile repo, + @NotNull String template, + @NotNull String source, + @NotNull String destination, + boolean doNotShowAuthorizationRequest) { + + List<String> arguments = new LinkedList<String>(); + arguments.add("-n"); + arguments.add("--template"); + arguments.add(template); + arguments.add(HgHistoryUtil.prepareParameter("rev", source)); + arguments.add(destination); + HgRemoteCommandExecutor commandExecutor = + new HgRemoteCommandExecutor(project, destination, ModalityState.any(), doNotShowAuthorizationRequest); + commandExecutor.setOutputAlwaysSuppressed(true); + return commandExecutor.executeInCurrentThread(repo, "outgoing", arguments); + } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandAuthenticator.java b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandAuthenticator.java index 14f6c981777b..01f9083da808 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandAuthenticator.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandAuthenticator.java @@ -39,10 +39,13 @@ class HgCommandAuthenticator { private GetPasswordRunnable myGetPassword; private final Project myProject; private boolean myForceAuthorization; + //todo replace silent mode and/or force authorization + private boolean mySilentMode; - public HgCommandAuthenticator(Project project, boolean forceAuthorization) { + public HgCommandAuthenticator(Project project, boolean forceAuthorization, boolean silent) { myProject = project; myForceAuthorization = forceAuthorization; + mySilentMode = silent; } public void saveCredentials() { @@ -71,7 +74,7 @@ class HgCommandAuthenticator { } public boolean promptForAuthentication(Project project, String proposedLogin, String uri, String path, @Nullable ModalityState state) { - GetPasswordRunnable runnable = new GetPasswordRunnable(project, proposedLogin, uri, path, myForceAuthorization); + GetPasswordRunnable runnable = new GetPasswordRunnable(project, proposedLogin, uri, path, myForceAuthorization, mySilentMode); ApplicationManager.getApplication().invokeAndWait(runnable, state == null ? ModalityState.defaultModalityState() : state); myGetPassword = runnable; return runnable.isOk(); @@ -96,19 +99,27 @@ class HgCommandAuthenticator { @Nullable private String myURL; private boolean myRememberPassword; private boolean myForceAuthorization; + private final boolean mySilent; - public GetPasswordRunnable(Project project, String proposedLogin, String uri, String path, boolean forceAuthorization) { + public GetPasswordRunnable(Project project, + String proposedLogin, + String uri, + String path, + boolean forceAuthorization, boolean silent) { this.myProject = project; this.myProposedLogin = proposedLogin; this.myURL = uri + path; this.myForceAuthorization = forceAuthorization; + mySilent = silent; } - + public void run() { // find if we've already been here final HgVcs vcs = HgVcs.getInstance(myProject); - if (vcs == null) { return; } + if (vcs == null) { + return; + } @NotNull final HgGlobalSettings hgGlobalSettings = vcs.getGlobalSettings(); @Nullable String rememberedLoginsForUrl = null; @@ -128,11 +139,14 @@ class HgCommandAuthenticator { final String key = keyForUrlAndLogin(myURL, login); try { final PasswordSafeImpl passwordSafe = (PasswordSafeImpl)PasswordSafe.getInstance(); - password = passwordSafe.getMemoryProvider().getPassword(myProject, HgCommandAuthenticator.class, key); - if (password == null) { + if (mySilent) { + password = passwordSafe.getMemoryProvider().getPassword(myProject, HgCommandAuthenticator.class, key); + } + else { password = passwordSafe.getPassword(myProject, HgCommandAuthenticator.class, key); } - } catch (PasswordSafeException e) { + } + catch (PasswordSafeException e) { LOG.info("Couldn't get password for key [" + key + "]", e); } } @@ -146,7 +160,13 @@ class HgCommandAuthenticator { return; } - final AuthDialog dialog = new AuthDialog(myProject, HgVcsMessages.message("hg4idea.dialog.login.password.required"), HgVcsMessages.message("hg4idea.dialog.login.description", myURL), + if (mySilent) { + ok = false; + return; + } + + final AuthDialog dialog = new AuthDialog(myProject, HgVcsMessages.message("hg4idea.dialog.login.password.required"), + HgVcsMessages.message("hg4idea.dialog.login.description", myURL), login, password, true); dialog.show(); if (dialog.isOK()) { @@ -182,5 +202,4 @@ class HgCommandAuthenticator { private static String keyForUrlAndLogin(String stringUrl, String login) { return login + ":" + stringUrl; } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgRemoteCommandExecutor.java b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgRemoteCommandExecutor.java index fdab67fbed6f..ce139cb16d9e 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgRemoteCommandExecutor.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgRemoteCommandExecutor.java @@ -30,16 +30,22 @@ import java.util.List; public class HgRemoteCommandExecutor extends HgCommandExecutor { @Nullable private ModalityState myState; + final boolean myIgnoreAuthorizationRequest; public HgRemoteCommandExecutor(@NotNull Project project, @Nullable String destination) { - this(project, destination, null); + this(project, destination, null, false); + } + + public HgRemoteCommandExecutor(@NotNull Project project, @Nullable String destination, boolean ignoreAuthorizationRequest) { + this(project, destination, null, ignoreAuthorizationRequest); } public HgRemoteCommandExecutor(@NotNull Project project, @Nullable String destination, - @Nullable ModalityState state) { + @Nullable ModalityState state, boolean ignoreAuthorizationRequest) { super(project, destination); myState = state; + myIgnoreAuthorizationRequest = ignoreAuthorizationRequest; } @Nullable @@ -48,7 +54,7 @@ public class HgRemoteCommandExecutor extends HgCommandExecutor { HgCommandResult result = executeInCurrentThread(repo, operation, arguments, false); - if (HgErrorUtil.isAuthorizationError(result)) { + if (!myIgnoreAuthorizationRequest && HgErrorUtil.isAuthorizationError(result)) { if (HgErrorUtil.hasAuthorizationInDestinationPath(myDestination)) { new HgCommandResultNotifier(myProject) .notifyError(result, "Authorization failed", "Your hgrc file settings have wrong username or password in [paths].\n" + @@ -62,11 +68,11 @@ public class HgRemoteCommandExecutor extends HgCommandExecutor { @Nullable private HgCommandResult executeInCurrentThread(@Nullable final VirtualFile repo, - @NotNull final String operation, - @Nullable final List<String> arguments, - boolean forceAuthorization) { + @NotNull final String operation, + @Nullable final List<String> arguments, + boolean forceAuthorization) { - PassReceiver passReceiver = new PassReceiver(myProject, forceAuthorization, myState); + PassReceiver passReceiver = new PassReceiver(myProject, forceAuthorization, myIgnoreAuthorizationRequest, myState); SocketServer passServer = new SocketServer(passReceiver); try { int passPort = passServer.start(); @@ -109,11 +115,13 @@ public class HgRemoteCommandExecutor extends HgCommandExecutor { private final Project myProject; private HgCommandAuthenticator myAuthenticator; private boolean myForceAuthorization; + private boolean mySilentMode; @Nullable private ModalityState myState; - private PassReceiver(Project project, boolean forceAuthorization, @Nullable ModalityState state) { + private PassReceiver(Project project, boolean forceAuthorization, boolean silent, @Nullable ModalityState state) { myProject = project; myForceAuthorization = forceAuthorization; + mySilentMode = silent; myState = state; } @@ -129,7 +137,7 @@ public class HgRemoteCommandExecutor extends HgCommandExecutor { String path = new String(readDataBlock(dataInputStream)); String proposedLogin = new String(readDataBlock(dataInputStream)); - HgCommandAuthenticator authenticator = new HgCommandAuthenticator(myProject, myForceAuthorization); + HgCommandAuthenticator authenticator = new HgCommandAuthenticator(myProject, myForceAuthorization, mySilentMode); boolean ok = authenticator.promptForAuthentication(myProject, proposedLogin, uri, path, myState); if (ok) { myAuthenticator = authenticator; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java index dfb576f98ab3..de565484e2d5 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java @@ -94,25 +94,35 @@ public class HgHistoryUtil { } /** - * <p>Get & parse hg log detailed output with commits, their parents and their changes.</p> + * <p>Get & parse hg log detailed output with commits, their parents and their changes. + * For null destination return log command result</p> * <p/> * <p>Warning: this is method is efficient by speed, but don't query too much, because the whole log output is retrieved at once, * and it can occupy too much memory. The estimate is ~600Kb for 1000 commits.</p> */ @NotNull - public static List<? extends VcsFullCommitDetails> history(@NotNull final Project project, @NotNull final VirtualFile root, int limit, + public static List<? extends VcsFullCommitDetails> history(@NotNull final Project project, + @NotNull final VirtualFile root, + int limit, @NotNull List<String> parameters) throws VcsException { - final VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project); - if (factory == null) { - return Collections.emptyList(); - } HgVcs hgvcs = HgVcs.getInstance(project); assert hgvcs != null; final HgVersion version = hgvcs.getVersion(); String[] templates = HgBaseLogParser.constructFullTemplateArgument(true, version); HgCommandResult result = getLogResult(project, root, version, limit, parameters, HgChangesetUtil.makeTemplate(templates)); + return createFullCommitsFromResult(project, root, result, version, false); + } + + public static List<? extends VcsFullCommitDetails> createFullCommitsFromResult(@NotNull Project project, + @NotNull VirtualFile root, + @Nullable HgCommandResult result, + @NotNull HgVersion version, boolean silent) { + final VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project); + if (factory == null) { + return Collections.emptyList(); + } List<HgFileRevision> hgRevisions = - getCommitRecords(project, result, new HgFileRevisionLogParser(project, getOriginalHgFile(project, root), version)); + getCommitRecords(project, result, new HgFileRevisionLogParser(project, getOriginalHgFile(project, root), version), silent); List<VcsFullCommitDetails> vcsFullCommitDetailsList = new ArrayList<VcsFullCommitDetails>(); for (HgFileRevision revision : hgRevisions) { @@ -184,6 +194,13 @@ public class HgHistoryUtil { public static <CommitInfo> List<CommitInfo> getCommitRecords(@NotNull Project project, @Nullable HgCommandResult result, @NotNull Function<String, CommitInfo> converter) { + return getCommitRecords(project, result, converter, false); + } + + @NotNull + public static <CommitInfo> List<CommitInfo> getCommitRecords(@NotNull Project project, + @Nullable HgCommandResult result, + @NotNull Function<String, CommitInfo> converter, boolean silent) { final List<CommitInfo> revisions = new LinkedList<CommitInfo>(); if (result == null) { return revisions; @@ -192,7 +209,12 @@ public class HgHistoryUtil { List<String> errors = result.getErrorLines(); if (errors != null && !errors.isEmpty()) { if (result.getExitValue() != 0) { - VcsNotifier.getInstance(project).notifyError(HgVcsMessages.message("hg4idea.error.log.command.execution"), errors.toString()); + if (silent) { + LOG.warn(errors.toString()); + } + else { + VcsNotifier.getInstance(project).notifyError(HgVcsMessages.message("hg4idea.error.log.command.execution"), errors.toString()); + } return Collections.emptyList(); } LOG.warn(errors.toString()); @@ -331,4 +353,8 @@ public class HgHistoryUtil { } return branchHeads; } + + public static String prepareParameter(String paramName, String value) { + return "--" + paramName + "=" + value; // no value escaping needed, because the parameter itself will be quoted by GeneralCommandLine + } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java index 4adec9dff515..3b989e448b61 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java @@ -180,11 +180,11 @@ public class HgLogProvider implements VcsLogProvider { boolean atLeastOneBranchExists = false; for (String branchName : filterCollection.getBranchFilter().getBranchNames()) { if (branchName.equals(TIP_REFERENCE) || branchExists(repository, branchName)) { - filterParameters.add(prepareParameter("branch", branchName)); + filterParameters.add(HgHistoryUtil.prepareParameter("branch", branchName)); atLeastOneBranchExists = true; } else if (branchName.equals(HEAD_REFERENCE)) { - filterParameters.add(prepareParameter("branch", ".")); + filterParameters.add(HgHistoryUtil.prepareParameter("branch", ".")); filterParameters.add("-r"); filterParameters.add("::."); //all ancestors for current revision; atLeastOneBranchExists = true; @@ -197,7 +197,7 @@ public class HgLogProvider implements VcsLogProvider { if (filterCollection.getUserFilter() != null) { for (String authorName : filterCollection.getUserFilter().getUserNames(root)) { - filterParameters.add(prepareParameter("user", authorName)); + filterParameters.add(HgHistoryUtil.prepareParameter("user", authorName)); } } @@ -223,7 +223,7 @@ public class HgLogProvider implements VcsLogProvider { if (filterCollection.getTextFilter() != null) { String textFilter = filterCollection.getTextFilter().getText(); - filterParameters.add(prepareParameter("keyword", textFilter)); + filterParameters.add(HgHistoryUtil.prepareParameter("keyword", textFilter)); } if (filterCollection.getStructureFilter() != null) { @@ -262,10 +262,6 @@ public class HgLogProvider implements VcsLogProvider { return HgHistoryUtil.getDescendingHeadsOfBranches(myProject, root, commitHash); } - private static String prepareParameter(String paramName, String value) { - return "--" + paramName + "=" + value; // no value escaping needed, because the parameter itself will be quoted by GeneralCommandLine - } - private static boolean branchExists(@NotNull HgRepository repository, @NotNull String branchName) { return repository.getBranches().keySet().contains(branchName) || HgUtil.getNamesWithoutHashes(repository.getBookmarks()).contains(branchName); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java index c60e46c63ced..06b74148156e 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java @@ -13,6 +13,7 @@ package org.zmlx.hg4idea.provider.commit; import com.intellij.dvcs.DvcsCommitAdditionalComponent; +import com.intellij.dvcs.push.ui.VcsPushDialog; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.progress.ProgressIndicator; @@ -37,6 +38,7 @@ import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.*; +import org.zmlx.hg4idea.action.HgActionUtil; import org.zmlx.hg4idea.command.*; import org.zmlx.hg4idea.execution.HgCommandException; import org.zmlx.hg4idea.execution.HgCommandExecutor; @@ -132,13 +134,12 @@ public class HgCheckinEnvironment implements CheckinEnvironment { // push if needed if (myNextCommitIsPushed && exceptions.isEmpty()) { - final VirtualFile preselectedRepo = repositoriesMap.size() == 1 ? repositoriesMap.keySet().iterator().next() : null; + final Set<VirtualFile> preselectedFiles = repositoriesMap.keySet(); HgRepositoryManager repositoryManager = HgUtil.getRepositoryManager(myProject); - final HgRepository repo = preselectedRepo != null ? repositoryManager.getRepositoryForFile(preselectedRepo) : null; - final Collection<HgRepository> repositories = repositoryManager.getRepositories(); + final List<HgRepository> preselectedRepositories = HgActionUtil.collectRepositoriesFromFiles(repositoryManager, preselectedFiles); UIUtil.invokeLaterIfNeeded(new Runnable() { public void run() { - new HgPusher(myProject).showDialogAndPush(repositories, repo); + new VcsPushDialog(myProject, preselectedRepositories).show(); } }); } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgOutgoingCommitsProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgOutgoingCommitsProvider.java new file mode 100644 index 000000000000..70055cafe1a1 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgOutgoingCommitsProvider.java @@ -0,0 +1,90 @@ +/* + * Copyright 2000-2014 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.push; + +import com.intellij.dvcs.push.*; +import com.intellij.dvcs.repo.Repository; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.vcs.log.VcsFullCommitDetails; +import org.jetbrains.annotations.NotNull; +import org.zmlx.hg4idea.HgVcs; +import org.zmlx.hg4idea.command.HgOutgoingCommand; +import org.zmlx.hg4idea.execution.HgCommandResult; +import org.zmlx.hg4idea.log.HgBaseLogParser; +import org.zmlx.hg4idea.log.HgHistoryUtil; +import org.zmlx.hg4idea.util.HgChangesetUtil; +import org.zmlx.hg4idea.util.HgErrorUtil; +import org.zmlx.hg4idea.util.HgVersion; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class HgOutgoingCommitsProvider extends OutgoingCommitsProvider { + + + private static final Logger LOG = Logger.getInstance(HgOutgoingCommitsProvider.class); + private static final String LOGIN_AND_REFRESH_LINK = "Enter Password & Refresh"; + + @NotNull + @Override + public OutgoingResult getOutgoingCommits(@NotNull final Repository repository, + @NotNull final PushSpec pushSpec, + boolean initial) { + final Project project = repository.getProject(); + HgVcs hgvcs = HgVcs.getInstance(project); + assert hgvcs != null; + final HgVersion version = hgvcs.getVersion(); + String[] templates = HgBaseLogParser.constructFullTemplateArgument(true, version); + HgOutgoingCommand hgOutgoingCommand = new HgOutgoingCommand(project); + HgTarget hgTarget = (HgTarget)pushSpec.getTarget(); + List<VcsError> errors = new ArrayList<VcsError>(); + if (hgTarget == null || StringUtil.isEmptyOrSpaces(hgTarget.myTarget)) { + errors.add(new VcsError("Hg push path could not be empty.")); + return new OutgoingResult(Collections.<VcsFullCommitDetails>emptyList(), errors); + } + HgCommandResult result = hgOutgoingCommand + .execute(repository.getRoot(), HgChangesetUtil.makeTemplate(templates), pushSpec.getSource().getPresentation(), + hgTarget.myTarget, initial); + if (result == null) { + errors.add(new VcsError("Couldn't execute hg outgoing command for " + repository)); + return new OutgoingResult(Collections.<VcsFullCommitDetails>emptyList(), errors); + } + List<String> resultErrors = result.getErrorLines(); + if (resultErrors != null && !resultErrors.isEmpty() && result.getExitValue() != 0) { + for (String error : resultErrors) { + if (HgErrorUtil.isAbortLine(error)) { + if (HgErrorUtil.isAuthorizationError(error)) { + VcsError authorizationError = + new VcsError(error + "<a href='authenticate'>" + LOGIN_AND_REFRESH_LINK + "</a>", new VcsErrorHandler() { + public void handleError(@NotNull CommitLoader commitLoader) { + commitLoader.reloadCommits(); + } + }); + errors.add(authorizationError); + } + else { + errors.add(new VcsError(error)); + } + } + } + LOG.warn(resultErrors.toString()); + } + return new OutgoingResult(HgHistoryUtil.createFullCommitsFromResult(project, repository.getRoot(), result, version, true), errors); + } +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushOptionsPanel.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushOptionsPanel.java new file mode 100644 index 000000000000..336f8ff1aa4c --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushOptionsPanel.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2014 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.push; + +import com.intellij.dvcs.push.VcsPushOptionsPanel; +import com.intellij.openapi.ui.ComboBox; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionListener; + +public class HgPushOptionsPanel extends VcsPushOptionsPanel { + + private final ComboBox myReferenceStrategyCombobox; + + public HgPushOptionsPanel() { + setLayout(new BorderLayout()); + myReferenceStrategyCombobox = new ComboBox(); + HgVcsPushOptionValue[] values = HgVcsPushOptionValue.values(); + DefaultComboBoxModel comboModel = new DefaultComboBoxModel(values); + myReferenceStrategyCombobox.setModel(comboModel); + JLabel referenceStrategyLabel = new JLabel("Export Bookmarks: "); + add(referenceStrategyLabel, BorderLayout.WEST); + add(myReferenceStrategyCombobox, BorderLayout.CENTER); + } + + @Override + @NotNull + public HgVcsPushOptionValue getValue() { + return (HgVcsPushOptionValue)myReferenceStrategyCombobox.getSelectedItem(); + } + + @Override + public void addValueChangeListener(ActionListener listener) { + myReferenceStrategyCombobox.addActionListener(listener); + } +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSource.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSource.java new file mode 100644 index 000000000000..babd49c9b31d --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSource.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2014 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.push; + +import com.intellij.dvcs.push.PushSource; +import org.jetbrains.annotations.NotNull; + +public class HgPushSource implements PushSource { + @NotNull private String myBranch; + + public HgPushSource(@NotNull String branch) { + myBranch = branch; + } + + @NotNull + @Override + public String getPresentation() { + return myBranch; + } + + @NotNull + public String getBranch() { + return myBranch; // presentation may differ from branch + } +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java new file mode 100644 index 000000000000..4bfa134a5e26 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java @@ -0,0 +1,109 @@ +/* + * Copyright 2000-2014 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.push; + +import com.intellij.dvcs.push.*; +import com.intellij.dvcs.repo.Repository; +import com.intellij.dvcs.repo.RepositoryManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.AbstractVcs; +import com.intellij.util.Function; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.HgVcs; +import org.zmlx.hg4idea.repo.HgRepository; +import org.zmlx.hg4idea.util.HgUtil; + +import java.util.Collection; + +public class HgPushSupport extends PushSupport<HgRepository> { + + @NotNull private final Project myProject; + @NotNull private final HgVcs myVcs; + + public HgPushSupport(@NotNull Project project) { + myProject = project; + myVcs = ObjectUtils.assertNotNull(HgVcs.getInstance(myProject)); + } + + @NotNull + @Override + public AbstractVcs getVcs() { + return myVcs; + } + + @NotNull + @Override + public Pusher getPusher() { + return new HgPusher(); + } + + @NotNull + @Override + public OutgoingCommitsProvider getOutgoingCommitsProvider() { + return new HgOutgoingCommitsProvider(); + } + + @Nullable + @Override + public HgTarget getDefaultTarget(@NotNull HgRepository repository) { + String defaultPushPath = repository.getRepositoryConfig().getDefaultPushPath(); + return defaultPushPath == null ? null : new HgTarget(defaultPushPath); + } + + @NotNull + @Override + public Collection<String> getTargetNames(@NotNull HgRepository repository) { + return ContainerUtil.map(repository.getRepositoryConfig().getPaths(), new Function<String, String>() { + @Override + public String fun(String s) { + return HgUtil.removePasswordIfNeeded(s); + } + }); + } + + @NotNull + @Override + public HgPushSource getSource(@NotNull HgRepository repository) { + String localBranch = HgUtil.getActiveBranchName(repository); + return new HgPushSource(localBranch); + } + + @Override + public HgTarget createTarget(@NotNull HgRepository repository, @NotNull String targetName) { + return new HgTarget(targetName); + } + + @NotNull + @Override + public RepositoryManager<HgRepository> getRepositoryManager() { + return HgUtil.getRepositoryManager(myProject); + } + + @Nullable + public VcsPushOptionsPanel getVcsPushOptionsPanel() { + return new HgPushOptionsPanel(); + } + + @Override + @Nullable + public VcsError validate(@NotNull Repository repository, @Nullable String targetToValidate) { + return StringUtil.isEmptyOrSpaces(targetToValidate) ? new VcsError("Please, specify remote push path for repository!") : null; + } +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java index 2b6108dddbbc..f019035a373f 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.zmlx.hg4idea; +package org.zmlx.hg4idea.push; +import com.intellij.dvcs.push.PushSpec; +import com.intellij.dvcs.push.Pusher; +import com.intellij.dvcs.push.VcsPushOptionValue; +import com.intellij.dvcs.repo.Repository; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsNotifier; -import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,52 +31,54 @@ import org.zmlx.hg4idea.command.HgPushCommand; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandResultHandler; import org.zmlx.hg4idea.repo.HgRepository; -import org.zmlx.hg4idea.ui.HgPushDialog; -import java.util.Collection; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class HgPusher { +public class HgPusher extends Pusher { private static final Logger LOG = Logger.getInstance(HgPusher.class); - private static Pattern PUSH_COMMITS_PATTERN = Pattern.compile(".*added (\\d+) changesets.*"); + private static final String ONE = "one"; + private static Pattern PUSH_COMMITS_PATTERN = Pattern.compile(".*(?:added|pushed) (\\d+|" + ONE + ") changeset.*"); // hg push command has definite exit values for some cases: // mercurial returns 0 if push was successful, 1 if nothing to push. see hg push --help private static int PUSH_SUCCEEDED_EXIT_VALUE = 0; private static int NOTHING_TO_PUSH_EXIT_VALUE = 1; - private final Project myProject; - - public HgPusher(Project project) { - myProject = project; - } - - public void showDialogAndPush (@NotNull Collection<HgRepository> repositories,@Nullable final HgRepository selectedRepo) { - - if (repositories.isEmpty()) { - VcsBalloonProblemNotifier.showOverChangesView(myProject, "No Mercurial repositories in the project", MessageType.ERROR); - return; - } - final AtomicReference<HgPushCommand> pushCommand = new AtomicReference<HgPushCommand>(); - final HgPushDialog dialog = new HgPushDialog(myProject, repositories, selectedRepo); - dialog.show(); - if (dialog.isOK()) { - pushCommand.set(preparePushCommand(myProject, dialog)); - new Task.Backgroundable(myProject, "Pushing...", false) { - @Override - public void run(@NotNull ProgressIndicator indicator) { - if (pushCommand.get() != null) { - push(myProject, pushCommand.get()); - } + @Override + public void push(@NotNull Map<Repository, PushSpec> pushSpecs, @Nullable VcsPushOptionValue vcsPushOptionValue, boolean force) { + for (Map.Entry<Repository, PushSpec> entry : pushSpecs.entrySet()) { + Repository repository = entry.getKey(); + HgRepository hgRepository = (HgRepository)repository; + PushSpec hgSpec = entry.getValue(); + HgTarget destination = (HgTarget)hgSpec.getTarget(); + if (destination == null) { + continue; + } + HgPushSource source = (HgPushSource)hgSpec.getSource(); + Project project = repository.getProject(); + final HgPushCommand pushCommand = new HgPushCommand(project, repository.getRoot(), destination.myTarget); + pushCommand.setIsNewBranch(true); // set always true, because it just allow mercurial to create a new one if needed + pushCommand.setForce(force); + String branchName = source.getBranch(); + if (branchName.equals(hgRepository.getCurrentBookmark())) { + if (vcsPushOptionValue == HgVcsPushOptionValue.Current) { + pushCommand.setBookmarkName(branchName); + } + else { + pushCommand.setRevision(branchName); } - }.queue(); + } + else { + pushCommand.setBranchName(branchName); + } + push(project, pushCommand); } } - private static void push(final Project project, HgPushCommand command) { + public static void push(@NotNull final Project project, @NotNull HgPushCommand command) { final VirtualFile repo = command.getRepo(); command.execute(new HgCommandResultHandler() { @Override @@ -91,9 +93,11 @@ public class HgPusher { String successDescription = String.format("Pushed %d %s [%s]", commitsNum, StringUtil.pluralize("commit", commitsNum), repo.getPresentableName()); VcsNotifier.getInstance(project).notifySuccess(successTitle, successDescription); - } else if (result.getExitValue() == NOTHING_TO_PUSH_EXIT_VALUE) { + } + else if (result.getExitValue() == NOTHING_TO_PUSH_EXIT_VALUE) { VcsNotifier.getInstance(project).notifySuccess("Nothing to push"); - } else { + } + else { new HgCommandResultNotifier(project).notifyError(result, "Push failed", "Failed to push to [" + repo.getPresentableName() + "]"); } @@ -101,17 +105,7 @@ public class HgPusher { }); } - private static HgPushCommand preparePushCommand(Project project, HgPushDialog dialog) { - final HgPushCommand command = new HgPushCommand(project, dialog.getRepository().getRoot(), dialog.getTarget()); - command.setRevision(dialog.getRevision()); - command.setForce(dialog.isForce()); - command.setBranchName(dialog.getBranch()); - command.setBookmarkName(dialog.getBookmarkName()); - command.setIsNewBranch(dialog.isNewBranch()); - return command; - } - - private static int getNumberOfPushedCommits(HgCommandResult result) { + private static int getNumberOfPushedCommits(@NotNull HgCommandResult result) { int numberOfCommitsInAllSubrepos = 0; final List<String> outputLines = result.getOutputLines(); for (String outputLine : outputLines) { @@ -119,7 +113,8 @@ public class HgPusher { final Matcher matcher = PUSH_COMMITS_PATTERN.matcher(outputLine); if (matcher.matches()) { try { - numberOfCommitsInAllSubrepos += Integer.parseInt(matcher.group(1)); + String numberOfCommits = matcher.group(1); + numberOfCommitsInAllSubrepos += ONE.equals(numberOfCommits) ? 1 : Integer.parseInt(numberOfCommits); } catch (NumberFormatException e) { LOG.error("getNumberOfPushedCommits ", e); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgTarget.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgTarget.java new file mode 100644 index 000000000000..8f5aca3838ca --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgTarget.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2014 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.push; + +import com.intellij.dvcs.push.PushTarget; +import org.jetbrains.annotations.NotNull; +import org.zmlx.hg4idea.util.HgUtil; + +public class HgTarget implements PushTarget { + @NotNull String myTarget; + + public HgTarget(@NotNull String name) { + myTarget = name; + } + + @Override + @NotNull + public String getPresentation() { + return HgUtil.removePasswordIfNeeded(myTarget); + } +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgVcsPushOptionValue.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgVcsPushOptionValue.java new file mode 100644 index 000000000000..5b35e7f5e6e0 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgVcsPushOptionValue.java @@ -0,0 +1,22 @@ +/* + * Copyright 2000-2014 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.push; + +import com.intellij.dvcs.push.VcsPushOptionValue; + +public enum HgVcsPushOptionValue implements VcsPushOptionValue { + None, Current +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java index 77c81ee80993..b670fb056c0c 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java @@ -21,6 +21,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcs.log.Hash; @@ -96,6 +97,12 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository { return myInfo.getState(); } + @Nullable + @Override + public AbstractVcs getVcs() { + return HgVcs.getInstance(getProject()); + } + @Override @NotNull public String getCurrentBranch() { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgErrorUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgErrorUtil.java index 1810370588b7..7592f5830ee5 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgErrorUtil.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgErrorUtil.java @@ -43,7 +43,7 @@ public final class HgErrorUtil { } final List<String> errorLines = result.getErrorLines(); for (String line : errorLines) { - if (!StringUtil.isEmptyOrSpaces(line) && line.trim().startsWith("abort:")) { + if (isAbortLine(line)) { return true; } } @@ -55,8 +55,7 @@ public final class HgErrorUtil { return false; } String line = getLastErrorLine(result); - return !StringUtil.isEmptyOrSpaces(line) && (line.contains("authorization required") || line.contains("authorization failed") - ); + return isAuthorizationError(line); } @Nullable @@ -119,4 +118,12 @@ public final class HgErrorUtil { Matcher matcher = UNCOMMITTED_PATTERN.matcher(result.getRawError()); return matcher.matches(); } + + public static boolean isAuthorizationError(String line) { + return !StringUtil.isEmptyOrSpaces(line) && (line.contains("authorization required") || line.contains("authorization failed")); + } + + public static boolean isAbortLine(String line) { + return !StringUtil.isEmptyOrSpaces(line) && line.trim().startsWith("abort:"); + } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java index 1cc100efb029..3bb14721f0a8 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java @@ -32,6 +32,7 @@ import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.*; import com.intellij.openapi.vcs.history.FileHistoryPanelImpl; import com.intellij.openapi.vcs.history.VcsFileRevisionEx; +import com.intellij.openapi.vcs.vfs.AbstractVcsVirtualFile; import com.intellij.openapi.vcs.vfs.VcsVirtualFile; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.LocalFileSystem; @@ -474,7 +475,7 @@ public abstract class HgUtil { */ @Nullable public static VirtualFile convertToLocalVirtualFile(@Nullable VirtualFile file) { - if (!(file instanceof VcsVirtualFile)) { + if (!(file instanceof AbstractVcsVirtualFile)) { return file; } LocalFileSystem lfs = LocalFileSystem.getInstance(); @@ -583,11 +584,16 @@ public abstract class HgUtil { if (state != HgRepository.State.NORMAL) { branchText += state.toString() + " "; } + return branchText + getActiveBranchName(repository); + } + + @NotNull + public static String getActiveBranchName(@NotNull HgRepository repository) { String branchOrBookMarkName = repository.getCurrentBookmark(); if (StringUtil.isEmptyOrSpaces(branchOrBookMarkName)) { branchOrBookMarkName = repository.getCurrentBranch(); } - return branchText + branchOrBookMarkName; + return branchOrBookMarkName; } @NotNull |