blob: 1c4b5d42221e93ac8573bcdabb29e6af79ee6846 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Ericsson AB.
* 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
*
* Contributors:
* Ericsson - initial API and implementation
*******************************************************************************/
package org.eclipse.egerrit.internal.ui.editors;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.NotEnabledException;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.expressions.EvaluationContext;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.egerrit.internal.core.EGerritCorePlugin;
import org.eclipse.egerrit.internal.core.GerritClient;
import org.eclipse.egerrit.internal.model.FetchInfo;
import org.eclipse.egerrit.internal.model.RevisionInfo;
import org.eclipse.egerrit.internal.ui.EGerritUIPlugin;
import org.eclipse.egerrit.internal.ui.utils.Messages;
import org.eclipse.egit.ui.JobFamilies;
import org.eclipse.egit.ui.internal.CommonUtils;
import org.eclipse.egit.ui.internal.commit.RepositoryCommit;
import org.eclipse.egit.ui.internal.fetch.FetchOperationUI;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.ErrorDialog;
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.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.ISources;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.handlers.IHandlerService;
/**
* Code to cherry-pick a revision
*/
public class CherryPickRevision extends Action {
private static final String EGIT_CHERRY_PICK = "org.eclipse.egit.ui.commit.CherryPick"; //$NON-NLS-1$
private RevCommit commit;
private Repository repo;
private RevisionInfo revision;
private GerritClient gerritClient;
public CherryPickRevision(RevisionInfo gerritRevision, GerritClient gerritClient) {
this.gerritClient = gerritClient;
this.revision = gerritRevision;
this.setText(Messages.CherryPickRevision_0);
}
@Override
public void run() {
repo = new FindLocalRepository(gerritClient, revision.getChangeInfo().getProject()).getRepository();
if (repo == null) {
Status status = new Status(IStatus.ERROR, EGerritCorePlugin.PLUGIN_ID, Messages.CherryPickRevision_1);
ErrorDialog.openError(Display.getDefault().getActiveShell(), Messages.CherryPickRevision_2,
Messages.CherryPickRevision_3, status);
return;
}
URIish remoteURI = getRemoteURI();
if (remoteURI != null) {
Job job = new WorkspaceJob(Messages.CherryPickRevision_4 + remoteURI.toPrivateString()) {
@Override
public IStatus runInWorkspace(IProgressMonitor monitor) {
try {
fetchChange(monitor);
} catch (CoreException | URISyntaxException | IOException e) {
return new Status(IStatus.ERROR, EGerritUIPlugin.PLUGIN_ID,
Messages.CherryPickRevision_5 + remoteURI.toPrivateString(), e);
}
return Status.OK_STATUS;
}
@Override
public boolean belongsTo(Object family) {
if (JobFamilies.FETCH.equals(family)) {
return true;
}
return super.belongsTo(family);
}
};
job.setUser(true);
job.schedule();
try {
job.join();
} catch (InterruptedException e) {
return;
}
cherryPickAfterFetch(job);
}
}
/**
* @param job
*/
private void cherryPickAfterFetch(Job job) {
try {
if (!job.getResult().isOK()) {
return;
}
initializeCommitFromRevision();
if (commit == null) {
Status status = new Status(IStatus.ERROR, EGerritCorePlugin.PLUGIN_ID, Messages.CherryPickRevision_6);
ErrorDialog.openError(Display.getDefault().getActiveShell(), Messages.CherryPickRevision_2,
Messages.CherryPickRevision_3, status);
}
if (!invokeEGitCherryPickCommand()) {
Status status = new Status(IStatus.ERROR, EGerritCorePlugin.PLUGIN_ID, Messages.CherryPickRevision_9);
ErrorDialog.openError(Display.getDefault().getActiveShell(), Messages.CherryPickRevision_2,
Messages.CherryPickRevision_3, status);
}
} catch (CoreException | IOException e) {
Status status = new Status(IStatus.ERROR, EGerritCorePlugin.PLUGIN_ID, Messages.CherryPickRevision_12);
ErrorDialog.openError(Display.getDefault().getActiveShell(), Messages.CherryPickRevision_2,
Messages.CherryPickRevision_3, status);
}
}
private void initializeCommitFromRevision() throws IOException, CoreException {
ObjectId commitId = repo.resolve(revision.getCommit().getCommit());
commit = null;
try (org.eclipse.jgit.revwalk.RevWalk revWalk = new org.eclipse.jgit.revwalk.RevWalk(repo)) {
commit = revWalk.parseCommit(commitId);
revWalk.dispose();
}
}
private String getRef() {
//Here we can pick any FetchInfo because the ref string is same everywhere
if (!revision.getFetch().isEmpty()) {
Entry<String, FetchInfo> x = revision.getFetch().iterator().next();
return x.getValue().getRef();
}
return null;
}
private boolean invokeEGitCherryPickCommand() {
final IStructuredSelection selection = new StructuredSelection(new RepositoryCommit(repo, commit));
ICommandService commandService = CommonUtils.getService(PlatformUI.getWorkbench(), ICommandService.class);
Command cmd = commandService.getCommand(EGIT_CHERRY_PICK);
if (!cmd.isDefined()) {
return false;
}
IHandlerService handlerService = CommonUtils.getService(PlatformUI.getWorkbench(), IHandlerService.class);
EvaluationContext c = null;
c = new EvaluationContext(handlerService.createContextSnapshot(false), selection.toList());
c.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection);
c.removeVariable(ISources.ACTIVE_MENU_SELECTION_NAME);
try {
handlerService.executeCommandInContext(new ParameterizedCommand(cmd, null), null, c);
} catch (ExecutionException | NotDefinedException | NotEnabledException | NotHandledException e) {
return false;
}
return true;
}
//Run the fetch in the workspace to give feedback to the user
private void fetchChange(IProgressMonitor monitor) throws CoreException, URISyntaxException, IOException {
final RefSpec spec = new RefSpec().setSource(getRef()).setDestination(Constants.FETCH_HEAD);
List<RefSpec> specs = new ArrayList<>(1);
specs.add(spec);
new FetchOperationUI(repo, getRemoteURI(), specs, 0, false).execute(monitor);
}
private URIish getRemoteURI() {
try {
return new URIish(gerritClient.getRepository().getURIBuilder(false).toString() + "/" //$NON-NLS-1$
+ revision.getChangeInfo().getProject());
} catch (URISyntaxException e) {
return null;
}
}
private boolean connectionTypeAvailable(String scheme) {
return revision.getFetch().get(scheme) != null;
}
}