diff options
Diffstat (limited to 'bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java')
-rw-r--r-- | bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java | 1141 |
1 files changed, 0 insertions, 1141 deletions
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 deleted file mode 100644 index fd0432ab8..000000000 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java +++ /dev/null @@ -1,1141 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2003 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.team.internal.ccvs.core.client; - -import java.io.*; -import java.util.*; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.*; -import org.eclipse.team.internal.ccvs.core.*; -import org.eclipse.team.internal.ccvs.core.client.Command.GlobalOption; -import org.eclipse.team.internal.ccvs.core.client.Command.QuietOption; -import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation; -import org.eclipse.team.internal.ccvs.core.connection.Connection; -import org.eclipse.team.internal.ccvs.core.syncinfo.NotifyInfo; -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.Util; -import org.eclipse.team.internal.core.streams.*; - -/** - * Maintains CVS communication state for the lifetime of a connection - * to a remote repository. This class covers the initialization, use, - * and eventual shutdown of a dialogue between a CVS client and a - * remote server. This dialogue may be monitored through the use of - * a console. - * - * Initially the Session is in a CLOSED state during which communication - * with the server cannot take place. Once OPENED, any number of commands - * may be issued serially to the server, one at a time. When finished, the - * Session MUST be CLOSED once again to prevent eventual local and/or - * remote resource exhaustion. The session can either be discarded, or - * re-opened for use with the same server though no state is persisted from - * previous connections except for console attributes. - * - * CVSExceptions are thrown only as a result of unrecoverable errors. Once - * this happens, commands must no longer be issued to the server. If the - * Session is in the OPEN state, it is still the responsibility of the - * caller to CLOSE it before moving on. - */ -public class Session { - public static final String CURRENT_LOCAL_FOLDER = "."; //$NON-NLS-1$ - public static final String CURRENT_REMOTE_FOLDER = ""; //$NON-NLS-1$ - public static final String SERVER_SEPARATOR = "/"; //$NON-NLS-1$ - - // default file transfer buffer size (in bytes) - private static final int TRANSFER_BUFFER_SIZE = 8192; - // update progress bar in increments of this size (in bytes) - // no incremental progress shown for files smaller than this size - private static final int TRANSFER_PROGRESS_INCREMENT = 32768; - - private static final boolean IS_CRLF_PLATFORM = Arrays.equals( - System.getProperty("line.separator").getBytes(), new byte[] { '\r', '\n' }); //$NON-NLS-1$ - - private CVSRepositoryLocation location; - private ICVSFolder localRoot; - private boolean outputToConsole; - private Connection connection = null; - private String validRequests = null; - private Date modTime = null; - private boolean noLocalChanges = false; - private boolean createBackups = true; - private int compressionLevel = 0; - private List expansions; - private Collection /* of ICVSFile */ textTransferOverrideSet = null; - private Map caseMappings; - - // state need to indicate whether - private boolean ignoringLocalChanges = false; - - // The resource bundle key that provides the file sending message - private String sendFileTitleKey; - private Map responseHandlers; - - /** - * Creates a new CVS session, initially in the CLOSED state. - * By default, command output is directed to the console. - * - * @param location the CVS repository location used for this session - * @param localRoot represents the current working directory of the client - */ - public Session(ICVSRepositoryLocation location, ICVSFolder localRoot) { - this(location, localRoot, true); - } - - /** - * Creates a new CVS session, initially in the CLOSED state. - * - * @param location the CVS repository location used for this session - * @param localRoot represents the current working directory of the client - * @param outputToConsole if true, command output is directed to the console - */ - public Session(ICVSRepositoryLocation location, ICVSFolder localRoot, boolean outputToConsole) { - this.location = (CVSRepositoryLocation) location; - this.localRoot = localRoot; - this.outputToConsole = outputToConsole; - } - - /** - * Register a case collision with the session. - * - * For folders, the desired path is where the folder should be and the actual path - * is where is was put temporarily. If one of the folders involved is pruned, the - * other can be placed properly (see Session#handleCaseCollisions()) - * - * For files, the desired path is where the file should be and the actual path is - * the emtpy path indicating that the resource was not loaded. - * - * This makes sense because the files in a folder are always communicated before the folders - * so a file can only collide with anothe file which can never be pruned so there's no - * point in loading the file in a temporary place. - */ - protected void addCaseCollision(String desiredLocalPath, String actualLocalPath) { - if (caseMappings == null) caseMappings = new HashMap(); - IPath desiredPath = new Path(desiredLocalPath); - IPath actualPath = new Path(actualLocalPath); - Assert.isTrue(actualPath.equals(Path.EMPTY) || (desiredPath.segmentCount() == actualPath.segmentCount())); - caseMappings.put(desiredPath, actualPath); - } - /* - * Add a module expansion receivered from the server. - * This is only used by the ModuleExpansionsHandler - */ - protected void addModuleExpansion(String expansion) { - expansions.add(expansion); - } - - /* - * Add a module expansion receivered from the server. - * This is only used by the ExpandModules command - */ - protected void resetModuleExpansion() { - if (expansions == null) - expansions = new ArrayList(); - else - expansions.clear(); - } - - /** - * Opens, authenticates and initializes a connection to the server specified - * for the remote location. - * - * @param monitor the progress monitor - * @throws IllegalStateException if the Session is not in the CLOSED state - */ - public void open(IProgressMonitor monitor) throws CVSException { - open(monitor, true /* write access*/); - } - - public void open(IProgressMonitor monitor, boolean writeAccess) throws CVSException { - if (connection != null) throw new IllegalStateException(); - monitor = Policy.monitorFor(monitor); - monitor.beginTask(null, 100); - boolean opened = false; - - try { - connection = getLocationForConnection(writeAccess).openConnection(Policy.subMonitorFor(monitor, 50)); - - // If we're connected to a CVSNT server or we don't know the platform, - // accept MT. Otherwise don't. - boolean useMT = ! (location.getServerPlatform() == CVSRepositoryLocation.CVS_SERVER); - if ( ! useMT) { - removeResponseHandler("MT"); //$NON-NLS-1$ - } - - // tell the server the names of the responses we can handle - connection.writeLine("Valid-responses " + makeResponseList()); //$NON-NLS-1$ - - // ask for the set of valid requests - IStatus status = Request.VALID_REQUESTS.execute(this, Policy.subMonitorFor(monitor, 40)); - if (!status.isOK()) { - throw new CVSException(status); - } - - // set the root directory on the server for this connection - connection.writeLine("Root " + getRepositoryRoot()); //$NON-NLS-1$ - - // enable compression - compressionLevel = CVSProviderPlugin.getPlugin().getCompressionLevel(); - if (compressionLevel != 0 && isValidRequest("gzip-file-contents")) { //$NON-NLS-1$ - // Enable the use of CVS 1.8 per-file compression mechanism. - // The newer Gzip-stream request seems to be problematic due to Java's - // GZIPInputStream tendency to block on read() rather than to return a - // partially filled buffer. The latter option would be better since it - // can make more effective use of the code dictionary, if it can be made - // to work... - connection.writeLine("gzip-file-contents " + Integer.toString(compressionLevel)); //$NON-NLS-1$ - } else { - compressionLevel = 0; - } - - // get the server platform if it is unknown - if (CVSProviderPlugin.getPlugin().isDetermineVersionEnabled() && location.getServerPlatform() == CVSRepositoryLocation.UNDETERMINED_PLATFORM) { - Command.VERSION.execute(this, location, Policy.subMonitorFor(monitor, 10)); - } - opened = true; - } finally { - if (connection != null && ! opened) { - try { - close(); - } catch (CVSException ex) { - CVSProviderPlugin.log(ex); - } - } - monitor.done(); - } - } - - /* - * Return the location to be used for this connection - */ - private CVSRepositoryLocation getLocationForConnection(boolean writeAccess) { - try { - if (writeAccess) { - String writeLocation = location.getWriteLocation(); - if (writeLocation != null) { - return (CVSRepositoryLocation)CVSProviderPlugin.getPlugin().getRepository(writeLocation); - } - } else { - String readLocation = location.getReadLocation(); - if (readLocation != null) { - return (CVSRepositoryLocation)CVSProviderPlugin.getPlugin().getRepository(readLocation); - } - } - } catch (CVSException e) { - CVSProviderPlugin.log(e); - } - return location; - } - - /** - * Closes a connection to the server. - * - * @throws IllegalStateException if the Session is not in the OPEN state - */ - public void close() throws CVSException { - if (connection != null) { - connection.close(); - connection = null; - validRequests = null; - } - } - - /** - * Determines if the server supports the specified request. - * - * @param request the request string to verify - * @return true iff the request is supported - */ - public boolean isValidRequest(String request) { - return (validRequests == null) || - (validRequests.indexOf(" " + request + " ") != -1); //$NON-NLS-1$ //$NON-NLS-2$ - } - - public boolean isCVSNT() { - if (location.getServerPlatform() == CVSRepositoryLocation.UNDETERMINED_PLATFORM) { - return location.getRootDirectory().indexOf(':') == 1; - } else { - return location.getServerPlatform() == CVSRepositoryLocation.CVSNT_SERVER; - } - } - - /** - * Return a local path that can be used to uniquely identify a resource - * if the platform does not support case variant names and there is a name collision - */ - protected String getUniquePathForCaseSensitivePath(String localPath, boolean creatingFolder) { - IPath path = new Path(localPath); - IPath existingMapping = null; - if (caseMappings != null) { - // Look for an existing parent path that has already been mapped - for (int i = 0; i < path.segmentCount(); i++) { - IPath key = path.removeLastSegments(i); - existingMapping = (IPath)caseMappings.get(key); - if (existingMapping != null) break; - } - } - if (existingMapping != null) { - if (existingMapping.segmentCount() == path.segmentCount()) { - return existingMapping.toString(); - } - // Convert the path to the mapped path - path = existingMapping.append(path.removeFirstSegments(existingMapping.segmentCount())); - } - if (creatingFolder) { - // Change the name of the folder to a case insensitive one - String folderName = path.lastSegment(); - // XXX We should ensure that each permutation of characters is unique - folderName = getUniqueNameForCaseVariant(folderName); - path = path.removeLastSegments(1).append(folderName); - } - return path.toString(); - } - - /* - * Return a name that is unique for a give case variant. - */ - private String getUniqueNameForCaseVariant(String name) { - char[] buffer = new char[name.length() * 2]; - int position = 0; - for (int i = 0; i < name.length(); i++) { - char c = name.charAt(i); - buffer[position++] = c; - if (Character.isLetter(c)) { - if (Character.isUpperCase(c)) { - buffer[position++] = '-'; - } else { - buffer[position++] = '_'; - } - } - } - return new String(buffer, 0, position); - } - - /** - * Returns the local root folder for this session. - * <p> - * Generally speaking, specifies the "current working directory" at - * the time of invocation of an equivalent CVS command-line client. - * </p> - * - * @return the local root folder - */ - public ICVSFolder getLocalRoot() { - return localRoot; - } - - /** - * Return the list of module expansions communicated from the server. - * - * The modules expansions are typically a directory path of length 1 - * but can be of greater length on occasion. - */ - public String[] getModuleExpansions() { - if (expansions == null) return new String[0]; - return (String[]) expansions.toArray(new String[expansions.size()]); - } - - /** - * Returns the repository root folder for this session. - * <p> - * Specifies the unqualified path to the CVS repository root folder - * on the server. - * </p> - * - * @return the repository root folder - */ - public String getRepositoryRoot() { - return location.getRootDirectory(); - } - - /** - * Returns an object representing the CVS repository location for this session. - * - * @return the CVS repository location - */ - public ICVSRepositoryLocation getCVSRepositoryLocation() { - return location; - } - - private IContainer getIResourceFor(ICVSFolder cvsFolder) throws CoreException, CVSException { - if (cvsFolder.isManaged()) { - return getIResourceFor(cvsFolder.getParent()).getFolder(new Path(cvsFolder.getName())); - } else { - return ResourcesPlugin.getWorkspace().getRoot().getProject(cvsFolder.getName()); - } - } - - protected void handleCaseCollisions() throws CVSException { - // Handle any case variant mappings - Map mappings = caseMappings; - if (mappings == null || mappings.size() == 0) return; - // We need to start at the longest paths and work to the shortest - // in case there are nested case collisions - List sortedCollisions = new ArrayList(); - sortedCollisions.addAll(mappings.keySet()); - Collections.sort(sortedCollisions, new Comparator() { - public int compare(Object arg0, Object arg1) { - int length0 = ((IPath)arg0).segmentCount(); - int length1 = ((IPath)arg1).segmentCount(); - if (length0 == length1) { - return arg0.toString().compareTo(arg1.toString()); - } - return length0 > length1 ? -1 : 1; - } - }); - // For each mapping, we need to see if one of the culprits was pruned - List unhandledMappings = new ArrayList(); - Iterator iterator = sortedCollisions.iterator(); - while (iterator.hasNext()) { - IPath desiredPath = (IPath)iterator.next(); - IPath actualPath = (IPath)mappings.get(desiredPath); - // Check for the empty path (i.e. unloaded file) - if (actualPath.equals(Path.EMPTY)) { - unhandledMappings.add(desiredPath); - continue; - } - // Check if the actualPath still exists (it may have been pruned) - ICVSFolder actualFolder = getLocalRoot().getFolder(actualPath.toString()); - if ( ! actualFolder.exists()) continue; - // Check if the desiredPath exists (we can only do this by trying to create it - ICVSFolder desiredFolder = getLocalRoot().getFolder(desiredPath.toString()); - try { - desiredFolder.mkdir(); - desiredFolder.delete(); - } catch (CVSException e) { - // Must still exists. Delete the collision - actualFolder.delete(); - actualFolder.unmanage(null); - unhandledMappings.add(desiredPath); - continue; - } - // The desired location is open (probably due to pruning) - try { - // We need to get the IResource for the actual and desired locations - IResource actualResource = getIResourceFor(actualFolder); - IResource desiredResource = actualResource.getParent().getFolder(new Path(desiredFolder.getName())); - // Move the actual to the desired location - actualResource.move(desiredResource.getFullPath(), false, null); - // We need to also move the sync info. Since sync info is a session property - // of the object, we can simpy reset the info for each moved resource - desiredFolder.accept(new ICVSResourceVisitor() { - public void visitFile(ICVSFile file) throws CVSException { - file.setSyncBytes(file.getSyncBytes(), ICVSFile.UNKNOWN); - } - public void visitFolder(ICVSFolder folder) throws CVSException { - folder.setFolderSyncInfo(folder.getFolderSyncInfo()); - folder.acceptChildren(this); - } - }); - // Unmanage the old location in order to remove the entry from the parent - actualFolder.unmanage(null); - } catch (CoreException e) { - CVSProviderPlugin.log(e); - unhandledMappings.add(desiredPath); - } - } - - if (unhandledMappings.size() > 0) { - MultiStatus status = new MultiStatus(CVSProviderPlugin.ID, CVSStatus.CASE_VARIANT_EXISTS, Policy.bind("PruneFolderVisitor.caseVariantsExist"), null);//$NON-NLS-1$ - Iterator iter = unhandledMappings.iterator(); - while (iter.hasNext()) { - IPath desiredPath = (IPath) iter.next(); - status.add(new CVSStatus(IStatus.ERROR, CVSStatus.CASE_VARIANT_EXISTS, - Policy.bind("PruneFolderVisitor.caseVariantExists", desiredPath.toString())));//$NON-NLS-1$ - } - if (status.getChildren().length == 1) { - throw new CVSException(status.getChildren()[0]); - } else { - throw new CVSException(status); - } - } - } - - /** - * Receives a line of text minus the newline from the server. - * - * @return the line of text - */ - public String readLine() throws CVSException { - return connection.readLine(); - } - - /** - * Sends a line of text followed by a newline to the server. - * - * @param line the line of text - */ - public void writeLine(String line) throws CVSException { - connection.writeLine(line); - } - - /** - * Sends an argument to the server. - * <p>e.g. sendArgument("Hello\nWorld\n Hello World") sends: - * <pre> - * Argument Hello \n - * Argumentx World \n - * Argumentx Hello World \n - * </pre></p> - * - * @param arg the argument to send - */ - public void sendArgument(String arg) throws CVSException { - connection.write("Argument "); //$NON-NLS-1$ - int oldPos = 0; - for (;;) { - int pos = arg.indexOf('\n', oldPos); - if (pos == -1) break; - connection.writeLine(arg.substring(oldPos, pos)); - connection.write("Argumentx "); //$NON-NLS-1$ - oldPos = pos + 1; - } - connection.writeLine(arg.substring(oldPos)); - } - - /** - * Sends a request to the server and flushes any output buffers. - * - * @param requestId the string associated with the request to be executed - */ - public void sendRequest(String requestId) throws CVSException { - connection.writeLine(requestId); - connection.flush(); - } - - /** - * Sends an Is-modified request to the server without the file contents. - * <p>e.g. if a file called "local_file" was modified, sends: - * <pre> - * Is-modified local_file \n - * </pre></p><p> - * This request is an optimized form of the Modified request and may not - * be supported by all servers. Hence, if it is not supported, a Modified - * request is sent instead along with the file's contents. According to - * the CVS protocol specification, this request is only safe for use with - * some forms of: admin, annotate, diff, editors, log, watch-add, watch-off, - * watch-on, watch-remove, and watchers.<br> - * It may be possible to use this for: add, export, remove and status.<br> - * Do not use with co, ci, history, init, import, release, rdiff, rtag, or update. - * </p><p> - * Note: The most recent Directory request must have specified the file's - * parent folder. - * </p> - * - * @param file the file that was modified - * @see #sendModified - */ - public void sendIsModified(ICVSFile file, boolean isBinary, IProgressMonitor monitor) - throws CVSException { - if (isValidRequest("Is-modified")) { //$NON-NLS-1$ - connection.writeLine("Is-modified " + file.getName()); //$NON-NLS-1$ - } else { - sendModified(file, isBinary, monitor); - } - } - - /** - * Sends a Static-directory request to the server. - * <p> - * Indicates that the directory specified in the most recent Directory request - * is static. No new files will be checked out into this directory unless - * explicitly requested. - * </p> - */ - public void sendStaticDirectory() throws CVSException { - connection.writeLine("Static-directory"); //$NON-NLS-1$ - } - - /** - * Sends a Directory request to the server with a constructed path. - * <p> - * It may be necessary at times to guess the remote path of a directory since - * it does not exist yet. In this case we construct a remote path based on the - * local path by prepending the local path with the repository root. This may - * not work in the presence of modules, so only use it for creating new projects. - * </p><p> - * Note: A CVS repository root can end with a trailing slash. The CVS server - * expects that the repository root sent contain this extra slash. Including - * the foward slash in addition to the absolute remote path makes for a string - * containing two consecutive slashes (e.g. /home/cvs/repo//projecta/a.txt). - * This is valid in the CVS protocol. - * </p> - */ - public void sendConstructedDirectory(String localDir) throws CVSException { - sendDirectory(localDir, getRepositoryRoot() + "/" + localDir); //$NON-NLS-1$ - } - - /** - * Sends a Directory request to the server. - * <p>e.g. sendDirectory("local_dir", "remote_dir") sends: - * <pre> - * Directory local_dir - * repository_root/remote_dir - * </pre></p> - * - * @param localDir the path of the local directory relative to localRoot - * @param remoteDir the path of the remote directory relative to repositoryRoot - */ - public void sendDirectory(String localDir, String remoteDir) throws CVSException { - if (localDir.length() == 0) localDir = "."; //$NON-NLS-1$ - connection.writeLine("Directory " + localDir); //$NON-NLS-1$ - connection.writeLine(remoteDir); - } - - /** - * Sends a Directory request for the localRoot. - */ - public void sendLocalRootDirectory() throws CVSException { - sendDirectory(".", localRoot.getRemoteLocation(localRoot)); //$NON-NLS-1$ - } - - /** - * Sends a Directory request for the localRoot with a constructed path. - * <p> - * Use this when creating a new project that does not exist in the repository. - * </p> - * @see #sendConstructedDirectory - */ - public void sendConstructedRootDirectory() throws CVSException { - sendConstructedDirectory(""); //$NON-NLS-1$ - } - - /** - * Sends an Entry request to the server. - * <p> - * Indicates that a file is managed (but it may not exist locally). Sends - * the file's entry line to the server to indicate the version that was - * previously checked out. - * </p><p> - * Note: The most recent Directory request must have specified the file's - * parent folder. - * </p> - * - * @param entryLine the formatted entry line of the managed file. - */ - public void sendEntry(byte[] syncBytes, String serverTimestamp) throws CVSException { - connection.write("Entry "); //$NON-NLS-1$ - if (serverTimestamp == null) { - serverTimestamp = ""; //$NON-NLS-1$ - } - int start = Util.getOffsetOfDelimeter(syncBytes, (byte)'/', 0, 3); - if (start == -1) { - // something is wrong with the entry line so just send it as is - // and let the server report the error. - connection.writeLine(syncBytes, 0, syncBytes.length); - return; - } - int end = Util.getOffsetOfDelimeter(syncBytes, (byte)'/', start + 1, 1); - if (end == -1) { - // something is wrong with the entry line so just send it as is - // and let the server report the error. - connection.writeLine(syncBytes, 0, syncBytes.length); - return; - } - connection.write(syncBytes, 0, start + 1); - connection.write(serverTimestamp); - connection.writeLine(syncBytes, end, syncBytes.length - end); - } - - /** - * Sends a global options to the server. - * <p>e.g. sendGlobalOption("-n") sends: - * <pre> - * Global_option -n \n - * </pre></p> - * - * @param option the global option to send - */ - public void sendGlobalOption(String option) throws CVSException { - connection.writeLine("Global_option " + option); //$NON-NLS-1$ - } - - /** - * Sends an Unchanged request to the server. - * <p>e.g. if a file called "local_file" was not modified, sends: - * <pre> - * Unchanged local_file \n - * </pre></p><p> - * Note: The most recent Directory request must have specified the file's - * parent folder. - * </p> - * - * @param file the file that was not modified - */ - public void sendUnchanged(ICVSFile file) throws CVSException { - connection.writeLine("Unchanged " + file.getName()); //$NON-NLS-1$ - } - - /** - * Sends the Notify request to the server - */ - public void sendNotify(ICVSFolder parent, NotifyInfo info) - throws CVSException { - - String filename = info.getName(); - connection.writeLine("Notify " + filename); //$NON-NLS-1$ - connection.writeLine(info.getServerLine(parent)); - } - - /** - * Sends a Questionable request to the server. - * <p> - * Indicates that a file exists locally but is unmanaged. Asks the server - * whether or not the file should be ignored in subsequent CVS operations. - * The reply to the request occurs in the form of special M-type message - * responses prefixed with '?' when the next command is executed. - * </p><p> - * Note: The most recent Directory request must have specified the file's - * parent folder. - * </p> - * - * @param resource the local file or folder - */ - public void sendQuestionable(ICVSResource resource) throws CVSException { - connection.writeLine("Questionable " + resource.getName()); //$NON-NLS-1$ - } - - /** - * Sends a Sticky tag request to the server. - * <p> - * Indicates that the directory specified in the most recent Directory request - * has a sticky tag or date, and sends the tag's contents. - * </p> - * - * @param tag the sticky tag associated with the directory - */ - public void sendSticky(String tag) throws CVSException { - connection.writeLine("Sticky " + tag); //$NON-NLS-1$ - } - - /** - * Sends a Modified request to the server along with the file contents. - * <p>e.g. if a file called "local_file" was modified, sends: - * <pre> - * Modified local_file \n - * file_permissions \n - * file_size \n - * [... file_contents ...] - * </pre></p><p> - * Under some circumstances, Is-modified may be used in place of this request.<br> - * Do not use with history, init, import, rdiff, release, rtag, or update. - * </p><p> - * Note: The most recent Directory request must have specified the file's - * parent folder. - * </p> - * - * @param file the file that was modified - * @param isBinary if true the file is sent without translating line delimiters - * @param monitor the progress monitor - * @see #sendIsModified - */ - public void sendModified(ICVSFile file, boolean isBinary, IProgressMonitor monitor) - throws CVSException { - sendModified(file, isBinary, true, monitor); - } - - public void sendModified(ICVSFile file, boolean isBinary, boolean sendBinary, IProgressMonitor monitor) - throws CVSException { - - String filename = file.getName(); - connection.writeLine("Modified " + filename); //$NON-NLS-1$ - // send the default permissions for now - connection.writeLine(ResourceSyncInfo.getDefaultPermissions()); - sendFile(file, isBinary, sendBinary, monitor); - } - - /** - * Sends a file to the remote CVS server, possibly translating line delimiters. - * <p> - * Line termination sequences are automatically converted to linefeeds only - * (required by the CVS specification) when sending non-binary files. This - * may alter the actual size and contents of the file that is sent. - * </p><p> - * Note: Non-binary files must be small enough to fit in available memory. - * </p> - * @param file the file to be sent - * @param isBinary is true if the file should be sent without translation - * @param monitor the progress monitor - */ - public void sendFile(ICVSFile file, boolean isBinary, IProgressMonitor monitor) throws CVSException { - sendFile(file, isBinary, true, monitor); - } - - public void sendFile(ICVSStorage file, boolean isBinary, boolean sendBinary, IProgressMonitor monitor) throws CVSException { - // check overrides - if (textTransferOverrideSet != null && - textTransferOverrideSet.contains(file)) isBinary = false; - - // update progress monitor - final 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$ - try { - InputStream in = null; - long length; - try { - if (isBinary && !sendBinary) { - byte[] bytes = "hello".getBytes(); //$NON-NLS-1$ - sendUncompressedBytes(new ByteArrayInputStream(bytes), bytes.length); - return; - } - - if (compressionLevel == 0) { - in = file.getContents(); - if (!isBinary && IS_CRLF_PLATFORM){ - // uncompressed text - byte[] buffer = new byte[TRANSFER_BUFFER_SIZE]; - in = new CRLFtoLFInputStream(in); - ByteCountOutputStream counter = new ByteCountOutputStream(); - try { - for (int count; (count = in.read(buffer)) != -1;) counter.write(buffer, 0, count); - } finally { - counter.close(); - } - in.close(); - length = counter.getSize(); - in = new CRLFtoLFInputStream(file.getContents()); - } else { - // uncompressed binary - length = file.getSize(); - } - in = new ProgressMonitorInputStream(in, length, TRANSFER_PROGRESS_INCREMENT, monitor) { - protected void updateMonitor(long bytesRead, long bytesTotal, IProgressMonitor monitor) { - if (bytesRead == 0) return; - Assert.isTrue(bytesRead <= bytesTotal); - monitor.subTask(Policy.bind("Session.transfer", //$NON-NLS-1$ - new Object[] { title, Long.toString(bytesRead >> 10), Long.toString(bytesTotal >> 10) })); - } - }; - sendUncompressedBytes(in, length); - } else { - monitor.subTask(Policy.bind("Session.calculatingCompressedSize", Util.toTruncatedPath(file, localRoot, 3))); //$NON-NLS-1$ - in = file.getContents(); - byte[] buffer = new byte[TRANSFER_BUFFER_SIZE]; - ByteCountOutputStream counter = new ByteCountOutputStream(); - OutputStream zout = new GZIPOutputStream(counter); - if (!isBinary && IS_CRLF_PLATFORM) in = new CRLFtoLFInputStream(in); - try { - for (int count; (count = in.read(buffer)) != -1;) zout.write(buffer, 0, count); - } finally { - zout.close(); - } - in.close(); - in = file.getContents(); - in = new ProgressMonitorInputStream(in, file.getSize(), TRANSFER_PROGRESS_INCREMENT, monitor) { - protected void updateMonitor(long bytesRead, long bytesTotal, IProgressMonitor monitor) { - if (bytesRead == 0) return; - Assert.isTrue(bytesRead <= bytesTotal); - monitor.subTask(Policy.bind("Session.transfer", //$NON-NLS-1$ - new Object[] { title, Long.toString(bytesRead >> 10), Long.toString(bytesTotal >> 10) })); - } - }; - if (!isBinary && IS_CRLF_PLATFORM) in = new CRLFtoLFInputStream(in); - sendCompressedBytes(in, counter.getSize()); - } - } finally { - if (in != null) in.close(); - } - } catch (IOException e) { - throw CVSException.wrapException(e); - } - } - - /* - * Send the contents of the input stream to CVS. - * Length must equal the number of bytes that will be transferred - * across the wire, that is, the compressed file size. - */ - private void sendCompressedBytes(InputStream in, long length) throws IOException, CVSException { - String sizeLine = "z" + Long.toString(length); //$NON-NLS-1$ - writeLine(sizeLine); - OutputStream out = connection.getOutputStream(); - GZIPOutputStream zo = new GZIPOutputStream(out); - byte[] buffer = new byte[TRANSFER_BUFFER_SIZE]; - for (int count; - (count = in.read(buffer)) != -1;) - zo.write(buffer, 0, count); - zo.finish(); - } - - /* - * Send the contents of the input stream to CVS. - * Length must equal the number of bytes that will be transferred - * across the wire. - */ - private void sendUncompressedBytes(InputStream in, long length) throws IOException, CVSException { - OutputStream out = connection.getOutputStream(); - String sizeLine = Long.toString(length); - writeLine(sizeLine); - byte[] buffer = new byte[TRANSFER_BUFFER_SIZE]; - for (int count; (count = in.read(buffer)) != -1;) out.write(buffer, 0, count); - } - - - - - /** - * Receives a file from the remote CVS server, possibly translating line delimiters. - * <p> - * Line termination sequences are automatically converted to platform format - * only when receiving non-binary files. This may alter the actual size and - * contents of the file that is received. - * </p><p> - * Translation is performed on-the-fly, so the file need not fit in available memory. - * </p> - * @param file the file to be received - * @param isBinary is true if the file should be received without translation - * @param responseType one of the ICVSFile updated types (UPDATED, CREATED, MERGED, UPDATE_EXISTING) - * indicating what repsonse type provided the file contents - * @param monitor the progress monitor - */ - public void receiveFile(ICVSStorage file, boolean isBinary, int responseType, IProgressMonitor monitor) - throws CVSException { - // check overrides - if (textTransferOverrideSet != null && - textTransferOverrideSet.contains(file)) isBinary = false; - - // update progress monitor - final 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$ - // get the file size from the server - long size; - boolean compressed = false; - try { - String sizeLine = readLine(); - if (sizeLine.charAt(0) == 'z') { - compressed = true; - sizeLine = sizeLine.substring(1); - } - size = Long.parseLong(sizeLine, 10); - } catch (NumberFormatException e) { - throw new CVSException(Policy.bind("Session.badInt"), e); //$NON-NLS-1$ - } - // create an input stream that spans the next 'size' bytes from the connection - InputStream in = new SizeConstrainedInputStream(connection.getInputStream(), size, true /*discardOnClose*/); - // setup progress monitoring - in = new ProgressMonitorInputStream(in, size, TRANSFER_PROGRESS_INCREMENT, monitor) { - protected void updateMonitor(long bytesRead, long bytesTotal, IProgressMonitor monitor) { - if (bytesRead == 0) return; - monitor.subTask(Policy.bind("Session.transfer", //$NON-NLS-1$ - new Object[] { title, Long.toString(bytesRead >> 10), Long.toString(bytesTotal >> 10) })); - } - }; - // if compression enabled, decompress on the fly - if (compressed) { - try { - in = new GZIPInputStream(in); - } catch (IOException e) { - throw CVSException.wrapException(e); - } - } - // if not binary, translate line delimiters on the fly - if (! isBinary) { - // switch from LF to CRLF if appropriate - if (IS_CRLF_PLATFORM) { - // auto-correct for CRLF line-ends that come from the server - in = new CRLFtoLFInputStream(in); - // convert LF to CRLF - in = new LFtoCRLFInputStream(in); - } else { - // be nice and warn about text files that contain CRLF - in = new CRLFDetectInputStream(in, file); - } - } - // write the file locally - file.setContents(in, responseType, true, new NullProgressMonitor()); - } - - /** - * Stores the value of the last Mod-time response encountered. - * Valid only for the duration of a single CVS command. - */ - void setModTime(Date modTime) { - this.modTime = modTime; - } - - /** - * Returns the stored value of the last Mod-time response, - * or null if there was none while processing the current command. - */ - Date getModTime() { - return modTime; - } - - /** - * Stores true if the -n global option was specified for the current command. - * Valid only for the duration of a single CVS command. - */ - void setNoLocalChanges(boolean noLocalChanges) { - this.noLocalChanges = noLocalChanges; - } - - /** - * Returns true if the -n global option was specified for the current command, - * false otherwise. - */ - boolean isNoLocalChanges() { - return noLocalChanges; - } - - /** - * Callback hook for the ValidRequestsHandler to specify the set of valid - * requests for this session. - */ - void setValidRequests(String validRequests) { - this.validRequests = " " + validRequests + " "; //$NON-NLS-1$ //$NON-NLS-2$ - } - - boolean isOutputToConsole() { - return outputToConsole; - } - - /** - * Stores a flag as to whether .# files will be created. (Default is true) - * @param createBackups if true, creates .# files at the server's request - */ - void setCreateBackups(boolean createBackups) { - this.createBackups = createBackups; - } - - /** - * Returns a flag as to whether .# files will be created. - */ - boolean isCreateBackups() { - return createBackups; - } - - /** - * Gets the sendFileTitleKey. - * @return Returns a String - */ - String getSendFileTitleKey() { - if (sendFileTitleKey == null) - return "Session.sending"; //$NON-NLS-1$ - return sendFileTitleKey; - } - - /** - * Sets the sendFileTitleKey. - * @param sendFileTitleKey The sendFileTitleKey to set - */ - 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; - } - - /** - * Filter the provided global options using parameters set on this session - * or globally. The session may add global options that correspond to user - * preferences or remove those that contradict requirements for this - * particular session. - * - * @param globalOptions the global options, read-only - * @return the filtered global options - */ - protected GlobalOption[] filterGlobalOptions(GlobalOption[] globalOptions) { - if (! Command.DO_NOT_CHANGE.isElementOf(globalOptions)) { - // Get the user preference for verbosity - QuietOption quietOption = CVSProviderPlugin.getPlugin().getQuietness(); - if (quietOption != null) { - globalOptions = quietOption.addToEnd(globalOptions); - } - // Get the user preference for read-only - if (CVSProviderPlugin.getPlugin().getPluginPreferences().getBoolean(CVSProviderPlugin.READ_ONLY)) { - if (!Command.MAKE_READ_ONLY.isElementOf(globalOptions)) { - globalOptions = Command.MAKE_READ_ONLY.addToEnd(globalOptions); - } - } - } - return globalOptions; - } - /** - * Method setIgnoringLocalChanges. - * @param b - */ - protected void setIgnoringLocalChanges(boolean b) { - ignoringLocalChanges = b; - } - /** - * Returns the ignoringLocalChanges. - * @return boolean - */ - protected boolean isIgnoringLocalChanges() { - return ignoringLocalChanges; - } - - /** - * Method getUniquePathForInvalidPath. - * @param localDir - * @return String - */ - public String getUniquePathForInvalidPath(String localDir) { - IPath oldPath = new Path(localDir); - int count = oldPath.segmentCount(); - for (int i = 0; i < count; i++) { - String segment = oldPath.segment(i); - if (segment.endsWith(".")) { //$NON-NLS-1$ - segment = segment + Policy.bind("Session.dot_2"); //$NON-NLS-1$ - oldPath = oldPath.removeLastSegments(count - i).append(segment).append(oldPath.removeFirstSegments(i + 1)); - } - } - return oldPath.toString(); - } - - /* - * Get the response handler map to be used for this session. The map is created by making a copy of the global - * reponse handler map. - */ - protected Map getReponseHandlers() { - if (responseHandlers == null) { - responseHandlers = Request.getReponseHandlerMap(); - } - return responseHandlers; - } - - /* - * Makes a list of all valid responses; for initializing a session. - * @return a space-delimited list of all valid response strings - */ - private String makeResponseList() { - StringBuffer result = new StringBuffer("ok error M E"); //$NON-NLS-1$ - Iterator elements = getReponseHandlers().keySet().iterator(); - while (elements.hasNext()) { - result.append(' '); - result.append((String) elements.next()); - } - - return result.toString(); - } - public void registerResponseHandler(ResponseHandler handler) { - getReponseHandlers().put(handler.getResponseID(), handler); - } - - public void removeResponseHandler(String responseID) { - getReponseHandlers().remove(responseID); - } - - public ResponseHandler getResponseHandler(String responseID) { - return (ResponseHandler)getReponseHandlers().get(responseID); - } - -} |