diff options
author | Jean Michel-Lemieux | 2002-03-14 21:07:51 +0000 |
---|---|---|
committer | Jean Michel-Lemieux | 2002-03-14 21:07:51 +0000 |
commit | 49ec2e4328d11773a71ab5c19c78eb7b27658b04 (patch) | |
tree | 20bf711e87d8b6aa3648c1ec6c60b4d76f18e670 | |
parent | e553ae8428e5b298e4cf15d7ba0206997d7091f7 (diff) | |
download | eclipse.platform.team-teamApiChangesBranch.tar.gz eclipse.platform.team-teamApiChangesBranch.tar.xz eclipse.platform.team-teamApiChangesBranch.zip |
*** empty log message ***teamApiChangesBranch
47 files changed, 982 insertions, 262 deletions
diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/RepositoryProvider.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/RepositoryProvider.java index 1f94a5b72..6a49a3f8c 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/RepositoryProvider.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/RepositoryProvider.java @@ -12,6 +12,7 @@ import org.eclipse.core.resources.IFileModificationValidator; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.team.core.*; +import org.eclipse.team.core.internal.Policy; /** * A concrete subclass of <code>RepositoryProvider</code> is created for each @@ -61,9 +62,28 @@ public abstract class RepositoryProvider implements IProjectNature { */ final public void configure() throws CoreException { RepositoryProvider provider = RepositoryProviderType.getProvider(getProject()); - if(provider!=null) { - throw new CoreException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, "A provider is already associated with this project: " + provider, null)); - } + // Core Bug 11395 + // When configure is called the nature has already been assigned to the project. This check will always + // fail. Also, if configure fails the nature is still added to the project. + //if(provider!=null) { + // throw new CoreException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, "A provider is already associated with this project: " + provider, null)); + //} + // Alternate slower check + RepositoryProviderType[] types = RepositoryProviderType.getAllProviderTypes(); + int count = 0; + for (int i = 0; i < types.length; i++) { + if(getProject().getNature(types[i].getID())!=null) { + count++; + } + } + if(count>1) { + try { + TeamPlugin.removeNatureFromProject(getProject(), getProviderType().getID(), null); + } catch(TeamException e) { + throw new CoreException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("RepositoryProvider_Error_removing_nature_from_project___1") + provider, null)); //$NON-NLS-1$ + } + throw new CoreException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("RepositoryProvider_Too_many_providers_associated_with_project___2") + provider, null)); //$NON-NLS-1$ + } configureProject(); } @@ -118,6 +138,6 @@ public abstract class RepositoryProvider implements IProjectNature { * @return a string description of this provider */ public String toString() { - return getProject().getName() + ":" + getProviderType(); + return getProject().getName() + ":" + getProviderType(); //$NON-NLS-1$ } } diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/RepositoryProviderType.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/RepositoryProviderType.java index ae1807244..1c865b34d 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/RepositoryProviderType.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/RepositoryProviderType.java @@ -15,6 +15,7 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.team.core.internal.Policy; /** * Describes a type of repository provider snf provides @@ -42,7 +43,7 @@ abstract public class RepositoryProviderType { */ final public static void addProviderType(RepositoryProviderType providerType) throws TeamException { if(providerTypes.containsKey(providerType.getID())) { - throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, "duplicate provider found in plugin.xml: " + providerType.getID(), null)); + throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("RepositoryProviderTypeduplicate_provider_found_in_plugin.xml___1") + providerType.getID(), null)); //$NON-NLS-1$ } else { providerTypes.put(providerType.getID(), providerType); } @@ -93,15 +94,16 @@ abstract public class RepositoryProviderType { final public RepositoryProvider getInstance(IProject project) { String id = getID(); try { - return (RepositoryProvider)project.getNature(id); + if(project.isOpen()) { + return (RepositoryProvider)project.getNature(id); + } } catch(ClassCastException e) { - TeamPlugin.log(new Status(IStatus.ERROR, TeamPlugin.ID, 0, "RepositoryProvider assigned to the project must be a subclass of RepositoryProvider: " + id, e)); - return null; + TeamPlugin.log(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("RepositoryProviderTypeRepositoryProvider_assigned_to_the_project_must_be_a_subclass_of_RepositoryProvider___2") + id, e)); //$NON-NLS-1$ } catch(CoreException ex) { // would happen if provider nature id is not registered with the resources plugin - TeamPlugin.log(new Status(IStatus.WARNING, TeamPlugin.ID, 0, "RepositoryProvider not registered as a nature id: " + id, ex)); - return null; + TeamPlugin.log(new Status(IStatus.WARNING, TeamPlugin.ID, 0, Policy.bind("RepositoryProviderTypeRepositoryProvider_not_registered_as_a_nature_id___3") + id, ex)); //$NON-NLS-1$ } + return null; } /** diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/TeamPlugin.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/TeamPlugin.java index 9757de179..d256ac334 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/TeamPlugin.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/TeamPlugin.java @@ -42,32 +42,29 @@ import org.eclipse.team.core.internal.Policy; * resource management plugin. * <p> * This plugin provides a lightweight registration and lookup service for - * associating projects with providers. The registration mechanism is - * based on the platform's project natures. Using projects natures allows - * manipulating a project in a nature-specific way, for example UI - * contributions can be made conditional based on the nature of a project. + * managing global ignores patterns and file type associations. Also it + * serves as a boot strap for registration of RepositoryProviderType classes. * </p> * - * @see ITeamNature - * @see ITeamProvider - * @see ITeamManager + * @see RepositoryProvider + * @see RepositoryProviderType */ final public class TeamPlugin extends Plugin { // The id of the core team plug-in - public static final String ID = "org.eclipse.team.core"; + public static final String ID = "org.eclipse.team.core"; //$NON-NLS-1$ // The id of the providers extension point - private static final String PROVIDER_EXTENSION = "repository-provider-type"; + private static final String PROVIDER_EXTENSION = "repository-provider-type"; //$NON-NLS-1$ // The id of the file types extension point - private static final String FILE_TYPES_EXTENSION = "fileTypes"; + private static final String FILE_TYPES_EXTENSION = "fileTypes"; //$NON-NLS-1$ // The id of the global ignore extension point - private static final String IGNORE_EXTENSION = "ignore"; + private static final String IGNORE_EXTENSION = "ignore"; //$NON-NLS-1$ // File name of the persisted global ignore patterns - private final static String GLOBALIGNORE_FILE = ".globalIgnores"; + private final static String GLOBALIGNORE_FILE = ".globalIgnores"; //$NON-NLS-1$ // The ignore list that is read at startup from the persisted file private static Map globalIgnore = new HashMap(11); @@ -91,7 +88,7 @@ final public class TeamPlugin extends Plugin { */ public void startup() throws CoreException { try { - Policy.localize("org.eclipse.team.core.internal.messages"); + Policy.localize("org.eclipse.team.core.internal.messages"); //$NON-NLS-1$ registry = new FileTypeRegistry(); registry.startup(); @@ -179,7 +176,7 @@ final public class TeamPlugin extends Plugin { // make sure that we update our state on disk savePluginState(); } catch (TeamException ex) { - TeamPlugin.log(IStatus.WARNING, "setting global ignore", ex); + TeamPlugin.log(IStatus.WARNING, Policy.bind("TeamPlugin_setting_global_ignore_7"), ex); //$NON-NLS-1$ } } @@ -196,7 +193,7 @@ final public class TeamPlugin extends Plugin { description.setNatureIds(newNatures); proj.setDescription(description, monitor); } catch(CoreException e) { - throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("manager.errorSettingNature", + throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("manager.errorSettingNature", //$NON-NLS-1$ proj.getName(), natureId), e)); } } @@ -213,7 +210,7 @@ final public class TeamPlugin extends Plugin { description.setNatureIds((String[])newNatures.toArray(new String[newNatures.size()])); proj.setDescription(description, monitor); } catch(CoreException e) { - throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("manager.errorRemovingNature", + throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("manager.errorRemovingNature", //$NON-NLS-1$ proj.getName(), natureId), e)); } } @@ -225,7 +222,7 @@ final public class TeamPlugin extends Plugin { IExtensionPoint extensionPoint = Platform.getPluginRegistry().getExtensionPoint(TeamPlugin.ID, TeamPlugin.PROVIDER_EXTENSION); if (extensionPoint == null) { - throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("manager.providerExtensionNotFound"), null)); + throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("manager.providerExtensionNotFound"), null)); //$NON-NLS-1$ } IExtension[] extensions = extensionPoint.getExtensions(); @@ -237,24 +234,24 @@ final public class TeamPlugin extends Plugin { if (configs.length == 0) { // there is no configuration element // log as an error but continue to instantiate other executable extensions. - TeamPlugin.log(IStatus.ERROR, Policy.bind("manager.providerNoConfigElems", extension.getUniqueIdentifier()), null); + TeamPlugin.log(IStatus.ERROR, Policy.bind("manager.providerNoConfigElems", extension.getUniqueIdentifier()), null); //$NON-NLS-1$ continue; } IConfigurationElement config = configs[0]; String configName = config.getName(); - if (!"repository".equals(config.getName())) { - String message = Policy.bind("resources.natureFormat", configName); + if (!"repository".equals(config.getName())) { //$NON-NLS-1$ + String message = Policy.bind("resources.natureFormat", configName); //$NON-NLS-1$ throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, message, null)); } try { - RepositoryProviderType providerType = (RepositoryProviderType) config.createExecutableExtension("provider-type"); + RepositoryProviderType providerType = (RepositoryProviderType) config.createExecutableExtension("provider-type"); //$NON-NLS-1$ RepositoryProviderType.addProviderType(providerType); } catch (ClassCastException e) { - String message = Policy.bind("resources.natureImplement", configName); + String message = Policy.bind("resources.natureImplement", configName); //$NON-NLS-1$ throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, message, null)); } catch (CoreException e){ - String message = Policy.bind("resources.natureImplement", configName); + String message = Policy.bind("resources.natureImplement", configName); //$NON-NLS-1$ throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, message, null)); } } @@ -272,10 +269,10 @@ final public class TeamPlugin extends Plugin { for (int i = 0; i < extensions.length; i++) { IConfigurationElement [] configElements = extensions[i].getConfigurationElements(); for (int j = 0; j < configElements.length; j++) { - String pattern = configElements[j].getAttribute("pattern"); + String pattern = configElements[j].getAttribute("pattern"); //$NON-NLS-1$ if (pattern != null) { - String selected = configElements[j].getAttribute("selected"); - boolean enabled = selected != null && selected.equalsIgnoreCase("true"); + String selected = configElements[j].getAttribute("selected"); //$NON-NLS-1$ + boolean enabled = selected != null && selected.equalsIgnoreCase("true"); //$NON-NLS-1$ // if this ignore doesn't already exist, add it to the global list if (!globalIgnore.containsKey(pattern)) { globalIgnore.put(pattern, new Boolean(enabled)); @@ -293,7 +290,7 @@ final public class TeamPlugin extends Plugin { private void savePluginState() throws TeamException { // save global ignore list to disk IPath pluginStateLocation = TeamPlugin.getPlugin().getStateLocation(); - File tempFile = pluginStateLocation.append(GLOBALIGNORE_FILE + ".tmp").toFile(); + File tempFile = pluginStateLocation.append(GLOBALIGNORE_FILE + ".tmp").toFile(); //$NON-NLS-1$ File stateFile = pluginStateLocation.append(GLOBALIGNORE_FILE).toFile(); try { DataOutputStream dos = new DataOutputStream(new FileOutputStream(tempFile)); @@ -303,9 +300,9 @@ final public class TeamPlugin extends Plugin { stateFile.delete(); boolean renamed = tempFile.renameTo(stateFile); if (!renamed) - throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, "renaming", null)); + throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("TeamPlugin_renaming_21"), null)); //$NON-NLS-1$ } catch (IOException ex) { - throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, "closing stream", ex)); + throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("TeamPlugin_closing_stream_22"), ex)); //$NON-NLS-1$ } } @@ -349,7 +346,7 @@ final public class TeamPlugin extends Plugin { } catch(FileNotFoundException e) { // not a fatal error, there just happens not to be any state to read } catch (IOException ex) { - throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, "closing stream", ex)); + throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("TeamPlugin_closing_stream_23"), ex)); //$NON-NLS-1$ } } } diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/FileModificationValidator.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/FileModificationValidator.java index 5359dc5e7..ebd30963c 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/FileModificationValidator.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/FileModificationValidator.java @@ -15,8 +15,8 @@ import org.eclipse.team.core.RepositoryProviderType; import org.eclipse.team.core.TeamPlugin; public class FileModificationValidator implements IFileModificationValidator { - private static final Status OK = new Status(Status.OK, TeamPlugin.ID, Status.OK, Policy.bind("FileModificationValidator.ok"), null); - private static final Status READ_ONLY = new Status(Status.ERROR, TeamPlugin.ID, Status.ERROR, Policy.bind("FileModificationValidator.isReadOnly"), null); + private static final Status OK = new Status(Status.OK, TeamPlugin.ID, Status.OK, Policy.bind("FileModificationValidator.ok"), null); //$NON-NLS-1$ + private static final Status READ_ONLY = new Status(Status.ERROR, TeamPlugin.ID, Status.ERROR, Policy.bind("FileModificationValidator.isReadOnly"), null); //$NON-NLS-1$ /* * @see IFileModificationValidator#validateEdit(IFile[], Object) @@ -45,7 +45,7 @@ public class FileModificationValidator implements IFileModificationValidator { if (result.length == 1) { return result[0]; } - return new MultiStatus(TeamPlugin.ID, 0, result, Policy.bind("FileModificationValidator.validateEdit"), null); + return new MultiStatus(TeamPlugin.ID, 0, result, Policy.bind("FileModificationValidator.validateEdit"), null); //$NON-NLS-1$ } /* diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/FileTypeRegistry.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/FileTypeRegistry.java index 30cc05d89..8abbd49bd 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/FileTypeRegistry.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/FileTypeRegistry.java @@ -28,10 +28,10 @@ import org.eclipse.team.core.TeamPlugin; */ public class FileTypeRegistry implements IFileTypeRegistry { // Constant for the saved state file name - private static final String STATE_FILE = ".fileTypes"; + private static final String STATE_FILE = ".fileTypes"; //$NON-NLS-1$ // The id of the file types extension point - private static final String FILE_TYPES_EXTENSION = "fileTypes"; + private static final String FILE_TYPES_EXTENSION = "fileTypes"; //$NON-NLS-1$ // Keys: file extensions. Values: Integers private Hashtable table; @@ -99,14 +99,14 @@ public class FileTypeRegistry implements IFileTypeRegistry { for (int i = 0; i < extensions.length; i++) { IConfigurationElement[] configElements = extensions[i].getConfigurationElements(); for (int j = 0; j < configElements.length; j++) { - String ext = configElements[j].getAttribute("extension"); + String ext = configElements[j].getAttribute("extension"); //$NON-NLS-1$ if (ext != null) { - String type = configElements[j].getAttribute("type"); + String type = configElements[j].getAttribute("type"); //$NON-NLS-1$ // If the extension doesn't already exist, add it. if (!containsExtension(ext)) { - if (type.equals("text")) { + if (type.equals("text")) { //$NON-NLS-1$ setValue(ext, TEXT); - } else if (type.equals("binary")) { + } else if (type.equals("binary")) { //$NON-NLS-1$ setValue(ext, BINARY); } } @@ -179,7 +179,7 @@ public class FileTypeRegistry implements IFileTypeRegistry { */ private void savePluginState() { IPath pluginStateLocation = TeamPlugin.getPlugin().getStateLocation(); - File tempFile = pluginStateLocation.append(STATE_FILE + ".tmp").toFile(); + File tempFile = pluginStateLocation.append(STATE_FILE + ".tmp").toFile(); //$NON-NLS-1$ File stateFile = pluginStateLocation.append(STATE_FILE).toFile(); try { DataOutputStream dos = new DataOutputStream(new FileOutputStream(tempFile)); diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/Policy.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/Policy.java index f429d24cd..f6eda9292 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/Policy.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/Policy.java @@ -50,7 +50,7 @@ public class Policy { } catch (MissingResourceException e) { return key; } catch (NullPointerException e) { - return "!" + key + "!"; + return "!" + key + "!"; //$NON-NLS-1$ //$NON-NLS-2$ } } @@ -64,7 +64,7 @@ public class Policy { } catch (MissingResourceException e) { return key; } catch (NullPointerException e) { - return "!" + key + "!"; + return "!" + key + "!"; //$NON-NLS-1$ //$NON-NLS-2$ } } diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/messages.properties b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/messages.properties index 24861f038..47cd4dfee 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/messages.properties +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/internal/messages.properties @@ -19,3 +19,13 @@ manager.coreException=Error creating validator decorator: core exception FileModificationValidator.validateEdit=Validate Edit FileModificationValidator.isReadOnly=File is Read Only. FileModificationValidator.ok=OK + +RepositoryProvider_Error_removing_nature_from_project___1=Error removing nature from project: +RepositoryProvider_Too_many_providers_associated_with_project___2=Too many providers associated with project: +RepositoryProviderTypeduplicate_provider_found_in_plugin.xml___1=duplicate provider found in plugin.xml: +RepositoryProviderTypeRepositoryProvider_assigned_to_the_project_must_be_a_subclass_of_RepositoryProvider___2=RepositoryProvider assigned to the project must be a subclass of RepositoryProvider: +RepositoryProviderTypeRepositoryProvider_not_registered_as_a_nature_id___3=RepositoryProvider not registered as a nature id: +TeamPlugin_setting_global_ignore_7=setting global ignore +TeamPlugin_renaming_21=renaming +TeamPlugin_closing_stream_22=closing stream +TeamPlugin_closing_stream_23=closing stream diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/sync/Assert.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/sync/Assert.java index 6af2dbd6f..0f19040dd 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/sync/Assert.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/sync/Assert.java @@ -28,7 +28,7 @@ private Assert() { * @exception IllegalArgumentException if the legality test failed */ public static boolean isLegal(boolean expression) { - return isLegal(expression, ""/*nonNLS*/); + return isLegal(expression, ""); //$NON-NLS-1$ } /** Asserts that an argument is legal. If the given boolean is * not <code>true</code>, an <code>IllegalArgumentException</code> @@ -53,7 +53,7 @@ public static boolean isLegal(boolean expression, String message) { * @exception IllegalArgumentException if the object is <code>null</code> */ public static void isNotNull(Object object) { - isNotNull(object, ""/*nonNLS*/); + isNotNull(object, ""/*nonNLS*/); //$NON-NLS-1$ } /** Asserts that the given object is not <code>null</code>. If this * is not the case, some kind of unchecked exception is thrown. @@ -65,7 +65,7 @@ public static void isNotNull(Object object) { */ public static void isNotNull(Object object, String message) { if (object == null) - throw new AssertionFailedException("null argument:" /*non NLS*/ + message); + throw new AssertionFailedException("null argument:" /*non NLS*/ + message); //$NON-NLS-1$ } /** Asserts that the given boolean is <code>true</code>. If this * is not the case, some kind of unchecked exception is thrown. @@ -75,7 +75,7 @@ public static void isNotNull(Object object, String message) { * if the check fails) */ public static boolean isTrue(boolean expression) { - return isTrue(expression, ""/*nonNLS*/); + return isTrue(expression, ""/*nonNLS*/); //$NON-NLS-1$ } /** Asserts that the given boolean is <code>true</code>. If this * is not the case, some kind of unchecked exception is thrown. @@ -88,7 +88,7 @@ public static boolean isTrue(boolean expression) { */ public static boolean isTrue(boolean expression, String message) { if (!expression) - throw new AssertionFailedException("assert failed:" /*non NLS*/ + message); + throw new AssertionFailedException("assert failed:" /*non NLS*/ + message); //$NON-NLS-1$ return expression; } /** diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/sync/RemoteSyncElement.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/sync/RemoteSyncElement.java index 571779e73..3ffd4be20 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/sync/RemoteSyncElement.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/sync/RemoteSyncElement.java @@ -368,25 +368,25 @@ public abstract class RemoteSyncElement extends LocalSyncElement implements IRem */ public String toString() { StringBuffer buffer = new StringBuffer(); - buffer.append(getName() + "["); + buffer.append(getName() + "["); //$NON-NLS-1$ int kind = getSyncKind(GRANULARITY_TIMESTAMP, null); if(kind==IN_SYNC) { - buffer.append("in-sync"); + buffer.append("in-sync"); //$NON-NLS-1$ } else { switch(kind & DIRECTION_MASK) { - case CONFLICTING: buffer.append("conflicting"); break; - case OUTGOING: buffer.append("outgoing"); break; - case INCOMING: buffer.append("incoming"); break; + case CONFLICTING: buffer.append("conflicting"); break; //$NON-NLS-1$ + case OUTGOING: buffer.append("outgoing"); break; //$NON-NLS-1$ + case INCOMING: buffer.append("incoming"); break; //$NON-NLS-1$ } switch(kind & DIRECTION_MASK) { - case CHANGE: buffer.append("change"); break; - case ADDITION: buffer.append("addition"); break; - case DELETION: buffer.append("deletion"); break; + case CHANGE: buffer.append("change"); break; //$NON-NLS-1$ + case ADDITION: buffer.append("addition"); break; //$NON-NLS-1$ + case DELETION: buffer.append("deletion"); break; //$NON-NLS-1$ } - if((kind & MANUAL_CONFLICT) != 0) buffer.append("{manual}"); - if((kind & AUTOMERGE_CONFLICT) != 0) buffer.append("{auto}"); + if((kind & MANUAL_CONFLICT) != 0) buffer.append("{manual}"); //$NON-NLS-1$ + if((kind & AUTOMERGE_CONFLICT) != 0) buffer.append("{auto}"); //$NON-NLS-1$ } - buffer.append("]"); + buffer.append("]"); //$NON-NLS-1$ return buffer.toString(); } }
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProvider.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProvider.java index 6298f0438..c72db56e1 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProvider.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProvider.java @@ -582,7 +582,7 @@ public class CVSProvider implements ICVSProvider { IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (int i = 0; i < projects.length; i++) { RepositoryProvider provider = RepositoryProviderType.getProvider(projects[i]); - if (provider.isOfType(CVSProviderPlugin.getTypeId())) { + if (provider!=null && provider.isOfType(CVSProviderPlugin.getTypeId())) { ICVSFolder folder = (ICVSFolder)CVSWorkspaceRoot.getCVSResourceFor(projects[i]); FolderSyncInfo info = folder.getFolderSyncInfo(); if (info != null) { diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java index b5fe9d0e6..d67375238 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java @@ -202,7 +202,7 @@ public class CVSProviderPlugin extends Plugin { IProject project = (IProject)resource; // Get the team provider for the project and RepositoryProvider provider = RepositoryProviderType.getProvider(project); - if(!provider.isOfType(NATURE_ID)) continue; + if(provider==null || !provider.isOfType(NATURE_ID)) continue; /* Check if the project description changed. */ if ((delta.getFlags() & IResourceDelta.DESCRIPTION) != 0) { /* The project description changed. Write the file. */ diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java index 445f128d4..f4bb6865e 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java @@ -5,12 +5,18 @@ package org.eclipse.team.ccvs.core; * All Rights Reserved. */ +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; +import java.util.Iterator; import java.util.List; -import java.util.Properties; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -40,8 +46,11 @@ import org.eclipse.team.internal.ccvs.core.client.ResponseHandler; import org.eclipse.team.internal.ccvs.core.client.Session; import org.eclipse.team.internal.ccvs.core.client.Tag; import org.eclipse.team.internal.ccvs.core.client.Update; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption; +import org.eclipse.team.internal.ccvs.core.client.listeners.AdminKSubstListener; import org.eclipse.team.internal.ccvs.core.client.listeners.DiffListener; +import org.eclipse.team.internal.ccvs.core.client.listeners.ICommandOutputListener; 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.resources.CVSRemoteSyncElement; @@ -80,7 +89,13 @@ import org.eclipse.team.internal.ccvs.core.util.Assert; * have them appear in Eclipse. This may be changed in the future. */ public class CVSTeamProvider extends RepositoryProvider { - + + private static final int CR_BYTE = 0x0D; + private static final int LF_BYTE = 0x0A; + private static final boolean IS_CRLF_PLATFORM = Arrays.equals( + System.getProperty("line.separator").getBytes(), + new byte[] { CR_BYTE, LF_BYTE }); + private CVSWorkspaceRoot workspaceRoot; private IProject project; private String comment = ""; //$NON-NLS-1$ @@ -639,7 +654,7 @@ public class CVSTeamProvider extends RepositoryProvider { CVSProvider.getInstance().addRepository(newLocation); // Set the project to use the new Locations - setRemoteRoot(newLocation, Policy.infiniteSubMonitorFor(monitor, 80)); + setRemoteRoot(newLocation, Policy.subMonitorFor(monitor, 80)); return true; } finally { monitor.done(); @@ -886,30 +901,40 @@ public class CVSTeamProvider extends RepositoryProvider { /* * This method expects to be passed an InfiniteSubProgressMonitor */ - private void setRemoteRoot(ICVSRepositoryLocation location, final IProgressMonitor monitor) throws TeamException { + private void setRemoteRoot(ICVSRepositoryLocation location, IProgressMonitor monitor) throws TeamException { // Check if there is a differnece between the new and old roots final String root = location.getLocation(); if (root.equals(workspaceRoot.getRemoteLocation())) return; - + try { - // 256 ticks gives us a maximum of 1024 which seems reasonable for folders is a project - monitor.beginTask(Policy.bind("CVSTeamProvider.folderInfo", project.getName()), 256); //$NON-NLS-1$ - - // Visit all the children folders in order to set the root in the folder sync info - workspaceRoot.getLocalRoot().accept(new ICVSResourceVisitor() { - public void visitFile(ICVSFile file) throws CVSException {}; - public void visitFolder(ICVSFolder folder) throws CVSException { - monitor.worked(1); - FolderSyncInfo info = folder.getFolderSyncInfo(); - if (info != null) { - monitor.subTask(Policy.bind("CVSTeamProvider.updatingFolder", info.getRepository())); //$NON-NLS-1$ - folder.setFolderSyncInfo(new FolderSyncInfo(info.getRepository(), root, info.getTag(), info.getIsStatic())); - folder.acceptChildren(this); + workspaceRoot.getLocalRoot().run(new ICVSRunnable() { + public void run(IProgressMonitor progress) throws CVSException { + try { + // 256 ticks gives us a maximum of 1024 which seems reasonable for folders is a project + progress.beginTask(null, 100); + final IProgressMonitor monitor = Policy.infiniteSubMonitorFor(progress, 100); + monitor.beginTask(Policy.bind("CVSTeamProvider.folderInfo", project.getName()), 256); //$NON-NLS-1$ + + // Visit all the children folders in order to set the root in the folder sync info + workspaceRoot.getLocalRoot().accept(new ICVSResourceVisitor() { + public void visitFile(ICVSFile file) throws CVSException {}; + public void visitFolder(ICVSFolder folder) throws CVSException { + monitor.worked(1); + FolderSyncInfo info = folder.getFolderSyncInfo(); + if (info != null) { + monitor.subTask(Policy.bind("CVSTeamProvider.updatingFolder", info.getRepository())); //$NON-NLS-1$ + folder.setFolderSyncInfo(new FolderSyncInfo(info.getRepository(), root, info.getTag(), info.getIsStatic())); + folder.acceptChildren(this); + } + }; + }); + } finally { + progress.done(); } - }; - }); + } + }, monitor); } finally { monitor.done(); } @@ -943,4 +968,226 @@ public class CVSTeamProvider extends RepositoryProvider { public RepositoryProviderType getProviderType() { return CVSRepositoryProviderType.getInstance(); } + + /** + * Fixes the line delimiters in the local file to reflect the platform's + * native encoding. Performs CR/LF -> LF or LF -> CR/LF conversion + * depending on the platform but does not affect delimiters that are + * already correctly encoded. + */ + public static void cleanLineDelimiters(IFile file, boolean useCRLF, IProgressMonitor progress) + throws CVSException { + try { + // convert delimiters in memory + boolean changed = false; + InputStream is = null; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + try { + is = new BufferedInputStream(file.getContents()); + boolean seenCR = false; + int c; + while ((c = is.read()) != -1) { + if (c == LF_BYTE) { + if (useCRLF) { + bos.write(CR_BYTE); + if (! seenCR) changed = true; // added CR + } else { + if (seenCR) changed = true; // stripped CR + } + bos.write(LF_BYTE); + seenCR = false; + } else { + if (seenCR) { + bos.write(CR_BYTE); // preserve orphaned carriage returns + seenCR = false; + } + if (c == CR_BYTE) { + seenCR = true; + } else { + bos.write(c); + } + } + } + if (seenCR) { + bos.write(CR_BYTE); // preserve orphaned carriage returns + } + } finally { + if (is != null) is.close(); + bos.close(); + } + if (changed) { + // write file back to disk with corrected delimiters if changes were made + ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); + file.setContents(bis, false /*force*/, true /*keepHistory*/, progress); + } else { + // otherwise make the file dirty + makeDirty(file); + } + } catch (CoreException e) { + throw CVSException.wrapException(file, Policy.bind("CVSTeamProvider.cleanLineDelimitersException"), e); + } catch (IOException e) { + throw CVSException.wrapException(file, Policy.bind("CVSTeamProvider.cleanLineDelimitersException"), e); + } + } + + /** + * Sets the keyword substitution mode for the specified resources. + * <p> + * Applies the following rules in order:<br> + * <ul> + * <li>If a file is not managed, skips it.</li> + * <li>If a file is not changing modes, skips it.</li> + * <li>If a file is being changed from binary to text, corrects line delimiters + * then commits it, then admins it.</li> + * <li>If a file is added, changes the resource sync information locally.</li> + * <li>Otherwise commits the file (with FORCE to create a new revision), then admins it.</li> + * </ul> + * All files that are admin'd are committed with FORCE to prevent other developers from + * casually trying to commit pending changes to the repository without first checking out + * a new copy. This is not a perfect solution, as they could just as easily do an UPDATE + * and not obtain the new keyword sync info. + * </p> + * + * @param resources the resources to set keyword substitution mode + * @param depth the recursion depth + * @param toKSubst the desired keyword substitution mode + * @param monitor the progress monitor + * @return a status code indicating success or failure of the operation + * + * @throws TeamException + */ + public IStatus setKeywordSubstitution(final IResource[] resources, final int depth, + final KSubstOption toKSubst, IProgressMonitor monitor) throws TeamException { + final IStatus[] result = new IStatus[] { ICommandOutputListener.OK }; + workspaceRoot.getLocalRoot().run(new ICVSRunnable() { + public void run(final IProgressMonitor monitor) throws CVSException { + final boolean toBinary = toKSubst.isBinary(); + final List /* of String */ filesToAdmin = new ArrayList(); + final List /* of String */ filesToCommit = new ArrayList(); + final Collection /* of ICVSFile */ filesToCommitAsText = new HashSet(); // need fast lookup + + final IProgressMonitor progress = Policy.monitorFor(monitor); + progress.beginTask(Policy.bind("CVSTeamProvider.preparingToSetKSubst"), 100); + try { + /*** get all possibly affected files (ensure no duplicates) ***/ + final Set /* of IFile */ files = new HashSet(); + for (int i = 0; i < resources.length; i++) { + final IResource currentResource = resources[i]; + // throw an exception if the resource is not a child of the receiver + checkIsChild(currentResource); + try { + currentResource.accept(new IResourceVisitor() { + public boolean visit(IResource resource) throws CoreException { + if (resource.getType() == IResource.FILE) { + files.add(resource); + } + // always return true and let the depth determine if children are visited + return true; + } + }, depth, false); + } catch (CoreException e) { + throw new CVSException(new Status(IStatus.ERROR, CVSProviderPlugin.ID, + TeamException.UNABLE, Policy.bind("CVSTeamProvider.visitError", //$NON-NLS-1$ + new Object[] { currentResource.getFullPath() }), e)); + } + } + progress.worked(5); + + /*** determine the resources to be committed and those to be admin'd ***/ + for (Iterator it = files.iterator(); it.hasNext();) { + IFile file = (IFile) it.next(); + ICVSFile mFile = CVSWorkspaceRoot.getCVSFileFor(file); + // only set keyword substitution if resource is a managed file + if (mFile.isManaged()) { + ResourceSyncInfo info = mFile.getSyncInfo(); + String fromMode = info.getKeywordMode(); + KSubstOption fromKSubst = KSubstOption.fromMode(fromMode); + + // make sure we commit all added or changed resources + String remotePath = mFile.getRelativePath(workspaceRoot.getLocalRoot()); + + // check if mode must be changed + if (! toKSubst.equals(fromKSubst)) { + if (info.isAdded()) { + // change resource sync info for outgoing addition + ResourceSyncInfo newInfo = new ResourceSyncInfo( + info.getName(), info.getRevision(), info.getTimeStamp(), toKSubst.toMode(), + info.getTag(), info.getPermissions()); + mFile.setSyncInfo(newInfo); + } else if (info.isDeleted()) { + // ignore deletions + } else { + // file exists remotely + boolean fromBinary = fromKSubst.isBinary(); + if (fromBinary && ! toBinary) { + // converting from binary to text + cleanLineDelimiters(file, IS_CRLF_PLATFORM, progress); + // remember to commit the cleaned resource as text before admin + filesToCommitAsText.add(mFile); + } else { + // force a commit to bump the revision number + makeDirty(file); + } + // remember to commit and admin the resource + filesToCommit.add(remotePath); // FORCE creation of a new revision + filesToAdmin.add(remotePath); + } + } + } + } + progress.worked(5); + + /*** commit then admin the resources ***/ + if (filesToAdmin.size() != 0 || filesToCommit.size() != 0) { + Session s = new Session(workspaceRoot.getRemoteLocation(), + workspaceRoot.getLocalRoot(), false); + IProgressMonitor sessionProgress = Policy.subMonitorFor(progress, 90); + sessionProgress.beginTask(Policy.bind("CVSTeamProvider.settingKSubst"), 5 + + filesToAdmin.size() + filesToCommit.size()); + try { + s.open(Policy.subMonitorFor(sessionProgress, 5)); + + // commit files that changed from binary to text + // NOTE: The files are committed as text with conversions even if the + // resource sync info still says "binary". + if (filesToCommit.size() != 0) { + s.setTextTransferOverride(filesToCommitAsText); + result[0] = Command.COMMIT.execute(s, Command.NO_GLOBAL_OPTIONS, + new LocalOption[] { Commit.DO_NOT_RECURSE, Commit.FORCE, + Commit.makeArgumentOption(Command.MESSAGE_OPTION, comment) }, + (String[]) filesToCommit.toArray(new String[filesToCommit.size()]), + null, Policy.subMonitorFor(sessionProgress, filesToCommit.size())); + s.setTextTransferOverride(null); + // if errors were encountered, abort + if (! result[0].isOK()) return; + } + + // admin files that changed keyword substitution mode + // NOTE: As confirmation of the completion of a command, the server replies + // with the RCS command output if a change took place. Rather than + // assume that the command succeeded, we listen for these lines + // and update the local ResourceSyncInfo for the particular files that + // were actually changed remotely. + result[0] = Command.ADMIN.execute(s, Command.NO_GLOBAL_OPTIONS, + new LocalOption[] { toKSubst }, + (String[]) filesToAdmin.toArray(new String[filesToAdmin.size()]), + new AdminKSubstListener(toKSubst.toMode()), + Policy.subMonitorFor(sessionProgress, filesToAdmin.size())); + } finally { + s.close(); + sessionProgress.done(); + } + } + } finally { + progress.done(); + } + } + }, monitor); + return result[0]; + } + + private static void makeDirty(IFile file) throws CVSException { + ICVSFile mFile = CVSWorkspaceRoot.getCVSFileFor(file); + mFile.setTimeStamp(null); + } }
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/AbstractStructureVisitor.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/AbstractStructureVisitor.java index 58429dd3b..43c02c6d5 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/AbstractStructureVisitor.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/AbstractStructureVisitor.java @@ -18,6 +18,7 @@ import org.eclipse.team.ccvs.core.ICVSResource; import org.eclipse.team.ccvs.core.ICVSResourceVisitor; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.Policy; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.resources.CVSEntryLineTag; import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; @@ -149,7 +150,7 @@ abstract class AbstractStructureVisitor implements ICVSResourceVisitor { // If the file exists, send the appropriate indication to the server if (mFile.exists()) { if (mFile.isModified()) { - boolean binary = (info != null) && ResourceSyncInfo.BINARY_TAG.equals(mFile.getSyncInfo().getKeywordMode()); + boolean binary = info != null && KSubstOption.fromMode(info.getKeywordMode()).isBinary(); if (sendModifiedContents) { session.sendModified(mFile, binary, monitor); } else { diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java index 2b2005fd2..5a23711dc 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java @@ -7,9 +7,11 @@ package org.eclipse.team.internal.ccvs.core.client; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import org.eclipse.core.runtime.IProgressMonitor; @@ -22,6 +24,7 @@ import org.eclipse.team.ccvs.core.ICVSFolder; import org.eclipse.team.ccvs.core.ICVSResource; import org.eclipse.team.ccvs.core.ICVSRunnable; import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.CVSProvider; import org.eclipse.team.internal.ccvs.core.Policy; import org.eclipse.team.internal.ccvs.core.client.listeners.ICommandOutputListener; @@ -81,13 +84,21 @@ public abstract class Command { public static final LocalOption[] NO_LOCAL_OPTIONS = new LocalOption[0]; // valid for: annotate checkout commit diff export log rdiff remove rtag status tag update public static final LocalOption DO_NOT_RECURSE = new LocalOption("-l"); //$NON-NLS-1$ - // valid for: add checkout export import update - public static final LocalOption KSUBST_BINARY = new LocalOption("-kb"); //$NON-NLS-1$ // valid for: checkout export update public static final LocalOption PRUNE_EMPTY_DIRECTORIES = new LocalOption("-P"); //$NON-NLS-1$ // valid for: checkout export update public static final LocalOption MESSAGE_OPTION = new LocalOption("-m"); //$NON-NLS-1$ + /*** Local options: keyword substitution mode ***/ + // valid for: add admin checkout export import update + private static final Map ksubstOptionMap = new HashMap(); + public static final KSubstOption KSUBST_BINARY = new KSubstOption("-kb"); //$NON-NLS-1$ + public static final KSubstOption KSUBST_TEXT = new KSubstOption("-ko"); //$NON-NLS-1$ + public static final KSubstOption KSUBST_TEXT_EXPAND = new KSubstOption("-kkv"); //$NON-NLS-1$ + public static final KSubstOption KSUBST_TEXT_EXPAND_LOCKER = new KSubstOption("-kkvl"); //$NON-NLS-1$ + public static final KSubstOption KSUBST_TEXT_VALUES_ONLY = new KSubstOption("-kv"); //$NON-NLS-1$ + public static final KSubstOption KSUBST_TEXT_KEYWORDS_ONLY = new KSubstOption("-kk"); //$NON-NLS-1$ + /*** Response handler map ***/ private static final Hashtable responseHandlers = new Hashtable(); static { @@ -541,14 +552,36 @@ public abstract class Command { /** * Returns the option part of the option */ - public String getOption() { + String getOption() { return option; } /** + * Compares two options for equality. + * @param other the other option + */ + public boolean equals(Object other) { + if (this == other) return true; + if (other instanceof Option) { + Option otherOption = (Option) other; + return option.equals(otherOption.option); + } + return false; + } + /** * Sends the option to a CVS server * @param session the CVS session */ public abstract void send(Session session) throws CVSException; + /* + * To make debugging a tad easier. + */ + public String toString() { + if (argument != null && argument.length() != 0) { + return option + " " + argument; + } else { + return option; + } + } } /** * Option subtype for global options that are common to all commands. @@ -587,6 +620,83 @@ public abstract class Command { if (argument != null) session.sendArgument(argument); } } + /** + * Options subtype for keyword substitution options. + */ + public static class KSubstOption extends LocalOption { + private String shortDisplayText; + private String longDisplayText; + + private KSubstOption(String option) { + this(option, Policy.bind("KSubstOption." + option + ".short"), + Policy.bind("KSubstOption." + option + ".long")); + } + private KSubstOption(String option, String shortDisplayText, String longDisplayText) { + super(option); + this.shortDisplayText = shortDisplayText; + this.longDisplayText = longDisplayText; + ksubstOptionMap.put(option, this); + } + /** + * Gets the KSubstOption instance for the specified mode. + * + * @param mode the mode, e.g. -kb + * @return an instance for that mode + */ + public static KSubstOption fromMode(String mode) { + if (mode.length() == 0) mode = "-kkv"; // use default + KSubstOption option = (KSubstOption) ksubstOptionMap.get(mode); + if (option == null) { + option = new KSubstOption(mode, + Policy.bind("KSubstOption.unknown.short", mode), + Policy.bind("KSubstOption.unknown.long", mode)); + ksubstOptionMap.put(mode, option); + } + return option; + } + /** + * Gets the KSubstOption instance for the specified file by pattern. + * + * @param filename the filename of interest + * @return an instance for that mode + */ + public static KSubstOption fromPattern(String filename) { + if (CVSProvider.isText(filename)) return KSUBST_TEXT_EXPAND; // XXX should this be KSUBST_TEXT? + return KSUBST_BINARY; + } + /** + * Returns an array of all valid modes. + */ + public static KSubstOption[] getAllKSubstOptions() { + return (KSubstOption[]) ksubstOptionMap.values().toArray(new KSubstOption[ksubstOptionMap.size()]); + } + /** + * Returns the entry line mode string for this instance. + */ + public String toMode() { + if (KSUBST_TEXT_EXPAND.equals(this)) return ""; + return getOption(); + } + /** + * Returns true if the substitution mode requires no data translation + * during file transfer. + */ + public boolean isBinary() { + return KSUBST_BINARY.equals(this); + } + /** + * Returns a short localized text string describing this mode. + */ + public String getShortDisplayText() { + return shortDisplayText; + } + /** + * Returns a long localized text string describing this mode. + */ + public String getLongDisplayText() { + return longDisplayText; + } + } /** * Makes a -m log message option. diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Commit.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Commit.java index 6545fe591..e1e59dc44 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Commit.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Commit.java @@ -14,6 +14,12 @@ import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption; public class Commit extends Command { /*** Local options: specific to commit ***/ + // Forces a file to be committed even if it has not been modified; implies -l. + // NOTE: This option is not fully supported -- a file will not be sent + // unless it is dirty. The primary use is to resend a file that may + // or may not be changed (e.g. could depend on CR/LF translations, etc...) + // and force the server to create a new revision and reply Checked-in. + public static final LocalOption FORCE = new LocalOption("-f"); protected Commit() { } protected String getCommandId() { diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/DiffStructureVisitor.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/DiffStructureVisitor.java index 524f317e9..15a9a1251 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/DiffStructureVisitor.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/DiffStructureVisitor.java @@ -6,6 +6,7 @@ package org.eclipse.team.internal.ccvs.core.client; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.team.ccvs.core.ICVSFile; import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; /** @@ -24,7 +25,7 @@ class DiffStructureVisitor extends FileStructureVisitor { * Send unmanaged files as modified with a default entry line. */ protected void sendFile(ICVSFile mFile, String mode) throws CVSException { - boolean binary = mode != null && mode.indexOf(ResourceSyncInfo.BINARY_TAG) != -1; + boolean binary = mode != null && KSubstOption.fromMode(mode).isBinary(); boolean newFile = false; if (mFile.isManaged()) { diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/ImportStructureVisitor.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/ImportStructureVisitor.java index 702dc336b..3aece0bdd 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/ImportStructureVisitor.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/ImportStructureVisitor.java @@ -14,7 +14,7 @@ import org.eclipse.team.ccvs.core.ICVSFolder; import org.eclipse.team.ccvs.core.ICVSResourceVisitor; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.Policy; -import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.util.FileNameMatcher; /** @@ -105,14 +105,12 @@ class ImportStructureVisitor implements ICVSResourceVisitor { return; } - String mode; + // XXX should we default to text or to binary? + boolean binary = false; if (wrapMatcher != null) { - mode = wrapMatcher.getMatch(mFile.getName()); - } else { - mode = ""; //$NON-NLS-1$ + String mode = wrapMatcher.getMatch(mFile.getName()); + if (mode != null) binary = KSubstOption.fromMode(mode).isBinary(); } - // XXX Is this condition right? - boolean binary = mode != null && mode.indexOf(ResourceSyncInfo.BINARY_TAG) != -1; session.sendModified(mFile, binary, monitor); } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java index bdd85698a..b492a3cfd 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.List; @@ -78,6 +79,7 @@ public class Session { private Date modTime = null; private boolean noLocalChanges = false; private List expansions; + private Collection /* of ICVSFile */ textTransferOverrideSet = null; // a shared buffer used for file transfers private byte[] transferBuffer = null; @@ -510,6 +512,10 @@ public class Session { */ public void sendFile(ICVSFile file, boolean isBinary, IProgressMonitor monitor) throws CVSException { + // check overrides + if (textTransferOverrideSet != null && + textTransferOverrideSet.contains(file)) isBinary = false; + // update progress monitor String title = Policy.bind(getSendFileTitleKey(), new Object[]{ Util.toTruncatedPath(file, localRoot, 3) }); //$NON-NLS-1$ monitor.subTask(Policy.bind("Session.transferNoSize", title)); //$NON-NLS-1$ @@ -605,6 +611,10 @@ public class Session { */ public void receiveFile(ICVSFile file, boolean isBinary, int responseType, IProgressMonitor monitor) throws CVSException { + // check overrides + if (textTransferOverrideSet != null && + textTransferOverrideSet.contains(file)) isBinary = false; + // update progress monitor String title = Policy.bind("Session.receiving", new Object[]{ Util.toTruncatedPath(file, localRoot, 3) }); //$NON-NLS-1$ monitor.subTask(Policy.bind("Session.transferNoSize", title)); //$NON-NLS-1$ @@ -780,5 +790,14 @@ public class Session { public void setSendFileTitleKey(String sendFileTitleKey) { this.sendFileTitleKey = sendFileTitleKey; } - + + /** + * Remembers a set of files that must be transferred as 'text' + * regardless of what the isBinary parameter to sendFile() is. + * + * @param textTransferOverrideSet the set of ICVSFiles to override, or null if none + */ + public void setTextTransferOverride(Collection textTransferOverrideSet) { + this.textTransferOverrideSet = textTransferOverrideSet; + } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/TagFileSender.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/TagFileSender.java index 97137fada..f6a131e52 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/TagFileSender.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/TagFileSender.java @@ -8,6 +8,7 @@ package org.eclipse.team.internal.ccvs.core.client; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.team.ccvs.core.ICVSFile; import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; /** @@ -35,7 +36,7 @@ class TagFileSender extends FileStructureVisitor { } if (! info.isAdded()) { session.sendEntry(info.getEntryLine(false, mFile.getTimeStamp())); - boolean binary = (info != null) && ResourceSyncInfo.BINARY_TAG.equals(mFile.getSyncInfo().getKeywordMode()); + boolean binary = info != null && KSubstOption.fromMode(info.getKeywordMode()).isBinary(); session.sendIsModified(mFile, binary, monitor); } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/UpdatedHandler.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/UpdatedHandler.java index ef4b4fb7c..320b18a50 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/UpdatedHandler.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/UpdatedHandler.java @@ -11,6 +11,7 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.team.ccvs.core.ICVSFile; import org.eclipse.team.ccvs.core.ICVSFolder; import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; import org.eclipse.team.internal.ccvs.core.util.Assert; import org.eclipse.team.internal.ccvs.core.util.EntryFileDateFormat; @@ -71,6 +72,7 @@ class UpdatedHandler extends ResponseHandler { String repositoryFile = session.readLine(); String entryLine = session.readLine(); String permissionsLine = session.readLine(); + ResourceSyncInfo info = new ResourceSyncInfo(entryLine, permissionsLine, null); // clear file update modifiers Date modTime = session.getModTime(); @@ -83,8 +85,8 @@ class UpdatedHandler extends ResponseHandler { Assert.isTrue(mParent.exists()); ICVSFile mFile = mParent.getFile(fileName); - boolean binary = entryLine.indexOf("/" + ResourceSyncInfo.BINARY_TAG) != -1; //$NON-NLS-1$ - boolean readOnly = permissionsLine.indexOf(READ_ONLY_FLAG) == -1; + boolean binary = KSubstOption.fromMode(info.getKeywordMode()).isBinary(); + boolean readOnly = info.getPermissions().indexOf(READ_ONLY_FLAG) == -1; session.receiveFile(mFile, binary, handlerType, monitor); if (readOnly) mFile.setReadOnly(true); @@ -101,14 +103,15 @@ class UpdatedHandler extends ResponseHandler { // having outgoing changes. // The purpose for having the two different timestamp options for merges is to // dissallow commit of files that have conflicts until they have been manually edited. - if(entryLine.indexOf(ResourceSyncInfo.MERGE_UNMODIFIED) != -1) { + if(info.getTimeStamp().indexOf(ResourceSyncInfo.MERGE_UNMODIFIED) != -1) { timestamp = ResourceSyncInfo.RESULT_OF_MERGE_CONFLICT + mFile.getTimeStamp(); } else { timestamp = ResourceSyncInfo.RESULT_OF_MERGE; } } else { timestamp = mFile.getTimeStamp(); - } - mFile.setSyncInfo(new ResourceSyncInfo(entryLine, permissionsLine, timestamp)); + } + mFile.setSyncInfo(new ResourceSyncInfo(info.getName(), info.getRevision(), + timestamp, info.getKeywordMode(), info.getTag(), info.getPermissions())); } }
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties index 124a71b91..d5b23d352 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties @@ -68,6 +68,9 @@ CVSTeamProvider.updatingFolder=Updating {0} CVSTeamProvider.scrubbingResource=Scrubbing {0} CVSTeamProvider.updatingFile=Updating {0} CVSTeamProvider.makeBranch=Creating branch +CVSTeamProvider.preparingToSetKSubst=Preparing to set keyword substitution mode +CVSTeamProvider.settingKSubst=Setting keyword substitution mode +CVSTeamProvider.cleanLineDelimitersException=Exception occurred while cleaning line delimiters ProjectDescriptionManager.unableToSetDescription=An error occured setting the project description ProjectDescriptionManager.unableToReadDescription=An error occured reading the project description @@ -138,6 +141,26 @@ Updated.numberFormat=Server did not send length of the file UnsupportedHandler.message=Unsupported response received from server RemovedHandler.invalid=Invalid removed response received from CVS server for {0} +KSubstOption.-kb.short=Binary +KSubstOption.-kb.long=Binary (-kb) +KSubstOption.-ko.short=Text +KSubstOption.-ko.long=Text (-ko) +KSubstOption.-kkv.short=Text -kkv +KSubstOption.-kkv.long=Text with keyword expansion (-kkv) +KSubstOption.-kkvl.short=Text -kkvl +KSubstOption.-kkvl.long=Text with keyword expansion and locker (-kkvl) +KSubstOption.-kv.short=Text -kv +KSubstOption.-kv.long=Text with keyword replacement (-kv) +KSubstOption.-kk.short=Text -kk +KSubstOption.-kk.long=Text with keyword compression (-kk) +KSubstOption.unknown.short=Unknown {0} +KSubstOption.unknown.long=Unknown ({0}) + +AdminKSubstListener.expectedRCSFile=Expected RCS file {0} to end in ',v' +AdminKSubstListener.commandRootNotManaged=Local root for this command is not managed +AdminKSubstListener.expectedChildOfCommandRoot=Expected RCS file {0} to be a child of remote root for this command {1} +AdminKSubstListener.couldNotSetResourceSyncInfo=Could not set resource sync info for {0}: {1} + CVSRepositoryLocation.nullLocation=Location must not be null CVSRepositoryLocation.emptyLocation=Location must not be empty CVSRepositoryLocation.endWhitespace=Location must not end with whitespace diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSRemoteSyncElement.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSRemoteSyncElement.java index 8708710fd..26f1d17a1 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSRemoteSyncElement.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSRemoteSyncElement.java @@ -18,9 +18,9 @@ import org.eclipse.team.core.sync.IRemoteResource; import org.eclipse.team.core.sync.IRemoteSyncElement; import org.eclipse.team.core.sync.RemoteSyncElement; import org.eclipse.team.internal.ccvs.core.CVSException; -import org.eclipse.team.internal.ccvs.core.CVSProvider; import org.eclipse.team.internal.ccvs.core.Policy; import org.eclipse.team.internal.ccvs.core.client.Update; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; import org.eclipse.team.internal.ccvs.core.util.Assert; @@ -159,8 +159,9 @@ public class CVSRemoteSyncElement extends RemoteSyncElement { if (local.exists()) { // We could have an incoming change or deletion if (remote == null) { + String mode = KSubstOption.fromPattern(local.getName()).toMode(); info = new ResourceSyncInfo(local.getName(), ResourceSyncInfo.ADDED_REVISION, ResourceSyncInfo.DUMMY_TIMESTAMP, - CVSProvider.isText(local.getName()) ? ResourceSyncInfo.USE_SERVER_MODE:ResourceSyncInfo.BINARY_TAG, local.getParent().getFolderSyncInfo().getTag(), null); + mode, local.getParent().getFolderSyncInfo().getTag(), null); revision = info.getRevision(); } else { info = remote.getSyncInfo(); diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java index b64af3058..414885796 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java @@ -254,9 +254,9 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { monitor.beginTask(null, 100); try { EclipseSynchronizer.getInstance().beginOperation(Policy.subMonitorFor(monitor, 5)); - job.run(Policy.subMonitorFor(monitor, 85)); + job.run(Policy.subMonitorFor(monitor, 60)); } finally { - EclipseSynchronizer.getInstance().endOperation(Policy.subMonitorFor(monitor, 8)); + EclipseSynchronizer.getInstance().endOperation(Policy.subMonitorFor(monitor, 35)); } } catch(CVSException e) { error[0] = e; diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ResourceSyncInfo.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ResourceSyncInfo.java index 133330b9e..02a758c57 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ResourceSyncInfo.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ResourceSyncInfo.java @@ -31,7 +31,6 @@ public class ResourceSyncInfo { // utility constants private static final String DIRECTORY_PREFIX = "D/"; //$NON-NLS-1$ - public static final String BINARY_TAG = "-kb"; //$NON-NLS-1$ public static final String USE_SERVER_MODE = ""; //$NON-NLS-1$ private static final String SEPERATOR = "/"; //$NON-NLS-1$ diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ProjectDescriptionManager.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ProjectDescriptionManager.java index 44255342d..7352733c7 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ProjectDescriptionManager.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ProjectDescriptionManager.java @@ -198,7 +198,7 @@ public class ProjectDescriptionManager { if (resource.getType() == IResource.PROJECT) { IProject project = (IProject)resource; RepositoryProvider provider = RepositoryProviderType.getProvider(project); - if (! provider.isOfType(CVSProviderPlugin.getTypeId())) continue; + if (provider!=null && !provider.isOfType(CVSProviderPlugin.getTypeId())) continue; // First, check if the .vcm_meta file for the project is in the delta. IResourceDelta[] children = delta.getAffectedChildren(IResourceDelta.REMOVED | IResourceDelta.ADDED | IResourceDelta.CHANGED); boolean inSync = false; diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceDeltaSyncHandler.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceDeltaSyncHandler.java index 80bc5e4c7..0058a9bbc 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceDeltaSyncHandler.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceDeltaSyncHandler.java @@ -204,7 +204,7 @@ public class ResourceDeltaSyncHandler implements IResourceDeltaVisitor { provider = RepositoryProviderType.getProvider(destination.getProject()); } - if(provider.isOfType(CVSProviderPlugin.getTypeId())) { + if(provider!=null && provider.isOfType(CVSProviderPlugin.getTypeId())) { delta.accept(visitor); } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceDeltaVisitor.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceDeltaVisitor.java index e4d79e7d0..f35448889 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceDeltaVisitor.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceDeltaVisitor.java @@ -56,7 +56,7 @@ public abstract class ResourceDeltaVisitor implements IResourceDeltaVisitor { provider = RepositoryProviderType.getProvider(destination.getProject()); } - if(provider.isOfType(CVSProviderPlugin.getTypeId())) { + if(provider != null && provider.isOfType(CVSProviderPlugin.getTypeId())) { delta.accept(visitor); } } diff --git a/bundles/org.eclipse.team.cvs.ui/plugin.properties b/bundles/org.eclipse.team.cvs.ui/plugin.properties index c5da82b40..9b754a6dc 100644 --- a/bundles/org.eclipse.team.cvs.ui/plugin.properties +++ b/bundles/org.eclipse.team.cvs.ui/plugin.properties @@ -60,6 +60,9 @@ ReplaceWithTagAction.tooltip=Replace with Version on CVS Server TagAction.label=&Tag... TagAction.tooltip=Tag +SetKeywordSubstitutionAction.label=&Set Keyword Substitution... +SetKeywordSubstitutionAction.tooltip=Set Keyword Substitution for Files on CVS Server + DefineBranchAction.label=&Define Branch Tag... DefineBranchAction.tooltip=Define a Branch Tag that Exists on CVS Server diff --git a/bundles/org.eclipse.team.cvs.ui/plugin.xml b/bundles/org.eclipse.team.cvs.ui/plugin.xml index afbae06fb..98428ebce 100644 --- a/bundles/org.eclipse.team.cvs.ui/plugin.xml +++ b/bundles/org.eclipse.team.cvs.ui/plugin.xml @@ -58,6 +58,12 @@ objectClass="org.eclipse.core.resources.IResource" adaptable="true"> <filter name="projectNature" value="org.eclipse.team.cvs.core.cvsnature"/> <action + id="org.eclipse.team.ccvs.ui.setKeywordSubstitution" + label="%SetKeywordSubstitutionAction.label" + tooltip="%SetKeywordSubstitutionAction.tooltip" + menubarPath="team.main/group2" + class="org.eclipse.team.internal.ccvs.ui.actions.SetKeywordSubstitutionAction"/> + <action id="org.eclipse.team.ccvs.ui.tag" label="%TagAction.label" tooltip="%TagAction.tooltip" diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorationRunnable.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorationRunnable.java index 06fb6d312..f70481884 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorationRunnable.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorationRunnable.java @@ -31,6 +31,7 @@ import org.eclipse.team.ccvs.core.ICVSResource; import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.core.RepositoryProviderType; import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; @@ -51,6 +52,11 @@ public class CVSDecorationRunnable implements Runnable { // Provides resources to be decorated and is notified when decoration has been calculated private IDecorationNotifier notifier; + // Remember the non posted decorated resources + List resources = new ArrayList(); + List decorations = new ArrayList(); + private final static int NUM_TO_BATCH = 50; + /* * Define a cached image descriptor which only creates the image data once */ @@ -89,33 +95,48 @@ public class CVSDecorationRunnable implements Runnable { if (resource == null) { return; } - // it is possible that the resource to be decorated is no longer associated - // with a CVS provider. This could happen if the team nature was removed - // between the time the decoration event was posted to the thread and the time - // the thread processes the decoration. - RepositoryProvider provider = RepositoryProviderType.getProvider(resource.getProject()); - if(!resource.exists() || provider==null || !provider.isOfType(CVSProviderPlugin.getTypeId())) { - continue; - } - // determine a if resource has outgoing changes (e.g. is dirty). - IPreferenceStore store = CVSUIPlugin.getPlugin().getPreferenceStore(); - boolean isDirty = false; - boolean computeDeepDirtyCheck = store.getBoolean(ICVSUIConstants.PREF_CALCULATE_DIRTY); - int type = resource.getType(); - if(type == IResource.FILE || computeDeepDirtyCheck) { - isDirty = isDirty(resource); - } - - // compute decorations - CVSDecoration decoration = computeTextLabelFor(resource, isDirty); - decoration.setOverlays(computeLabelOverlaysFor(resource, isDirty, (CVSTeamProvider)provider)); + CVSDecoration decoration = decorate(resource); // notify that decoration is ready - notifier.decorated(resource, decoration); + if(decoration!=null) { + resources.add(resource); + decorations.add(decoration); + if(!resources.isEmpty() && (notifier.remaining()==0 || resources.size() >= NUM_TO_BATCH)) { + notifier.decorated((IResource[])resources.toArray(new IResource[resources.size()]), + (CVSDecoration[])decorations.toArray(new CVSDecoration[decorations.size()])); + resources.clear(); + decorations.clear(); + } + } } } + public CVSDecoration decorate(IResource resource) { + // it is possible that the resource to be decorated is no longer associated + // with a CVS provider. This could happen if the team nature was removed + // between the time the decoration event was posted to the thread and the time + // the thread processes the decoration. + RepositoryProvider provider = RepositoryProviderType.getProvider(resource.getProject()); + if(!resource.exists() || provider==null || !provider.isOfType(CVSProviderPlugin.getTypeId())) { + return null; + } + + // determine a if resource has outgoing changes (e.g. is dirty). + IPreferenceStore store = CVSUIPlugin.getPlugin().getPreferenceStore(); + boolean isDirty = false; + boolean computeDeepDirtyCheck = store.getBoolean(ICVSUIConstants.PREF_CALCULATE_DIRTY); + int type = resource.getType(); + if(type == IResource.FILE || computeDeepDirtyCheck) { + isDirty = isDirty(resource); + } + + // compute decorations + CVSDecoration decoration = computeTextLabelFor(resource, isDirty); + decoration.setOverlays(computeLabelOverlaysFor(resource, isDirty, (CVSTeamProvider)provider)); + return decoration; + } + private CVSDecoration computeTextLabelFor(IResource resource, boolean isDirty) { Map bindings = new HashMap(3); String format = ""; //$NON-NLS-1$ @@ -172,13 +193,17 @@ public class CVSDecorationRunnable implements Runnable { } else { bindings.put(CVSDecoratorConfiguration.FILE_REVISION, fileInfo.getRevision()); } - bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, CVSDecorator.getFileTypeString(fileInfo.getName(), fileInfo.getKeywordMode())); + KSubstOption option = fileInfo.getKeywordMode() != null ? + KSubstOption.fromMode(fileInfo.getKeywordMode()) : + KSubstOption.fromPattern(fileInfo.getName()); + bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, option.getShortDisplayText()); if (tag != null && (tag.getType() != CVSTag.HEAD)) { bindings.put(CVSDecoratorConfiguration.RESOURCE_TAG, tag.getName()); } } else { // only show the type that cvs will use when comitting the file - bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, CVSDecorator.getFileTypeString(file.getName(), null)); + KSubstOption option = KSubstOption.fromPattern(file.getName()); + bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, option.getShortDisplayText()); } break; } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorator.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorator.java index f96a0eaa5..afa2608df 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorator.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorator.java @@ -33,7 +33,8 @@ import org.eclipse.team.ccvs.core.IResourceStateChangeListener; import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.core.RepositoryProviderType; import org.eclipse.team.internal.ccvs.core.CVSProvider; -import org.eclipse.team.internal.ccvs.core.util.Assert; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; +import org.eclipse.team.internal.ccvs.core.client.Command;import org.eclipse.team.internal.ccvs.core.util.Assert; import org.eclipse.team.internal.ccvs.core.util.ResourceDeltaVisitor; /** @@ -81,6 +82,7 @@ public class CVSDecorator extends LabelProvider implements ILabelDecorator, IRes } protected void finished() { resourceStateChanged((IResource[])changedResources.toArray(new IResource[changedResources.size()])); + changedResources.clear(); } protected int getEventMask() { return IResourceChangeEvent.PRE_AUTO_BUILD; @@ -88,12 +90,7 @@ public class CVSDecorator extends LabelProvider implements ILabelDecorator, IRes } public CVSDecorator() { - // The decorator is a singleton, there should never be more than one instance. - // temporary until the UI component properly calls dispose when the workbench shutsdown - // UI Bug 9633 - Assert.isTrue(theDecorator==null); - theDecorator = this; - + // thread that calculates the decoration for a resource decoratorUpdateThread = new Thread(new CVSDecorationRunnable(this), "CVS"); //$NON-NLS-1$ decoratorUpdateThread.start(); CVSProviderPlugin.addResourceStateChangeListener(this); @@ -191,18 +188,26 @@ public class CVSDecorator extends LabelProvider implements ILabelDecorator, IRes /* * @see IDecorationNotifier#notify(IResource, CVSDecoration) */ - public synchronized void decorated(IResource resource, CVSDecoration decoration) { - // ignore resources that aren't in the workbench anymore. - if(resource.exists() && !shutdown) { - cache.put(resource, decoration); - postLabelEvents(new LabelProviderChangedEvent[] { new LabelProviderChangedEvent(this, resource)}); + public synchronized void decorated(IResource[] resources, CVSDecoration[] decorations) { + List events = new ArrayList(); + if(!shutdown) { + for (int i = 0; i < resources.length; i++) { + IResource resource= resources[i]; + if(resource.exists()) { + cache.put(resource, decorations[i]); + events.add(new LabelProviderChangedEvent(this, resource)); + } + } + postLabelEvents((LabelProviderChangedEvent[]) events.toArray(new LabelProviderChangedEvent[events.size()])); } } /* * @see IResourceChangeListener#resourceChanged(IResourceChangeEvent) */ - + public int remaining() { + return decoratorNeedsUpdating.size(); + } /* * @see IResourceStateChangeListener#resourceStateChanged(IResource[]) */ @@ -345,33 +350,9 @@ public class CVSDecorator extends LabelProvider implements ILabelDecorator, IRes } } - public static void shutdownAll() { - if(theDecorator!=null) { - theDecorator.dispose(); - } - } + - public static String getFileTypeString(String name, String keyword) { - StringBuffer buffer = new StringBuffer(); - boolean isBinary = false; - if(keyword!=null) { - if (keyword.equals("-kb")) { //$NON-NLS-1$ - isBinary = true; - } - } else { - isBinary = !CVSProvider.isText(name); - } - - if(isBinary) { - buffer.append(Policy.bind("CVSFilePropertiesPage.binary")); - } else { - buffer.append(Policy.bind("CVSFilePropertiesPage.text")); - if(keyword!=null && !keyword.equals("-ko") && !"".equals(keyword)) { //$NON-NLS-1$ //$NON-NLS-2$ - buffer.append(" " + keyword); //$NON-NLS-1$ - } - } - return buffer.toString(); - } + /* * @see IBaseLabelProvider#dispose() @@ -383,7 +364,7 @@ public class CVSDecorator extends LabelProvider implements ILabelDecorator, IRes shutdown(); // unregister change listeners - changeListener.register(); + changeListener.deregister(); CVSProviderPlugin.removeResourceStateChangeListener(this); // dispose of images created as overlays diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecoratorPreferencesPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecoratorPreferencesPage.java index 4bfe11aea..51da566bf 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecoratorPreferencesPage.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecoratorPreferencesPage.java @@ -32,6 +32,7 @@ import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Text; import org.eclipse.team.ccvs.core.ICVSRepositoryLocation; import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; @@ -104,7 +105,8 @@ public class CVSDecoratorPreferencesPage extends PreferencePage implements IWork try { ICVSRepositoryLocation location = CVSRepositoryLocation.fromString(":pserver:username@host.acme.org:/home/cvsroot"); //$NON-NLS-1$ bindings.put(CVSDecoratorConfiguration.RESOURCE_TAG, "v2_0"); //$NON-NLS-1$ - bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, CVSDecorator.getFileTypeString("file.txt",null)); //$NON-NLS-1$ + bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, + KSubstOption.fromPattern("file.txt").getShortDisplayText()); //$NON-NLS-1$ bindings.put(CVSDecoratorConfiguration.FILE_REVISION, "1.34"); //$NON-NLS-1$ bindings.put(CVSDecoratorConfiguration.DIRTY_FLAG, dirtyFlag.getText()); bindings.put(CVSDecoratorConfiguration.ADDED_FLAG, addedFlag.getText()); diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFilePropertiesPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFilePropertiesPage.java index 300dc96d9..66018f2d6 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFilePropertiesPage.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFilePropertiesPage.java @@ -16,6 +16,7 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.team.ccvs.core.CVSTag; import org.eclipse.team.ccvs.core.ICVSFile; import org.eclipse.team.core.TeamException; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; import org.eclipse.ui.dialogs.PropertyPage; @@ -62,16 +63,7 @@ public class CVSFilePropertiesPage extends PropertyPage { // Keyword Mode createLabel(composite, Policy.bind("CVSFilePropertiesPage.keywordMode")); - String keywordMode = syncInfo.getKeywordMode(); - if (keywordMode.equals("-kb")) { - createLabel(composite, Policy.bind("CVSFilePropertiesPage.binary")); - } else if (keywordMode.equals("-ko")) { - createLabel(composite, Policy.bind("CVSFilePropertiesPage.textNoKeyword")); - } else if (keywordMode.equals("")) { - createLabel(composite, Policy.bind("CVSFilePropertiesPage.text")); - } else { - createLabel(composite, keywordMode); - } + createLabel(composite, KSubstOption.fromMode(syncInfo.getKeywordMode()).getLongDisplayText()); // Tag createLabel(composite, Policy.bind("CVSFilePropertiesPage.tag")); diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSPropertiesPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSPropertiesPage.java index 8cfc6239b..2832e082a 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSPropertiesPage.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSPropertiesPage.java @@ -17,9 +17,11 @@ import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; @@ -28,13 +30,16 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Text; import org.eclipse.team.ccvs.core.CVSProviderPlugin; +import org.eclipse.team.ccvs.core.CVSTag; import org.eclipse.team.ccvs.core.CVSTeamProvider; +import org.eclipse.team.ccvs.core.ICVSFolder; import org.eclipse.team.ccvs.core.ICVSRemoteResource; import org.eclipse.team.ccvs.core.ICVSRepositoryLocation; import org.eclipse.team.ccvs.core.IUserInfo; import org.eclipse.team.core.RepositoryProviderType; import org.eclipse.team.core.TeamException; import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; +import org.eclipse.team.internal.ccvs.ui.wizards.UpdateWizard; import org.eclipse.ui.dialogs.PropertyPage; public class CVSPropertiesPage extends PropertyPage { @@ -48,8 +53,10 @@ public class CVSPropertiesPage extends PropertyPage { Label pathLabel; Label moduleLabel; Label portLabel; + Label tagLabel; boolean passwordChanged; + boolean connectionInfoChanged; IUserInfo info; CVSTeamProvider provider; @@ -63,35 +70,65 @@ public class CVSPropertiesPage extends PropertyPage { Composite composite = new Composite(parent, SWT.NULL); composite.setLayoutData(new GridData(GridData.FILL_BOTH)); GridLayout layout = new GridLayout(); - layout.numColumns = 2; + layout.numColumns = 3; composite.setLayout(layout); - Label label = createLabel(composite, Policy.bind("CVSPropertiesPage.connectionType")); + Label label = createLabel(composite, Policy.bind("CVSPropertiesPage.connectionType"), 1); methodType = createCombo(composite); - label = createLabel(composite, Policy.bind("CVSPropertiesPage.user")); + label = createLabel(composite, Policy.bind("CVSPropertiesPage.user"), 1); userText = createTextField(composite); - label = createLabel(composite, Policy.bind("CVSPropertiesPage.password")); + label = createLabel(composite, Policy.bind("CVSPropertiesPage.password"), 1); passwordText = createTextField(composite); passwordText.setEchoChar('*'); - label = createLabel(composite, Policy.bind("CVSPropertiesPage.host")); - hostLabel = createLabel(composite, ""); + label = createLabel(composite, Policy.bind("CVSPropertiesPage.host"), 1); + hostLabel = createLabel(composite, "", 2); - label = createLabel(composite, Policy.bind("CVSPropertiesPage.port")); - portLabel = createLabel(composite, ""); + label = createLabel(composite, Policy.bind("CVSPropertiesPage.port"), 1); + portLabel = createLabel(composite, "", 2); - label = createLabel(composite, Policy.bind("CVSPropertiesPage.path")); - pathLabel = createLabel(composite, ""); + label = createLabel(composite, Policy.bind("CVSPropertiesPage.path"), 1); + pathLabel = createLabel(composite, "", 2); - label = createLabel(composite, Policy.bind("CVSPropertiesPage.module")); - moduleLabel = createLabel(composite, ""); + label = createLabel(composite, Policy.bind("CVSPropertiesPage.module"), 1); + moduleLabel = createLabel(composite, "", 2); + + label = createLabel(composite, Policy.bind("CVSPropertiesPage.tag"), 1); + tagLabel = createLabel(composite, "", 1); + GridData data = new GridData(GridData.FILL_HORIZONTAL); + tagLabel.setLayoutData(data); + + Button changeTag = new Button(composite, SWT.PUSH); + data = new GridData(GridData.HORIZONTAL_ALIGN_END); + changeTag.setLayoutData(data); + changeTag.setText(Policy.bind("CVSPropertiesPage.update")); + changeTag.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + UpdateWizard wizard = new UpdateWizard(); + wizard.setProject(project); + WizardDialog dialog = new WizardDialog(getShell(), wizard); + dialog.open(); + initializeTag(); + } + }); initializeValues(); passwordText.addListener(SWT.Modify, new Listener() { public void handleEvent(Event event) { passwordChanged = true; + connectionInfoChanged = true; + } + }); + userText.addListener(SWT.Modify, new Listener() { + public void handleEvent(Event event) { + connectionInfoChanged = true; + } + }); + methodType.addListener(SWT.Modify, new Listener() { + public void handleEvent(Event event) { + connectionInfoChanged = true; } }); return composite; @@ -106,6 +143,7 @@ public class CVSPropertiesPage extends PropertyPage { Combo combo = new Combo(parent, SWT.READ_ONLY); GridData data = new GridData(GridData.FILL_HORIZONTAL); data.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH; + data.horizontalSpan = 2; combo.setLayoutData(data); return combo; } @@ -117,11 +155,11 @@ public class CVSPropertiesPage extends PropertyPage { * @param text the text for the new label * @return the new label */ - protected Label createLabel(Composite parent, String text) { + protected Label createLabel(Composite parent, String text, int span) { Label label = new Label(parent, SWT.LEFT); label.setText(text); GridData data = new GridData(); - data.horizontalSpan = 1; + data.horizontalSpan = span; data.horizontalAlignment = GridData.FILL; label.setLayoutData(data); return label; @@ -138,6 +176,7 @@ public class CVSPropertiesPage extends PropertyPage { data.verticalAlignment = GridData.CENTER; data.grabExcessVerticalSpace = false; data.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH; + data.horizontalSpan = 2; text.setLayoutData(data); return text; } @@ -163,7 +202,6 @@ public class CVSPropertiesPage extends PropertyPage { private void initializeValues() { passwordChanged = false; - // property page is added with a nature filter - hence the unchecked typecast provider = (CVSTeamProvider)RepositoryProviderType.getProvider(project); if (provider == null) return; @@ -199,11 +237,35 @@ public class CVSPropertiesPage extends PropertyPage { } catch (TeamException e) { handle(e); } + + initializeTag(); + } + + private void initializeTag() { + provider = (CVSTeamProvider)RepositoryProviderType.getProvider(project); + if (provider == null) return; + CVSWorkspaceRoot cvsRoot = provider.getCVSWorkspaceRoot(); + try { + ICVSFolder local = cvsRoot.getCVSFolderFor(project); + CVSTag tag = local.getFolderSyncInfo().getTag(); + String tagName; + if (tag == null) { + tagName = "HEAD"; + } else { + tagName = tag.getName(); + } + tagLabel.setText(tagName); + } catch (TeamException e) { + handle(e); + } } /* * @see PreferencesPage#performOk */ public boolean performOk() { + if ( ! connectionInfoChanged) { + return true; + } info.setUsername(userText.getText()); if (passwordChanged) { info.setPassword(passwordText.getText()); diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java index 6ecfad7ec..a6dd3d465 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java @@ -246,7 +246,6 @@ public class CVSUIPlugin extends AbstractUIPlugin { * @see Plugin#shutdown() */ public void shutdown() throws CoreException { - CVSDecorator.shutdownAll(); changeListener.deregister(); super.shutdown(); try { diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/IDecorationNotifier.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/IDecorationNotifier.java index 541086bfa..d465f5893 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/IDecorationNotifier.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/IDecorationNotifier.java @@ -17,5 +17,10 @@ public interface IDecorationNotifier { /** * Called to associate a decoration to a resource. */ - public void decorated(IResource resource, CVSDecoration decoration); + public void decorated(IResource[] resource, CVSDecoration[] decoration); + + /** + * Number of resources remaining to be decorated + */ + public int remaining(); } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/CheckoutAsAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/CheckoutAsAction.java index e620868ea..ddf36d545 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/CheckoutAsAction.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/CheckoutAsAction.java @@ -10,10 +10,13 @@ import java.util.ArrayList; import java.util.Iterator; import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.IInputValidator; import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.IStructuredSelection; @@ -78,7 +81,17 @@ public class CheckoutAsAction extends TeamAction { String name = folders[0].getName(); // Prompt for name final int[] result = new int[] { InputDialog.OK }; - final InputDialog dialog = new InputDialog(shell, Policy.bind("CheckoutAsAction.enterProjectTitle"), Policy.bind("CheckoutAsAction.enterProject"), name, null); + final InputDialog dialog = new InputDialog(shell, Policy.bind("CheckoutAsAction.enterProjectTitle"), Policy.bind("CheckoutAsAction.enterProject"), name, + new IInputValidator() { + public String isValid(String newText) { + IStatus status = ResourcesPlugin.getWorkspace().validateName(newText, IResource.PROJECT); + if (status.isOK()) { + return ""; //$NON-NLS-1$ + } + return status.getMessage(); + } + + }); shell.getDisplay().syncExec(new Runnable() { public void run() { result[0] = dialog.open(); diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SetKeywordSubstitutionAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SetKeywordSubstitutionAction.java index f78310986..0febdc012 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SetKeywordSubstitutionAction.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SetKeywordSubstitutionAction.java @@ -8,10 +8,11 @@ package org.eclipse.team.internal.ccvs.ui.actions; import org.eclipse.core.resources.IResource; import org.eclipse.jface.action.IAction; import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.team.ccvs.core.CVSProviderPlugin; import org.eclipse.team.ccvs.core.CVSTeamProvider; import org.eclipse.team.ccvs.core.ICVSResource; -import org.eclipse.team.core.ITeamManager; -import org.eclipse.team.core.ITeamProvider; +import org.eclipse.team.core.RepositoryProvider; +import org.eclipse.team.core.RepositoryProviderType; import org.eclipse.team.core.TeamException; import org.eclipse.team.core.TeamPlugin; import org.eclipse.team.internal.ccvs.core.client.Command; @@ -50,15 +51,14 @@ public class SetKeywordSubstitutionAction extends TeamAction { protected boolean isEnabled() throws TeamException { IResource[] resources = getSelectedResources(); if (resources.length == 0) return false; - ITeamManager manager = TeamPlugin.getManager(); for (int i = 0; i < resources.length; i++) { IResource resource = resources[i]; // resource must be local if (! resource.isAccessible()) return false; // provider must be CVS - ITeamProvider provider = manager.getProvider(resource.getProject()); + RepositoryProvider provider = RepositoryProviderType.getProvider(resource.getProject()); if (provider == null) return false; - if (! (provider instanceof CVSTeamProvider)) return false; + if (!provider.isOfType(CVSProviderPlugin.getTypeId())) return false; // resource must either be a project, or it must be managed if (resource.getType() != IResource.PROJECT) { ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource); diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties index 8e2c58741..dae2be486 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties @@ -91,9 +91,6 @@ CVSFilePropertiesPage.baseTimestamp=Base Timestamp: CVSFilePropertiesPage.dirty=Dirty: CVSFilePropertiesPage.modified=Modified: CVSFilePropertiesPage.keywordMode=Keyword Mode: -CVSFilePropertiesPage.binary=Binary -CVSFilePropertiesPage.textNoKeyword=Text with no keyword expansion -CVSFilePropertiesPage.text=Text CVSFilePropertiesPage.tag=Tag: CVSFilePropertiesPage.none=(none) CVSFilePropertiesPage.version={0} (Version) @@ -113,6 +110,8 @@ CVSPropertiesPage.port=Port: CVSPropertiesPage.path=Repository path: CVSPropertiesPage.module=Module: CVSPropertiesPage.defaultPort=Default +CVSPropertiesPage.tag=Tag: +CVSPropertiesPage.update=Change &Tag... CVSPreferencePage.pruneEmptyDirectories=&Prune empty directories CVSPreferencePage.timeoutValue=&Communication timeout value (in seconds) @@ -321,6 +320,54 @@ ResourcePropertiesPage.checkedIn=Checked In #ResourcePropertiesPage.none=none ResourcePropertiesPage.error=Error +SetKeywordSubstitution.title=Set Keyword Substitution + +SetKeywordSubstitution.working=Setting keyword substitution mode... +SetKeywordSubstitution.problemsMessage=Problems encountered setting keyword substitution +SetKeywordSubstitution.errorTitle=Errors Occurred +SetKeywordSubstitution.warningTitle=Warnings Occured + +SetKeywordSubstitution.SharedFilesPage.pageTitle=\ + Warning some of the selected files are already shared in the repository. +SetKeywordSubstitution.SharedFilesPage.pageDescription=\ + Do you want to exclude these files from this operation? +SetKeywordSubstitution.SharedFilesPage.contents=\ + Since the keyword substitution mode attribute is not version controlled, the \ + change will be reflected immediately on all branches and in all revisions of \ + any affected files that are already shared in the repository. You should inform \ + all developers that they must delete and check out fresh copies of the affected \ + files before committing new changes to the repository. You may also experience \ + side-effects working with earlier revisions of these files. +SetKeywordSubstitution.SharedFilesPage.onlyAddedFilesButton=Don't change files that are already shared in the repository. +SetKeywordSubstitution.SharedFilesPage.committedFiles=Selected files that are already shared in the repository: + +SetKeywordSubstitution.OutgoingChangesPage.pageTitle=\ + Warning some of the selected files have outgoing changes. +SetKeywordSubstitution.OutgoingChangesPage.pageDescription=\ + Do you want to exclude these files from this operation? +SetKeywordSubstitution.OutgoingChangesPage.contents=\ + This operation may commit changes to files without providing a chance to resolve \ + conflicts first. +SetKeywordSubstitution.OutgoingChangesPage.onlyCleanFilesButton=Don't change files with outgoing changes. +SetKeywordSubstitution.OutgoingChangesPage.changedFiles=Selected files with outgoing changes. + +SetKeywordSubstitution.SelectModePage.pageTitle=Select and change keyword substitution mode +SetKeywordSubstitution.SelectModePage.pageDescription=\ + The keyword substitution mode specifies transformations to be performed \ + on files during CVS operations. +SetKeywordSubstitution.SelectModePage.contents=\ + If you are uncertain, choose 'Text' for plain text files, and 'Binary' for all others. +SetKeywordSubstitution.SelectModePage.binaryLabel=\ + Binary files are stored in the repository without alteration.\n\ + CVS does not directly support conflict resolution for binary files. +SetKeywordSubstitution.SelectModePage.textLabel=\ + Text files are stored in the repository in a neutral format but are retrieved in the platform's native text encoding.\n\ + CVS supports conflict resoltion and differencing of text files with single line granularity. +SetKeywordSubstitution.SelectModePage.textWithSubstitutions=Text with Keyword Substitution... +SetKeywordSubstitution.SelectModePage.textWithSubstitutionsLabel=\ + Text files may also contain keywords that are substituted with their value by the CVS server during file transfers.\n\ + Please consult the CVS documentation for a description of the various supported keywords and modes. + SharingWizard.autoConnectTitle=Connect Project to Repository SharingWizard.couldNotImport=Could Not Import SharingWizard.couldNotImportLong=Your resources could not be imported into the repository because a module with that name already exists. @@ -351,6 +398,12 @@ TagAction.enterTag=Please enter a version tag: UpdateAction.update=Problems encountered performing update UpdateAction.updating=Updating... +UpdateWizard.title=Update +UpdateWizard.updatePage=Update + +UpdateWizardPage.description=&Select a tag to update the project sharing to: +UpdateWizardPage.overwrite=&Overwrite local changes + UserValidationDialog.required=Password Required UserValidationDialog.labelUser=Enter a user name and password for the following repository:\n{0} UserValidationDialog.labelPassword=Enter a password for {0} in the following repository:\n{1} diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSCatchupReleaseViewer.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSCatchupReleaseViewer.java index b204b7b67..01be6ee7c 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSCatchupReleaseViewer.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSCatchupReleaseViewer.java @@ -30,9 +30,9 @@ import org.eclipse.team.core.TeamException; import org.eclipse.team.core.sync.IRemoteResource; import org.eclipse.team.core.sync.IRemoteSyncElement; import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; -import org.eclipse.team.internal.ccvs.ui.CVSDecorator; import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; import org.eclipse.team.internal.ccvs.ui.HistoryView; import org.eclipse.team.internal.ccvs.ui.ICVSUIConstants; @@ -172,13 +172,10 @@ public class CVSCatchupReleaseViewer extends CatchupReleaseViewer { try { ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor((IFile) resource); ResourceSyncInfo info = cvsFile.getSyncInfo(); - String kw; - if (info!=null) { - kw = CVSDecorator.getFileTypeString(resource.getName(), info.getKeywordMode()); - } else { - kw = CVSDecorator.getFileTypeString(resource.getName(), null); - } - postfix.append("(" + kw + ")"); + KSubstOption option = info != null && info.getKeywordMode() != null ? + KSubstOption.fromMode(info.getKeywordMode()) : + KSubstOption.fromPattern(resource.getName()); + postfix.append("(" + option.getShortDisplayText() + ")"); } catch(CVSException e) { ErrorDialog.openError(getControl().getShell(), null, null, e.getStatus()); } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/BranchWizard.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/BranchWizard.java index b696818d7..9aa07a9b5 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/BranchWizard.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/BranchWizard.java @@ -20,10 +20,6 @@ import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.wizard.Wizard; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; import org.eclipse.team.ccvs.core.CVSTag; import org.eclipse.team.ccvs.core.CVSTeamProvider; import org.eclipse.team.ccvs.core.ICVSRemoteFolder; @@ -42,7 +38,7 @@ import org.eclipse.team.internal.ccvs.ui.model.BranchTag; public class BranchWizard extends Wizard { BranchWizardVersionPage versionPage; BranchWizardBranchPage branchPage; - BranchWizardMethodPage methodPage; + //BranchWizardMethodPage methodPage; IResource[] resources; public BranchWizard() { @@ -55,8 +51,8 @@ public class BranchWizard extends Wizard { addPage(versionPage); branchPage = new BranchWizardBranchPage("branchPage", Policy.bind("BranchWizard.createABranch"), CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_WIZBAN_BRANCH)); addPage(branchPage); - methodPage = new BranchWizardMethodPage("methodPage", Policy.bind("BranchWizard.createABranch"), CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_WIZBAN_BRANCH)); - addPage(methodPage); + //methodPage = new BranchWizardMethodPage("methodPage", Policy.bind("BranchWizard.createABranch"), CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_WIZBAN_BRANCH)); + //addPage(methodPage); } public boolean performFinish() { final boolean[] result = new boolean[] {false}; @@ -71,7 +67,8 @@ public class BranchWizard extends Wizard { if (versionString != null) { versionTag = new CVSTag(versionString, CVSTag.VERSION); } - boolean eclipseWay = methodPage.getEclipseWay(); + boolean eclipseWay = true; + //boolean eclipseWay = methodPage.getEclipseWay(); // To do: use the wizard's progress monitor RepositoryManager manager = CVSUIPlugin.getPlugin().getRepositoryManager(); @@ -146,25 +143,4 @@ public class BranchWizard extends Wizard { } return result; } - - /** - * A helper method used by pages to display indented descriptions - */ - protected static Composite createDescriptionComposite(Composite parent, int parentColumns) { - Composite composite = new Composite(parent, SWT.NULL); - - // GridLayout - GridLayout layout = new GridLayout(); - layout.marginWidth = 10; - layout.marginHeight = 0; - composite.setLayout(layout); - - // GridData - GridData data = new GridData(); - data.verticalAlignment = GridData.FILL; - data.horizontalAlignment = GridData.FILL; - data.horizontalSpan = parentColumns; - composite.setLayoutData(data); - return composite; - } } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/BranchWizardMethodPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/BranchWizardMethodPage.java index bb057746d..c74045ba0 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/BranchWizardMethodPage.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/BranchWizardMethodPage.java @@ -53,7 +53,7 @@ public class BranchWizardMethodPage extends CVSWizardPage { data.horizontalSpan = 2; eclipseWay.setLayoutData(data); - Composite eclipseDescriptionComposite = BranchWizard.createDescriptionComposite(composite, 2); + Composite eclipseDescriptionComposite = createDescriptionComposite(composite, 2); Label eclipseDescription = new Label(eclipseDescriptionComposite, SWT.WRAP); eclipseDescription.setText(Policy.bind("BranchWizardMethodPage.eclipseDescription")); //$NON-NLS-1$ data = new GridData(); @@ -72,7 +72,7 @@ public class BranchWizardMethodPage extends CVSWizardPage { data.horizontalSpan = 2; cvsWay.setLayoutData(data); - Composite cvsDescriptionComposite = BranchWizard.createDescriptionComposite(composite, 2); + Composite cvsDescriptionComposite = createDescriptionComposite(composite, 2); Label cvsDescription = new Label(cvsDescriptionComposite, SWT.WRAP); cvsDescription.setText(Policy.bind("BranchWizardMethodPage.cvsDescription")); //$NON-NLS-1$ data = new GridData(); @@ -90,4 +90,22 @@ public class BranchWizardMethodPage extends CVSWizardPage { private void updateEnablement() { setPageComplete(true); } + + private Composite createDescriptionComposite(Composite parent, int parentColumns) { + Composite composite = new Composite(parent, SWT.NULL); + + // GridLayout + GridLayout layout = new GridLayout(); + layout.marginWidth = 10; + layout.marginHeight = 0; + composite.setLayout(layout); + + // GridData + GridData data = new GridData(); + data.verticalAlignment = GridData.FILL; + data.horizontalAlignment = GridData.FILL; + data.horizontalSpan = parentColumns; + composite.setLayoutData(data); + return composite; + } }
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SetKeywordSubstitutionOperation.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SetKeywordSubstitutionOperation.java index 3a66af8b0..f36ca4384 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SetKeywordSubstitutionOperation.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SetKeywordSubstitutionOperation.java @@ -22,9 +22,9 @@ import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.swt.widgets.Shell; import org.eclipse.team.ccvs.core.CVSStatus; import org.eclipse.team.ccvs.core.CVSTeamProvider; -import org.eclipse.team.core.ITeamProvider; +import org.eclipse.team.core.RepositoryProvider; +import org.eclipse.team.core.RepositoryProviderType; import org.eclipse.team.core.TeamException; -import org.eclipse.team.core.TeamPlugin; import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; import org.eclipse.team.internal.ccvs.ui.Policy; @@ -115,7 +115,7 @@ public class SetKeywordSubstitutionOperation implements IRunnableWithProgress { protected Hashtable getProviderMapping(IResource[] resources) { Hashtable result = new Hashtable(); for (int i = 0; i < resources.length; i++) { - ITeamProvider provider = TeamPlugin.getManager().getProvider(resources[i].getProject()); + RepositoryProvider provider = RepositoryProviderType.getProvider(resources[i].getProject()); List list = (List)result.get(provider); if (list == null) { list = new ArrayList(); diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/UpdateWizard.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/UpdateWizard.java index c5cbd6eb7..0e2366316 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/UpdateWizard.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/UpdateWizard.java @@ -17,6 +17,7 @@ import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.wizard.Wizard; import org.eclipse.team.ccvs.core.CVSTeamProvider; +import org.eclipse.team.core.RepositoryProviderType; import org.eclipse.team.core.TeamException; import org.eclipse.team.core.TeamPlugin; import org.eclipse.team.internal.ccvs.core.CVSException; @@ -62,7 +63,7 @@ public class UpdateWizard extends Wizard { getContainer().run(false, false, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException { try { - CVSTeamProvider provider = ((CVSTeamProvider)TeamPlugin.getManager().getProvider(project)); + CVSTeamProvider provider = ((CVSTeamProvider)RepositoryProviderType.getProvider(project)); provider.update(new IResource[] {project}, updatePage.getLocalOptions(), updatePage.getTag(), null, monitor); result[0] = true; } catch (TeamException e) { diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/CVSTestSetup.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/CVSTestSetup.java index 6db103257..84be67f13 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/CVSTestSetup.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/CVSTestSetup.java @@ -36,7 +36,7 @@ public class CVSTestSetup extends TestSetup { } public static void loadProperties() { - String propertiesFile = System.getProperty("eclipse.cvs.properties"); + String propertiesFile = "e:/repository.properties"; if (propertiesFile == null) return; File file = new File(propertiesFile); if (file.isDirectory()) file = new File(file, "repository.properties"); diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/CVSProviderTest.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/CVSProviderTest.java index c575e9130..c4a4dc56c 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/CVSProviderTest.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/CVSProviderTest.java @@ -3,18 +3,33 @@ package org.eclipse.team.tests.ccvs.core.provider; * (c) Copyright IBM Corp. 2000, 2002. * All Rights Reserved. */ +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import junit.framework.Test; import junit.framework.TestSuite; +import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; import org.eclipse.team.ccvs.core.CVSProviderPlugin; import org.eclipse.team.ccvs.core.CVSTag; +import org.eclipse.team.ccvs.core.CVSTeamProvider; +import org.eclipse.team.ccvs.core.ICVSFile; +import org.eclipse.team.core.IFileTypeRegistry; import org.eclipse.team.core.TeamException; +import org.eclipse.team.core.TeamPlugin; 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.resources.CVSWorkspaceRoot; +import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; import org.eclipse.team.tests.ccvs.core.CVSTestSetup; import org.eclipse.team.tests.ccvs.core.EclipseTest; import org.eclipse.team.tests.ccvs.core.JUnitTestCase; @@ -218,5 +233,139 @@ public class CVSProviderTest extends EclipseTest { getProvider(copy).get(new IResource[] {copy}, IResource.DEPTH_INFINITE, DEFAULT_MONITOR); assertEquals(project, copy); } + + public void testCleanLineDelimiters() throws TeamException, CoreException, IOException { + // Create a project + IProject project = getUniqueTestProject("testCleanLineDelimiters"); + IFile file = project.getFile("testfile"); + IProgressMonitor monitor = new NullProgressMonitor(); + + // empty file + setFileContents(file, ""); + CVSTeamProvider.cleanLineDelimiters(file, false, monitor); + assertEqualsFileContents(file, ""); + CVSTeamProvider.cleanLineDelimiters(file, true, monitor); + assertEqualsFileContents(file, ""); + + // one byte + setFileContents(file, "a"); + CVSTeamProvider.cleanLineDelimiters(file, false, monitor); + assertEqualsFileContents(file, "a"); + CVSTeamProvider.cleanLineDelimiters(file, true, monitor); + assertEqualsFileContents(file, "a"); + + // single orphan carriage return (should be preserved) + setFileContents(file, "\r"); + CVSTeamProvider.cleanLineDelimiters(file, false, monitor); + assertEqualsFileContents(file, "\r"); + CVSTeamProvider.cleanLineDelimiters(file, true, monitor); + assertEqualsFileContents(file, "\r"); + + // single line feed + setFileContents(file, "\n"); + CVSTeamProvider.cleanLineDelimiters(file, false, monitor); + assertEqualsFileContents(file, "\n"); + CVSTeamProvider.cleanLineDelimiters(file, true, monitor); + assertEqualsFileContents(file, "\r\n"); + + // single carriage return line feed + setFileContents(file, "\r\n"); + CVSTeamProvider.cleanLineDelimiters(file, true, monitor); + assertEqualsFileContents(file, "\r\n"); + CVSTeamProvider.cleanLineDelimiters(file, false, monitor); + assertEqualsFileContents(file, "\n"); + + // mixed text with orphaned CR's + setFileContents(file, "The \r\n quick brown \n fox \r\r\r\n jumped \n\n over \r\n the \n lazy dog.\r\n"); + CVSTeamProvider.cleanLineDelimiters(file, false, monitor); + assertEqualsFileContents(file, "The \n quick brown \n fox \r\r\n jumped \n\n over \n the \n lazy dog.\n"); + setFileContents(file, "The \r\n quick brown \n fox \r\r\r\n jumped \n\n over \r\n the \n lazy dog.\r\n"); + CVSTeamProvider.cleanLineDelimiters(file, true, monitor); + assertEqualsFileContents(file, "The \r\n quick brown \r\n fox \r\r\r\n jumped \r\n\r\n over \r\n the \r\n lazy dog.\r\n"); + } + + public void testKeywordSubstitution() throws TeamException, CoreException, IOException { + testKeywordSubstitution(Command.KSUBST_BINARY); // -kb + testKeywordSubstitution(Command.KSUBST_TEXT); // -ko + testKeywordSubstitution(Command.KSUBST_TEXT_EXPAND); // -kkv + } + + private void testKeywordSubstitution(KSubstOption ksubst) throws TeamException, CoreException, IOException { + // setup some known file types + TeamPlugin.getFileTypeRegistry().setValue("xbin", IFileTypeRegistry.BINARY); + TeamPlugin.getFileTypeRegistry().setValue("xtxt", IFileTypeRegistry.TEXT); + + // create a test project + IProject project = createProject("testKeywordSubstitution", new String[] { "dummy" }); + addResources(project, new String[] { "binary.xbin", "text.xtxt", "folder1/", "folder1/a.xtxt" }, true); + addResources(project, new String[] { "added.xbin", "added.xtxt" }, false); + assertHasKSubstOption(project, "binary.xbin", Command.KSUBST_BINARY); + assertHasKSubstOption(project, "added.xbin", Command.KSUBST_BINARY); + // XXX should these be KSUBST_TEXT instead? + assertHasKSubstOption(project, "text.xtxt", Command.KSUBST_TEXT_EXPAND); + assertHasKSubstOption(project, "folder1/a.xtxt", Command.KSUBST_TEXT_EXPAND); + assertHasKSubstOption(project, "added.xtxt", Command.KSUBST_TEXT_EXPAND); + + // change keyword substitution + IStatus status = getProvider(project).setKeywordSubstitution(new IResource[] { project }, + IResource.DEPTH_INFINITE, ksubst, null); + assertTrue("Status should be ok, was: " + status.toString(), status.isOK()); + assertHasKSubstOption(project, "binary.xbin", ksubst); + assertHasKSubstOption(project, "text.xtxt", ksubst); + assertHasKSubstOption(project, "folder1/a.xtxt", ksubst); + assertHasKSubstOption(project, "added.xtxt", ksubst); + assertHasKSubstOption(project, "added.xbin", ksubst); + + // verify that substitution mode changed remotely and "added.xtxt", "added.xbin" don't exist + IProject copy = checkoutCopy(project, "-copy"); + assertHasKSubstOption(copy, "binary.xbin", ksubst); + assertHasKSubstOption(copy, "text.xtxt", ksubst); + assertHasKSubstOption(copy, "folder1/a.xtxt", ksubst); + assertDoesNotExistInWorkspace(copy.getFile("added.xtxt")); + assertDoesNotExistInWorkspace(copy.getFile("added.xbin")); + + // commit added files then checkout the copy again + commitResources(project, new String[] { "added.xbin", "added.xtxt" }); + IProject copy2 = checkoutCopy(project, "-copy2"); + assertHasKSubstOption(copy2, "added.xtxt", ksubst); + assertHasKSubstOption(copy2, "added.xbin", ksubst); + + // verify that local contents are up to date + assertEquals(project, copy2); + } + + public static void setFileContents(IFile file, String string) throws CoreException { + InputStream is = new ByteArrayInputStream(string.getBytes()); + if (file.exists()) { + file.setContents(is, false /*force*/, true /*keepHistory*/, null); + } else { + file.create(is, false /*force*/, null); + } + } + public static String getFileContents(IFile file) throws CoreException, IOException { + StringBuffer buf = new StringBuffer(); + InputStream is = new BufferedInputStream(file.getContents()); + try { + int c; + while ((c = is.read()) != -1) buf.append((char)c); + } finally { + is.close(); + } + return buf.toString(); + } + + public static void assertEqualsFileContents(IFile file, String string) throws CoreException, IOException { + String other = getFileContents(file); + assertEquals(string, other); + } + + public static void assertHasKSubstOption(IContainer container, String filename, KSubstOption ksubst) + throws TeamException { + IFile file = container.getFile(new Path(filename)); + ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor(file); + ResourceSyncInfo info = cvsFile.getSyncInfo(); + KSubstOption other = KSubstOption.fromMode(info.getKeywordMode()); + assertEquals(ksubst, other); + } } diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/RemoteResourceTest.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/RemoteResourceTest.java index 9006b82e8..f7c6c1714 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/RemoteResourceTest.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/RemoteResourceTest.java @@ -230,7 +230,7 @@ public class RemoteResourceTest extends EclipseTest { public void testFileRevisions() throws TeamException, CoreException, IOException { // Create a project with an empty file - IProject project = createProject("testEmptyFile", new String[] { "file.txt"}); + IProject project = createProject("testFileRevisions", new String[] { "file.txt"}); IFile file = project.getFile("file.txt"); JUnitTestCase.waitMsec(1500); file.setContents(new ByteArrayInputStream("hi there".getBytes()), false, false, DEFAULT_MONITOR); |