Skip to main content
summaryrefslogblamecommitdiffstats
blob: 3fc09d18df4577079be806f9ad4f8e1c875b2f1c (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
                                                                                
                                                       










                                                                                 
                           
                   
 

                                    

                                                     

                                                

                                                    

                                                                      
                                                                         
                                                                   
                                                     
                                                
                                     







                                                                          

                                                                                                                       

                                                     




















































                                                                                                                    
 









                                                                          
                                                                                                                                
                                                          
                                                                                                             
                                                                             
                                                              
                                                                      
                                        
                                         
                                                                                 
                     
                        


                                                                                              
                                                                                                                        


                                                                                                    

                                                                                                                     
                                                                                                                                     





                                                                                  
                        
                                                                       
                                                                        





                                                                                                                             
                                                                                                                                                     

                                                                                         
                                 


                                                                                                          
                                                                                                                                        


                                                                 
                                         












                                                                                               
                                                                                                       
                        

                                                                   






                                                                                                                                     

                                                                                                                   


                 
                                                                                                                                                                                       










                                                                                                                                                      
                                         








                                                                                                                      












                                                                                                     
                                                                                                     


                                                                            
                         
                        
















                                                                                                              
                                






                                                                                                                  
                                              



                                                                                                               
                           




                                  


                                                                                            



                                                                                      
                                                                                                                                                               
                        
                                                     
                                                                      


                                                      
                                                 
                                                                                                                
                                                                         
                                                      






                                                                                                         
                                                                                                 


                                                                                                                       
                                                                                                                                                            






                                                      


                                                                                                                         

         







                                                                                            



                                                                                              
                                                                                                                                         









                                                           
                                                      
                                                                                                            
                                                                                 
                                                                                                                                                                                        




















                                                                                                        
                                                      
                                                                             






                                                                                                                                


                                                                                                                           















                                                                         
                                                                
















                                                                                               
                                                                                            















                                                                                                                                                                   
                                                                                                                               

















                                                                                                                                                                                             

         
                                                                                                     
                                      
                                                                                                                                                      
                        
                                                                                                                                                          





                                                        
                                                                                                         






                                                                                                                                             



                                                                                                               



                                                                                                                                                   


                                                                                                                         
                         



                                       
 








                                                                                                                                                      
 
/*******************************************************************************
 * Copyright (c) 2000, 2004 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.io.File;
import java.io.IOException;
import java.util.*;

import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.MultiRule;
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.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer;
import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin;
import org.eclipse.team.internal.ccvs.ui.Policy;
import org.eclipse.ui.IWorkbenchPart;
/**
 * This class acts as an abstract class for checkout operations.
 * It provides a few common methods.
 */
public abstract class CheckoutProjectOperation extends CheckoutOperation {

	private String targetLocation;

	public CheckoutProjectOperation(IWorkbenchPart part, ICVSRemoteFolder[] remoteFolders, String targetLocation) {
		super(part, remoteFolders);
		this.targetLocation = targetLocation;
	}
	
	/**
	 * Create and open the project, using a custom location if there is one.
	 * 
	 * @param project
	 * @param monitor
	 * @throws CVSException
	 */
	protected void createAndOpenProject(IProject project, IProgressMonitor monitor) throws CVSException {
		try {
			monitor.beginTask(null, 5);
			IProjectDescription desc = getDescriptionFor(project);
			if (project.exists()) {
				if (desc != null) {
					project.move(desc, true, Policy.subMonitorFor(monitor, 3));
				}
			} else {
				if (desc == null) {
					// create in default location
					project.create(Policy.subMonitorFor(monitor, 3));
				} else {
					// create in some other location
					project.create(desc, Policy.subMonitorFor(monitor, 3));
				}
			}
			if (!project.isOpen()) {
				project.open(Policy.subMonitorFor(monitor, 2));
			}
		} catch (CoreException e) {
			throw CVSException.wrapException(e);
		} finally {
			monitor.done();
		}
	}
	
	protected IProjectDescription getDescriptionFor(IProject project) {
		if (targetLocation == null) return null;
		String projectName = project.getName();
		IProjectDescription description = ResourcesPlugin.getWorkspace().newProjectDescription(projectName);
		description.setLocation(getTargetLocationFor(project));
		return description;
	}
	
	/**
	 * Return the target location where the given project should be located or
	 * null if the default location should be used.
	 * 
	 * @param project
	 */
	protected IPath getTargetLocationFor(IProject project) {
		if (targetLocation == null) return null;
		return new Path(targetLocation);
	}

	protected String getRemoteModuleName(ICVSRemoteFolder resource) {
		String moduleName;
		if (resource.isDefinedModule()) {
			moduleName = resource.getName();
		} else {
			moduleName = resource.getRepositoryRelativePath();
		}
		return moduleName;
	}

	protected IStatus checkout(final ICVSRemoteFolder resource, IProject project, IProgressMonitor pm) throws CVSException {
		// Get the location and the workspace root
		ICVSFolder root = CVSWorkspaceRoot.getCVSFolderFor(ResourcesPlugin.getWorkspace().getRoot());
		ICVSRepositoryLocation repository = resource.getRepository();
		// Open a connection session to the repository
		final Session session = new Session(repository, root);
		pm.beginTask(null, 100);
		Policy.checkCanceled(pm);
		session.open(Policy.subMonitorFor(pm, 5), false /* read-only */);
		try {
			
			// Check to see if the entire repo is being checked out.
			if (project == null && resource.getName().equals(".")) { //$NON-NLS-1$
				// No project was specified but we need on for this to work
				String name = new Path(null, resource.getRepository().getRootDirectory()).lastSegment();
				project = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
			}
			
			// Determine the local target projects (either the project provider or the module expansions)
			// Note: Module expansions can be run over the same connection as a checkout
			final IProject[] targetProjects = determineProjects(session, resource, project, Policy.subMonitorFor(pm, 5));
			if (targetProjects == null) {
				// An error occurred and was recorded so return it
				return getLastError();
			} else if (targetProjects.length == 0) {
				return OK;
			}
			
			final boolean sendModuleName = project != null;
			final IStatus[] result = new IStatus[] { null };
			ISchedulingRule schedulingRule = getSchedulingRule(targetProjects);
			if (schedulingRule instanceof IResource && ((IResource)schedulingRule).getType() == IResource.ROOT) {
				// One of the projects is mapped to a provider that locks the workspace.
				// Just return the workspace root rule
				try {
					Platform.getJobManager().beginRule(schedulingRule, pm);
					result[0] = performCheckout(session, resource, targetProjects, sendModuleName, Policy.subMonitorFor(pm, 90));
				} finally {
					Platform.getJobManager().endRule(schedulingRule);
				}
			} else {
				EclipseSynchronizer.getInstance().run(schedulingRule, new ICVSRunnable() {
					public void run(IProgressMonitor monitor) throws CVSException {
						result[0] = performCheckout(session, resource, targetProjects, sendModuleName, monitor);
					}
				}, Policy.subMonitorFor(pm, 90));
			}
			return result[0];
		} catch (CVSException e) {
			// An exception occurred either during the module-expansion or checkout
			// Since we were able to make a connection, return the status so the
			// checkout of any other modules can proceed
			return e.getStatus();
		} finally {
			session.close();
			pm.done();
		}
	}

	private ISchedulingRule getSchedulingRule(IProject[] projects) {
		if (projects.length == 1) {
			return ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(projects[0]);
		} else {
			Set rules = new HashSet();
			for (int i = 0; i < projects.length; i++) {
				ISchedulingRule modifyRule = ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(projects[i]);
				if (modifyRule instanceof IResource && ((IResource)modifyRule).getType() == IResource.ROOT) {
					// One of the projects is mapped to a provider that locks the workspace.
					// Just return the workspace root rule
					return modifyRule;
				}
				rules.add(modifyRule);
			}
			return new MultiRule((ISchedulingRule[]) rules.toArray(new ISchedulingRule[rules.size()]));
		}
	}

	/* private */ IStatus performCheckout(Session session, ICVSRemoteFolder resource, IProject[] targetProjects, boolean sendModuleName, IProgressMonitor pm) throws CVSException {
		// Set the task name of the progress monitor to let the user know
		// which project we're on. Don't use subTask since that will be
		// changed when the checkout command is run.
		String taskName;
		if (targetProjects.length == 1) {
			taskName = Policy.bind("CheckoutProjectOperation.8", resource.getName(), targetProjects[0].getName()); //$NON-NLS-1$
		} else {
			taskName = Policy.bind("CheckoutProjectOperation.9", resource.getName(), String.valueOf(targetProjects.length)); //$NON-NLS-1$
		}
		pm.beginTask(taskName, 100);
		pm.setTaskName(taskName);
		Policy.checkCanceled(pm);
		try {
			// Scrub the local contents if requested
			if (performScrubProjects()) {
				IStatus result = scrubProjects(resource, targetProjects, Policy.subMonitorFor(pm, 9));
				if (!result.isOK()) {
					return result;
				}
			}
				
			// Determine if t
			// in which case we'll use -d to flatten the directory structure.
			// Only flatten the directory structure if the folder is not a root folder
			IProject project = null;
			if (targetProjects.length == 1) {
				if (sendModuleName) {
					project = targetProjects[0];
				} else if (targetProjects[0].getName().equals(resource.getName())) {
					// The target project has the same name as the remote folder.
					// If the repository relative path has multiple segments
					// we will want to flatten the directory structure
					String path = resource.getRepositoryRelativePath();
					if (!path.equals(FolderSyncInfo.VIRTUAL_DIRECTORY)
							&& new Path(null, path).segmentCount() > 1) {
						project = targetProjects[0];
					}
				}
			}
			
			try {
				// Build the local options
				List localOptions = new ArrayList();
				// Add the option to load into the target project if one was supplied
				if (project != null) {
					localOptions.add(Checkout.makeDirectoryNameOption(project.getName()));
				}
				// Prune empty directories if pruning enabled
				if (CVSProviderPlugin.getPlugin().getPruneEmptyDirectories()) 
					localOptions.add(Checkout.PRUNE_EMPTY_DIRECTORIES);
				// Add the options related to the CVSTag
				CVSTag tag = resource.getTag();
				if (tag == null) {
					// A null tag in a remote resource indicates HEAD
					tag = CVSTag.DEFAULT;
				}
				localOptions.add(Update.makeTagOption(tag));
				
				// Perform the checkout
				IStatus status = Command.CHECKOUT.execute(session,
					Command.NO_GLOBAL_OPTIONS,
					(LocalOption[])localOptions.toArray(new LocalOption[localOptions.size()]),
					new String[]{getRemoteModuleName(resource)},
					null,
					Policy.subMonitorFor(pm, 90));
				return status;
			} finally {
				// Map the projects if they have CVS meta infomation even if a failure occurred
				refreshProjects(targetProjects, Policy.subMonitorFor(pm, 1));
			}
		} finally {
			pm.done();
		}
	}

	/*
	 * Determine the workspace project(s) that will be affected by the checkout. 
	 * If project is not null, then it will be the only target project of the checkout. 
	 * Otherwise, the remote folder could expand to multiple projects.
	 * 
	 * If the remote resource is a folder which is not a root folder (i.e. a/b/c),
	 * then the target project will be the last segment (i.e. c).
	 */
	private IProject[] determineProjects(Session session, final ICVSRemoteFolder remoteFolder, IProject project, IProgressMonitor pm) throws CVSException {
			
		Set targetProjectSet = new HashSet();
		String moduleName = getRemoteModuleName(remoteFolder);
		if (project == null) {
			
			// Fetch the module expansions
			Policy.checkCanceled(pm);
			IStatus status = Request.EXPAND_MODULES.execute(session, new String[] {moduleName}, pm);
			if (status.getCode() == CVSStatus.SERVER_ERROR) {
				collectStatus(status);
				return null;
			}
			
			// Convert the module expansions to local projects
			String[] expansions = session.getModuleExpansions();
			if (expansions.length == 1 && expansions[0].equals(moduleName)) {
				// For a remote folder, use the last segment as the project to be created
				String lastSegment = new Path(null, expansions[0]).lastSegment();
				targetProjectSet.add(ResourcesPlugin.getWorkspace().getRoot().getProject(lastSegment));
			} else {
				for (int j = 0; j < expansions.length; j++) {
					targetProjectSet.add(ResourcesPlugin.getWorkspace().getRoot().getProject(new Path(null, expansions[j]).segment(0)));
				}
			}
			
		} else {
			targetProjectSet.add(project);
		}
		
		// Return the local projects affected by the checkout
		IProject[] targetProjects = (IProject[]) targetProjectSet.toArray(new IProject[targetProjectSet.size()]);
		return targetProjects;
	}

	/**
	 * Return true if the target projects should be scrubbed before the checkout occurs.
	 * Default is to scrub the projects. Can be overridden by subclasses.
	 */
	protected boolean performScrubProjects() {
		return true;
	}

	/*
	 * This method is invoked to scrub the local projects that are the check out target of
	 * a single remote module.
	 */
	private IStatus scrubProjects(ICVSRemoteFolder remoteFolder, IProject[] projects, IProgressMonitor monitor) throws CVSException {
		if (projects == null) {
			monitor.done();
			return OK;
		}
		// Prompt first before any work is done
		if (projects.length > 1) {
			setInvolvesMultipleResources(true);
		}
		for (int i=0;i<projects.length;i++) {
			IProject project = projects[i];
			Policy.checkCanceled(monitor);
			if (needsPromptForOverwrite(project) && !promptToOverwrite(remoteFolder, project)) {
				// User said no to this project but not no to all
				return new CVSStatus(IStatus.INFO, CVSStatus.CANCEL, Policy.bind("CheckoutProjectOperation.0", remoteFolder.getRepositoryRelativePath())); //$NON-NLS-1$
			}
		}
		// Create the projects and remove any previous content
		monitor.beginTask(null, projects.length * 100); //$NON-NLS-1$
		for (int i=0;i<projects.length;i++) {
			IProject project = projects[i];
			createAndOpenProject(project, Policy.subMonitorFor(monitor, 10));
			scrubProject(project, Policy.subMonitorFor(monitor, 90));
		}
		monitor.done();
		return OK;
	}

	private void scrubProject(IProject project, IProgressMonitor monitor) throws CVSException {
		try {
			// unmap the project from any previous repository provider
			if (RepositoryProvider.getProvider(project) != null)
				RepositoryProvider.unmap(project);
			// We do not want to delete the project to avoid a project deletion delta
			// We do not want to delete the .project to avoid core exceptions
			IResource[] children = project.members(IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS);
			Policy.checkCanceled(monitor);
			monitor.beginTask(null, 100 + children.length * 100);
			monitor.subTask(Policy.bind("CheckoutOperation.scrubbingProject", project.getName())); //$NON-NLS-1$	
			try {
				for (int j = 0; j < children.length; j++) {
					if ( ! children[j].getName().equals(".project")) {//$NON-NLS-1$
						children[j].delete(true /*force*/, Policy.subMonitorFor(monitor, 100));
					}
				}
				// Make sure there is no sync info cached for the project since
				// a reader thread may have caused it to be loaded since the unmap.
				EclipseSynchronizer.getInstance().flush(project, true, Policy.subMonitorFor(monitor, 100));
			} finally {
				monitor.done();
			}
		} catch (TeamException e) {
			throw CVSException.wrapException(e);
		} catch (CoreException e) {
			throw CVSException.wrapException(e);
		}
	}

	protected boolean needsPromptForOverwrite(IProject project) {
				
		// First, check the description location
		IProjectDescription desc = getDescriptionFor(project);
		if (desc != null) {
			File localLocation = desc.getLocation().toFile();
			if (localLocation.exists()) return true;
		}
				
		// Next, check if the resource itself exists
		if (project.exists()) return true;
				
		// Finally, check if the location in the workspace exists;
		File localLocation  = getFileLocation(project);
		if (localLocation.exists()) return true;
				
		// The target doesn't exist
		return false;
	}
	
	protected File getFileLocation(IProject project) {
		return new File(project.getParent().getLocation().toFile(), project.getName());
	}
	
	private boolean promptToOverwrite(ICVSRemoteFolder remoteFolder, IProject project) {
		// First, if the project exists in the workspace, prompt
		if (project.exists()) {
			if (!promptToOverwrite(
					Policy.bind("CheckoutOperation.confirmOverwrite"),  //$NON-NLS-1$
					Policy.bind("CheckoutOperation.thisResourceExists", project.getName(), getRemoteModuleName(remoteFolder)))) { //$NON-NLS-1$
				return false;
			}
		}
		// Even if the project exists, check the target location
		IPath path = getTargetLocationFor(project);
		File localLocation = null;
		if (path == null) {
			try {
				// There is no custom location. However, still prompt
				// if the project directory in the workspace directory 
				// would be overwritten.
				if (!project.exists() || !project.isOpen() || project.getDescription().getLocation() != null) {
					localLocation = getFileLocation(project);
				}
			} catch (CoreException e) {
				CVSUIPlugin.log(e);
			}
		} else {
			localLocation = path.toFile();
		}
		if (localLocation != null && localLocation.exists()) {
			try {
				return (promptToOverwrite(
						Policy.bind("CheckoutOperation.confirmOverwrite"),  //$NON-NLS-1$
						Policy.bind("CheckoutOperation.thisExternalFileExists", localLocation.getCanonicalPath(), getRemoteModuleName(remoteFolder)))); //$NON-NLS-1$
			} catch (IOException e) {
				CVSUIPlugin.log(CVSException.wrapException(e));
			}
		}
		return true;
	}

	protected String getOverwritePromptMessage(ICVSRemoteFolder remoteFolder, IProject project) {
		if(project.exists()) {
			return Policy.bind("CheckoutOperation.thisResourceExists", project.getName(), getRemoteModuleName(remoteFolder));//$NON-NLS-1$
		} else {
			return Policy.bind("CheckoutOperation.thisExternalFileExists", project.getName(), getRemoteModuleName(remoteFolder));//$NON-NLS-1$
		}
	}
	
	/*
	 * Bring the provied projects into the workspace
	 */
	private void refreshProjects(IProject[] projects, IProgressMonitor monitor) throws CVSException {
		monitor.beginTask(null, projects.length * 100);
		try {
			for (int i = 0; i < projects.length; i++) {
				IProject project = projects[i];
				// Register the project with Team
				try {
					monitor.subTask(Policy.bind("CheckoutOperation.refreshingProject", project.getName())); //$NON-NLS-1$
					ICVSFolder folder = CVSWorkspaceRoot.getCVSFolderFor(project);
					if (folder.isCVSFolder()) {
						RepositoryProvider.map(project, CVSProviderPlugin.getTypeId());
					}
				} catch (TeamException e) {
					throw CVSException.wrapException(e);
				}
				CVSTeamProvider provider = (CVSTeamProvider)RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId());
				if (provider != null) {
					provider.setWatchEditEnabled(CVSProviderPlugin.getPlugin().isWatchEditEnabled());
				}
			}
		} finally {
			monitor.done();
		}
	}

	protected String getTaskName() {
		ICVSRemoteFolder[] remoteFolders = getRemoteFolders();
		if (remoteFolders.length == 1) {
			return Policy.bind("CheckoutSingleProjectOperation.taskname", remoteFolders[0].getName()); //$NON-NLS-1$
		} else {
			return Policy.bind("CheckoutMultipleProjectsOperation.taskName", new Integer(remoteFolders.length).toString());  //$NON-NLS-1$
		}
	}
	
}

Back to the top