Package org.eclipse.egit.ui.internal.clone

Source Code of org.eclipse.egit.ui.internal.clone.AbstractGitCloneWizard

/*******************************************************************************
* Copyright (C) 2008, Roger C. Soares <rogersoares@intelinet.com.br>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
* Copyright (C) 2010, Benjamin Muskalla <bmuskalla@eclipsesource.com>
* Copyright (C) 2012, Stefan Lay <stefan.lay@sap.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.clone;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

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.egit.core.RepositoryUtil;
import org.eclipse.egit.core.internal.util.ProjectUtil;
import org.eclipse.egit.core.op.CloneOperation;
import org.eclipse.egit.core.op.CloneOperation.PostCloneTask;
import org.eclipse.egit.core.op.ConfigureFetchAfterCloneTask;
import org.eclipse.egit.core.op.ConfigurePushAfterCloneTask;
import org.eclipse.egit.core.op.SetRepositoryConfigPropertyTask;
import org.eclipse.egit.core.securestorage.UserPasswordCredentials;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.JobFamilies;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.internal.SecureStoreUtils;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.clone.GitCloneSourceProviderExtension.CloneSourceProvider;
import org.eclipse.egit.ui.internal.components.RepositorySelection;
import org.eclipse.egit.ui.internal.credentials.EGitCredentialsProvider;
import org.eclipse.egit.ui.internal.provisional.wizards.GitRepositoryInfo;
import org.eclipse.egit.ui.internal.provisional.wizards.GitRepositoryInfo.PushInfo;
import org.eclipse.egit.ui.internal.provisional.wizards.GitRepositoryInfo.RepositoryConfigProperty;
import org.eclipse.egit.ui.internal.provisional.wizards.IRepositorySearchResult;
import org.eclipse.egit.ui.internal.provisional.wizards.NoRepositoryInfoException;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.IWizardContainer;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.IWorkingSet;

/**
* Implements the basic functionality of a clone wizard
*/
public abstract class AbstractGitCloneWizard extends Wizard {

  /**
   * a page for branch selection
   */
  protected SourceBranchPage validSource;

  /**
   * a page for selection of the clone destination
   */
  protected CloneDestinationPage cloneDestination;

  /**
   * the path where a clone has been created in
   */
  protected String alreadyClonedInto;

  /**
   * whether the clone operation is done later on by the caller of the wizard
   */
  protected boolean callerRunsCloneOperation;

  /**
   * the result which was found when the last search was done
   */
  protected IRepositorySearchResult currentSearchResult;

  private CloneOperation cloneOperation;

  /**
   * Construct the clone wizard based on given repository search result. If
   * the search result is an instance of org.eclipse.jface.wizard.WizardPage,
   * then the page is shown in the wizard before the repository info is read.
   * The repository location page that allows the repository info to be
   * provided by different search providers is not shown.
   *
   * @param searchResult
   *            the search result to initialize the clone wizard with.
   */
  public AbstractGitCloneWizard(IRepositorySearchResult searchResult) {
    this();
    this.currentSearchResult = searchResult;
  }

  /**
   * Construct the clone wizard with a repository location page that allows
   * the repository info to be provided by different search providers.
   */
  public AbstractGitCloneWizard() {
    setNeedsProgressMonitor(true);
    validSource = new SourceBranchPage() {

      @Override
      public void setVisible(boolean visible) {
        if (visible) {
          setSelection(getRepositorySelection());
          setCredentials(getCredentials());
        }
        super.setVisible(visible);
      }
    };
    cloneDestination = new CloneDestinationPage() {
      @Override
      public void setVisible(boolean visible) {
        if (visible)
          setSelection(getRepositorySelection(),
              validSource.getAvailableBranches(),
              validSource.getSelectedBranches(),
              validSource.getHEAD());
        super.setVisible(visible);
      }
    };
  }

  /**
   * subclasses may add pages to the Wizard which will be shown before the clone step
   */
  protected abstract void addPreClonePages();

  /**
   * subclasses may add pages to the Wizard which will be shown after the clone step
   */
  protected abstract void addPostClonePages();

  @Override
  final public void addPages() {
    if (hasSearchResult())
      addRepositorySearchPage();
    else
      addRepositoryLocationPage();
    addPreClonePages();
    addPage(validSource);
    addPage(cloneDestination);
    addPostClonePages();
  }

  /**
   * @return if the search result is set
   */
  protected boolean hasSearchResult() {
    return currentSearchResult != null;
  }

  private void addRepositorySearchPage() {
    if (currentSearchResult instanceof WizardPage)
      addPage((WizardPage)currentSearchResult);
  }

  private void addRepositoryLocationPage() {
    List<CloneSourceProvider> cloneSourceProviders = getCloneSourceProviders();
    if (hasSingleCloneSourceProviderWithFixedLocation(cloneSourceProviders))
      try {
        addPage(cloneSourceProviders.get(0).getRepositorySearchPage());
      } catch (CoreException e) {
        Activator.logError(e.getLocalizedMessage(), e);
      }
    else
      addPage(new RepositoryLocationPage(cloneSourceProviders));
  }

