Package org.eclipse.egit.core.op

Source Code of org.eclipse.egit.core.op.PushOperation

/*******************************************************************************
* Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
* Copyright (C) 2011, Mathias Kinzler <mathias.kinzler@sap.com>
* Copyright (C) 2012, Robin Stocker <robin@nibor.org>
*
* 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.core.op;

import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.util.Collection;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.egit.core.Activator;
import org.eclipse.egit.core.EclipseGitProgressTransformer;
import org.eclipse.egit.core.internal.CoreText;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.osgi.util.NLS;

/**
* Push operation: pushing from local repository to one or many remote ones.
*/
public class PushOperation {
  private static final int WORK_UNITS_PER_TRANSPORT = 10;

  private final Repository localDb;

  private final PushOperationSpecification specification;

  private final boolean dryRun;

  private final String remoteName;

  private final int timeout;

  private OutputStream out;

  private PushOperationResult operationResult;

  private CredentialsProvider credentialsProvider;

  /**
   * Create push operation for provided specification.
   *
   * @param localDb
   *            local repository.
   * @param specification
   *            specification of ref updates for remote repositories.
   * @param dryRun
   *            true if push operation should just check for possible result
   *            and not really update remote refs, false otherwise - when push
   *            should act normally.
   * @param timeout
   *            the timeout in seconds (0 for no timeout)
   */
  public PushOperation(final Repository localDb,
      final PushOperationSpecification specification,
      final boolean dryRun, int timeout) {
    this(localDb, null, specification, dryRun, timeout);
  }

  /**
   * Creates a push operation for a remote configuration.
   *
   * @param localDb
   * @param remoteName
   * @param dryRun
   * @param timeout
   */
  public PushOperation(final Repository localDb, final String remoteName,
      final boolean dryRun, int timeout) {
    this(localDb, remoteName, null, dryRun, timeout);
  }

  private PushOperation(final Repository localDb, final String remoteName,
      PushOperationSpecification specification, final boolean dryRun,
      int timeout) {
    this.localDb = localDb;
    this.specification = specification;
    this.dryRun = dryRun;
    this.remoteName = remoteName;
    this.timeout = timeout;
  }

  /**
   * @param credentialsProvider
   */
  public void setCredentialsProvider(CredentialsProvider credentialsProvider) {
    this.credentialsProvider = credentialsProvider;
  }

  /**
   * @return the operation's credentials provider
   */
  public CredentialsProvider getCredentialsProvider() {
    return credentialsProvider;
  }

  /**
   * @return push operation result
   */
  public PushOperationResult getOperationResult() {
    if (operationResult == null)
      throw new IllegalStateException(CoreText.OperationNotYetExecuted);
    return operationResult;
  }

  /**
   * @return operation specification, as provided in constructor (may be
   *         <code>null</code>)
   */
  public PushOperationSpecification getSpecification() {
    return specification;
  }

