blob: 6c76d37a514976b668d5478208d91d4abc3dbe82 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2015, Obeo.
*
* 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.emf.compare.egit.internal.merge;
//CHECKSTYLE:OFF
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.egit.core.Activator;
import org.eclipse.egit.core.internal.CoreText;
import org.eclipse.egit.core.internal.storage.WorkspaceFileRevision;
import org.eclipse.egit.core.synchronize.GitRemoteResource;
import org.eclipse.emf.compare.egit.internal.storage.GitLocalResourceVariant;
import org.eclipse.osgi.util.NLS;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.diff.IDiff;
import org.eclipse.team.core.diff.ITwoWayDiff;
import org.eclipse.team.core.diff.provider.ThreeWayDiff;
import org.eclipse.team.core.history.IFileRevision;
import org.eclipse.team.core.mapping.provider.ResourceDiff;
import org.eclipse.team.core.synchronize.SyncInfo;
import org.eclipse.team.core.variants.IResourceVariant;
import org.eclipse.team.internal.core.mapping.ResourceVariantFileRevision;
import org.eclipse.team.internal.core.mapping.SyncInfoToDiffConverter;
/**
* The default implementation of SyncInfoToDiffConverter uses inaccurate information with regards to some of
* EGit features.
* <p>
* SyncInfoToDiffConverter#asFileRevision(IResourceVariant) is called when a user double-clicks a revision
* from the synchronize view (among others). However, the default implementation returns an IFileRevision with
* no comment, author or timestamp information.
* </p>
* <p>
* SyncInfoToDiffConverter#getDeltaFor(SyncInfo) had been originally thought by Team to be used for
* synchronizations that considered local changes. This is not always the case with EGit. For example, a user
* might try and compare two refs together from the Git repository explorer (right click > synchronize with
* each other). In such a case, the local files must not be taken into account.
* </p>
* <p>
* Most of the private methods here were copy/pasted from the super implementation.
* </p>
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
@SuppressWarnings("restriction")
public class GitSyncInfoToDiffConverter extends SyncInfoToDiffConverter {
private GitResourceVariantTreeProvider variantTreeProvider;
/**
* Creates our diff converter given the provider of our variant trees.
*
* @param variantTreeProvider
* Provides the resource variant trees that should be used to query file revisions.
*/
public GitSyncInfoToDiffConverter(GitResourceVariantTreeProvider variantTreeProvider) {
this.variantTreeProvider = variantTreeProvider;
}
@Override
public IDiff getDeltaFor(SyncInfo info) {
if (info.getComparator().isThreeWay()) {
ITwoWayDiff local = getLocalDelta(info);
ITwoWayDiff remote = getRemoteDelta(info);
return new ThreeWayDiff(local, remote);
} else {
if (info.getKind() != SyncInfo.IN_SYNC) {
IResourceVariant remote = info.getRemote();
IResource local = info.getLocal();
int kind;
if (remote == null) {
kind = IDiff.REMOVE;
} else if (!local.exists()) {
kind = IDiff.ADD;
} else {
kind = IDiff.CHANGE;
}
if (local.getType() == IResource.FILE) {
IFileRevision after = asFileState(remote);
IFileRevision before = getLocalFileRevision((IFile)local);
return new ResourceDiff(info.getLocal(), kind, 0, before, after);
}
// For folders, we don't need file states
return new ResourceDiff(info.getLocal(), kind);
}
return null;
}
}
private ITwoWayDiff getLocalDelta(SyncInfo info) {
int direction = SyncInfo.getDirection(info.getKind());
if (direction == SyncInfo.OUTGOING || direction == SyncInfo.CONFLICTING) {
IResourceVariant ancestor = info.getBase();
IResource local = info.getLocal();
int kind;
if (ancestor == null) {
kind = IDiff.ADD;
} else if (!local.exists()) {
kind = IDiff.REMOVE;
} else {
kind = IDiff.CHANGE;
}
if (local.getType() == IResource.FILE) {
IFileRevision before = asFileState(ancestor);
IFileRevision after = getLocalFileRevision((IFile)local);
return new ResourceDiff(info.getLocal(), kind, 0, before, after);
}
// For folders, we don't need file states
return new ResourceDiff(info.getLocal(), kind);
}
return null;
}
/**
* Returns a file revision from the source tree for this local file.
*
* @param local
* The local file.
* @return The file revision that should be considered for the local (left) side of a delta
*/
public IFileRevision getLocalFileRevision(IFile local) {
try {
return asFileState(variantTreeProvider.getSourceTree().getResourceVariant(local));
} catch (TeamException e) {
String error = NLS.bind(CoreText.GitResourceVariantTreeSubscriber_CouldNotFindSourceVariant,
local.getName());
Activator.logError(error, e);
// fall back to the working tree version
return WorkspaceFileRevision.forFile(variantTreeProvider.getRepository(), local);
}
}
/*
* copied from the private implementation in SyncInfoToDiffConverter
*/
private ITwoWayDiff getRemoteDelta(SyncInfo info) {
int direction = SyncInfo.getDirection(info.getKind());
if (direction == SyncInfo.INCOMING || direction == SyncInfo.CONFLICTING) {
IResourceVariant ancestor = info.getBase();
IResourceVariant remote = info.getRemote();
int kind;
if (ancestor == null) {
kind = IDiff.ADD;
} else if (remote == null) {
kind = IDiff.REMOVE;
} else {
kind = IDiff.CHANGE;
}
// For folders, we don't need file states
if (info.getLocal().getType() == IResource.FILE) {
IFileRevision before = asFileState(ancestor);
IFileRevision after = asFileState(remote);
return new ResourceDiff(info.getLocal(), kind, 0, before, after);
}
return new ResourceDiff(info.getLocal(), kind);
}
return null;
}
/*
* copied from the private implementation in SyncInfoToDiffConverter
*/
private IFileRevision asFileState(final IResourceVariant variant) {
if (variant == null) {
return null;
} else if (variant instanceof GitLocalResourceVariant) {
return WorkspaceFileRevision.forFile(variantTreeProvider.getRepository(),
((GitLocalResourceVariant)variant).getResource());
}
return asFileRevision(variant);
}
@Override
protected ResourceVariantFileRevision asFileRevision(IResourceVariant variant) {
if (variant instanceof GitRemoteResource) {
return new GitResourceVariantFileRevision((GitRemoteResource)variant);
}
return new ResourceVariantFileRevision(variant);
}
}
// CHECKSTYLE:ON