blob: c9b134a8c19f3633bfc3781b15f2c08754ac59ed [file] [log] [blame]
package org.eclipse.team.internal.ccvs.core.util;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.xerces.parsers.SAXParser;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.internal.ccvs.core.CVSTeamProvider;
import org.eclipse.team.internal.ccvs.core.ICVSFile;
import org.eclipse.team.internal.ccvs.core.ICVSFolder;
import org.eclipse.team.internal.ccvs.core.Policy;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* This class handles the updating of the .vcm_meta file in projects managed by the CVSTeamProvider.
*
* It does so by listening to deltas on the project description and the .vcm_meta file itself.
*
*/
public class ProjectDescriptionManager implements IResourceChangeListener {
public final static IPath PROJECT_DESCRIPTION_PATH = new Path(".vcm_meta"); //$NON-NLS-1$
public final static IPath CORE_PROJECT_DESCRIPTION_PATH = new Path(".project"); //$NON-NLS-1$
public final static boolean UPDATE_PROJECT_DESCRIPTION_ON_LOAD = true;
public static final String VCMMETA_MARKER = "org.eclipse.team.cvs.core.vcmmeta"; //$NON-NLS-1$
/*
* Read the project meta file into the provider description
*/
public static void readProjectDescription(IProjectDescription desc, InputStream stream) throws IOException, CVSException {
SAXParser parser = new SAXParser();
parser.setContentHandler(new ProjectDescriptionContentHandler(desc));
try {
parser.parse(new InputSource(stream));
} catch (SAXException ex) {
throw new CVSException(IStatus.ERROR, IStatus.ERROR, Policy.bind("ProjectDescriptionManager.unableToReadDescription"), ex); //$NON-NLS-1$
}
}
public static void writeProjectDescription(IProject project, IProgressMonitor progress) throws CVSException {
// generate the new contents of the project meta file into a string
ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
String newContents = null;
try {
IProjectDescription desc = project.getDescription();
ProjectDescriptionWriter.writeProjectDescription(desc, byteOutputStream);
byteOutputStream.close();
newContents = byteOutputStream.toString("UTF8"); //$NON-NLS-1$
} catch (IOException ex) {
throw CVSException.wrapException(project, Policy.bind("ProjectDescriptionManager.ioDescription"), ex); //$NON-NLS-1$
} catch (CoreException ex) {
throw CVSException.wrapException(project, Policy.bind("ProjectDescriptionManager.coreDescription"), ex); //$NON-NLS-1$
}
IFile descResource = project.getFile(PROJECT_DESCRIPTION_PATH);
if (descResource.exists()) {
// check if the existing contents are the same before rewriting
String oldContents = null;
try {
StringBuffer stringBuffer = new StringBuffer();
InputStream is = ((IFile) descResource).getContents();
byte[] buf = new byte[512];
int result = is.read(buf);
while (result != -1) {
stringBuffer.append(new String(buf, 0, result, "UTF8")); //$NON-NLS-1$
result = is.read(buf);
}
oldContents = stringBuffer.toString();
is.close();
} catch (IOException ex) {
throw CVSException.wrapException(project, Policy.bind("ProjectDescriptionManager.ioDescription"), ex); //$NON-NLS-1$
} catch (CoreException ex) {
throw CVSException.wrapException(project, Policy.bind("ProjectDescriptionManager.coreDescription"), ex); //$NON-NLS-1$
}
if (oldContents.equals(newContents)) {
// the contents of the new file would be the same as the old
return;
}
try {
descResource.setContents(
new ByteArrayInputStream(byteOutputStream.toByteArray()),
false,
false,
progress);
} catch (CoreException ex) {
throw CVSException.wrapException(project, Policy.bind("ProjectDescriptionManager.coreDescription"), ex); //$NON-NLS-1$
}
} else {
try {
descResource.create(
new ByteArrayInputStream(byteOutputStream.toByteArray()),
false,
progress);
} catch (CoreException ex) {
throw CVSException.wrapException(descResource, Policy.bind("ProjectDescriptionManager.coreDescription"), ex); //$NON-NLS-1$
}
}
}
/*
* To be called whenever the project description file is believed to have changed by
* a load/loadIfIncoming operation.
*/
public static void updateProjectIfNecessary(IProject project, IProgressMonitor progress) throws CoreException, CVSException {
IFile descResource = project.getFile(PROJECT_DESCRIPTION_PATH);
if (descResource.exists() && UPDATE_PROJECT_DESCRIPTION_ON_LOAD) {
// If a managed .project files exists, don't read the .vcm_meta
ICVSFile coreDescResource = CVSWorkspaceRoot.getCVSFileFor(project.getFile(CORE_PROJECT_DESCRIPTION_PATH));
if (coreDescResource.exists() && coreDescResource.isManaged()) {
createVCMMetaMarker(descResource);
Util.logError(Policy.bind("ProjectDescriptionManager.vcmmetaIgnored", project.getName()), null); //$NON-NLS-1$
return;
} else {
ICVSFolder folder = CVSWorkspaceRoot.getCVSFolderFor(project);
if (! folder.isCVSFolder()) {
createVCMMetaMarker(descResource);
Util.logError(Policy.bind("ProjectDescriptionManager.vcmmetaIgnored", project.getName()), null); //$NON-NLS-1$
return;
}
}
// update project description file (assuming it has changed)
IProjectDescription desc = project.getDescription();
DataInputStream is = null;
try {
is = new DataInputStream(((IFile) descResource).getContents());
try {
readProjectDescription(desc, is);
} finally {
is.close();
}
try {
project.setDescription(desc, IResource.FORCE | IResource.KEEP_HISTORY, progress);
} catch (CoreException ex) {
// Failing to set the description is probably due to a missing nature
// Other natures are still set
Util.logError(Policy.bind("ProjectDescriptionManager.unableToSetDescription"), ex); //$NON-NLS-1$
}
// Make sure we are still marked as a CVS project
if(RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId()) == null)
RepositoryProvider.map(project, CVSProviderPlugin.getTypeId());
// Mark the .vcm_meta file with a problem marker
if (project.getFile(CORE_PROJECT_DESCRIPTION_PATH).exists()) {
createVCMMetaMarker(descResource);
}
} catch(TeamException ex) {
Util.logError(Policy.bind("ProjectDescriptionManager.unableToReadDescription"), ex); //$NON-NLS-1$
// something went wrong, delete the project description file
descResource.delete(true, progress);
} catch (IOException ex) {
Util.logError(Policy.bind("ProjectDescriptionManager.unableToReadDescription"), ex); //$NON-NLS-1$
// something went wrong, delete the project description file
descResource.delete(true, progress);
}
}
}
/*
* Write out the project description file.
*
* For now just do it. It would be nice to detect the proper conditions
*
*/
public static void writeProjectDescriptionIfNecessary(CVSTeamProvider provider, IResource resource, IProgressMonitor monitor) throws CVSException {
if (resource.getType() == IResource.PROJECT || isProjectDescription(resource)) {
IProject project = resource.getProject();
if (project.getFile(PROJECT_DESCRIPTION_PATH).exists() /* || ! project.getFile(CORE_PROJECT_DESCRIPTION_PATH).exists() */) {
writeProjectDescription(project, monitor);
}
}
}
public static boolean isProjectDescription(IResource resource) {
return resource.getProjectRelativePath().equals(PROJECT_DESCRIPTION_PATH);
}
public void resourceChanged(IResourceChangeEvent event) {
try {
IResourceDelta root = event.getDelta();
IResourceDelta[] projectDeltas = root.getAffectedChildren(IResourceDelta.CHANGED | IResourceDelta.ADDED);
for (int i = 0; i < projectDeltas.length; i++) {
IResourceDelta delta = projectDeltas[i];
IResource resource = delta.getResource();
if (resource.getType() == IResource.PROJECT) {
IProject project = (IProject)resource;
RepositoryProvider provider = RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId());
if (provider == null) continue;
// First, check if the .vcm_meta file for the project is in the delta.
IResourceDelta[] children = delta.getAffectedChildren(IResourceDelta.ADDED);
boolean inSync = false;
for (int j = 0; j < children.length; j++) {
IResourceDelta childDelta = children[j];
IResource childResource = childDelta.getResource();
if (isProjectDescription(childResource))
switch (childDelta.getKind()) {
case IResourceDelta.REMOVED:
writeProjectDescriptionIfNecessary((CVSTeamProvider)provider, project, Policy.monitorFor(null));
inSync = true;
break;
case IResourceDelta.CHANGED:
case IResourceDelta.ADDED:
updateProjectIfNecessary(project, Policy.monitorFor(null));
inSync = true;
break;
}
}
// Check if we didn't do anything above and the project description changed.
if (! inSync && (delta.getFlags() & IResourceDelta.DESCRIPTION) != 0) {
writeProjectDescriptionIfNecessary((CVSTeamProvider)provider, project, Policy.monitorFor(null));
}
}
}
} catch (CVSException ex) {
Util.logError(Policy.bind("ProjectDescriptionManager.cannotUpdateDesc"), ex); //$NON-NLS-1$
} catch (CoreException ex) {
Util.logError(Policy.bind("ProjectDescriptionManager.cannotUpdateDesc"), ex); //$NON-NLS-1$
}
}
protected static IMarker createVCMMetaMarker(IResource resource) {
try {
IMarker[] markers = resource.findMarkers(VCMMETA_MARKER, false, IResource.DEPTH_ZERO);
if (markers.length == 1) {
return markers[0];
}
IMarker marker = resource.createMarker(VCMMETA_MARKER);
marker.setAttribute(IMarker.MESSAGE, Policy.bind("ProjectDescriptionManager.vcmmetaMarker" , resource.getName(), resource.getProject().getName())); //$NON-NLS-1$
return marker;
} catch (CoreException e) {
Util.logError(Policy.bind("ProjectDescriptionManager.markerError"), e); //$NON-NLS-1$
}
return null;
}
}