blob: df51bc1cec5d6676accf8074b94d7a9583bcec74 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* IBM - Initial API and implementation
******************************************************************************/
package org.eclipse.team.internal.ccvs.core;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IPluginDescriptor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.core.runtime.Status;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.Team;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.internal.ccvs.core.client.Command;
import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption;
import org.eclipse.team.internal.ccvs.core.client.Command.QuietOption;
import org.eclipse.team.internal.ccvs.core.client.listeners.IConsoleListener;
import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.core.resources.FileModificationManager;
import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
import org.eclipse.team.internal.ccvs.core.util.AddDeleteMoveListener;
import org.eclipse.team.internal.ccvs.core.util.ProjectDescriptionManager;
import org.eclipse.team.internal.ccvs.core.util.SyncFileChangeListener;
import org.eclipse.team.internal.ccvs.core.util.Util;
public class CVSProviderPlugin extends Plugin {
// preference names
public static final String READ_ONLY = "cvs.read.only"; //$NON-NLS-1$
// external command to run for ext connection method
public static final String DEFAULT_CVS_RSH = "ssh"; //$NON-NLS-1$
// external command parameters
public static final String DEFAULT_CVS_RSH_PARAMETERS = "{host} -l {user}"; //$NON-NLS-1$
// remote command to run for ext connection method
public static final String DEFAULT_CVS_SERVER = "cvs"; //$NON-NLS-1$
// determines if empty directories received from the server should be pruned.
public static final boolean DEFAULT_PRUNE = true;
// determines if new directories should be discovered during update.
public static final boolean DEFAULT_FETCH = true;
// communication timeout with the server
public static final int DEFAULT_TIMEOUT = 60;
// file transfer compression level (0 - 9)
public static final int DEFAULT_COMPRESSION_LEVEL = 0;
// default text keyword substitution mode
public static final KSubstOption DEFAULT_TEXT_KSUBST_OPTION = Command.KSUBST_TEXT_EXPAND;
// cvs plugin extension points and ids
public static final String ID = "org.eclipse.team.cvs.core"; //$NON-NLS-1$
public static final String PT_AUTHENTICATOR = "authenticator"; //$NON-NLS-1$
public static final String PT_CONNECTIONMETHODS = "connectionmethods"; //$NON-NLS-1$
public static final String PT_FILE_MODIFICATION_VALIDATOR = "filemodificationvalidator"; //$NON-NLS-1$
// Directory to cache file contents
private static final String CACHE_DIRECTORY = ".cache"; //$NON-NLS-1$
// Maximum lifespan of local cache file, in milliseconds
private static final long CACHE_FILE_LIFESPAN = 60*60*1000; // 1hr
private Hashtable cacheFileNames;
private Hashtable cacheFileTimes;
private long lastCacheCleanup;
private int cacheDirSize;
private QuietOption quietness;
private int compressionLevel = DEFAULT_COMPRESSION_LEVEL;
private KSubstOption defaultTextKSubstOption = DEFAULT_TEXT_KSUBST_OPTION;
private int communicationsTimeout = DEFAULT_TIMEOUT;
private boolean pruneEmptyDirectories = DEFAULT_PRUNE;
private boolean fetchAbsentDirectories = DEFAULT_FETCH;
private boolean promptOnFileDelete = true;
private boolean promptOnFolderDelete = true;
private boolean showTasksOnAddAndDelete = false;
private boolean replaceUnmanaged = true;
private boolean repositoriesAreBinary = false;
private String cvsRshCommand = DEFAULT_CVS_RSH;
private String cvsRshParameters = DEFAULT_CVS_RSH_PARAMETERS;
private String cvsServer = DEFAULT_CVS_SERVER;
private IConsoleListener consoleListener;
private boolean determineVersionEnabled = true;
private static CVSProviderPlugin instance;
// CVS specific resource delta listeners
private IResourceChangeListener preAutoBuildListener;
private AddDeleteMoveListener addDeleteMoveListener;
private FileModificationManager fileModificationManager;
private static final String REPOSITORIES_STATE_FILE = ".cvsProviderState"; //$NON-NLS-1$
// version numbers for the state file (a positive number indicates version 1)
private static final int REPOSITORIES_STATE_FILE_VERSION_2 = -1;
private Map repositories = new HashMap();
private List repositoryListeners = new ArrayList();
/**
* The identifier for the CVS nature
* (value <code>"org.eclipse.team.cvs.core.nature"</code>).
* The presence of this nature on a project indicates that it is
* CVS-capable.
*
* @see org.eclipse.core.resources.IProject#hasNature
*/
private static final String NATURE_ID = ID + ".cvsnature"; //$NON-NLS-1$
/**
* Constructor for CVSProviderPlugin.
* @param descriptor
*/
public CVSProviderPlugin(IPluginDescriptor descriptor) {
super(descriptor);
setPlugin(this);
}
/**
* Convenience method for logging CVSExceptiuons to the plugin log
*/
public static void log(TeamException e) {
// For now, we'll log the status. However we should do more
log(e.getStatus());
}
public static void log(IStatus status) {
// For now, we'll log the status. However we should do more
getPlugin().getLog().log(status);
}
/**
* Returns the singleton plug-in instance.
*
* @return the plugin instance
*/
public static synchronized CVSProviderPlugin getPlugin() {
return instance;
}
private static synchronized void setPlugin(CVSProviderPlugin plugin) {
instance = plugin;
}
/**
* Answers the repository provider type id for the cvs plugin
*/
public static String getTypeId() {
return NATURE_ID;
}
/**
* Sets the file transfer compression level. (if supported)
* Valid levels are: 0 (disabled), 1 (worst/fastest) - 9 (best/slowest)
*/
public void setCompressionLevel(int level) {
compressionLevel = level;
}
/**
* Gets the file transfer compression level.
*/
public int getCompressionLevel() {
return compressionLevel;
}
/**
* Sets the default keyword substitution mode for text files.
*/
public void setDefaultTextKSubstOption(KSubstOption ksubst) {
defaultTextKSubstOption = ksubst;
}
/**
* Gets the default keyword substitution mode for text files.
*/
public KSubstOption getDefaultTextKSubstOption() {
return defaultTextKSubstOption;
}
/**
* Should the CVS adapter prune empty directories
*/
public boolean getPruneEmptyDirectories() {
return pruneEmptyDirectories;
}
/**
* Set whether the CVS adapter should prune empty directories
*/
public void setPruneEmptyDirectories(boolean prune) {
pruneEmptyDirectories = prune;
}
/**
* Get the communications timeout value in seconds
*/
public int getTimeout() {
return communicationsTimeout;
}
/**
* Set the timeout value for communications to a value in seconds.
* The value must be greater than or equal 0. If is it 0, there is no timeout.
*/
public void setTimeout(int timeout) {
this.communicationsTimeout = Math.max(0, timeout);
}
/**
* Set the quietness option to use with cvs commands.
* Can be "", "-q" or "-Q"
*/
public void setQuietness(QuietOption option) {
this.quietness = option;
}
/**
* Get the quietness option for commands
*/
public QuietOption getQuietness() {
return quietness;
}
/**
* Set the console listener for commands.
* @param consoleListener the listener
*/
public void setConsoleListener(IConsoleListener consoleListener) {
this.consoleListener = consoleListener;
}
/**
* Get the console listener for commands.
* @return the consoleListener, or null
*/
public IConsoleListener getConsoleListener() {
return consoleListener;
}
/**
* @see Plugin#startup()
*/
public void startup() throws CoreException {
super.startup();
Policy.localize("org.eclipse.team.internal.ccvs.core.messages"); //$NON-NLS-1$
// load the state which includes the known repositories
loadState();
// Initialize CVS change listeners. Note tha the report type is important.
IWorkspace workspace = ResourcesPlugin.getWorkspace();
addDeleteMoveListener = new AddDeleteMoveListener();
fileModificationManager = new FileModificationManager();
// Group the two PRE_AUTO_BUILD listeners together for efficiency
final IResourceChangeListener projectDescriptionListener = new ProjectDescriptionManager();
final IResourceChangeListener metaFileSyncListener = new SyncFileChangeListener();
preAutoBuildListener = new IResourceChangeListener() {
public void resourceChanged(IResourceChangeEvent event) {
projectDescriptionListener.resourceChanged(event);
metaFileSyncListener.resourceChanged(event);
}
};
workspace.addResourceChangeListener(preAutoBuildListener, IResourceChangeEvent.PRE_AUTO_BUILD);
workspace.addResourceChangeListener(addDeleteMoveListener, IResourceChangeEvent.POST_AUTO_BUILD);
workspace.addResourceChangeListener(fileModificationManager, IResourceChangeEvent.POST_CHANGE);
fileModificationManager.registerSaveParticipant();
CVSProviderPlugin.addResourceStateChangeListener(addDeleteMoveListener);
createCacheDirectory();
}
/**
* @see Plugin#shutdown()
*/
public void shutdown() throws CoreException {
super.shutdown();
// save the state which includes the known repositories
saveState();
savePluginPreferences();
// remove listeners
IWorkspace workspace = ResourcesPlugin.getWorkspace();
workspace.removeResourceChangeListener(preAutoBuildListener);
workspace.removeResourceChangeListener(fileModificationManager);
workspace.removeResourceChangeListener(addDeleteMoveListener);
// remove all of this plugin's save participants. This is easier than having
// each class that added itself as a participant to have to listen to shutdown.
workspace.removeSaveParticipant(this);
deleteCacheDirectory();
}
/**
* @see org.eclipse.core.runtime.Plugin#initializeDefaultPluginPreferences()
*/
protected void initializeDefaultPluginPreferences(){
Preferences store = getPluginPreferences();
store.setDefault(READ_ONLY, false);
}
/**
* Gets the cvsRshCommand.
* @return Returns a String
*/
public String getCvsRshCommand() {
return cvsRshCommand;
}
/**
* Sets the cvsRshCommand.
* @param cvsRshCommand The cvsRshCommand to set
*/
public void setCvsRshCommand(String cvsRshCommand) {
this.cvsRshCommand = cvsRshCommand;
}
/**
* Returns the cvsRshParameters.
* @return String
*/
public String getCvsRshParameters() {
return cvsRshParameters;
}
/**
* Sets the cvsRshParameters.
* @param cvsRshParameters The cvsRshParameters to set
*/
public void setCvsRshParameters(String cvsRshParameters) {
this.cvsRshParameters = cvsRshParameters;
}
/**
* Gets the cvsServer.
* @return Returns a String
*/
public String getCvsServer() {
return cvsServer;
}
/**
* Sets the cvsServer.
* @param cvsServer The cvsServer to set
*/
public void setCvsServer(String cvsServer) {
this.cvsServer = cvsServer;
}
/**
* Gets the etchAbsentDirectories.
* @return Returns a boolean
*/
public boolean getFetchAbsentDirectories() {
return fetchAbsentDirectories;
}
public boolean getRepositoriesAreBinary() {
return repositoriesAreBinary;
}
/**
* Sets the fetchAbsentDirectories.
* @param etchAbsentDirectories The etchAbsentDirectories to set
*/
public void setFetchAbsentDirectories(boolean fetchAbsentDirectories) {
this.fetchAbsentDirectories = fetchAbsentDirectories;
}
public boolean getPromptOnFileDelete() {
return promptOnFileDelete;
}
public void setPromptOnFileDelete(boolean prompt) {
promptOnFileDelete = prompt;
}
public void setRepositoriesAreBinary(boolean binary) {
repositoriesAreBinary = binary;
}
public boolean getPromptOnFolderDelete() {
return promptOnFolderDelete;
}
public void setPromptOnFolderDelete(boolean prompt) {
promptOnFolderDelete = prompt;
}
private static List listeners = new ArrayList();
/*
* @see ITeamManager#addResourceStateChangeListener(IResourceStateChangeListener)
*/
public static void addResourceStateChangeListener(IResourceStateChangeListener listener) {
listeners.add(listener);
}
/*
* @see ITeamManager#removeResourceStateChangeListener(IResourceStateChangeListener)
*/
public static void removeResourceStateChangeListener(IResourceStateChangeListener listener) {
listeners.remove(listener);
}
public static void broadcastSyncInfoChanges(final IResource[] resources) {
for(Iterator it=listeners.iterator(); it.hasNext();) {
final IResourceStateChangeListener listener = (IResourceStateChangeListener)it.next();
ISafeRunnable code = new ISafeRunnable() {
public void run() throws Exception {
listener.resourceSyncInfoChanged(resources);
}
public void handleException(Throwable e) {
// don't log the exception....it is already being logged in Platform#run
}
};
Platform.run(code);
}
}
public static void broadcastModificationStateChanges(final IResource[] resources) {
for(Iterator it=listeners.iterator(); it.hasNext();) {
final IResourceStateChangeListener listener = (IResourceStateChangeListener)it.next();
ISafeRunnable code = new ISafeRunnable() {
public void run() throws Exception {
listener.resourceModified(resources);
}
public void handleException(Throwable e) {
// don't log the exception....it is already being logged in Platform#run
}
};
Platform.run(code);
}
}
protected static void broadcastProjectConfigured(final IProject project) {
for(Iterator it=listeners.iterator(); it.hasNext();) {
final IResourceStateChangeListener listener = (IResourceStateChangeListener)it.next();
ISafeRunnable code = new ISafeRunnable() {
public void run() throws Exception {
listener.projectConfigured(project);
}
public void handleException(Throwable e) {
// don't log the exception....it is already being logged in Platform#run
}
};
Platform.run(code);
}
}
protected static void broadcastProjectDeconfigured(final IProject project) {
for(Iterator it=listeners.iterator(); it.hasNext();) {
final IResourceStateChangeListener listener = (IResourceStateChangeListener)it.next();
ISafeRunnable code = new ISafeRunnable() {
public void run() throws Exception {
listener.projectDeconfigured(project);
}
public void handleException(Throwable e) {
// don't log the exception....it is already being logged in Platform#run
}
};
Platform.run(code);
}
}
/**
* Gets the showTasksOnAddAndDelete.
* @return Returns a boolean
*/
public boolean getShowTasksOnAddAndDelete() {
return showTasksOnAddAndDelete;
}
/**
* Sets the showTasksOnAddAndDelete.
* @param showTasksOnAddAndDelete The showTasksOnAddAndDelete to set
*/
public void setShowTasksOnAddAndDelete(boolean showTasksOnAddAndDelete) {
this.showTasksOnAddAndDelete = showTasksOnAddAndDelete;
}
/**
* Gets the replaceUnmanaged.
* @return Returns a boolean
*/
public boolean isReplaceUnmanaged() {
return replaceUnmanaged;
}
/**
* Sets the replaceUnmanaged.
* @param replaceUnmanaged The replaceUnmanaged to set
*/
public void setReplaceUnmanaged(boolean replaceUnmanaged) {
this.replaceUnmanaged = replaceUnmanaged;
}
private void createCacheDirectory() {
try {
IPath cacheLocation = getStateLocation().append(CACHE_DIRECTORY);
File file = cacheLocation.toFile();
if (file.exists()) {
deleteFile(file);
}
file.mkdir();
cacheFileNames = new Hashtable();
cacheFileTimes = new Hashtable();
lastCacheCleanup = -1;
cacheDirSize = 0;
} catch (IOException e) {
log(new Status(IStatus.ERROR, ID, 0, Policy.bind("CVSProviderPlugin.errorCreatingCache", e.getMessage()), e)); //$NON-NLS-1$
}
}
private void deleteCacheDirectory() {
try {
IPath cacheLocation = getStateLocation().append(CACHE_DIRECTORY);
File file = cacheLocation.toFile();
if (file.exists()) {
deleteFile(file);
}
cacheFileNames = cacheFileTimes = null;
lastCacheCleanup = -1;
cacheDirSize = 0;
} catch (IOException e) {
log(new Status(IStatus.ERROR, ID, 0, Policy.bind("CVSProviderPlugin.errorDeletingCache", e.getMessage()), e)); //$NON-NLS-1$
}
}
private void deleteFile(File file) throws IOException {
if (file.isDirectory()) {
File[] children = file.listFiles();
for (int i = 0; i < children.length; i++) {
deleteFile(children[i]);
}
}
file.delete();
}
public synchronized File getCacheFileFor(String path) throws IOException {
String physicalPath;
if (cacheFileNames.containsKey(path)) {
/*
* cache hit
*/
physicalPath = (String)cacheFileNames.get(path);
registerHit(path);
} else {
/*
* cache miss
*/
physicalPath = String.valueOf(cacheDirSize++);
cacheFileNames.put(path, physicalPath);
registerHit(path);
clearOldCacheEntries();
}
return getCacheFileForPhysicalPath(physicalPath);
}
private File getCacheFileForPhysicalPath(String physicalPath) throws IOException {
return new File(getStateLocation().append(CACHE_DIRECTORY).toFile(), physicalPath);
}
private void registerHit(String path) {
cacheFileTimes.put(path, Long.toString(new Date().getTime()));
}
private void clearOldCacheEntries() throws IOException {
long current = new Date().getTime();
if ((lastCacheCleanup!=-1) && (current - lastCacheCleanup < CACHE_FILE_LIFESPAN)) return;
Enumeration e = cacheFileTimes.keys();
while (e.hasMoreElements()) {
String f = (String)e.nextElement();
long lastHit = Long.valueOf((String)cacheFileTimes.get(f)).longValue();
if ((current - lastHit) > CACHE_FILE_LIFESPAN) purgeCacheFile(f);
}
}
private void purgeCacheFile(String path) throws IOException {
File f = getCacheFileForPhysicalPath((String)cacheFileNames.get(path));
f.delete();
cacheFileTimes.remove(path);
cacheFileNames.remove(path);
}
/*
* Add the repository location to the cahced locations
*/
private void addToRepositoriesCache(ICVSRepositoryLocation repository) {
repositories.put(repository.getLocation(), repository);
Iterator it = repositoryListeners.iterator();
while (it.hasNext()) {
ICVSListener listener = (ICVSListener)it.next();
listener.repositoryAdded(repository);
}
}
private void removeFromRepositoriesCache(ICVSRepositoryLocation repository) {
if (repositories.remove(repository.getLocation()) != null) {
Iterator it = repositoryListeners.iterator();
while (it.hasNext()) {
ICVSListener listener = (ICVSListener)it.next();
listener.repositoryRemoved(repository);
}
}
}
/**
* Register to receive notification of repository creation and disposal
*/
public void addRepositoryListener(ICVSListener listener) {
repositoryListeners.add(listener);
}
/**
* De-register a listener
*/
public void removeRepositoryListener(ICVSListener listener) {
repositoryListeners.remove(listener);
}
/**
* Create a repository instance from the given properties.
* The supported properties are:
*
* connection The connection method to be used
* user The username for the connection
* password The password used for the connection (optional)
* host The host where the repository resides
* port The port to connect to (optional)
* root The server directory where the repository is located
*
* The created instance is not known by the provider and it's user information is not cached.
* The purpose of the created location is to allow connection validation before adding the
* location to the provider.
*
* This method will throw a CVSException if the location for the given configuration already
* exists.
*/
public ICVSRepositoryLocation createRepository(Properties configuration) throws CVSException {
// Create a new repository location
CVSRepositoryLocation location = CVSRepositoryLocation.fromProperties(configuration);
// Check the cache for an equivalent instance and if there is one, throw an exception
CVSRepositoryLocation existingLocation = (CVSRepositoryLocation)repositories.get(location.getLocation());
if (existingLocation != null) {
throw new CVSException(new CVSStatus(CVSStatus.ERROR, Policy.bind("CVSProvider.alreadyExists"))); //$NON-NLS-1$
}
return location;
}
/**
* Add the repository to the receiver's list of known repositories. Doing this will enable
* password caching accross platform invokations.
*/
public void addRepository(ICVSRepositoryLocation repository) throws CVSException {
// Check the cache for an equivalent instance and if there is one, just update the cache
CVSRepositoryLocation existingLocation = (CVSRepositoryLocation)repositories.get(repository.getLocation());
if (existingLocation != null) {
((CVSRepositoryLocation)repository).updateCache();
} else {
// Cache the password and register the repository location
addToRepositoriesCache(repository);
((CVSRepositoryLocation)repository).updateCache();
}
saveState();
}
/**
* Dispose of the repository location
*
* Removes any cached information about the repository such as a remembered password.
*/
public void disposeRepository(ICVSRepositoryLocation repository) throws CVSException {
((CVSRepositoryLocation)repository).dispose();
removeFromRepositoriesCache(repository);
}
/**
* Answer whether the provided repository location is known by the provider or not.
* The location string corresponds to the Strin returned by ICVSRepositoryLocation#getLocation()
*/
public boolean isKnownRepository(String location) {
return repositories.get(location) != null;
}
/**
* Return a list of the know repository locations
*/
public ICVSRepositoryLocation[] getKnownRepositories() {
return (ICVSRepositoryLocation[])repositories.values().toArray(new ICVSRepositoryLocation[repositories.size()]);
}
/**
* Get the repository instance which matches the given String. The format of the String is
* the same as that returned by ICVSRepositoryLocation#getLocation().
* The format is:
*
* connection:user[:password]@host[#port]:root
*
* where [] indicates optional and the identier meanings are:
*
* connection The connection method to be used
* user The username for the connection
* password The password used for the connection (optional)
* host The host where the repository resides
* port The port to connect to (optional)
* root The server directory where the repository is located
*
* It is expected that the instance requested by using this method exists.
* If the repository location does not exist, it will be automatically created
* and cached with the provider.
*
* WARNING: Providing the password as part of the String will result in the password being part
* of the location permanently. This means that it cannot be modified by the authenticator.
*/
public ICVSRepositoryLocation getRepository(String location) throws CVSException {
ICVSRepositoryLocation repository = (ICVSRepositoryLocation)repositories.get(location);
if (repository == null) {
repository = CVSRepositoryLocation.fromString(location);
addToRepositoriesCache(repository);
}
return repository;
}
private void loadState() {
try {
IPath pluginStateLocation = CVSProviderPlugin.getPlugin().getStateLocation().append(REPOSITORIES_STATE_FILE);
File file = pluginStateLocation.toFile();
if (file.exists()) {
try {
DataInputStream dis = new DataInputStream(new FileInputStream(file));
readState(dis);
dis.close();
} catch (IOException e) {
throw new TeamException(new Status(Status.ERROR, CVSProviderPlugin.ID, TeamException.UNABLE, Policy.bind("CVSProvider.ioException"), e)); //$NON-NLS-1$
}
} else {
// If the file did not exist, then prime the list of repositories with
// the providers with which the projects in the workspace are shared.
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
for (int i = 0; i < projects.length; i++) {
RepositoryProvider provider = RepositoryProvider.getProvider(projects[i], CVSProviderPlugin.getTypeId());
if (provider!=null) {
ICVSFolder folder = (ICVSFolder)CVSWorkspaceRoot.getCVSResourceFor(projects[i]);
FolderSyncInfo info = folder.getFolderSyncInfo();
if (info != null) {
ICVSRepositoryLocation result = getRepository(info.getRoot());
}
}
}
saveState();
}
} catch (TeamException e) {
Util.logError(Policy.bind("CVSProvider.errorLoading"), e);//$NON-NLS-1$
}
}
private void saveState() {
try {
IPath pluginStateLocation = CVSProviderPlugin.getPlugin().getStateLocation();
File tempFile = pluginStateLocation.append(REPOSITORIES_STATE_FILE + ".tmp").toFile(); //$NON-NLS-1$
File stateFile = pluginStateLocation.append(REPOSITORIES_STATE_FILE).toFile();
try {
DataOutputStream dos = new DataOutputStream(new FileOutputStream(tempFile));
writeState(dos);
dos.close();
if (stateFile.exists()) {
stateFile.delete();
}
boolean renamed = tempFile.renameTo(stateFile);
if (!renamed) {
throw new TeamException(new Status(Status.ERROR, CVSProviderPlugin.ID, TeamException.UNABLE, Policy.bind("CVSProvider.rename", tempFile.getAbsolutePath()), null)); //$NON-NLS-1$
}
} catch (IOException e) {
throw new TeamException(new Status(Status.ERROR, CVSProviderPlugin.ID, TeamException.UNABLE, Policy.bind("CVSProvider.save",stateFile.getAbsolutePath()), e)); //$NON-NLS-1$
}
} catch (TeamException e) {
Util.logError(Policy.bind("CVSProvider.errorSaving"), e);//$NON-NLS-1$
}
}
private void readState(DataInputStream dis) throws IOException, CVSException {
int count = dis.readInt();
if (count >= 0) {
// this is the version 1 format of the state file
for (int i = 0; i < count; i++) {
getRepository(dis.readUTF());
}
} else if (count == REPOSITORIES_STATE_FILE_VERSION_2) {
count = dis.readInt();
for (int i = 0; i < count; i++) {
ICVSRepositoryLocation root = getRepository(dis.readUTF());
String programName = dis.readUTF();
if (!programName.equals(CVSRepositoryLocation.DEFAULT_REMOTE_CVS_PROGRAM_NAME)) {
((CVSRepositoryLocation)root).setRemoteCVSProgramName(programName);
}
}
} else {
Util.logError(Policy.bind("CVSProviderPlugin.unknownStateFileVersion", new Integer(count).toString()), null); //$NON-NLS-1$
}
}
private void writeState(DataOutputStream dos) throws IOException {
// Write the repositories
dos.writeInt(REPOSITORIES_STATE_FILE_VERSION_2);
// Write out the repos
Collection repos = repositories.values();
dos.writeInt(repos.size());
Iterator it = repos.iterator();
while (it.hasNext()) {
CVSRepositoryLocation root = (CVSRepositoryLocation)it.next();
dos.writeUTF(root.getLocation());
dos.writeUTF(root.getRemoteCVSProgramName());
}
}
public static boolean isText(IFile file) {
if (CVSProviderPlugin.getPlugin().getRepositoriesAreBinary()) return false;
return Team.getType(file) == Team.TEXT;
}
/**
* Gets the determineVersionEnabled.
* @return boolean
*/
public boolean isDetermineVersionEnabled() {
return determineVersionEnabled;
}
/**
* Sets the determineVersionEnabled.
* @param determineVersionEnabled The determineVersionEnabled to set
*/
public void setDetermineVersionEnabled(boolean determineVersionEnabled) {
this.determineVersionEnabled = determineVersionEnabled;
}
/**
* Set the program name of the given repository location.
* The program name is the expected prefix on server text messages.
* Since we extract information out of these messages, we need to
* know what prefix to expect. The default is "cvs".
*/
public void setCVSProgramName(ICVSRepositoryLocation location, String programName) {
((CVSRepositoryLocation)location).setRemoteCVSProgramName(programName);
saveState();
}
/**
* Method getResetTimestampOfFalseChange.
* @return boolean
*/
public boolean getResetTimestampOfFalseChange() {
return true;
}
/**
* Returns the fileModificationManager.
* @return FileModificationManager
*/
public FileModificationManager getFileModificationManager() {
return fileModificationManager;
}
}