All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jgit.transport.PushProcess Maven / Gradle / Ivy

There is a newer version: 2.2.0-build001
Show newest version
/*
 * Copyright (C) 2008, Marek Zawirski 
 * and other copyright owners as documented in the project's IP log.
 *
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Distribution License v1.0 which
 * accompanies this distribution, is reproduced below, and is
 * available at http://www.eclipse.org/org/documents/edl-v10.php
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following
 *   disclaimer in the documentation and/or other materials provided
 *   with the distribution.
 *
 * - Neither the name of the Eclipse Foundation, Inc. nor the
 *   names of its contributors may be used to endorse or promote
 *   products derived from this software without specific prior
 *   written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.eclipse.jgit.transport;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.RemoteRefUpdate.Status;

/**
 * Class performing push operation on remote repository.
 *
 * @see Transport#push(ProgressMonitor, Collection)
 */
class PushProcess {
	/** Task name for {@link ProgressMonitor} used during opening connection. */
	static final String PROGRESS_OPENING_CONNECTION = JGitText.get().openingConnection;

	/** Transport used to perform this operation. */
	private final Transport transport;

	/** Push operation connection created to perform this operation */
	private PushConnection connection;

	/** Refs to update on remote side. */
	private final Map toPush;

	/** Revision walker for checking some updates properties. */
	private final RevWalk walker;

	/**
	 * Create process for specified transport and refs updates specification.
	 *
	 * @param transport
	 *            transport between remote and local repository, used to create
	 *            connection.
	 * @param toPush
	 *            specification of refs updates (and local tracking branches).
	 * @throws TransportException
	 */
	PushProcess(final Transport transport,
			final Collection toPush) throws TransportException {
		this.walker = new RevWalk(transport.local);
		this.transport = transport;
		this.toPush = new HashMap();
		for (final RemoteRefUpdate rru : toPush) {
			if (this.toPush.put(rru.getRemoteName(), rru) != null)
				throw new TransportException(MessageFormat.format(
						JGitText.get().duplicateRemoteRefUpdateIsIllegal, rru.getRemoteName()));
		}
	}

	/**
	 * Perform push operation between local and remote repository - set remote
	 * refs appropriately, send needed objects and update local tracking refs.
	 * 

* When {@link Transport#isDryRun()} is true, result of this operation is * just estimation of real operation result, no real action is performed. * * @param monitor * progress monitor used for feedback about operation. * @return result of push operation with complete status description. * @throws NotSupportedException * when push operation is not supported by provided transport. * @throws TransportException * when some error occurred during operation, like I/O, protocol * error, or local database consistency error. */ PushResult execute(final ProgressMonitor monitor) throws NotSupportedException, TransportException { try { monitor.beginTask(PROGRESS_OPENING_CONNECTION, ProgressMonitor.UNKNOWN); final PushResult res = new PushResult(); connection = transport.openPush(); try { res.setAdvertisedRefs(transport.getURI(), connection .getRefsMap()); res.setRemoteUpdates(toPush); monitor.endTask(); final Map preprocessed = prepareRemoteUpdates(); if (transport.isDryRun()) modifyUpdatesForDryRun(); else if (!preprocessed.isEmpty()) connection.push(monitor, preprocessed); } finally { connection.close(); res.addMessages(connection.getMessages()); } if (!transport.isDryRun()) updateTrackingRefs(); for (final RemoteRefUpdate rru : toPush.values()) { final TrackingRefUpdate tru = rru.getTrackingRefUpdate(); if (tru != null) res.add(tru); } return res; } finally { walker.release(); } } private Map prepareRemoteUpdates() throws TransportException { final Map result = new HashMap(); for (final RemoteRefUpdate rru : toPush.values()) { final Ref advertisedRef = connection.getRef(rru.getRemoteName()); final ObjectId advertisedOld = (advertisedRef == null ? ObjectId .zeroId() : advertisedRef.getObjectId()); if (rru.getNewObjectId().equals(advertisedOld)) { if (rru.isDelete()) { // ref does exist neither locally nor remotely rru.setStatus(Status.NON_EXISTING); } else { // same object - nothing to do rru.setStatus(Status.UP_TO_DATE); } continue; } // caller has explicitly specified expected old object id, while it // has been changed in the mean time - reject if (rru.isExpectingOldObjectId() && !rru.getExpectedOldObjectId().equals(advertisedOld)) { rru.setStatus(Status.REJECTED_REMOTE_CHANGED); continue; } // create ref (hasn't existed on remote side) and delete ref // are always fast-forward commands, feasible at this level if (advertisedOld.equals(ObjectId.zeroId()) || rru.isDelete()) { rru.setFastForward(true); result.put(rru.getRemoteName(), rru); continue; } // check for fast-forward: // - both old and new ref must point to commits, AND // - both of them must be known for us, exist in repository, AND // - old commit must be ancestor of new commit boolean fastForward = true; try { RevObject oldRev = walker.parseAny(advertisedOld); final RevObject newRev = walker.parseAny(rru.getNewObjectId()); if (!(oldRev instanceof RevCommit) || !(newRev instanceof RevCommit) || !walker.isMergedInto((RevCommit) oldRev, (RevCommit) newRev)) fastForward = false; } catch (MissingObjectException x) { fastForward = false; } catch (Exception x) { throw new TransportException(transport.getURI(), MessageFormat.format( JGitText.get().readingObjectsFromLocalRepositoryFailed, x.getMessage()), x); } rru.setFastForward(fastForward); if (!fastForward && !rru.isForceUpdate()) rru.setStatus(Status.REJECTED_NONFASTFORWARD); else result.put(rru.getRemoteName(), rru); } return result; } private void modifyUpdatesForDryRun() { for (final RemoteRefUpdate rru : toPush.values()) if (rru.getStatus() == Status.NOT_ATTEMPTED) rru.setStatus(Status.OK); } private void updateTrackingRefs() { for (final RemoteRefUpdate rru : toPush.values()) { final Status status = rru.getStatus(); if (rru.hasTrackingRefUpdate() && (status == Status.UP_TO_DATE || status == Status.OK)) { // update local tracking branch only when there is a chance that // it has changed; this is possible for: // -updated (OK) status, // -up to date (UP_TO_DATE) status try { rru.updateTrackingRef(walker); } catch (IOException e) { // ignore as RefUpdate has stored I/O error status } } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy