blob: f1cdba5f072b31732c3cf95d025bc0017b3fe343 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ccvs.ui.operations;
import java.util.*;
import org.eclipse.compare.CompareUI;
import org.eclipse.core.runtime.*;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.internal.ccvs.core.*;
import org.eclipse.team.internal.ccvs.core.client.*;
import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption;
import org.eclipse.team.internal.ccvs.core.client.listeners.RDiffSummaryListener;
import org.eclipse.team.internal.ccvs.core.resources.*;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
import org.eclipse.team.internal.ccvs.core.util.Assert;
import org.eclipse.team.internal.ccvs.ui.*;
import org.eclipse.team.internal.ccvs.ui.Policy;
import org.eclipse.team.internal.ui.TeamUIPlugin;
import org.eclipse.ui.IWorkbenchPage;
/**
* Compare the two versions of given remote folders obtained from the two tags specified.
*/
public class RemoteCompareOperation extends RemoteOperation implements RDiffSummaryListener.IFileDiffListener {
private CVSTag left;
private CVSTag right;
private RemoteFolderTree leftTree, rightTree;
public static CVSTag getTag(ICVSRemoteResource resource) throws CVSException {
CVSTag tag = null;
try {
if (resource.isContainer()) {
tag = ((ICVSRemoteFolder)resource).getTag();
} else {
ICVSRemoteFile file = (ICVSRemoteFile)resource;
String revision = file.getRevision();
if (revision.equals(ResourceSyncInfo.ADDED_REVISION)) {
ResourceSyncInfo info =file.getSyncInfo();
if (info != null) tag = info.getTag();
} else {
tag = new CVSTag(revision, CVSTag.VERSION);
}
}
} catch (TeamException e) {
throw CVSException.wrapException(e);
}
if (tag == null) tag = CVSTag.DEFAULT;
return tag;
}
/**
* Compare two versions of the given remote resource.
* @param shell
* @param remoteResource the resource whose tags are being compared
* @param left the earlier tag (not null)
* @param right the later tag (not null)
*/
public RemoteCompareOperation(Shell shell, ICVSRemoteResource remoteResource, CVSTag tag) {
super(shell, new ICVSRemoteResource[] {remoteResource});
Assert.isNotNull(tag);
this.right = tag;
try {
this.left = getTag(remoteResource);
} catch (CVSException e) {
// This shouldn't happen but log it just in case
CVSProviderPlugin.log(e);
}
if (this.left == null) {
this.left = CVSTag.DEFAULT;
}
}
/*
* This command only supports the use of a single resource
*/
private ICVSRemoteResource getRemoteResource() {
return getRemoteResources()[0];
}
/* (non-Javadoc)
* @see org.eclipse.team.internal.ccvs.ui.operations.CVSOperation#execute(org.eclipse.core.runtime.IProgressMonitor)
*/
protected void execute(IProgressMonitor monitor) throws CVSException {
leftTree = rightTree = null;
boolean fetchContents = CVSUIPlugin.getPlugin().getPluginPreferences().getBoolean(ICVSUIConstants.PREF_CONSIDER_CONTENTS);
monitor.beginTask(getTaskName(), 50 + (fetchContents ? 100 : 0));
try {
ICVSRemoteResource resource = getRemoteResource();
IStatus status = buildTrees(resource, Policy.subMonitorFor(monitor, 50));
if (status.isOK() && fetchContents) {
String[] overlappingFilePaths = getOverlappingFilePaths();
if (overlappingFilePaths.length > 0) {
fetchFileContents(leftTree, overlappingFilePaths, Policy.subMonitorFor(monitor, 50));
fetchFileContents(rightTree, overlappingFilePaths, Policy.subMonitorFor(monitor, 50));
}
}
collectStatus(status);
openCompareEditor(leftTree, rightTree);
} finally {
monitor.done();
}
}
private String[] getOverlappingFilePaths() {
String[] leftFiles = getFilePaths(leftTree);
String[] rightFiles = getFilePaths(rightTree);
Set set = new HashSet();
for (int i = 0; i < rightFiles.length; i++) {
String rightFile = rightFiles[i];
for (int j = 0; j < leftFiles.length; j++) {
String leftFile = leftFiles[j];
if (leftFile.equals(rightFile)) {
set.add(leftFile);
}
}
}
return (String[]) set.toArray(new String[set.size()]);
}
private void fetchFileContents(RemoteFolderTree tree, String[] overlappingFilePaths, IProgressMonitor monitor) throws CVSException {
FileContentCachingService.fetchFileContents(tree, overlappingFilePaths, monitor);
}
private String[] getFilePaths(RemoteFolderTree tree) {
ICVSRemoteResource[] children = tree.getChildren();
List result = new ArrayList();
for (int i = 0; i < children.length; i++) {
ICVSRemoteResource resource = children[i];
if (resource.isContainer()) {
result.addAll(Arrays.asList(getFilePaths((RemoteFolderTree)resource)));
} else {
result.add(resource.getRepositoryRelativePath());
}
}
return (String[]) result.toArray(new String[result.size()]);
}
/*
* Build the two trees uses the reponses from "cvs rdiff -s ...".
*/
private IStatus buildTrees(ICVSRemoteResource resource, IProgressMonitor monitor) throws CVSException {
// Initialize the resulting trees
leftTree = new RemoteFolderTree(null, resource.getRepository(), ICVSRemoteFolder.REPOSITORY_ROOT_FOLDER_NAME, left);
leftTree.setChildren(new ICVSRemoteResource[0]);
rightTree = new RemoteFolderTree(null, resource.getRepository(), ICVSRemoteFolder.REPOSITORY_ROOT_FOLDER_NAME, right);
rightTree.setChildren(new ICVSRemoteResource[0]);
Command.QuietOption oldOption= CVSProviderPlugin.getPlugin().getQuietness();
Session session = new Session(resource.getRepository(), leftTree, false);
try {
monitor.beginTask(getTaskName(), 100);
CVSProviderPlugin.getPlugin().setQuietness(Command.VERBOSE);
session.open(Policy.subMonitorFor(monitor, 10));
IStatus status = Command.RDIFF.execute(session,
Command.NO_GLOBAL_OPTIONS,
getLocalOptions(),
new ICVSResource[] { resource },
new RDiffSummaryListener(this),
Policy.subMonitorFor(monitor, 90));
return status;
} finally {
try {
session.close();
} finally {
CVSProviderPlugin.getPlugin().setQuietness(oldOption);
}
monitor.done();
}
}
private LocalOption[] getLocalOptions() {
return new LocalOption[] {RDiff.SUMMARY, RDiff.makeTagOption(left), RDiff.makeTagOption(right)};
}
/* (non-Javadoc)
* @see org.eclipse.team.internal.ccvs.ui.operations.CVSOperation#getTaskName()
*/
protected String getTaskName() {
return Policy.bind("RemoteCompareOperation.0", new Object[] {left.getName(), right.getName(), getRemoteResource().getRepositoryRelativePath()}); //$NON-NLS-1$
}
/* (non-Javadoc)
* @see org.eclipse.team.internal.ccvs.core.client.listeners.RDiffSummaryListener.IFileDiffListener#fileDiff(java.lang.String, java.lang.String, java.lang.String)
*/
public void fileDiff(String remoteFilePath, String leftRevision, String rightRevision) {
try {
addFile(rightTree, right, new Path(remoteFilePath), rightRevision);
} catch (CVSException e) {
CVSUIPlugin.log(e);
}
try {
addFile(leftTree, left, new Path(remoteFilePath), leftRevision);
} catch (CVSException e) {
CVSUIPlugin.log(e);
}
}
/* (non-Javadoc)
* @see org.eclipse.team.internal.ccvs.core.client.listeners.RDiffSummaryListener.IFileDiffListener#newFile(java.lang.String, java.lang.String)
*/
public void newFile(String remoteFilePath, String rightRevision) {
try {
addFile(rightTree, right, new Path(remoteFilePath), rightRevision);
} catch (CVSException e) {
CVSUIPlugin.log(e);
}
}
/* (non-Javadoc)
* @see org.eclipse.team.internal.ccvs.core.client.listeners.RDiffSummaryListener.IFileDiffListener#deletedFile(java.lang.String)
*/
public void deletedFile(String remoteFilePath, String leftRevision) {
// The leftRevision may be null in which case the tag is used
try {
addFile(leftTree, left, new Path(remoteFilePath), leftRevision);
} catch (CVSException e) {
CVSUIPlugin.log(e);
}
}
/* (non-Javadoc)
* @see org.eclipse.team.internal.ccvs.core.client.listeners.RDiffSummaryListener.IFileDiffListener#directory(java.lang.String)
*/
public void directory(String remoteFolderPath) {
try {
getFolder(leftTree, left, new Path(remoteFolderPath), Path.EMPTY);
} catch (CVSException e) {
CVSUIPlugin.log(e);
}
try {
getFolder(rightTree, right, new Path(remoteFolderPath), Path.EMPTY);
} catch (CVSException e) {
CVSUIPlugin.log(e);
}
}
/*
* Get the folder at the given path in the given tree, creating any missing folders as needed.
*/
private ICVSRemoteFolder getFolder(RemoteFolderTree tree, CVSTag tag, IPath remoteFolderPath, IPath parentPath) throws CVSException {
if (remoteFolderPath.segmentCount() == 0) return tree;
String name = remoteFolderPath.segment(0);
ICVSResource child;
IPath childPath = parentPath.append(name);
if (tree.childExists(name)) {
child = tree.getChild(name);
} else {
child = new RemoteFolderTree(tree, tree.getRepository(), childPath.toString(), tag);
((RemoteFolderTree)child).setChildren(new ICVSRemoteResource[0]);
addChild(tree, (ICVSRemoteResource)child);
}
return getFolder((RemoteFolderTree)child, tag, remoteFolderPath.removeFirstSegments(1), childPath);
}
private void addChild(RemoteFolderTree tree, ICVSRemoteResource resource) {
ICVSRemoteResource[] children = tree.getChildren();
ICVSRemoteResource[] newChildren;
if (children == null) {
newChildren = new ICVSRemoteResource[] { resource };
} else {
newChildren = new ICVSRemoteResource[children.length + 1];
System.arraycopy(children, 0, newChildren, 0, children.length);
newChildren[children.length] = resource;
}
tree.setChildren(newChildren);
}
private void addFile(RemoteFolderTree tree, CVSTag tag, Path filePath, String revision) throws CVSException {
RemoteFolderTree parent = (RemoteFolderTree)getFolder(tree, tag, filePath.removeLastSegments(1), Path.EMPTY);
String name = filePath.lastSegment();
ICVSRemoteFile file = new RemoteFile(parent, 0, name, revision, null, tag);
addChild(parent, file);
}
/*
* Only intended to be overridden by test cases.
*/
protected void openCompareEditor(final ICVSRemoteFolder leftTree, final ICVSRemoteFolder rightTree) {
if (leftTree == null || rightTree == null) return;
Display.getDefault().asyncExec(new Runnable() {
public void run() {
CompareUI.openCompareEditorOnPage(
new CVSCompareEditorInput(new ResourceEditionNode(leftTree), new ResourceEditionNode(rightTree)),
getTargetPage());
}
});
}
protected IWorkbenchPage getTargetPage() {
return TeamUIPlugin.getActivePage();
}
}