| /******************************************************************************* |
| * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com> |
| * Copyright (C) 2012, Robin Stocker <robin@nibor.org> |
| * Copyright (C) 2013, Laurent Goubet <laurent.goubet@obeo.fr> |
| * Copyright (C) 2015, IBM Corporation (Dani Megert <daniel_megert@ch.ibm.com>) |
| * |
| * 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 |
| * http://www.eclipse.org/legal/epl-v10.html |
| *******************************************************************************/ |
| package org.eclipse.egit.ui.internal.history.command; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.commands.AbstractHandler; |
| import org.eclipse.core.commands.ExecutionEvent; |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.egit.core.AdapterUtils; |
| import org.eclipse.egit.core.internal.util.ResourceUtil; |
| import org.eclipse.egit.ui.internal.UIText; |
| import org.eclipse.egit.ui.internal.history.GitHistoryPage; |
| import org.eclipse.egit.ui.internal.history.HistoryPageInput; |
| import org.eclipse.egit.ui.internal.repository.tree.RefNode; |
| import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode; |
| import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jgit.lib.Constants; |
| import org.eclipse.jgit.lib.ObjectId; |
| import org.eclipse.jgit.lib.Ref; |
| import org.eclipse.jgit.lib.Repository; |
| import org.eclipse.jgit.revplot.PlotCommit; |
| import org.eclipse.jgit.revwalk.RevCommit; |
| import org.eclipse.jgit.revwalk.RevTag; |
| import org.eclipse.jgit.revwalk.RevWalk; |
| import org.eclipse.team.ui.history.IHistoryPage; |
| import org.eclipse.team.ui.history.IHistoryView; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.handlers.HandlerUtil; |
| |
| /** |
| * Common helper methods for the history command handlers |
| */ |
| abstract class AbstractHistoryCommandHandler extends AbstractHandler { |
| protected IWorkbenchPart getPart(ExecutionEvent event) |
| throws ExecutionException { |
| return HandlerUtil.getActivePartChecked(event); |
| } |
| |
| private Object getInput(ExecutionEvent event) throws ExecutionException { |
| IWorkbenchPart part = getPart(event); |
| if (!(part instanceof IHistoryView)) |
| throw new ExecutionException( |
| UIText.AbstractHistoryCommanndHandler_NoInputMessage); |
| return (((IHistoryView) part).getHistoryPage().getInput()); |
| } |
| |
| protected Repository getRepository(ExecutionEvent event) |
| throws ExecutionException { |
| Object input = getInput(event); |
| if (input == null) { |
| return null; |
| } |
| if (input instanceof HistoryPageInput) { |
| return ((HistoryPageInput) input).getRepository(); |
| } |
| if (input instanceof RepositoryTreeNode) { |
| return ((RepositoryTreeNode) input).getRepository(); |
| } |
| IResource resource = AdapterUtils.adapt(input, IResource.class); |
| if (resource != null) { |
| Repository repository = ResourceUtil.getRepository(resource); |
| if (repository != null) { |
| return repository; |
| } |
| } |
| |
| Repository repo = AdapterUtils.adapt(input, Repository.class); |
| if (repo != null) { |
| return repo; |
| } |
| |
| throw new ExecutionException( |
| UIText.AbstractHistoryCommanndHandler_CouldNotGetRepositoryMessage); |
| } |
| |
| protected String getRepoRelativePath(Repository repo, File file) { |
| IPath workdirPath = new Path(repo.getWorkTree().getPath()); |
| IPath filePath = new Path(file.getPath()).setDevice(null); |
| return filePath.removeFirstSegments(workdirPath.segmentCount()) |
| .toString(); |
| } |
| |
| /** |
| * @param event |
| * @return the tags |
| * @throws ExecutionException |
| */ |
| protected List<RevTag> getRevTags(ExecutionEvent event) |
| throws ExecutionException { |
| Repository repo = getRepository(event); |
| Collection<Ref> revTags = repo.getTags().values(); |
| List<RevTag> tags = new ArrayList<>(); |
| try (RevWalk walk = new RevWalk(repo)) { |
| for (Ref ref : revTags) { |
| try { |
| tags.add(walk.parseTag(repo.resolve(ref.getName()))); |
| } catch (IOException e) { |
| throw new ExecutionException(e.getMessage(), e); |
| } |
| } |
| return tags; |
| } |
| } |
| |
| protected GitHistoryPage getPage() { |
| IWorkbenchWindow window = PlatformUI.getWorkbench() |
| .getActiveWorkbenchWindow(); |
| if (window == null) |
| return null; |
| if (window.getActivePage() == null) |
| return null; |
| IWorkbenchPart part = window.getActivePage().getActivePart(); |
| return getPageFromPart(part); |
| } |
| |
| protected GitHistoryPage getPage(ExecutionEvent event) |
| throws ExecutionException { |
| IWorkbenchPart part = getPart(event); |
| return getPageFromPart(part); |
| } |
| |
| private GitHistoryPage getPageFromPart(IWorkbenchPart part) { |
| if (!(part instanceof IHistoryView)) |
| return null; |
| IHistoryView view = (IHistoryView) part; |
| IHistoryPage page = view.getHistoryPage(); |
| if (page instanceof GitHistoryPage) |
| return (GitHistoryPage) page; |
| return null; |
| } |
| |
| protected IStructuredSelection getSelection(GitHistoryPage page) { |
| if (page == null) |
| return StructuredSelection.EMPTY; |
| ISelection selection = page.getSelectionProvider().getSelection(); |
| return getStructuredSelection(selection); |
| } |
| |
| protected IStructuredSelection getSelection(ExecutionEvent event) |
| throws ExecutionException { |
| ISelection selection = HandlerUtil.getCurrentSelectionChecked(event); |
| return getStructuredSelection(selection); |
| } |
| |
| private IStructuredSelection getStructuredSelection(ISelection selection) { |
| if (selection instanceof IStructuredSelection) |
| return (IStructuredSelection) selection; |
| else |
| return StructuredSelection.EMPTY; |
| } |
| |
| /** |
| * @param event |
| * @return ID of selected commit |
| * @throws ExecutionException |
| * if no or multiple commits were found |
| */ |
| protected ObjectId getSelectedCommitId(ExecutionEvent event) |
| throws ExecutionException { |
| IStructuredSelection selection = getSelection(event); |
| if (selection.size() != 1) |
| throw new ExecutionException( |
| UIText.AbstractHistoryCommandHandler_ActionRequiresOneSelectedCommitMessage); |
| |
| RevCommit commit = (RevCommit) selection.getFirstElement(); |
| return commit.getId(); |
| } |
| |
| /** |
| * Gets the selected commit, re-parsed to have correct parent information |
| * regardless of how history was walked. |
| * |
| * @param event |
| * @return the selected commit, never null |
| * @throws ExecutionException |
| * if no or multiple commits were found |
| */ |
| protected RevCommit getSelectedCommit(ExecutionEvent event) |
| throws ExecutionException { |
| List<RevCommit> commits = getSelectedCommits(event); |
| if (commits.size() != 1) |
| throw new ExecutionException( |
| UIText.AbstractHistoryCommandHandler_ActionRequiresOneSelectedCommitMessage); |
| return commits.get(0); |
| } |
| |
| /** |
| * Gets the selected commits, re-parsed to have correct parent information |
| * regardless of how history was walked. |
| * |
| * @param event |
| * @return the selected commits, or an empty list |
| * @throws ExecutionException |
| */ |
| protected List<RevCommit> getSelectedCommits(ExecutionEvent event) |
| throws ExecutionException { |
| Repository repository = getRepository(event); |
| if (repository == null) |
| return Collections.emptyList(); |
| IStructuredSelection selection = getSelection(event); |
| if (selection.isEmpty()) |
| return Collections.emptyList(); |
| List<RevCommit> commits = new ArrayList<>(); |
| try (RevWalk walk = new RevWalk(repository)) { |
| for (Object element : selection.toList()) { |
| RevCommit commit = (RevCommit) element; |
| // Re-parse commit to clear effects of TreeFilter |
| RevCommit reparsed = walk.parseCommit(commit.getId()); |
| commits.add(reparsed); |
| } |
| } catch (IOException e) { |
| throw new ExecutionException(e.getMessage(), e); |
| } |
| return commits; |
| } |
| |
| /** |
| * Utility to get a list of Refs from a commit in order to handle ambiguous |
| * selections when a Ref is preferred over a commit. |
| * |
| * @param commit |
| * @param repo |
| * @param refPrefixes |
| * e.g. "refs/heads/" or "" |
| * @return a list of RefNodes |
| */ |
| protected List<RefNode> getRefNodes(ObjectId commit, Repository repo, |
| String... refPrefixes) { |
| List<Ref> availableBranches = new ArrayList<>(); |
| List<RefNode> nodes = new ArrayList<>(); |
| try { |
| Map<String, Ref> branches = new HashMap<>(); |
| for (String refPrefix : refPrefixes) { |
| branches.putAll(repo.getRefDatabase().getRefs(refPrefix)); |
| } |
| for (Ref branch : branches.values()) { |
| ObjectId objectId = branch.getLeaf().getObjectId(); |
| if (objectId != null && objectId.equals(commit)) { |
| availableBranches.add(branch); |
| } |
| } |
| RepositoryNode repoNode = new RepositoryNode(null, repo); |
| for (Ref ref : availableBranches) { |
| nodes.add(new RefNode(repoNode, repo, ref)); |
| } |
| |
| } catch (IOException e) { |
| // ignore here |
| } |
| return nodes; |
| } |
| |
| protected List<Ref> getBranchesOfCommit(IStructuredSelection selection, |
| final Repository repo, boolean hideCurrentBranch) |
| throws IOException { |
| String head = repo.getFullBranch(); |
| return getBranchesOfCommit(selection, head, hideCurrentBranch); |
| } |
| |
| protected List<Ref> getBranchesOfCommit(IStructuredSelection selection) { |
| return getBranchesOfCommit(selection, (String) null, false); |
| } |
| |
| private List<Ref> getBranchesOfCommit(IStructuredSelection selection, |
| String head, |
| boolean hideCurrentBranch) { |
| final List<Ref> branchesOfCommit = new ArrayList<>(); |
| if (selection.isEmpty()) |
| return branchesOfCommit; |
| PlotCommit commit = (PlotCommit) selection.getFirstElement(); |
| |
| int refCount = commit.getRefCount(); |
| for (int i = 0; i < refCount; i++) { |
| Ref ref = commit.getRef(i); |
| String refName = ref.getName(); |
| if (hideCurrentBranch && head != null && refName.equals(head)) |
| continue; |
| if (refName.startsWith(Constants.R_HEADS) |
| || refName.startsWith(Constants.R_REMOTES)) |
| branchesOfCommit.add(ref); |
| } |
| return branchesOfCommit; |
| } |
| |
| protected Repository getRepository(GitHistoryPage page) { |
| if (page == null) |
| return null; |
| HistoryPageInput input = page.getInputInternal(); |
| if (input == null) |
| return null; |
| |
| final Repository repository = input.getRepository(); |
| return repository; |
| } |
| |
| /** |
| * Get renamed path in commit |
| * |
| * @param path |
| * @param commit |
| * @return path respecting renames |
| */ |
| protected String getRenamedPath(final String path, final ObjectId commit) { |
| return getPage().getRenamedPath(path, commit); |
| } |
| } |