| /******************************************************************************* |
| * Copyright (c) 2000, 2006 IBM Corporation and others. |
| * 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 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.team.internal.ccvs.core.resources; |
| |
| import java.util.*; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.team.core.RepositoryProvider; |
| 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.*; |
| import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation; |
| import org.eclipse.team.internal.ccvs.core.connection.CVSServerException; |
| import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; |
| import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; |
| |
| /** |
| * This class can be used to fetch and cache file contents for remote files. |
| */ |
| public class UpdateContentCachingService implements IUpdateMessageListener { |
| |
| private CVSRepositoryLocation repository; |
| private ICVSFolder remoteRoot; |
| private final CVSTag tag; |
| private final int depth; |
| private boolean fetchAbsentDirectories = true; |
| private ArrayList removed = new ArrayList(); |
| |
| public class SandboxUpdate extends Update { |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.team.internal.ccvs.core.client.Update#shouldRetrieveAbsentDirectories(org.eclipse.team.internal.ccvs.core.client.Session) |
| */ |
| protected boolean shouldRetrieveAbsentDirectories(Session session) { |
| return fetchAbsentDirectories; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.team.internal.ccvs.core.client.Command#commandFinished(org.eclipse.team.internal.ccvs.core.client.Session, org.eclipse.team.internal.ccvs.core.client.Command.GlobalOption[], org.eclipse.team.internal.ccvs.core.client.Command.LocalOption[], org.eclipse.team.internal.ccvs.core.ICVSResource[], org.eclipse.core.runtime.IProgressMonitor, org.eclipse.core.runtime.IStatus) |
| */ |
| protected IStatus commandFinished(Session session, GlobalOption[] globalOptions, LocalOption[] localOptions, ICVSResource[] resources, IProgressMonitor monitor, IStatus status) throws CVSException { |
| // Don't do anything (i.e. don't prune) |
| return status; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.team.internal.ccvs.core.client.Command#doExecute(org.eclipse.team.internal.ccvs.core.client.Session, org.eclipse.team.internal.ccvs.core.client.Command.GlobalOption[], org.eclipse.team.internal.ccvs.core.client.Command.LocalOption[], java.lang.String[], org.eclipse.team.internal.ccvs.core.client.listeners.ICommandOutputListener, org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| protected IStatus doExecute(Session session, GlobalOption[] globalOptions, LocalOption[] localOptions, String[] arguments, ICommandOutputListener listener, IProgressMonitor monitor) throws CVSException { |
| session.registerResponseHandler(new SandboxUpdatedHandler(UpdatedHandler.HANDLE_CREATED)); |
| session.registerResponseHandler(new SandboxUpdatedHandler(UpdatedHandler.HANDLE_MERGED)); |
| session.registerResponseHandler(new SandboxUpdatedHandler(UpdatedHandler.HANDLE_UPDATE_EXISTING)); |
| session.registerResponseHandler(new SandboxUpdatedHandler(UpdatedHandler.HANDLE_UPDATED)); |
| return super.doExecute(session, globalOptions, localOptions, arguments, listener, monitor); |
| } |
| } |
| |
| /** |
| * This class overrides the "Created" handler in order to configure the remote file |
| * to receive and cache the contents |
| */ |
| public class SandboxUpdatedHandler extends UpdatedHandler { |
| public SandboxUpdatedHandler(int type) { |
| super(type); |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.team.internal.ccvs.core.client.UpdatedHandler#receiveTargetFile(org.eclipse.team.internal.ccvs.core.client.Session, org.eclipse.team.internal.ccvs.core.ICVSFile, java.lang.String, java.util.Date, boolean, boolean, org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| protected void receiveTargetFile( |
| Session session, |
| ICVSFile mFile, |
| String entryLine, |
| Date modTime, |
| boolean binary, |
| boolean readOnly, |
| boolean executable, |
| IProgressMonitor monitor) |
| throws CVSException { |
| |
| // Set the sync info first so that the contents are cached properly |
| ResourceSyncInfo info = new ResourceSyncInfo(entryLine, modTime); |
| // We're always excepting new revisions so the file is clean |
| mFile.setSyncInfo(info, ICVSFile.CLEAN); |
| |
| // receive the file contents from the server |
| session.receiveFile(mFile, binary, getHandlerType(), monitor); |
| |
| // Handle execute |
| try { |
| if (executable) mFile.setExecutable(true); |
| } catch (CVSException e) { |
| // Just log and keep going |
| CVSProviderPlugin.log(e); |
| } |
| } |
| } |
| |
| public static RemoteFolder buildRemoteTree(final CVSRepositoryLocation repository, ICVSFolder root, CVSTag tag, int depth, IProgressMonitor monitor) throws CVSException { |
| monitor.beginTask(null, 100); |
| try { |
| RemoteFolder tree = buildBaseTree(repository, root, tag, Policy.subMonitorFor(monitor, 50)); |
| UpdateContentCachingService service = new UpdateContentCachingService(repository, tree, tag, depth); |
| service.setFetchAbsentDirectories(getFetchAbsentDirectories(root)); |
| if (!service.cacheFileContents(Policy.subMonitorFor(monitor, 50))) |
| return null; |
| return tree; |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| private void setFetchAbsentDirectories(boolean fetchAbsentDirectories) { |
| this.fetchAbsentDirectories = fetchAbsentDirectories; |
| } |
| |
| private static boolean getFetchAbsentDirectories(ICVSFolder root) { |
| IResource resource = root.getIResource(); |
| if (resource != null) { |
| IProject project = resource.getProject(); |
| RepositoryProvider provider = RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId()); |
| if (provider instanceof CVSTeamProvider) { |
| CVSTeamProvider cp = (CVSTeamProvider) provider; |
| try { |
| return cp.getFetchAbsentDirectories(); |
| } catch (CVSException e) { |
| CVSProviderPlugin.log(e); |
| } |
| } |
| } |
| return CVSProviderPlugin.getPlugin().getFetchAbsentDirectories(); |
| } |
| |
| private static RemoteFolder buildBaseTree(final CVSRepositoryLocation repository, ICVSFolder root, CVSTag tag, IProgressMonitor progress) throws CVSException { |
| try { |
| RemoteFolderTreeBuilder builder = new RemoteFolderTreeBuilder(repository, root, tag) { |
| protected RemoteFolder createRemoteFolder(ICVSFolder local, RemoteFolder parent, FolderSyncInfo folderSyncInfo) { |
| return new RemoteFolderSandbox(parent, local.getName(), repository, folderSyncInfo.getRepository(), folderSyncInfo.getTag(), folderSyncInfo.getIsStatic()); |
| } |
| protected RemoteFile createRemoteFile(RemoteFolder remote, byte[] syncBytes) throws CVSException { |
| return new RemoteFile(remote, syncBytes){ |
| public boolean isModified(IProgressMonitor monitor) throws CVSException { |
| return false; |
| } |
| public void delete() { |
| RemoteFolderSandbox parent = (RemoteFolderSandbox)getParent(); |
| parent.remove(this); |
| } |
| }; |
| } |
| protected boolean isPruneEmptyDirectories() { |
| return true; |
| } |
| }; |
| progress.beginTask(null, 100); |
| IProgressMonitor subProgress = Policy.infiniteSubMonitorFor(progress, 100); |
| subProgress.beginTask(null, 512); |
| subProgress.subTask(NLS.bind(CVSMessages.RemoteFolderTreeBuilder_buildingBase, new String[] { root.getName() })); |
| RemoteFolder tree = builder.buildBaseTree(null, root, subProgress); |
| if (tree == null) { |
| // The local tree is empty and was pruned. |
| // Return the root folder so that the operation can proceed |
| FolderSyncInfo folderSyncInfo = root.getFolderSyncInfo(); |
| if (folderSyncInfo == null) return null; |
| return new RemoteFolderSandbox(null, root.getName(), repository, folderSyncInfo.getRepository(), folderSyncInfo.getTag(), folderSyncInfo.getIsStatic()); |
| } |
| return tree; |
| } finally { |
| progress.done(); |
| } |
| } |
| |
| public static RemoteFile buildRemoteTree(CVSRepositoryLocation repository, ICVSFile file, CVSTag tag, IProgressMonitor monitor) throws CVSException { |
| monitor.beginTask(null, 100); |
| try { |
| RemoteFolderTreeBuilder builder = new RemoteFolderTreeBuilder(repository, file.getParent(), tag); |
| RemoteFile remote = builder.buildTree(file, Policy.subMonitorFor(monitor, 10)); |
| |
| if (remote == null) |
| return null; |
| |
| byte[] syncBytes = remote.getSyncBytes(); |
| if (builder.getFileDiffs().length > 0) { |
| // Getting the storage of the file will cache the contents |
| remote.getStorage(Policy.subMonitorFor(monitor, 90)); |
| } |
| // We need to set the sync bytes back because the content fetch |
| // makes the handle sticky |
| remote.setSyncBytes(syncBytes, ICVSFile.CLEAN); |
| return remote; |
| } catch (TeamException e) { |
| throw CVSException.wrapException(e); |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| public UpdateContentCachingService(CVSRepositoryLocation repository, RemoteFolder tree, CVSTag tag, int depth) { |
| this.repository = repository; |
| this.remoteRoot = tree; |
| this.tag = tag; |
| this.depth = depth; |
| } |
| |
| private boolean cacheFileContents(IProgressMonitor monitor) throws CVSException { |
| // Fetch the file contents for all out-of-sync files by running an update |
| // on the remote tree passing the known changed files as arguments |
| monitor.beginTask(null, 100); |
| Policy.checkCanceled(monitor); |
| Session session = new Session(repository, remoteRoot, false); |
| session.open(Policy.subMonitorFor(monitor, 10), false /* read-only */); |
| try { |
| Policy.checkCanceled(monitor); |
| IStatus status = new SandboxUpdate().execute(session, |
| Command.NO_GLOBAL_OPTIONS, |
| getLocalOptions(), |
| new String[] { Session.CURRENT_LOCAL_FOLDER }, |
| new UpdateListener(this), |
| Policy.subMonitorFor(monitor, 90)); |
| if (!status.isOK()) { |
| if (status.getCode() == CVSStatus.SERVER_ERROR) { |
| CVSServerException e = new CVSServerException(status); |
| if ( ! e.isNoTagException() && e.containsErrors()) |
| throw e; |
| return false; |
| } else if (status.getSeverity() == IStatus.ERROR && isReportableError(status)) { |
| throw new CVSException(status); |
| } |
| } |
| for (Iterator iterator = removed.iterator(); iterator.hasNext();) { |
| ICVSResource resource = (ICVSResource) iterator.next(); |
| if (resource.exists()) |
| resource.delete(); |
| } |
| } finally { |
| session.close(); |
| monitor.done(); |
| } |
| return true; |
| } |
| |
| private boolean isReportableError(IStatus status) { |
| return CVSStatus.isInternalError(status) |
| || status.getCode() == TeamException.UNABLE |
| || status.getCode() == CVSStatus.INVALID_LOCAL_RESOURCE_PATH |
| || status.getCode() == CVSStatus.RESPONSE_HANDLING_FAILURE; |
| } |
| |
| private LocalOption[] getLocalOptions() { |
| ArrayList options = new ArrayList(); |
| if (tag != null) |
| options.add(Update.makeTagOption(tag)); |
| |
| if (depth != IResource.DEPTH_INFINITE ) |
| options.add(Command.DO_NOT_RECURSE); |
| |
| if (fetchAbsentDirectories) |
| options.add(Update.RETRIEVE_ABSENT_DIRECTORIES); |
| |
| if (!options.isEmpty()) |
| return (LocalOption[]) options.toArray(new LocalOption[options.size()]); |
| |
| return Command.NO_LOCAL_OPTIONS; |
| } |
| |
| public void directoryDoesNotExist(ICVSFolder commandRoot, String path) { |
| try { |
| removed.add(commandRoot.getChild(path)); |
| } catch (CVSException e) { |
| CVSProviderPlugin.log(e); |
| } |
| } |
| |
| public void directoryInformation(ICVSFolder commandRoot, String path, |
| boolean newDirectory) { |
| // Nothing to do |
| } |
| |
| public void fileDoesNotExist(ICVSFolder parent, String filename) { |
| try { |
| removed.add(parent.getChild(filename)); |
| } catch (CVSException e) { |
| CVSProviderPlugin.log(e); |
| } |
| } |
| |
| public void fileInformation(int type, ICVSFolder parent, String filename) { |
| // Nothing to do |
| } |
| } |