  private boolean hasSingleCloneSourceProviderWithFixedLocation(
      List<CloneSourceProvider> cloneSourceProviders) {
    return cloneSourceProviders.size() == 1 && cloneSourceProviders.get(0).hasFixLocation();
  }

  /**
   * @return a list of CloneSourceProviders, may be extended by a subclass
   */
  protected List<CloneSourceProvider> getCloneSourceProviders() {
    return GitCloneSourceProviderExtension.getCloneSourceProvider();
  }

  /**
   * Do the clone using data which were collected on the pages
   * {@code validSource} and {@code cloneDestination}
   *
   * @param gitRepositoryInfo
   * @return if clone was successful
   * @throws URISyntaxException
   */
  protected boolean performClone(GitRepositoryInfo gitRepositoryInfo) throws URISyntaxException {
    URIish uri = new URIish(gitRepositoryInfo.getCloneUri());
    UserPasswordCredentials credentials = gitRepositoryInfo.getCredentials();
    setWindowTitle(NLS.bind(UIText.GitCloneWizard_jobName, uri.toString()));
    final boolean allSelected;
    final Collection<Ref> selectedBranches;
    if (validSource.isSourceRepoEmpty()) {
      // fetch all branches of empty repo
      allSelected = true;
      selectedBranches = Collections.emptyList();
    } else {
      allSelected = validSource.isAllSelected();
      selectedBranches = validSource.getSelectedBranches();
    }
    final File workdir = cloneDestination.getDestinationFile();
    final Ref ref = cloneDestination.getInitialBranch();
    final String remoteName = cloneDestination.getRemote();

    boolean created = workdir.exists();
    if (!created)
      created = workdir.mkdirs();

    if (!created || !workdir.isDirectory()) {
      final String errorMessage = NLS.bind(
          UIText.GitCloneWizard_errorCannotCreate, workdir.getPath());
      ErrorDialog.openError(getShell(), getWindowTitle(),
          UIText.GitCloneWizard_failed, new Status(IStatus.ERROR,
              Activator.getPluginId(), 0, errorMessage, null));
      // let's give user a chance to fix this minor problem
      return false;
    }

    int timeout = Activator.getDefault().getPreferenceStore()
        .getInt(UIPreferences.REMOTE_CONNECTION_TIMEOUT);
    final CloneOperation op = new CloneOperation(uri, allSelected,
        selectedBranches, workdir, ref != null ? ref.getName() : null,
        remoteName, timeout);
    if (credentials != null)
      op.setCredentialsProvider(new EGitCredentialsProvider(
          credentials.getUser(), credentials.getPassword()));
    else
      op.setCredentialsProvider(new EGitCredentialsProvider());
    op.setCloneSubmodules(cloneDestination.isCloneSubmodules());

    configureFetchSpec(op, gitRepositoryInfo, remoteName);
    configurePush(op, gitRepositoryInfo, remoteName);
    configureRepositoryConfig(op, gitRepositoryInfo);

    if (cloneDestination.isImportProjects()) {
      final IWorkingSet[] sets = cloneDestination.getWorkingSets();
      op.addPostCloneTask(new PostCloneTask() {
        public void execute(Repository repository,
            IProgressMonitor monitor) throws CoreException {
          importProjects(repository, sets);
        }
      });
    }

    alreadyClonedInto = workdir.getPath();

    if (!callerRunsCloneOperation)
      runAsJob(uri, op, gitRepositoryInfo);
    else
      cloneOperation = op;
    return true;
  }

  @Override
  public IWizardPage getNextPage(IWizardPage page) {
    if (page instanceof IRepositorySearchResult) {
      currentSearchResult = (IRepositorySearchResult)page;
      return validSource;
    }
    return super.getNextPage(page);
  }

  /**
   * @return the repository selected by the user
   */
  protected RepositorySelection getRepositorySelection() {
    try {
      return (new RepositorySelection(new URIish(currentSearchResult.getGitRepositoryInfo().getCloneUri()), null));
    } catch (URISyntaxException e) {
      Activator.error(UIText.GitImportWizard_errorParsingURI, e);
      return null;
    } catch (NoRepositoryInfoException e) {
      Activator.error(UIText.GitImportWizard_noRepositoryInfo, e);
      return null;
    } catch (Exception e) {
      Activator.error(e.getMessage(), e);
      return null;
    }
  }

  /**
   * @return the credentials
   */
  protected UserPasswordCredentials getCredentials() {
    try {
      return currentSearchResult.getGitRepositoryInfo().getCredentials();
    } catch (NoRepositoryInfoException e) {
      Activator.error(UIText.GitImportWizard_noRepositoryInfo, e);
      return null;
    } catch (Exception e) {
      Activator.error(e.getMessage(), e);
      return null;
    }
  }

  private void configureFetchSpec(CloneOperation op,
      GitRepositoryInfo gitRepositoryInfo, String remoteName) {
    for (String fetchRefSpec : gitRepositoryInfo.getFetchRefSpecs())
      op.addPostCloneTask(new ConfigureFetchAfterCloneTask(remoteName, fetchRefSpec));
  }

