diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffSideView.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffSideView.java index dd9198d2bb4c..26ea37f5e798 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffSideView.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffSideView.java @@ -45,6 +45,7 @@ import javax.swing.border.Border; import java.awt.*; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; +import java.awt.event.MouseEvent; public class DiffSideView { private final JComponent MOCK_COMPONENT = new JPanel(); @@ -157,6 +158,9 @@ public class DiffSideView { private final EditorMouseAdapter myMouseListener = new EditorMouseAdapter() { public void mouseReleased(EditorMouseEvent e) { + if (e.getMouseEvent().getButton() != MouseEvent.BUTTON1) { + return; + } if (!isInMyArea(e)) return; OpenFileDescriptor descriptor = getOpenFileDescriptor(e); if (descriptor == null) return; diff --git a/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java b/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java index 7a0640adc507..8b28dc10350f 100644 --- a/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java +++ b/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java @@ -23,15 +23,17 @@ import com.intellij.openapi.vcs.CheckoutProvider; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import git4idea.commands.Git; import git4idea.GitVcs; import git4idea.actions.BasicAction; +import git4idea.commands.Git; import git4idea.commands.GitCommandResult; +import git4idea.commands.GitLineHandlerListener; +import git4idea.commands.GitStandardProgressAnalyzer; import git4idea.i18n.GitBundle; import git4idea.jgit.GitHttpAdapter; -import git4idea.util.GitUIUtil; import git4idea.update.GitFetchResult; import git4idea.update.GitFetcher; +import git4idea.util.GitUIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -83,7 +85,7 @@ public class GitCheckoutProvider implements CheckoutProvider { new Task.Backgroundable(project, GitBundle.message("cloning.repository", sourceRepositoryURL)) { @Override public void run(@NotNull ProgressIndicator indicator) { - cloneResult.set(doClone(project, git, directoryName, parentDirectory, sourceRepositoryURL)); + cloneResult.set(doClone(project, indicator, git, directoryName, parentDirectory, sourceRepositoryURL)); } @Override @@ -106,20 +108,23 @@ public class GitCheckoutProvider implements CheckoutProvider { }.queue(); } - private static boolean doClone(@NotNull Project project, @NotNull Git git, @NotNull String directoryName, @NotNull String parentDirectory, - @NotNull String sourceRepositoryURL) { + private static boolean doClone(@NotNull Project project, @NotNull ProgressIndicator indicator, @NotNull Git git, + @NotNull String directoryName, @NotNull String parentDirectory, @NotNull String sourceRepositoryURL) { if (GitHttpAdapter.shouldUseJGit(sourceRepositoryURL)) { GitFetchResult result = GitHttpAdapter.cloneRepository(project, new File(parentDirectory, directoryName), sourceRepositoryURL); GitFetcher.displayFetchResult(project, result, "Clone failed", result.getErrors()); return result.isSuccess(); } else { - return cloneNatively(project, git, new File(parentDirectory), sourceRepositoryURL, directoryName); + return cloneNatively(project, indicator, git, new File(parentDirectory), sourceRepositoryURL, directoryName); } } - private static boolean cloneNatively(Project project, @NotNull Git git, File directory, String url, String cloneDirectoryName) { - GitCommandResult result = git.clone(project, directory, url, cloneDirectoryName); + private static boolean cloneNatively(@NotNull Project project, @NotNull final ProgressIndicator indicator, + @NotNull Git git, @NotNull File directory, @NotNull String url, @NotNull String cloneDirectoryName) { + indicator.setIndeterminate(false); + GitLineHandlerListener progressListener = GitStandardProgressAnalyzer.createListener(indicator); + GitCommandResult result = git.clone(project, directory, url, cloneDirectoryName, progressListener); if (result.success()) { return true; } diff --git a/plugins/git4idea/src/git4idea/commands/Git.java b/plugins/git4idea/src/git4idea/commands/Git.java index c9fc7f0555c7..480be2106c2a 100644 --- a/plugins/git4idea/src/git4idea/commands/Git.java +++ b/plugins/git4idea/src/git4idea/commands/Git.java @@ -47,7 +47,8 @@ public interface Git { @Nullable List relativePaths) throws VcsException; @NotNull - GitCommandResult clone(@NotNull Project project, @NotNull File parentDirectory, @NotNull String url, @NotNull String clonedDirectoryName); + GitCommandResult clone(@NotNull Project project, @NotNull File parentDirectory, @NotNull String url, @NotNull String clonedDirectoryName, + @NotNull GitLineHandlerListener... progressListeners); @NotNull GitCommandResult config(@NotNull GitRepository repository, String... params); diff --git a/plugins/git4idea/src/git4idea/commands/GitHandler.java b/plugins/git4idea/src/git4idea/commands/GitHandler.java index 1ec1a1cb04d0..e50e95952094 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandler.java @@ -356,7 +356,7 @@ public abstract class GitHandler { * @return is "--progress" parameter supported by this version of Git. */ public boolean addProgressParameter() { - if (GitVersionSpecialty.ABLE_TO_USE_PROGRESS.existsIn(myVcs.getVersion())) { + if (GitVersionSpecialty.ABLE_TO_USE_PROGRESS_IN_REMOTE_COMMANDS.existsIn(myVcs.getVersion())) { addParameters("--progress"); return true; } diff --git a/plugins/git4idea/src/git4idea/commands/GitImpl.java b/plugins/git4idea/src/git4idea/commands/GitImpl.java index e6577f27711c..18b4b775cb9d 100644 --- a/plugins/git4idea/src/git4idea/commands/GitImpl.java +++ b/plugins/git4idea/src/git4idea/commands/GitImpl.java @@ -131,10 +131,12 @@ public class GitImpl implements Git { @Override @NotNull public GitCommandResult clone(@NotNull Project project, @NotNull File parentDirectory, @NotNull String url, - @NotNull String clonedDirectoryName) { + @NotNull String clonedDirectoryName, @NotNull GitLineHandlerListener... listeners) { GitLineHandlerPasswordRequestAware handler = new GitLineHandlerPasswordRequestAware(project, parentDirectory, GitCommand.CLONE); + handler.addParameters("--progress"); handler.addParameters(url); handler.addParameters(clonedDirectoryName); + addListeners(handler, listeners); return run(handler, true); } @@ -361,6 +363,7 @@ public class GitImpl implements Git { GitCommand.PUSH); h.setSilent(false); addListeners(h, listeners); + h.addProgressParameter(); h.addParameters(remote); h.addParameters(spec); return run(h, true); diff --git a/plugins/git4idea/src/git4idea/commands/GitStandardProgressAnalyzer.java b/plugins/git4idea/src/git4idea/commands/GitStandardProgressAnalyzer.java index d442218ac7d7..28eca505ba2a 100644 --- a/plugins/git4idea/src/git4idea/commands/GitStandardProgressAnalyzer.java +++ b/plugins/git4idea/src/git4idea/commands/GitStandardProgressAnalyzer.java @@ -15,6 +15,8 @@ */ package git4idea.commands; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.util.Key; import gnu.trove.TObjectDoubleHashMap; import gnu.trove.TObjectDoubleProcedure; @@ -32,6 +34,19 @@ public class GitStandardProgressAnalyzer implements GitProgressAnalyzer { // but it looks simpler than storing current operation, checking that ther was no skipped, etc. private TObjectDoubleHashMap myOperationsProgress = new TObjectDoubleHashMap(4); + public static GitLineHandlerListener createListener(final ProgressIndicator indicator) { + final GitStandardProgressAnalyzer progressAnalyzer = new GitStandardProgressAnalyzer(); + return new GitLineHandlerAdapter() { + @Override + public void onLineAvailable(String line, Key outputType) { + final double fraction = progressAnalyzer.analyzeProgress(line); + if (fraction >= 0) { + indicator.setFraction(fraction); + } + } + }; + } + /** * A long git command usually consists of the operations in this enum. * A pattern is used to match the operation from the git output. fraction is used to indicate which part of the total git command @@ -52,14 +67,14 @@ public class GitStandardProgressAnalyzer implements GitProgressAnalyzer { } }, COMPRESSING_OBJECTS(".*Compressing objects: +(\\d{1,3})%.*", 0.1), - RECEVING_OBJECTS(".*Receiving objects: +(\\d{1,3})%.*", 0.8), + RECEIVING_OR_WRITING_OBJECTS(".*(?:Receiving|Writing) objects: +(\\d{1,3})%.*", 0.8), // receiving on fetch, writing on push RESOLVING_DELTAS(".*Resolving deltas: +(\\d{1,3})%.*", 0.05); private Pattern myPattern; private double myFractionInTotal; Operation(String pattern, double fractionInTotal) { - myPattern = Pattern.compile(pattern); + myPattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE); myFractionInTotal = fractionInTotal; } diff --git a/plugins/git4idea/src/git4idea/config/GitVersionSpecialty.java b/plugins/git4idea/src/git4idea/config/GitVersionSpecialty.java index 37a2d4aff285..22e1167d1825 100644 --- a/plugins/git4idea/src/git4idea/config/GitVersionSpecialty.java +++ b/plugins/git4idea/src/git4idea/config/GitVersionSpecialty.java @@ -37,11 +37,10 @@ import org.jetbrains.annotations.NotNull; public enum GitVersionSpecialty { /** - * This version of git has "--progress" parameter in long-going commands (such as clone or fetch). - * Note that while pull, clone and fetch received the parameter since 1.7.1.1, - * some other commands (like merge) might have achieved it later. + * This version of git has "--progress" parameter in long-going remote commands: clone, fetch, pull, push. + * Note that other commands (like merge) don't have this parameter in this version yet. */ - ABLE_TO_USE_PROGRESS { + ABLE_TO_USE_PROGRESS_IN_REMOTE_COMMANDS { @Override public boolean existsIn(@NotNull GitVersion version) { return version.isLaterOrEqual(new GitVersion(1, 7, 1, 1)); diff --git a/plugins/git4idea/src/git4idea/merge/GitPullDialog.java b/plugins/git4idea/src/git4idea/merge/GitPullDialog.java index 0d061c6b03ed..d44804cb59ab 100644 --- a/plugins/git4idea/src/git4idea/merge/GitPullDialog.java +++ b/plugins/git4idea/src/git4idea/merge/GitPullDialog.java @@ -157,6 +157,9 @@ public class GitPullDialog extends DialogWrapper { GitLineHandler h = new GitLineHandler(myProject, gitRoot(), pull ? GitCommand.PULL : GitCommand.MERGE); // ignore merge failure for the pull h.ignoreErrorCode(1); + if (pull) { + h.addProgressParameter(); + } h.addParameters("--no-stat"); if (myNoCommitCheckBox.isSelected()) { h.addParameters("--no-commit"); diff --git a/plugins/git4idea/src/git4idea/push/GitPusher.java b/plugins/git4idea/src/git4idea/push/GitPusher.java index e72486279037..251b55f50933 100644 --- a/plugins/git4idea/src/git4idea/push/GitPusher.java +++ b/plugins/git4idea/src/git4idea/push/GitPusher.java @@ -31,6 +31,8 @@ import git4idea.*; import git4idea.branch.GitBranchPair; import git4idea.commands.Git; import git4idea.commands.GitCommandResult; +import git4idea.commands.GitLineHandlerListener; +import git4idea.commands.GitStandardProgressAnalyzer; import git4idea.config.GitConfigUtil; import git4idea.config.GitVcsSettings; import git4idea.config.UpdateMethod; @@ -396,7 +398,8 @@ public final class GitPusher { @NotNull private GitSimplePushResult pushNatively(GitRepository repository, GitPushSpec pushSpec) { GitPushRejectedDetector rejectedDetector = new GitPushRejectedDetector(); - GitCommandResult res = myGit.push(repository, pushSpec, rejectedDetector); + GitLineHandlerListener progressListener = GitStandardProgressAnalyzer.createListener(myProgressIndicator); + GitCommandResult res = myGit.push(repository, pushSpec, rejectedDetector, progressListener); if (rejectedDetector.rejected()) { Collection rejectedBranches = rejectedDetector.getRejectedBranches(); return GitSimplePushResult.reject(rejectedBranches); diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryManagerImpl.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryManagerImpl.java index da1f15ab787b..b3aec771aa04 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryManagerImpl.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryManagerImpl.java @@ -39,23 +39,24 @@ public class GitRepositoryManagerImpl extends AbstractProjectComponent implement private static final Logger LOG = Logger.getInstance(GitRepositoryManager.class); - @NotNull private final AbstractVcs myVcs; @NotNull private final ProjectLevelVcsManager myVcsManager; + @NotNull private AbstractVcs myVcs; @NotNull private final Map myRepositories = new HashMap(); @NotNull private final ReentrantReadWriteLock REPO_LOCK = new ReentrantReadWriteLock(); @NotNull private final GitPlatformFacade myPlatformFacade; - public GitRepositoryManagerImpl(@NotNull Project project, @NotNull GitPlatformFacade platformFacade) { + public GitRepositoryManagerImpl(@NotNull Project project, @NotNull GitPlatformFacade platformFacade, + @NotNull ProjectLevelVcsManager vcsManager) { super(project); myPlatformFacade = platformFacade; - myVcsManager = ProjectLevelVcsManager.getInstance(myProject); - myVcs = platformFacade.getVcs(myProject); + myVcsManager = vcsManager; } @Override public void initComponent() { + myVcs = myPlatformFacade.getVcs(myProject); Disposer.register(myProject, this); myProject.getMessageBus().connect().subscribe(ProjectLevelVcsManager.VCS_CONFIGURATION_CHANGED, this); GitRootScanner rootScanner = new GitRootScanner(myProject); diff --git a/plugins/git4idea/src/git4idea/update/GitFetcher.java b/plugins/git4idea/src/git4idea/update/GitFetcher.java index b7b4d0029573..c904ab769a35 100644 --- a/plugins/git4idea/src/git4idea/update/GitFetcher.java +++ b/plugins/git4idea/src/git4idea/update/GitFetcher.java @@ -211,6 +211,7 @@ public class GitFetcher { private GitFetchResult fetchNatively(@NotNull VirtualFile root, @NotNull GitRemote remote, @Nullable String branch) { final GitLineHandlerPasswordRequestAware h = new GitLineHandlerPasswordRequestAware(myProject, root, GitCommand.FETCH); + h.addProgressParameter(); if (GitVersionSpecialty.SUPPORTS_FETCH_PRUNE.existsIn(myVcs.getVersion())) { h.addParameters("--prune"); } @@ -221,7 +222,7 @@ public class GitFetcher { h.addParameters(getFetchSpecForBranch(branch, remoteName)); } - final GitTask fetchTask = new GitTask(myProject, h, "Fetching..."); + final GitTask fetchTask = new GitTask(myProject, h, "Fetching " + remote.getFirstUrl()); fetchTask.setProgressIndicator(myProgressIndicator); fetchTask.setProgressAnalyzer(new GitStandardProgressAnalyzer()); diff --git a/plugins/git4idea/src/git4idea/update/GitMergeUpdater.java b/plugins/git4idea/src/git4idea/update/GitMergeUpdater.java index 11fd0ff42fac..38bdd91983f7 100644 --- a/plugins/git4idea/src/git4idea/update/GitMergeUpdater.java +++ b/plugins/git4idea/src/git4idea/update/GitMergeUpdater.java @@ -76,7 +76,8 @@ public class GitMergeUpdater extends GitUpdater { GitUntrackedFilesOverwrittenByOperationDetector untrackedFilesDetector = new GitUntrackedFilesOverwrittenByOperationDetector(myRoot); mergeHandler.addLineListener(untrackedFilesDetector); - final GitTask mergeTask = new GitTask(myProject, mergeHandler, "Merging changes"); + String progressTitle = makeProgressTitle("Merging"); + final GitTask mergeTask = new GitTask(myProject, mergeHandler, progressTitle); mergeTask.setProgressIndicator(myProgressIndicator); mergeTask.setProgressAnalyzer(new GitStandardProgressAnalyzer()); final AtomicReference updateResult = new AtomicReference(); diff --git a/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java b/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java index d4a7f0b49e39..467a60418c09 100644 --- a/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java +++ b/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java @@ -73,7 +73,8 @@ public class GitRebaseUpdater extends GitUpdater { GitUntrackedFilesOverwrittenByOperationDetector untrackedFilesDetector = new GitUntrackedFilesOverwrittenByOperationDetector(myRoot); rebaseHandler.addLineListener(untrackedFilesDetector); - GitTask rebaseTask = new GitTask(myProject, rebaseHandler, "Rebasing"); + String progressTitle = makeProgressTitle("Rebasing"); + GitTask rebaseTask = new GitTask(myProject, rebaseHandler, progressTitle); rebaseTask.setProgressIndicator(myProgressIndicator); rebaseTask.setProgressAnalyzer(new GitStandardProgressAnalyzer()); final AtomicReference updateResult = new AtomicReference(); diff --git a/plugins/git4idea/src/git4idea/update/GitUpdater.java b/plugins/git4idea/src/git4idea/update/GitUpdater.java index ca6d53ff2929..71b703a60811 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdater.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdater.java @@ -24,6 +24,7 @@ import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitBranch; import git4idea.GitRevisionNumber; +import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.branch.GitBranchPair; import git4idea.branch.GitBranchUtil; @@ -33,6 +34,7 @@ import git4idea.commands.GitSimpleHandler; import git4idea.config.GitConfigUtil; import git4idea.config.GitVcsSettings; import git4idea.merge.MergeChangeCollector; +import git4idea.repo.GitRepositoryManager; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -48,11 +50,12 @@ public abstract class GitUpdater { @NotNull protected final Project myProject; @NotNull protected final Git myGit; - protected final @NotNull VirtualFile myRoot; - protected final @NotNull Map myTrackedBranches; - protected final @NotNull ProgressIndicator myProgressIndicator; - protected final @NotNull UpdatedFiles myUpdatedFiles; - protected final @NotNull AbstractVcsHelper myVcsHelper; + @NotNull protected final VirtualFile myRoot; + @NotNull protected final Map myTrackedBranches; + @NotNull protected final ProgressIndicator myProgressIndicator; + @NotNull protected final UpdatedFiles myUpdatedFiles; + @NotNull protected final AbstractVcsHelper myVcsHelper; + @NotNull protected final GitRepositoryManager myRepositoryManager; protected final GitVcs myVcs; protected GitRevisionNumber myBefore; // The revision that was before update @@ -68,6 +71,7 @@ public abstract class GitUpdater { myUpdatedFiles = updatedFiles; myVcsHelper = AbstractVcsHelper.getInstance(project); myVcs = GitVcs.getInstance(project); + myRepositoryManager = GitUtil.getRepositoryManager(myProject); } /** @@ -174,4 +178,10 @@ public abstract class GitUpdater { String output = handler.run(); return output != null && !output.isEmpty(); } + + @NotNull + protected String makeProgressTitle(@NotNull String operation) { + return myRepositoryManager.moreThanOneRoot() ? String.format("%s %s...", operation, myRoot.getName()) : operation + "..."; + } + } diff --git a/plugins/git4idea/testFramework/git4idea/test/GitTestImpl.java b/plugins/git4idea/testFramework/git4idea/test/GitTestImpl.java index b9de164ca7fb..fcc15ac61730 100644 --- a/plugins/git4idea/testFramework/git4idea/test/GitTestImpl.java +++ b/plugins/git4idea/testFramework/git4idea/test/GitTestImpl.java @@ -74,7 +74,7 @@ public class GitTestImpl implements Git { public GitCommandResult clone(@NotNull Project project, @NotNull File parentDirectory, @NotNull String url, - @NotNull String clonedDirectoryName) { + @NotNull String clonedDirectoryName, @NotNull GitLineHandlerListener... progressListeners) { throw new UnsupportedOperationException(); } diff --git a/plugins/git4idea/tests/git4idea/tests/GitStandardProgressAnalyzerTest.java b/plugins/git4idea/tests/git4idea/tests/GitStandardProgressAnalyzerTest.java index 13286ceed271..cb7c5c5ca8e5 100644 --- a/plugins/git4idea/tests/git4idea/tests/GitStandardProgressAnalyzerTest.java +++ b/plugins/git4idea/tests/git4idea/tests/GitStandardProgressAnalyzerTest.java @@ -16,8 +16,8 @@ package git4idea.tests; import git4idea.commands.GitStandardProgressAnalyzer; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import org.junit.Before; +import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -32,7 +32,7 @@ public class GitStandardProgressAnalyzerTest { private static final double EPS = 0.00001; private GitStandardProgressAnalyzer myProgressModifier; - @BeforeMethod + @Before public void setUp() { myProgressModifier = new GitStandardProgressAnalyzer(); } @@ -54,8 +54,16 @@ public class GitStandardProgressAnalyzerTest { @Test public void recevingObjects() { - assertEquals(myProgressModifier.analyzeProgress("remote: Receiving objects: 70% (595/850), 4.18 MiB | 223 KiB/s"), 0.15 + 0.8 * 0.7, EPS); + assertEquals(myProgressModifier.analyzeProgress("remote: Receiving objects: 70% (595/850), 4.18 MiB | 223 KiB/s"), + 0.15 + 0.8 * 0.7, EPS); } + + @Test + public void writingObjects() { + assertEquals(myProgressModifier.analyzeProgress("Writing objects: 60% (3/5), 49.91 MiB | 422 KiB/s"), + 0.15 + 0.8 * 0.6, EPS); + } + @Test public void resolvingDeltas() { assertEquals(myProgressModifier.analyzeProgress("remote: Resolving deltas: 34% (289/850)"), 0.95 + 0.05 * 0.34, EPS); @@ -99,6 +107,7 @@ public class GitStandardProgressAnalyzerTest { } } Object resolvingDeltasOperation = null; + assert operationClass != null; for (Object enumConstant : operationClass.getEnumConstants()) { if (enumConstant.toString() == "RESOLVING_DELTAS") { resolvingDeltasOperation = enumConstant;