com.genuitec.eclipse.gerrit.tools.internal.changes.commands.FetchChangeCommand.java Source code

Java tutorial

Introduction

Here is the source code for com.genuitec.eclipse.gerrit.tools.internal.changes.commands.FetchChangeCommand.java

Source

/**
 *  Copyright (c) 2015 Genuitec LLC.
 *  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:
 *  Piotr Tomiak <piotr@genuitec.com> - initial API and implementation
 */
package com.genuitec.eclipse.gerrit.tools.internal.changes.commands;

import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.egit.core.EclipseGitProgressTransformer;
import org.eclipse.egit.ui.internal.credentials.EGitCredentialsProvider;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.TagOpt;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;

import com.genuitec.eclipse.gerrit.tools.internal.changes.dialogs.FetchChangeBranchDialog;
import com.genuitec.eclipse.gerrit.tools.internal.utils.commands.SafeCommandHandler;
import com.genuitec.eclipse.gerrit.tools.utils.MessageLinkDialog;
import com.genuitec.eclipse.gerrit.tools.utils.RepositoryUtils;

@SuppressWarnings("restriction")
public class FetchChangeCommand extends SafeCommandHandler {

    @Override
    protected Object internalExecute(ExecutionEvent event) throws Exception {
        Shell shell = HandlerUtil.getActiveShell(event);

        Repository repository = RepositoryUtils.getRepository(HandlerUtil.getCurrentSelection(event));
        if (repository == null) {
            return null;
        }

        //configure branch creation
        try {
            FetchChangeBranchDialog fetchChangeBranchDialog = new FetchChangeBranchDialog(shell, repository);
            if (fetchChangeBranchDialog.open() != IDialogConstants.OK_ID) {
                return null;
            }
            //perform branch operation
            try {
                ProgressMonitorDialog progressDialog = new ProgressMonitorDialog(shell);
                final CreateChangeBranchOperation op = new CreateChangeBranchOperation(progressDialog.getShell(),
                        event, repository, fetchChangeBranchDialog.getSettings());
                progressDialog.run(true, true, op);
            } catch (InterruptedException e) {
                //ignore
            }
        } catch (NoClassDefFoundError err) {
            MessageLinkDialog.openWarning(shell, "Mylyn for Gerrit is not installed",
                    "To be able to fetch a change from Gerrit, please install Mylyn Gerrit connector. Detailed instructions can be found <a>here</a>.",
                    new MessageLinkDialog.IMessageLinkDialogListener() {
                        @Override
                        public void linkSelected(SelectionEvent e) {
                            try {
                                PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(new URL(
                                        "https://github.com/Genuitec/gerrit-tools/wiki/Fetch-from-Gerrit-setup"));
                            } catch (Exception ex) {
                                RepositoryUtils.handleException(ex);
                            }
                        }
                    });
        }

        return null;
    }

    private static class CreateChangeBranchOperation implements IRunnableWithProgress {

        private Repository repo;
        private Map<String, Object> settings;
        private ExecutionEvent event;

        public CreateChangeBranchOperation(Shell shell, ExecutionEvent event, Repository repository,
                Map<String, Object> settings) {
            this.repo = repository;
            this.settings = settings;
            this.event = event;
        }

        public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
            final String changeBranch = "refs/heads/changes/" + settings.get(FetchChangeBranchDialog.PROP_BRANCH)
                    + "/" + settings.get(FetchChangeBranchDialog.PROP_CHANGE_ID) + "-"
                    + convertToBranchName((String) settings.get(FetchChangeBranchDialog.PROP_CHANGE_TITLE)) + "/"
                    + settings.get(FetchChangeBranchDialog.PROP_PATCHSET_ID);

            int changeId = Integer.parseInt((String) settings.get(FetchChangeBranchDialog.PROP_CHANGE_ID));
            int patchSetId = Integer.parseInt((String) settings.get(FetchChangeBranchDialog.PROP_PATCHSET_ID));
            try {
                List<URIish> urls = new RemoteConfig(repo.getConfig(), "origin").getURIs(); //$NON-NLS-1$
                if (urls.isEmpty()) {
                    throw new InvocationTargetException(
                            new RuntimeException("Repository is not configured for fetch"));
                }
                List<RefSpec> refSpecs = new ArrayList<RefSpec>();
                refSpecs.add(
                        new RefSpec(String.format("+refs/changes/%02d/%d/%d", changeId % 100, changeId, patchSetId)
                                + ":" + changeBranch));

                URIish uri = urls.get(0);
                new Git(repo).fetch().setRemote(uri.toPrivateString()).setRefSpecs(refSpecs)
                        .setRemoveDeletedRefs(true).setTagOpt(TagOpt.NO_TAGS).setDryRun(false).setTimeout(3000)
                        .setCredentialsProvider(new EGitCredentialsProvider())
                        .setProgressMonitor(new EclipseGitProgressTransformer(monitor)).call();

                if ((Boolean) settings.get(FetchChangeBranchDialog.PROP_CHECKOUT)) {
                    Display.getDefault().asyncExec(new Runnable() {
                        @Override
                        public void run() {
                            new SwitchToChangeBranchCommand().execute(event, repo, changeBranch);
                        }
                    });
                }
            } catch (Exception e) {
                RepositoryUtils.handleException(e);
            }
        }

        private String convertToBranchName(String name) {
            StringBuilder sb = new StringBuilder(name.length());
            for (int i = 0; i < name.length() && i < 30; i++) {
                char ch = name.charAt(i);
                if (ch < 40 || ch == '~' || ch == '^' || ch == ':' || ch == 177 || ch == '?' || ch == '*'
                        || ch == '/' || ch == '\\' || ch == '.' || ch == '@' || ch == ' ') {
                    sb.append('_');
                } else if (ch == '[') {
                    sb.append('(');
                } else if (ch == ']') {
                    sb.append(')');
                } else {
                    sb.append(ch);
                }
            }
            return sb.toString();
        }

    }

}