  private void configurePush(CloneOperation op,
      GitRepositoryInfo gitRepositoryInfo, String remoteName) {
    for (PushInfo pushInfo : gitRepositoryInfo.getPushInfos())
      try {
        URIish uri = pushInfo.getPushUri() != null ? new URIish(
            pushInfo.getPushUri()) : null;
        ConfigurePushAfterCloneTask task = new ConfigurePushAfterCloneTask(
            remoteName, pushInfo.getPushRefSpec(), uri);
        op.addPostCloneTask(task);
      } catch (URISyntaxException e) {
        Activator.handleError(UIText.GitCloneWizard_failed, e, true);
      }
  }

  private void configureRepositoryConfig(CloneOperation op, GitRepositoryInfo gitRepositoryInfo) {
    for (RepositoryConfigProperty p : gitRepositoryInfo.getRepositoryConfigProperties()) {
      SetRepositoryConfigPropertyTask task = new SetRepositoryConfigPropertyTask(
          p.getSection(), p.getSubsection(), p.getName(),
          p.getValue());
      op.addPostCloneTask(task);
    }
  }

  private void importProjects(final Repository repository,
      final IWorkingSet[] sets) {
    String repoName = Activator.getDefault().getRepositoryUtil()
        .getRepositoryName(repository);
    Job importJob = new WorkspaceJob(MessageFormat.format(
        UIText.GitCloneWizard_jobImportProjects, repoName)) {

      public IStatus runInWorkspace(IProgressMonitor monitor) {
        List<File> files = new ArrayList<File>();
        ProjectUtil.findProjectFiles(files, repository.getWorkTree(),
            true, monitor);
        if (files.isEmpty())
          return Status.OK_STATUS;

        Set<ProjectRecord> records = new LinkedHashSet<ProjectRecord>();
        for (File file : files)
          records.add(new ProjectRecord(file));
        try {
          ProjectUtils.createProjects(records, sets, monitor);
        } catch (InvocationTargetException e) {
          Activator.logError(e.getLocalizedMessage(), e);
        } catch (InterruptedException e) {
          Activator.logError(e.getLocalizedMessage(), e);
        }
        return Status.OK_STATUS;
      }
    };
    importJob.schedule();
  }

  /**
   * @param container
   * @param repositoryInfo
   */
  public void runCloneOperation(IWizardContainer container, final GitRepositoryInfo repositoryInfo) {
    try {
      container.run(true, true, new IRunnableWithProgress() {
        public void run(IProgressMonitor monitor)
            throws InvocationTargetException, InterruptedException {
          executeCloneOperation(cloneOperation, repositoryInfo, monitor);
        }
      });
    } catch (InvocationTargetException e) {
      Activator.handleError(UIText.GitCloneWizard_failed, e.getCause(),
          true);
    } catch (InterruptedException e) {
      // nothing to do
    }
  }

  private void runAsJob(final URIish uri, final CloneOperation op,
      final GitRepositoryInfo repositoryInfo) {
    final Job job = new Job(NLS.bind(UIText.GitCloneWizard_jobName,
        uri.toString())) {
      @Override
      protected IStatus run(final IProgressMonitor monitor) {
        try {
          return executeCloneOperation(op, repositoryInfo, monitor);
        } catch (InterruptedException e) {
          return Status.CANCEL_STATUS;
        } catch (InvocationTargetException e) {
          Throwable thr = e.getCause();
          return new Status(IStatus.ERROR, Activator.getPluginId(),
              0, thr.getMessage(), thr);
        }
      }

      @Override
      public boolean belongsTo(Object family) {
        if (JobFamilies.CLONE.equals(family))
          return true;
        return super.belongsTo(family);
      }
    };
    job.setUser(true);
    job.schedule();
  }

  private IStatus executeCloneOperation(final CloneOperation op,
      final GitRepositoryInfo repositoryInfo,
      final IProgressMonitor monitor) throws InvocationTargetException,
      InterruptedException {

    final RepositoryUtil util = Activator.getDefault().getRepositoryUtil();

    op.run(monitor);
    util.addConfiguredRepository(op.getGitDir());
    try {
      if (repositoryInfo.shouldSaveCredentialsInSecureStore())
        SecureStoreUtils.storeCredentials(repositoryInfo.getCredentials(),
            new URIish(repositoryInfo.getCloneUri()));
    } catch (Exception e) {
      Activator.error(e.getMessage(), e);
    }
    return Status.OK_STATUS;
  }

  /**
   * @param newValue
   *            if true the clone wizard just creates a clone operation. The
   *            caller has to run this operation using runCloneOperation. If
   *            false the clone operation is performed using a job.
   */
  public void setCallerRunsCloneOperation(boolean newValue) {
    callerRunsCloneOperation = newValue;
  }

}
TOP

Related Classes of org.eclipse.egit.ui.internal.clone.AbstractGitCloneWizard

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.