| /******************************************************************************* |
| * Copyright (c) 2000, 2007 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Matt McCutchen <hashproduct+eclipse@gmail.com> - Bug 179174 CVS client sets timestamps back when replacing |
| *******************************************************************************/ |
| package org.eclipse.team.internal.ccvs.core.client; |
| |
| import java.util.*; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.team.internal.ccvs.core.*; |
| import org.eclipse.team.internal.ccvs.core.client.listeners.ICommandOutputListener; |
| |
| /** |
| * Abstract base class for command requests. |
| * Provides a framework for implementing command execution. |
| */ |
| public abstract class Command extends Request { |
| /*** Command singleton instances ***/ |
| public final static Add ADD = new Add(); |
| public final static Admin ADMIN = new Admin(); |
| public final static Annotate ANNOTATE = new Annotate(); |
| public final static Checkout CHECKOUT = new CheckoutWithOverwrite(); |
| public final static Commit COMMIT = new Commit(); |
| public final static Diff DIFF = new Diff(); |
| public final static RDiff RDIFF = new RDiff(); |
| public final static Editors EDITORS = new Editors(); |
| public final static Import IMPORT = new Import(); |
| public final static Log LOG = new Log(); |
| public final static Remove REMOVE = new Remove(); |
| public final static Status STATUS = new Status(); |
| public final static Tag TAG = new Tag(); |
| // The CUSTOM_TAG command has special handling for added and removed resources. |
| // This behavior supports branching with local changes in the workspace |
| public final static Tag CUSTOM_TAG = new Tag(true); |
| public final static RTag RTAG = new RTag(); |
| public final static Update UPDATE = new Update(); |
| public final static Update REPLACE = new Replace(); |
| public final static SyncUpdate SYNCUPDATE = new SyncUpdate(); |
| public final static Version VERSION = new Version(); |
| public final static NOOPCommand NOOP = new NOOPCommand(); |
| |
| // Empty argument array |
| public final static String[] NO_ARGUMENTS = new String[0]; |
| |
| /*** Global options ***/ |
| // Empty global option array |
| public static final GlobalOption[] NO_GLOBAL_OPTIONS = new GlobalOption[0]; |
| // Do not change file contents |
| public static final GlobalOption DO_NOT_CHANGE = new GlobalOption("-n"); //$NON-NLS-1$ |
| // Do not record this operation into CVS command history |
| public static final GlobalOption DO_NOT_LOG = new GlobalOption("-l"); //$NON-NLS-1$ |
| // Make new working files read-only |
| public static final GlobalOption MAKE_READ_ONLY = new GlobalOption("-r"); //$NON-NLS-1$ |
| // Trace command execution |
| public static final GlobalOption TRACE_EXECUTION = new GlobalOption("-t"); //$NON-NLS-1$ |
| |
| /*** Global options: quietness ***/ |
| // Don't be quiet (normal verbosity) |
| public static final QuietOption VERBOSE = new QuietOption(""); //$NON-NLS-1$ |
| // Be somewhat quiet (suppress informational messages) |
| public static final QuietOption PARTLY_QUIET = new QuietOption("-q"); //$NON-NLS-1$ |
| // Be really quiet (silent but for serious problems) |
| public static final QuietOption SILENT = new QuietOption("-Q"); //$NON-NLS-1$ |
| |
| /*** Local options: common to many commands ***/ |
| // Empty local option array |
| 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 RECURSE = new LocalOption("-R"); //$NON-NLS-1$ |
| public static final LocalOption DO_NOT_RECURSE = new LocalOption("-l"); //$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$ |
| |
| /*** Default command output listener ***/ |
| protected static final ICommandOutputListener DEFAULT_OUTPUT_LISTENER = new CommandOutputListener(); |
| |
| /** |
| * Prevents client code from instantiating us. |
| */ |
| protected Command() { } |
| |
| /** |
| * Provides the default command output listener which is used to accumulate errors. |
| * |
| * Subclasses can override this method in order to properly interpret information |
| * received from the server. |
| */ |
| protected ICommandOutputListener getDefaultCommandOutputListener() { |
| return DEFAULT_OUTPUT_LISTENER; |
| } |
| |
| /** |
| * Sends the command's arguments to the server. |
| * [template method] |
| * <p> |
| * The default implementation sends all arguments. Subclasses may override |
| * this method to provide alternate behaviour. |
| * </p> |
| * |
| * @param session the CVS session |
| * @param arguments the arguments that were supplied by the caller of execute() |
| */ |
| protected void sendArguments(Session session, String[] arguments) throws CVSException { |
| for (int i = 0; i < arguments.length; ++i) { |
| session.sendArgument(arguments[i]); |
| } |
| } |
| |
| /** |
| * Describes the local resource state to the server prior to command execution. |
| * [template method] |
| * <p> |
| * Commands must override this method to inform the server about the state of |
| * local resources using the Entries, Modified, Unchanged, and Questionable |
| * requests as needed. |
| * </p> |
| * <p> |
| * This method should return the resources that are of interest to the |
| * <code>Command#commandFinished()</code> method. In most cases, it |
| * is the same resources that are provided but in some cases (e.g. Commit) |
| * the resources to be passed to the above method are different. |
| * </p> |
| * |
| * @param session the CVS session |
| * @param globalOptions the global options for the command |
| * @param localOptions the local options for the command |
| * @param resources the resource arguments for the command |
| * @param monitor the progress monitor |
| * @return ICVSResource[] |
| */ |
| protected abstract ICVSResource[] sendLocalResourceState(Session session, GlobalOption[] globalOptions, |
| LocalOption[] localOptions, ICVSResource[] resources, IProgressMonitor monitor) |
| throws CVSException; |
| |
| /** |
| * Cleans up after command execution. |
| * [template method] |
| * <p> |
| * The default implementation is a no-op. Subclasses may override this |
| * method to follow up command execution on the server with clean up |
| * operations on local resources. |
| * </p> |
| * |
| * @param session the CVS session |
| * @param globalOptions the global options for the command |
| * @param localOptions the local options for the command |
| * @param resources the resource arguments for the command |
| * @param monitor the progress monitor |
| * @param status the status accumulated so far. If the code == CVSStatus.SERVER_ERROR |
| * then the command failed |
| * @return status the status past in plus any additional status accumulated during the finish |
| */ |
| protected IStatus commandFinished(Session session, GlobalOption[] globalOptions, |
| LocalOption[] localOptions, ICVSResource[] resources, IProgressMonitor monitor, |
| IStatus status) throws CVSException { |
| return status; |
| } |
| |
| /** |
| * Sends the local working directory path prior to command execution. |
| * [template method] |
| * <p> |
| * The default implementation sends the paths of local root directory |
| * (assuming it exists). Subclasses may override this method to provide |
| * alternate behaviour. |
| * </p> |
| * |
| * @param session the CVS session |
| */ |
| protected void sendLocalWorkingDirectory(Session session) throws CVSException { |
| ICVSFolder localRoot = session.getLocalRoot(); |
| if (localRoot.isCVSFolder()) { |
| session.sendLocalRootDirectory(); |
| } else { |
| session.sendConstructedRootDirectory(); |
| } |
| } |
| |
| /** |
| * Computes an array of ICVSResources corresponding to command arguments. |
| * [template method] |
| * <p> |
| * The default implementation assumes that all arguments supplied to the |
| * command represent resources in the local root that are to be manipulated. |
| * Subclasses must override this method if this assumption does not hold. |
| * </p> |
| * @param session the CVS session |
| * @param localOptions the command local options |
| * @param arguments the command arguments |
| * @return the resource arguments for the command |
| */ |
| protected ICVSResource[] computeWorkResources(Session session, |
| LocalOption[] localOptions, String[] arguments) throws CVSException { |
| ICVSFolder localRoot = session.getLocalRoot(); |
| |
| if (arguments.length == 0) { |
| // As a convenience, passing no arguments to the CVS command |
| // implies the command will operate on the local root folder. |
| return new ICVSResource[] { localRoot }; |
| } else { |
| // Assume all arguments represent resources that are descendants |
| // of the local root folder. |
| ICVSResource[] resources = new ICVSResource[arguments.length]; |
| for (int i = 0; i < arguments.length; i++) { |
| ICVSResource resource = localRoot.getChild(arguments[i]); |
| // file does not exist, it could have been deleted. It doesn't matter |
| // which type we return since only the name of the resource is used |
| // and sent to the server. |
| if(resource==null) { |
| if(localRoot.getName().length()==0) { |
| // Return a folder because it is the safest choice when |
| // localRoot is a handle to the IWorkspaceRoot! |
| resource = localRoot.getFolder(arguments[i]); |
| } else { |
| resource = localRoot.getFile(arguments[i]); |
| } |
| } |
| resources[i] = resource; |
| } |
| return resources; |
| } |
| } |
| |
| /** |
| * Send an array of Resources. |
| * @param localOptions |
| * |
| * @see Command#sendFileStructure(ICVSResource,IProgressMonitor,boolean,boolean,boolean) |
| */ |
| protected void sendFileStructure(Session session, ICVSResource[] resources, |
| LocalOption[] localOptions, boolean emptyFolders, IProgressMonitor monitor) throws CVSException { |
| checkResourcesManaged(session, resources); |
| |
| new FileStructureVisitor(session, localOptions, emptyFolders, true).visit(session, resources, monitor); |
| } |
| |
| /** |
| * Checks that all work resources are managed. |
| * @param session TODO |
| * @param resources the resource arguments for the command |
| * |
| * @throws CVSException if some resources are not managed |
| */ |
| protected void checkResourcesManaged(Session session, ICVSResource[] resources) throws CVSException { |
| for (int i = 0; i < resources.length; ++i) { |
| ICVSFolder folder; |
| if (resources[i].isFolder()) { |
| folder = (ICVSFolder) resources[i]; |
| } |
| else { |
| folder = resources[i].getParent(); |
| } |
| if (!folder.isCVSFolder() && folder.exists()) { |
| IStatus status = new CVSStatus(IStatus.ERROR,CVSStatus.ERROR,NLS.bind(CVSMessages.Command_argumentNotManaged, new String[] { folder.getName() }),session.getLocalRoot()); |
| throw new CVSException(status); |
| } |
| } |
| } |
| |
| /** |
| * Executes a CVS command. |
| * <p> |
| * Dispatches the commands, retrieves the results, and determines whether or |
| * not an error occurred. A listener may be supplied to capture message text |
| * that would normally be written to the standard error and standard output |
| * streams of a command line CVS client. |
| * </p> |
| * @param session the open CVS session |
| * @param globalOptions the array of global options, or NO_GLOBAL_OPTIONS |
| * @param localOptions the array of local options, or NO_LOCAL_OPTIONS |
| * @param arguments the array of arguments (usually filenames relative to localRoot), or NO_ARGUMENTS |
| * @param listener the command output listener, or null to discard all messages |
| * @param monitor the progress monitor |
| * @return a status code indicating success or failure of the operation |
| * @throws CVSException if a fatal error occurs (e.g. connection timeout) |
| */ |
| public final IStatus execute(final Session session, final GlobalOption[] globalOptions, |
| final LocalOption[] localOptions, final String[] arguments, final ICommandOutputListener listener, |
| IProgressMonitor pm) throws CVSException { |
| final IStatus[] status = new IStatus[1]; |
| ICVSRunnable job = monitor -> { |
| // update the global and local options |
| GlobalOption[] gOptions = filterGlobalOptions(session, globalOptions); |
| LocalOption[] lOptions = filterLocalOptions(session, gOptions, localOptions); |
| |
| // print the invocation string to the console |
| if (session.isOutputToConsole() || Policy.isDebugProtocol()) { |
| IPath commandRootPath; |
| IResource resource = session.getLocalRoot().getIResource(); |
| if (resource == null) { |
| commandRootPath = Path.EMPTY; |
| } else { |
| commandRootPath = resource.getFullPath(); |
| } |
| String line = constructCommandInvocationString(commandRootPath, gOptions, lOptions, arguments); |
| ConsoleListeners.getInstance().commandInvoked(session, line); |
| if (Policy.isDebugProtocol()) Policy.printProtocolLine("CMD> " + line); //$NON-NLS-1$ |
| } |
| |
| // run the command |
| try { |
| session.setCurrentCommand(Command.this); |
| status[0] = doExecute(session, gOptions, lOptions, arguments, listener, monitor); |
| notifyConsoleOnCompletion(session, status[0], null); |
| } catch (CVSException e1) { |
| notifyConsoleOnCompletion(session, null, e1); |
| throw e1; |
| } catch (RuntimeException e2) { |
| notifyConsoleOnCompletion(session, null, e2); |
| throw e2; |
| } |
| }; |
| if (isWorkspaceModification()) { |
| session.getLocalRoot().run(job, pm); |
| } else { |
| job.run(pm); |
| } |
| return status[0]; |
| } |
| |
| /** |
| * Return whether this command modifies the workspace. |
| * If <code>true</code> is returned, a scheduling rule on |
| * the session local root is obtained. Otherwise, no |
| * scheduling rule is obtained. By default, <code>true</code> |
| * is returned |
| * @return whether this command modifies the workspace |
| */ |
| protected boolean isWorkspaceModification() { |
| return true; |
| } |
| |
| private void notifyConsoleOnCompletion(Session session, IStatus status, Exception exception) { |
| ConsoleListeners.getInstance().commandCompleted(session, status, exception); |
| if (Policy.isDebugProtocol()) { |
| if (status != null) Policy.printProtocolLine("RESULT> " + status.toString()); //$NON-NLS-1$ |
| else Policy.printProtocolLine("RESULT> " + exception.toString()); //$NON-NLS-1$ |
| } |
| } |
| |
| protected IStatus doExecute(Session session, GlobalOption[] globalOptions, |
| LocalOption[] localOptions, String[] arguments, ICommandOutputListener listener, |
| IProgressMonitor monitor) throws CVSException { |
| ICVSResource[] resources = null; |
| /*** setup progress monitor ***/ |
| monitor = Policy.monitorFor(monitor); |
| monitor.beginTask(null, 100); |
| Policy.checkCanceled(monitor); |
| try { |
| /*** prepare for command ***/ |
| // clear stale command state from previous runs |
| session.setNoLocalChanges(DO_NOT_CHANGE.isElementOf(globalOptions)); |
| session.setModTime(null); |
| |
| /*** initiate command ***/ |
| // send global options |
| for (int i = 0; i < globalOptions.length; i++) { |
| globalOptions[i].send(session); |
| } |
| Policy.checkCanceled(monitor); |
| // send local options |
| for (int i = 0; i < localOptions.length; i++) { |
| localOptions[i].send(session); |
| } |
| Policy.checkCanceled(monitor); |
| // compute the work resources |
| resources = computeWorkResources(session, localOptions, arguments); |
| Policy.checkCanceled(monitor); |
| // send local working directory state contributes 48% of work |
| resources = sendLocalResourceState(session, globalOptions, localOptions, |
| resources, Policy.infiniteSubMonitorFor(monitor, 48)); |
| Policy.checkCanceled(monitor); |
| // escape file names, see bug 149683 |
| for(int i = 0; i < arguments.length; i++){ |
| if(arguments[i].startsWith("-")){ //$NON-NLS-1$ |
| arguments[i] = "./" + arguments[i]; //$NON-NLS-1$ |
| } |
| } |
| // send arguments |
| sendArguments(session, arguments); |
| // send local working directory path |
| sendLocalWorkingDirectory(session); |
| |
| // if no listener was provided, use the command's default in order to get error reporting |
| if (listener == null) listener = getDefaultCommandOutputListener(); |
| |
| /*** execute command and process responses ***/ |
| // Processing responses contributes 50% of work. |
| IStatus status = executeRequest(session, listener, Policy.subMonitorFor(monitor, 50)); |
| |
| // Finished adds last 2% of work. |
| status = commandFinished(session, globalOptions, localOptions, resources, Policy.subMonitorFor(monitor, 2), |
| status); |
| return status; |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Constucts the CVS command invocation string corresponding to the arguments. |
| * |
| * @param globalOptions the global options |
| * @param localOption the local options |
| * @param arguments the arguments |
| * @return the command invocation string |
| */ |
| private String constructCommandInvocationString(IPath commandRootPath, GlobalOption[] globalOptions, |
| LocalOption[] localOptions, String[] arguments) { |
| StringBuffer commandLine = new StringBuffer("cvs"); //$NON-NLS-1$ |
| for (int i = 0; i < globalOptions.length; ++i) { |
| String option = globalOptions[i].toString(); |
| if (option.length() == 0) continue; |
| commandLine.append(' '); |
| commandLine.append(option); |
| } |
| commandLine.append(' '); |
| commandLine.append(getRequestId()); |
| for (int i = 0; i < localOptions.length; ++i) { |
| String option = localOptions[i].toString(); |
| if (option.length() == 0) continue; |
| commandLine.append(' '); |
| commandLine.append(option); |
| } |
| for (int i = 0; i < arguments.length; ++i) { |
| if (arguments[i].length() == 0) continue; |
| commandLine.append(" \""); //$NON-NLS-1$ |
| IPath completePath = commandRootPath; |
| if (!arguments[i].equals(Session.CURRENT_LOCAL_FOLDER)) { |
| completePath = completePath.append(arguments[i]); |
| } |
| commandLine.append(completePath.toString()); |
| commandLine.append('"'); |
| } |
| return commandLine.toString(); |
| } |
| |
| /** |
| * Superclass for all CVS command options |
| */ |
| protected static abstract class Option { |
| protected String option, argument; |
| protected Option(String option, String argument) { |
| this.option = option; |
| this.argument = argument; |
| } |
| /** |
| * Determines if this option is an element of an array of options |
| * @param array the array of options |
| * @return true iff the array contains this option |
| */ |
| public boolean isElementOf(Option[] array) { |
| return findOption(array, option) != null; |
| } |
| /** |
| * Returns the option part of the option |
| */ |
| 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 + '"'; //$NON-NLS-1$ |
| } else { |
| return option; |
| } |
| } |
| } |
| /** |
| * Option subtype for global options that are common to all commands. |
| */ |
| public static class GlobalOption extends Option { |
| protected GlobalOption(String option) { |
| super(option, null); |
| } |
| public void send(Session session) throws CVSException { |
| session.sendGlobalOption(option); |
| } |
| /** |
| * Add the given global option to the end of the provided list |
| * |
| * @param newOption |
| * @param options |
| * @return GlobalOption[] |
| */ |
| protected GlobalOption[] addToEnd(GlobalOption[] options) { |
| GlobalOption[] globalOptions = new GlobalOption[options.length + 1]; |
| System.arraycopy(options, 0, globalOptions, 0, options.length); |
| globalOptions[globalOptions.length - 1] = this; |
| return globalOptions; |
| } |
| } |
| /** |
| * Option subtype for global quietness options. |
| */ |
| public static final class QuietOption extends GlobalOption { |
| private QuietOption(String option) { |
| super(option); |
| } |
| public void send(Session session) throws CVSException { |
| if (option.length() != 0) super.send(session); |
| } |
| } |
| /** |
| * Option subtype for local options that vary from command to command. |
| */ |
| public static class LocalOption extends Option { |
| protected LocalOption(String option) { |
| super(option, null); |
| } |
| protected LocalOption(String option, String argument) { |
| super(option, argument); |
| } |
| public void send(Session session) throws CVSException { |
| session.sendArgument(option); |
| if (argument != null) session.sendArgument(argument); |
| } |
| public LocalOption[] addTo(LocalOption[] options) { |
| if (this.isElementOf(options)) { |
| return options; |
| } |
| LocalOption[] newOptions = new LocalOption[options.length + 1]; |
| System.arraycopy(options, 0, newOptions, 0, options.length); |
| newOptions[options.length] = this; |
| return newOptions; |
| } |
| public LocalOption[] removeFrom(LocalOption[] options) { |
| if (!this.isElementOf(options)) { |
| return options; |
| } |
| List result = new ArrayList(); |
| for (int i = 0; i < options.length; i++) { |
| Command.LocalOption option = options[i]; |
| if (!option.equals(this)) { |
| result.add(option); |
| } |
| } |
| return (LocalOption[]) result.toArray(new LocalOption[result.size()]); |
| } |
| } |
| /** |
| * Options subtype for keyword substitution options. |
| */ |
| public static class KSubstOption extends LocalOption { |
| private boolean isUnknownMode; |
| private KSubstOption(String option) { |
| this(option, false); |
| } |
| private KSubstOption(String option, boolean isUnknownMode) { |
| super(option); |
| this.isUnknownMode = isUnknownMode; |
| 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 //$NON-NLS-1$ |
| KSubstOption option = (KSubstOption) ksubstOptionMap.get(mode); |
| if (option == null) option = new KSubstOption(mode, true); |
| return option; |
| } |
| /** |
| * Gets the KSubstOption instance for the specified file. |
| * |
| * @param file the file to get the option for |
| * @return an instance for that mode |
| */ |
| public static KSubstOption fromFile(IFile file) { |
| if (CVSProviderPlugin.isText(file)) |
| return getDefaultTextMode(); |
| 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. Note that it might return blank strings |
| * for certain options. For UI, use {@link #toMode()} which will always return the a string |
| * containing the keyword substitution. |
| */ |
| public String toEntryLineMode() { |
| if (KSUBST_TEXT_EXPAND.equals(this)) return ""; //$NON-NLS-1$ |
| return getOption(); |
| } |
| |
| /** |
| * Returns the entry line mode string for this instance. |
| */ |
| public String toMode(){ |
| 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() { |
| if (isUnknownMode) |
| return NLS.bind(CVSMessages.KSubstOption_unknown_short, new String[] { option }); |
| if (option.equals("-kb")) //$NON-NLS-1$ |
| return CVSMessages.KSubstOption__kb_short; |
| if (option.equals("-kkv")) //$NON-NLS-1$ |
| return CVSMessages.KSubstOption__kkv_short; |
| if (option.equals("-ko")) //$NON-NLS-1$ |
| return CVSMessages.KSubstOption__ko_short; |
| if (option.equals("-kk")) //$NON-NLS-1$ |
| return CVSMessages.KSubstOption__kk_short; |
| if (option.equals("-kv")) //$NON-NLS-1$ |
| return CVSMessages.KSubstOption__kv_short; |
| if (option.equals("-kkvl")) //$NON-NLS-1$ |
| return CVSMessages.KSubstOption__kkvl_short; |
| return NLS.bind(CVSMessages.KSubstOption_unknown_short, new String[] { option }); |
| } |
| /** |
| * Returns a long localized text string describing this mode. |
| */ |
| public String getLongDisplayText() { |
| if (isUnknownMode) |
| return NLS.bind(CVSMessages.KSubstOption_unknown_long, new String[] { option }); |
| if (option.equals("-kb")) //$NON-NLS-1$ |
| return CVSMessages.KSubstOption__kb_long; |
| if (option.equals("-kkv")) //$NON-NLS-1$ |
| return CVSMessages.KSubstOption__kkv_long; |
| if (option.equals("-ko")) //$NON-NLS-1$ |
| return CVSMessages.KSubstOption__ko_long; |
| if (option.equals("-kk")) //$NON-NLS-1$ |
| return CVSMessages.KSubstOption__kk_long; |
| if (option.equals("-kv")) //$NON-NLS-1$ |
| return CVSMessages.KSubstOption__kv_long; |
| if (option.equals("-kkvl")) //$NON-NLS-1$ |
| return CVSMessages.KSubstOption__kkvl_long; |
| return NLS.bind(CVSMessages.KSubstOption_unknown_long, new String[] { option }); |
| } |
| /** |
| * Return the text mode that will be used by default |
| */ |
| public static KSubstOption getDefaultTextMode() { |
| return CVSProviderPlugin.getPlugin().getDefaultTextKSubstOption(); |
| } |
| } |
| |
| /** |
| * Makes a -m log message option. |
| * Valid for: add commit import |
| */ |
| public static LocalOption makeArgumentOption(LocalOption option, String argument) { |
| if(argument == null) { |
| argument = ""; //$NON-NLS-1$ |
| } |
| return new LocalOption(option.getOption(), argument); |
| } |
| |
| /** |
| * Makes a -r or -D option for a tag. |
| * Valid for: checkout export history rdiff update |
| */ |
| public static LocalOption makeTagOption(CVSTag tag) { |
| int type = tag.getType(); |
| switch (type) { |
| case CVSTag.BRANCH: |
| case CVSTag.VERSION: |
| return new LocalOption("-r", tag.getName()); //$NON-NLS-1$ |
| case CVSTag.DATE: |
| return new LocalOption("-D", tag.getName()); //$NON-NLS-1$ |
| default: |
| // tag must not be HEAD |
| throw new IllegalArgumentException(CVSMessages.Command_invalidTag); |
| } |
| } |
| |
| /** |
| * Find a specific option in an array of options |
| * @param array the array of options |
| * @param option the option string to search for |
| * @return the first element matching the option string, or null if none |
| */ |
| public static Option findOption(Option[] array, String option) { |
| for (int i = 0; i < array.length; ++i) { |
| if (array[i].getOption().equals(option)) return array[i]; |
| } |
| return null; |
| } |
| |
| /** |
| * Collect all arguments of a specific option from an array of options |
| * @param array the array of options |
| * @param option the option string to search for |
| * @return an array of all arguments of belonging to matching options |
| */ |
| protected static String[] collectOptionArguments(Option[] array, String option) { |
| List /* of String */ list = new ArrayList(); |
| for (int i = 0; i < array.length; ++i) { |
| if (array[i].getOption().equals(option)) { |
| list.add(array[i].argument); |
| } |
| } |
| return (String[]) list.toArray(new String[list.size()]); |
| } |
| |
| /** |
| * Allows commands to filter the set of global options to be sent. |
| * This method invokes the method of the same name on the session |
| * itself in order to get any session wide or globally set options. |
| * Subclasses that override this method should call the superclass. |
| * |
| * @param session the session |
| * @param globalOptions the global options, read-only |
| * @return the filtered global options |
| */ |
| protected GlobalOption[] filterGlobalOptions(Session session, GlobalOption[] globalOptions) { |
| return session.filterGlobalOptions(globalOptions); |
| } |
| |
| /** |
| * Allows commands to filter the set of local options to be sent. |
| * Subclasses that override this method should call the superclass. |
| * |
| * @param session the session |
| * @param globalOptions the global options, read-only |
| * @param localOptions the local options, read-only |
| * @return the filtered local options |
| */ |
| protected LocalOption[] filterLocalOptions(Session session, GlobalOption[] globalOptions, LocalOption[] localOptions) { |
| return localOptions; |
| } |
| |
| /** |
| * Execute a CVS command on an array of ICVSResource. This method simply converts |
| * the ICVSResource to String paths relative to the local root of the session and |
| * invokes <code>execute(Session, GlobalOption[], LocalOption[], String[], ICommandOutputListener, IProgressMonitor)</code>. |
| * </p> |
| * @param session the open CVS session |
| * @param globalOptions the array of global options, or NO_GLOBAL_OPTIONS |
| * @param localOptions the array of local options, or NO_LOCAL_OPTIONS |
| * @param arguments the array of ICVSResource to be operated on |
| * @param listener the command output listener, or null to discard all messages |
| * @param monitor the progress monitor |
| * @return a status code indicating success or failure of the operation |
| * @throws CVSException if a fatal error occurs (e.g. connection timeout) |
| * |
| * @see Command#execute(Session, GlobalOption[], LocalOption[], String[], ICommandOutputListener, IProgressMonitor) |
| */ |
| public final IStatus execute(Session session, GlobalOption[] globalOptions, LocalOption[] localOptions, ICVSResource[] arguments, |
| ICommandOutputListener listener, IProgressMonitor pm) throws CVSException { |
| |
| String[] stringArguments = convertArgumentsForOpenSession(arguments, session); |
| return execute(session, globalOptions, localOptions, stringArguments, listener, pm); |
| } |
| |
| protected String[] convertArgumentsForOpenSession(ICVSResource[] arguments, Session openSession) throws CVSException { |
| // Convert arguments |
| List stringArguments = new ArrayList(arguments.length); |
| for (int i = 0; i < arguments.length; i++) { |
| stringArguments.add(arguments[i].getRelativePath(openSession.getLocalRoot())); |
| } |
| return (String[]) stringArguments.toArray(new String[stringArguments.size()]); |
| } |
| |
| /** |
| * Method mergeStatus. |
| * @param status |
| * @param cVSStatus |
| * @return IStatus |
| */ |
| protected IStatus mergeStatus(IStatus accumulatedStatus, IStatus newStatus) { |
| if (accumulatedStatus.isMultiStatus()) { |
| ((MultiStatus)accumulatedStatus).merge(newStatus); |
| return accumulatedStatus; |
| } |
| if (accumulatedStatus.isOK()) return newStatus; |
| if (newStatus.isOK()) return accumulatedStatus; |
| MultiStatus result = new MultiStatus(CVSProviderPlugin.ID, IStatus.INFO, |
| new IStatus[] {accumulatedStatus, newStatus}, |
| NLS.bind(CVSMessages.Command_warnings, new String[] { getDisplayText() }), null); |
| return result; |
| } |
| } |