  /**
   * @param actMonitor
   *            may be <code>null</code> if progress monitoring is not desired
   * @throws InvocationTargetException
   *             not really used: failure is communicated via the result (see
   *             {@link #getOperationResult()})
   */
  public void run(IProgressMonitor actMonitor)
      throws InvocationTargetException {

    if (operationResult != null)
      throw new IllegalStateException(CoreText.OperationAlreadyExecuted);

    if (this.specification != null)
      for (URIish uri : this.specification.getURIs()) {
        for (RemoteRefUpdate update : this.specification
            .getRefUpdates(uri))
          if (update.getStatus() != Status.NOT_ATTEMPTED)
            throw new IllegalStateException(
                CoreText.RemoteRefUpdateCantBeReused);
      }
    IProgressMonitor monitor;
    if (actMonitor == null)
      monitor = new NullProgressMonitor();
    else
      monitor = actMonitor;

    final int totalWork;
    if (specification != null)
      totalWork = specification.getURIsNumber()
          * WORK_UNITS_PER_TRANSPORT;
    else
      totalWork = 1;
    if (dryRun)
      monitor.beginTask(CoreText.PushOperation_taskNameDryRun, totalWork);
    else
      monitor.beginTask(CoreText.PushOperation_taskNameNormalRun,
          totalWork);

    operationResult = new PushOperationResult();
    Git git = new Git(localDb);

    if (specification != null)
      for (final URIish uri : specification.getURIs()) {
        final SubProgressMonitor subMonitor = new SubProgressMonitor(
            monitor, WORK_UNITS_PER_TRANSPORT,
            SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);

        try {
          if (monitor.isCanceled()) {
            operationResult.addOperationResult(uri,
                CoreText.PushOperation_resultCancelled);
            continue;
          }

          Collection<RemoteRefUpdate> refUpdates = specification.getRefUpdates(uri);
          final EclipseGitProgressTransformer gitSubMonitor = new EclipseGitProgressTransformer(
              subMonitor);

          try {
            Transport transport = Transport.open(localDb, uri);
            transport.setDryRun(dryRun);
            transport.setTimeout(timeout);
            if (credentialsProvider != null)
              transport.setCredentialsProvider(credentialsProvider);
            PushResult result = transport.push(gitSubMonitor, refUpdates, out);

            operationResult.addOperationResult(result.getURI(), result);
            specification.addURIRefUpdates(result.getURI(), result.getRemoteUpdates());
          } catch (JGitInternalException e) {
            String errorMessage = e.getCause() != null ? e
                .getCause().getMessage() : e.getMessage();
            String userMessage = NLS.bind(
                    CoreText.PushOperation_InternalExceptionOccurredMessage,
                    errorMessage);
            handleException(uri, e, userMessage);
          } catch (Exception e) {
            handleException(uri, e, e.getMessage());
          }

          monitor.worked(WORK_UNITS_PER_TRANSPORT);
        } finally {
          // Dirty trick to get things always working.
          subMonitor.beginTask("", WORK_UNITS_PER_TRANSPORT); //$NON-NLS-1$
          subMonitor.done();
          subMonitor.done();
        }
      }
    else {
      final EclipseGitProgressTransformer gitMonitor = new EclipseGitProgressTransformer(
          monitor);
      try {
        Iterable<PushResult> results = git.push().setRemote(
            remoteName).setDryRun(dryRun).setTimeout(timeout)
            .setProgressMonitor(gitMonitor).setCredentialsProvider(
credentialsProvider)
            .setOutputStream(out).call();
        for (PushResult result : results) {
          operationResult.addOperationResult(result.getURI(), result);
        }
      } catch (JGitInternalException e) {
        String errorMessage = e.getCause() != null ? e.getCause()
            .getMessage() : e.getMessage();
        String userMessage = NLS.bind(
            CoreText.PushOperation_InternalExceptionOccurredMessage,
            errorMessage);
        URIish uri = getPushURIForErrorHandling();
        handleException(uri, e, userMessage);
      } catch (Exception e) {
        URIish uri = getPushURIForErrorHandling();
        handleException(uri, e, e.getMessage());
      }
    }
    monitor.done();
  }

  private void handleException(final URIish uri, Exception e,
      String userMessage) {
    String uriString;
    if (uri != null) {
      operationResult.addOperationResult(uri, userMessage);
      uriString = uri.toString();
    } else
      uriString = "retrieving URI failed"; //$NON-NLS-1$

    String userMessageForUri = NLS.bind(
        CoreText.PushOperation_ExceptionOccurredDuringPushOnUriMessage,
        uriString, userMessage);
    Activator.logError(userMessageForUri, e);
  }

  private URIish getPushURIForErrorHandling() {
    RemoteConfig rc = null;
    try {
      rc = new RemoteConfig(localDb.getConfig(), remoteName);
      return rc.getPushURIs().isEmpty() ? rc.getURIs().get(0) : rc
          .getPushURIs().get(0);
    } catch (URISyntaxException e) {
      // should not happen
      Activator.logError("Reading RemoteConfig failed", e); //$NON-NLS-1$
      return null;
    }
  }

  /**
   * Sets the output stream this operation will write sideband messages to.
   *
   * @param out
   *            the outputstream to write to
   * @since 3.0
   */
  public void setOutputStream(OutputStream out) {
    this.out = out;
  }
}
TOP

Related Classes of org.eclipse.egit.core.op.PushOperation

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.