blob: 0bfc4c02c57a9c6e560a6bdedc9354ae1326d67d [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 java.util.Arrays;
import java.util.Set;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.egit.core.internal.CoreText;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.diff.IDiff;
import org.eclipse.team.core.synchronize.SyncInfo;
import org.eclipse.team.core.variants.IResourceVariant;
import org.eclipse.team.core.variants.IResourceVariantComparator;
import org.eclipse.team.core.variants.IResourceVariantTree;
import org.eclipse.team.core.variants.ResourceVariantTreeSubscriber;
import org.eclipse.team.internal.core.mapping.SyncInfoToDiffConverter;
/**
* This implementation of a {@link ResourceVariantTreeSubscriber} takes its input from a
* {@link GitResourceVariantTreeProvider}.
* <p>
* This allows us to hijack all calls from the default subscriber for "local" resources to our actual source
* tree, which could be the local working directory as well as it could be a branch.
* </p>
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
@SuppressWarnings("restriction")
public class GitResourceVariantTreeSubscriber extends ResourceVariantTreeSubscriber {
private GitResourceVariantTreeProvider variantTreeProvider;
private final SyncInfoToDiffConverter syncInfoConverter;
private final IResourceVariantComparator comparator;
/**
* @param variantTreeProvider
* The instance that will provide the base, source and remote trees to this subscriber.
*/
public GitResourceVariantTreeSubscriber(GitResourceVariantTreeProvider variantTreeProvider) {
this.variantTreeProvider = variantTreeProvider;
syncInfoConverter = new GitSyncInfoToDiffConverter(variantTreeProvider);
comparator = new GitVariantComparator(variantTreeProvider.getSourceTree());
}
@Override
public IResourceVariantTree getBaseTree() {
return variantTreeProvider.getBaseTree();
}
@Override
public IResourceVariantTree getRemoteTree() {
return variantTreeProvider.getRemoteTree();
}
/**
* @return the source resource variant tree.
*/
public IResourceVariantTree getSourceTree() {
return variantTreeProvider.getSourceTree();
}
@Override
public IDiff getDiff(IResource resource) throws CoreException {
final SyncInfo info = getSyncInfo(resource);
if (info == null || info.getKind() == SyncInfo.IN_SYNC) {
return null;
}
return syncInfoConverter.getDeltaFor(info);
}
@Override
public SyncInfo getSyncInfo(IResource resource) throws TeamException {
// Overridden here to properly catch and re-throw the forwarded
// TeamException
try {
return super.getSyncInfo(resource);
} catch (ForwardedTeamException e) {
throw (TeamException)e.getCause();
}
}
@Override
public String getName() {
return CoreText.GitResourceVariantTreeSubscriber_name;
}
@Override
public boolean isSupervised(IResource resource) throws TeamException {
return variantTreeProvider.getKnownResources().contains(resource);
}
@Override
public IResource[] roots() {
final Set<IResource> roots = variantTreeProvider.getRoots();
return roots.toArray(new IResource[roots.size()]);
}
@Override
public IResourceVariantComparator getResourceComparator() {
return comparator;
}
/**
* We have a source tree whereas Team only knows about "local" files. This will always use said
* {@link #oursTree source tree} when comparing variants.
*/
private static class GitVariantComparator implements IResourceVariantComparator {
private final IResourceVariantTree oursTree;
public GitVariantComparator(IResourceVariantTree oursTree) {
this.oursTree = oursTree;
}
public boolean compare(IResource local, IResourceVariant remote) {
try {
final IResourceVariant oursVariant = oursTree.getResourceVariant(local);
if (oursVariant == null) {
return remote == null;
}
return compare(oursVariant, remote);
} catch (TeamException e) {
// We can't throw the TeamException from here, but we can't let
// the comparison go through either.
// This is only called from "getSyncInfo", we'll forward this
// exception and rethrow it from there.
throw new ForwardedTeamException(e);
}
}
public boolean compare(IResourceVariant base, IResourceVariant remote) {
return Arrays.equals(base.asBytes(), remote.asBytes());
}
public boolean isThreeWay() {
return true;
}
}
/**
* This should never be thrown outside of this class. The only purpose of this exception is to encapsulate
* a TeamException where it cannot be thrown.
*/
private static class ForwardedTeamException extends RuntimeException {
/** Generated SUID. */
private static final long serialVersionUID = 4074010396155542178L;
public ForwardedTeamException(TeamException e) {
super(e);
}
}
}
// CHECKSTYLE:ON