package org.tmatesoft.svn.core.wc2;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.util.SVNLogType;
/**
* Represents switch operation.
* Switches working tree of <code>target</code> to <code>switchTarget</code>\
* <code>switchTarget</code>'s <code>pegRevision</code> at <code>revision</code>.
*
* <p/>
* Summary of purpose: this is normally used to switch a working directory
* over to another line of development, such as a branch or a tag. Switching
* an existing working directory is more efficient than checking out
* <code>switchTarget</code> from scratch.
*
* <p/>
* If <code>depth</code> is {@link SVNDepth#INFINITY}, switches fully
* recursively. Else if it is {@link SVNDepth#IMMEDIATES}, switches
* <code>target</code> and its file children (if any), and switches
* subdirectories but does not update them. Else if {@link SVNDepth#FILES},
* switches just file children, ignoring subdirectories completely. Else if
* {@link SVNDepth#EMPTY}, switches just <code>target</code> and touches
* nothing underneath it.
*
* <p/>
* If externals are ignored (<code>ignoreExternals</code> is <code>true</code>), doesn't process
* externals definitions as part of this operation.
*
* <p/>
* If <code>allowUnversionedObstructions</code> is <code>true</code> then the switch tolerates existing
* unversioned items that obstruct added paths. Only obstructions of the
* same type (file or directory) as the added item are tolerated. The text of
* obstructing files is left as-is, effectively treating it as a user
* modification after the switch. Working properties of obstructing items
* are set equal to the base properties. If
* <code>allowUnversionedObstructions</code> is <code>false</code> then the switch will abort if there are
* any unversioned obstructing items.
*
* <p/>
* If the caller's {@link ISVNEventHandler} is non-<code>null</code>, it is invoked for paths affected by the
* switch, and also for files restored from text-base. Also
* {@link ISVNEventHandler#checkCancelled()} will be used at various places
* during the switch to check whether the caller wants to stop the switch.
*
* <p/>
* This operation requires repository access (in case the repository is not
* on the same machine, network connection is established).
*
* <p/>
* {@link #run()} method returns value of the revision value to which the working copy was actually
* switched.
*
* <p/>
* {@link #run()} method returns value of the revision to which the working copy was actually switched.
* <ul>
* <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE}
* error code - if <code>target</code> is not in the repository yet
* <li/>exception with {@link SVNErrorCode#ENTRY_MISSING_URL} error code
* - if <code>switchTarget</code> directory has no URL
* <li/>exception with {@link SVNErrorCode#WC_INVALID_SWITCH} error code
* - if <code>switchTarget</code> is not the same repository as <code>target</code>'s repository
* <li/>exception with {@link SVNErrorCode#CLIENT_UNRELATED_RESOURCES} error code
* - if <code>ignoreAncestry</code> is <code>false</code> and
* <code>switchTarget</code> shares no common ancestry with <code>target</code>
* </ul>
*
* @author TMate Software Ltd.
* @version 1.7
*/
public class SvnSwitch extends AbstractSvnUpdate<Long> {
private boolean depthIsSticky;
private boolean ignoreAncestry;
private SvnTarget switchTarget;
protected SvnSwitch(SvnOperationFactory factory) {
super(factory);
}
/**
* Returns whether depth is sticky.
* If <code>depthIsSticky</code> is set the operation will use <code>depth</code> as status scope, otherwise
* {@link SVNDepth#UNKNOWN} will be used.
*
* @return <code>true</code> if the depth is sticky, otherwise <code>false</code>
*/
public boolean isDepthIsSticky() {
return depthIsSticky;
}
/**
* Returns whether to ignore ancestry when calculating merges.
*
* @return <code>true</code> if ancestry should be ignored, otherwise <code>false</code>
* @since 1.7, Subversion 1.7
*/
public boolean isIgnoreAncestry() {
return ignoreAncestry;
}
/**
* Returns the repository location as a target against which the item will be switched.
*
* @return switch target
*/
public SvnTarget getSwitchTarget() {
return switchTarget;
}
/**
* Sets whether depth is sticky.
* If <code>depthIsSticky</code> is set the operation will use <code>depth</code> as status scope, otherwise
* {@link SVNDepth#UNKNOWN} will be used.
*
* @param depthIsSticky <code>true</code> if the depth is sticky, otherwise <code>false</code>
*/
public void setDepthIsSticky(boolean depthIsSticky) {
this.depthIsSticky = depthIsSticky;
}
/**
* Sets whether to ignore ancestry when calculating merges.
*
* @param ignoreAncestry <code>true</code> if ancestry should be ignored, otherwise <code>false</code>
* @since 1.7, Subversion 1.7
*/
public void setIgnoreAncestry(boolean ignoreAncestry) {
this.ignoreAncestry = ignoreAncestry;
}
/**
* Sets the repository location as a target against which the item will be switched.
*
* @param switchTarget switch target
*/
public void setSwitchTarget(SvnTarget switchTarget) {
this.switchTarget = switchTarget;
}
@Override
protected void ensureArgumentsAreValid() throws SVNException {
super.ensureArgumentsAreValid();
if (getDepth() == SVNDepth.EXCLUDE) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNSUPPORTED_FEATURE, "Cannot both exclude and switch a path");
SVNErrorManager.error(err, SVNLogType.WC);
}
}
/**
* Gets whether the operation changes working copy
* @return <code>true</code> if the operation changes the working copy, otherwise <code>false</code>
*/
@Override
public boolean isChangesWorkingCopy() {
return true;
}
}