diff options
author | Stefan Dirix | 2015-05-20 16:04:57 +0000 |
---|---|---|
committer | Thomas Wolf | 2016-12-18 09:51:10 +0000 |
commit | e3bed9a8e1b86430e6be93ca1029301e64fe1dfa (patch) | |
tree | 0f980a72e11983f4125a40fbb03f5a6506597e02 | |
parent | ab481b10062ee0184adbc65441593d75472f73ec (diff) | |
download | egit-e3bed9a8e1b86430e6be93ca1029301e64fe1dfa.tar.gz egit-e3bed9a8e1b86430e6be93ca1029301e64fe1dfa.tar.xz egit-e3bed9a8e1b86430e6be93ca1029301e64fe1dfa.zip |
Compare/ReplaceWithPrevious support for multiple resources (in mappings)
The CompareWithPrevious and ReplaceWithPrevious actions now also support
scenarios where the current selection consists of a single object but
maps to multiple files (commonly via ResourceMappings).
The previous commit is the next-to-last commit which touched any of the
resources.
Bug: 496916
Change-Id: I1a208bd9949711e602309cac702a5a158b0eab4b
Signed-off-by: Stefan Dirix <sdirix@eclipsesource.com>
Signed-off-by: Philip Langer <planger@eclipsesource.com>
Also-by: Laurent Delaigue <laurent.delaigue@obeo.fr>
Also-by: Mathieu Cartaud <mathieu.cartaud@obeo.fr>
4 files changed, 143 insertions, 60 deletions
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CommonUtils.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CommonUtils.java index bc738fce5e..0078fd799e 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CommonUtils.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CommonUtils.java @@ -6,6 +6,7 @@ * Copyright (C) 2014, IBM Corporation (Markus Keller <markus_keller@ch.ibm.com>) * Copyright (C) 2015, IBM Corporation (Dani Megert <daniel_megert@ch.ibm.com>) * Copyright (C) 2015, Thomas Wolf <thomas.wolf@paranor.ch> + * Copyright (C) 2016, Stefan Dirix <sdirix@eclipsesource.com> * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -18,6 +19,7 @@ import java.nio.file.Path; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -29,6 +31,7 @@ import org.eclipse.core.resources.IResource; import org.eclipse.jface.util.Policy; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.util.StringUtils; import org.eclipse.ui.ISources; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.commands.ICommandService; @@ -263,4 +266,24 @@ public class CommonUtils { } return -1; } + + /** + * Creates a comma separated list of all non-null resource names. The last + * element is separated with an ampersand. + * + * @param resources + * the collection of {@link IResource}s. + * @return A comma separated list the resource names. The last element is + * separated with an ampersand. + */ + public static String getResourceNames(Iterable<IResource> resources) { + final List<String> names = new LinkedList<>(); + for (IResource resource : resources) { + if (resource.getName() != null) { + names.add(resource.getName()); + } + } + + return StringUtils.join(names, ", ", " & "); //$NON-NLS-1$ //$NON-NLS-2$ + } } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/CompareWithPreviousActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/CompareWithPreviousActionHandler.java index 56f0033f4b..78c744382a 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/CompareWithPreviousActionHandler.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/CompareWithPreviousActionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2013 GitHub Inc. and others. + * Copyright (c) 2011, 2016 GitHub Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -9,12 +9,14 @@ * Kevin Sawicki (GitHub Inc.) - initial API and implementation * François Rey - gracefully ignore linked resources * Laurent Goubet <laurent.goubet@obeo.fr> + * Stefan Dirix <sdirix@eclipsesource.com> *******************************************************************************/ package org.eclipse.egit.ui.internal.actions; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicReference; @@ -22,10 +24,12 @@ import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IResource; import org.eclipse.egit.ui.Activator; +import org.eclipse.egit.ui.internal.CommonUtils; import org.eclipse.egit.ui.internal.CompareUtils; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.dialogs.CommitSelectDialog; import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; @@ -48,23 +52,24 @@ public class CompareWithPreviousActionHandler extends RepositoryActionHandler { if (repository == null) { return null; } - final IResource[] resources = getSelectedResources(event); - if (resources.length != 1) { - return null; - } - try { - IWorkbenchPage workBenchPage = HandlerUtil - .getActiveWorkbenchWindowChecked(event).getActivePage(); - final PreviousCommit previous = getPreviousRevision(event, - resources[0]); - if (previous != null) { - CompareUtils.compare(resources, repository, Constants.HEAD, - previous.commit.getName(), true, workBenchPage); + if (resources != null && resources.length > 0) { + try { + IWorkbenchPage workBenchPage = HandlerUtil + .getActiveWorkbenchWindowChecked(event).getActivePage(); + final RevCommit previous = getPreviousRevision(event, + resources); + if (previous != null) { + CompareUtils.compare(resources, repository, Constants.HEAD, + previous.getName(), true, workBenchPage); + } else { + showNotFoundDialog(event, resources); + } + } catch (Exception e) { + Activator.handleError( + UIText.CompareWithRefAction_errorOnSynchronize, e, + true); } - } catch (Exception e) { - Activator.handleError( - UIText.CompareWithRefAction_errorOnSynchronize, e, true); } return null; @@ -72,25 +77,26 @@ public class CompareWithPreviousActionHandler extends RepositoryActionHandler { @Override public boolean isEnabled() { - IResource[] selectedResources = getSelectedResources(); - return super.isEnabled() && selectedResources.length == 1 && - selectionMapsToSingleRepository(); + IStructuredSelection selection = getSelection(); + return super.isEnabled() && selection.size() == 1 + && selectionMapsToSingleRepository(); } - private PreviousCommit getPreviousRevision(final ExecutionEvent event, - final IResource resource) throws IOException { + private RevCommit getPreviousRevision(final ExecutionEvent event, + final IResource[] resources) throws IOException { + final List<RevCommit> previousList = findPreviousCommits( + Arrays.asList(resources)); - final List<PreviousCommit> previousList = findPreviousCommits(); + final AtomicReference<RevCommit> previous = new AtomicReference<>(); - final AtomicReference<PreviousCommit> previous = new AtomicReference<>(); - if (previousList.size() == 0) - showNotFoundDialog(event, resource); - else if (previousList.size() == 1) + if (previousList.size() == 0) { + return null; + } else if (previousList.size() == 1) previous.set(previousList.get(0)); else { final List<RevCommit> commits = new ArrayList<>(); - for (PreviousCommit pc : previousList) - commits.add(pc.commit); + for (RevCommit pc : previousList) + commits.add(pc); HandlerUtil.getActiveShell(event).getDisplay() .syncExec(new Runnable() { @Override @@ -98,9 +104,8 @@ public class CompareWithPreviousActionHandler extends RepositoryActionHandler { CommitSelectDialog dlg = new CommitSelectDialog( HandlerUtil.getActiveShell(event), commits); if (dlg.open() == Window.OK) - for (PreviousCommit pc : previousList) - if (pc.commit.equals(dlg - .getSelectedCommit())) { + for (RevCommit pc : previousList) + if (pc.equals(dlg.getSelectedCommit())) { previous.set(pc); break; } @@ -112,10 +117,14 @@ public class CompareWithPreviousActionHandler extends RepositoryActionHandler { } private void showNotFoundDialog(final ExecutionEvent event, - IResource resource) { + IResource[] resources) { + + final String resourceNames = CommonUtils + .getResourceNames(Arrays.asList(resources)); + final String message = MessageFormat .format(UIText.CompareWithPreviousActionHandler_MessageRevisionNotFound, - resource.getName()); + resourceNames); PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { @Override diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ReplaceWithPreviousActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ReplaceWithPreviousActionHandler.java index d4585b6fa2..54eb63a098 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ReplaceWithPreviousActionHandler.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ReplaceWithPreviousActionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2012, Mathias Kinzler <mathias.kinzler@sap.com> + * Copyright (C) 2012, 2016 Mathias Kinzler <mathias.kinzler@sap.com> * and other copyright owners as documented in the project's IP log. * * All rights reserved. This program and the accompanying materials @@ -11,16 +11,18 @@ package org.eclipse.egit.ui.internal.actions; import java.io.IOException; import java.text.MessageFormat; -import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.egit.ui.internal.CommonUtils; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.dialogs.CommitSelectDialog; import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.jgit.revwalk.RevCommit; @@ -34,33 +36,31 @@ public class ReplaceWithPreviousActionHandler extends protected String gatherRevision(ExecutionEvent event) throws ExecutionException { IResource[] resources = getSelectedResources(event); - if (resources.length != 1) - throw new ExecutionException( - "Unexpected number of selected Resources"); //$NON-NLS-1$ try { - List<PreviousCommit> pcs = findPreviousCommits(); - List<RevCommit> previousCommits = new ArrayList<>(); - for (PreviousCommit pc: pcs) - previousCommits.add(pc.commit); - int parentCount = previousCommits.size(); + List<RevCommit> pcs = findPreviousCommits(Arrays.asList(resources)); + + int parentCount = pcs.size(); if (parentCount == 0) { + final String resourceNames = CommonUtils + .getResourceNames(Arrays.asList(resources)); + MessageDialog .openError( getShell(event), UIText.ReplaceWithPreviousActionHandler_NoParentCommitDialogTitle, MessageFormat .format(UIText.ReplaceWithPreviousActionHandler_NoParentCommitDialogMessage, - resources[0].getName())); + resourceNames)); throw new OperationCanceledException(); } else if (parentCount > 1) { CommitSelectDialog dlg = new CommitSelectDialog( - getShell(event), previousCommits); + getShell(event), pcs); if (dlg.open() == Window.OK) return dlg.getSelectedCommit().getName(); else throw new OperationCanceledException(); } else - return previousCommits.get(0).getName(); + return pcs.get(0).getName(); } catch (IOException e) { throw new ExecutionException(e.getMessage(), e); } @@ -68,8 +68,8 @@ public class ReplaceWithPreviousActionHandler extends @Override public boolean isEnabled() { - IResource[] selectedResources = getSelectedResources(); - return super.isEnabled() && selectedResources.length == 1 && - selectionMapsToSingleRepository(); + IStructuredSelection selection = getSelection(); + return super.isEnabled() && selection.size() == 1 + && selectionMapsToSingleRepository(); } } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryActionHandler.java index 8b26f23980..cf026ec08b 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryActionHandler.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryActionHandler.java @@ -8,6 +8,7 @@ * Copyright (C) 2012, 2013 François Rey <eclipse.org_@_francois_._rey_._name> * Copyright (C) 2013 Laurent Goubet <laurent.goubet@obeo.fr> * Copyright (C) 2015, IBM Corporation (Dani Megert <daniel_megert@ch.ibm.com>) + * Copyright (C) 2016, Stefan Dirix <sdirix@eclipsesource.com> * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -19,6 +20,7 @@ package org.eclipse.egit.ui.internal.actions; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; @@ -51,6 +53,8 @@ import org.eclipse.jgit.revwalk.FollowFilter; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevSort; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.filter.OrTreeFilter; +import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; @@ -454,20 +458,18 @@ abstract class RepositoryActionHandler extends AbstractHandler { return path; } - protected List<PreviousCommit> findPreviousCommits() throws IOException { - List<PreviousCommit> result = new ArrayList<>(); + protected RevCommit getHeadCommit(IResource resource) throws IOException { Repository repository = getRepository(); - IResource resource = getSelectedResources()[0]; if (resource == null) { - return result; + return null; } RepositoryMapping mapping = RepositoryMapping.getMapping(resource); if (mapping == null) { - return result; + return null; } String path = mapping.getRepoRelativePath(resource); if (path == null) { - return result; + return null; } try (RevWalk rw = new RevWalk(repository)) { rw.sort(RevSort.COMMIT_TIME_DESC, true); @@ -479,7 +481,59 @@ abstract class RepositoryActionHandler extends AbstractHandler { rw.setTreeFilter(filter); } - Ref head = repository.exactRef(Constants.HEAD); + Ref head = repository.findRef(Constants.HEAD); + if (head == null) { + return null; + } + RevCommit headCommit = rw.parseCommit(head.getObjectId()); + rw.close(); + return headCommit; + } + } + + /** + * Returns the previous commit of the given resources. + * + * @param resources + * The {@link IResource} for which the previous commit shall be + * determined. + * @return The second to last commit which touched any of the given + * resources. + * @throws IOException + * When the commit can not be parsed. + */ + protected List<RevCommit> findPreviousCommits( + Collection<IResource> resources) throws IOException { + List<RevCommit> result = new ArrayList<>(); + Repository repository = getRepository(); + RepositoryMapping mapping = RepositoryMapping.getMapping(resources + .iterator().next() + .getProject()); + if (mapping == null) { + return result; + } + try (RevWalk rw = new RevWalk(repository)) { + rw.sort(RevSort.COMMIT_TIME_DESC, true); + rw.sort(RevSort.BOUNDARY, true); + + List<TreeFilter> filters = new ArrayList<>(); + DiffConfig diffConfig = repository.getConfig().get(DiffConfig.KEY); + for (IResource resource : resources) { + String path = mapping.getRepoRelativePath(resource); + + if (path != null && path.length() > 0) { + filters.add(FollowFilter.create(path, diffConfig)); + } + } + + if (filters.size() >= 2) { + TreeFilter filter = OrTreeFilter.create(filters); + rw.setTreeFilter(filter); + } else if (filters.size() == 1) { + rw.setTreeFilter(filters.get(0)); + } + + Ref head = repository.findRef(Constants.HEAD); if (head == null) { return result; } @@ -495,10 +549,7 @@ abstract class RepositoryActionHandler extends AbstractHandler { RevCommit previousCommit = rw.next(); while (previousCommit != null && result.size() < directParents.size()) { if (directParents.contains(previousCommit)) { - String previousPath = getPreviousPath(repository, - rw.getObjectReader(), headCommit, previousCommit, - path); - result.add(new PreviousCommit(previousCommit, previousPath)); + result.add(previousCommit); } previousCommit = rw.next(); } |