package org.tmatesoft.svn.core.wc2; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNException; /** * Represents copy operation. * Copies each source in <code>sources</code> to operation's <code>target</code> * representing working copy path, * or converts a disjoint working copy to a copied one, * or does virtual copy (see below). * * <ul> * <li> * <b> If <code>disjoint</code> and <code>virtual</code> are <code>false</code>:</b> * * <p/> * If multiple <code>sources</code> are given, <code>target</code> must be a * directory, and <code>sources</code> will be copied as children of * directory. * * <p/> * Each <code>src</code> in <code>sources</code> must be files or * directories under version control, or URLs of a versioned item in the * repository. If <code>sources</code> has multiple items, they must be all * repository URLs or all working copy paths. * * <p/> * The parent of <code>target</code> must already exist. * * <p/> * If <code>sources</code> has only one item, attempts to copy it to * <code>target</code>. If <code>failWhenDstExists</code> is <code>false</code> * and <code>target</code> already exists, * attempts to copy the item as a child of <code>target</code>. If * <code>failWhenDstExists</code> is <code>true</code> * and <code>target</code> already exists, throws an {@link SVNException} with * the {@link SVNErrorCode#FS_ALREADY_EXISTS} error code. * * <p/> * If <code>sources</code> has multiple items, and * <code>failWhenDstExists</code> is <code>false</code>, * all <code>sources</code> are copied as children of <code>target</code>. If * any child of <code>target</code> already exists with the same name any item * in <code>sources</code>, throws an {@link SVNException} with the * {@link SVNErrorCode#FS_ALREADY_EXISTS} error code. * * <p/> * If <code>sources</code> has multiple items, and * <code>failWhenDstExists</code> is <code>true</code>, * throws an {@link SVNException} with the * {@link SVNErrorCode#CLIENT_MULTIPLE_SOURCES_DISALLOWED}. * * <p/> * If the caller's {@link org.tmatesoft.svn.core.wc.ISVNEventHandler} is non-<code>null</code>, invokes * it for each item added at the new location. * * <p/> * This method is just a variant of a local add operation, where * <code>sources</code> are scheduled for addition as copies. No changes * will happen to the repository until a commit occurs. This scheduling can * be removed with {@link SvnRevert}. * * <p/> * Note: this routine requires repository access only when sources are URLs. * * </li> * * <li> * * <b> If <code>disjoint</code> is <code>true</code>:</b> * * <p/> * <code>Targets</code> represent the roots of the working copies located in another working copies. * * <p/> * This copy operation uses only <code>sources</code> as operation's parameters. * * <p/> * Note: this routine does not require repository access. However if it's * performed on an old format working copy where repository root urls were * not written, the routine will connect to the repository to fetch the * repository root urls. * * {@link #run()} throws {@link SVNException} in the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE} * error code - if <code>target</code> is either not a * directory, or has no parent at all; if the current local * filesystem parent of <code>target</code> is actually a * child of it in the repository * <li/>exception with * {@link SVNErrorCode#ENTRY_EXISTS} error code - if <code> * target</code> is not a disjoint working copy, i.e. there is * already a versioned item under the parent path of <code> * target</code>; if <code>target</code> is not in the * repository yet (has got a schedule for addition flag) * <li/> * exception with {@link SVNErrorCode#WC_INVALID_SCHEDULE} error * code - if <code>target</code> is not from the same * repository as the parent directory; if the parent of <code> * target</code> is scheduled for deletion; if <code>target * </code> is scheduled for deletion * </ul> * * </li> * <li> * * <b> If <code>virtual</code> is <code>true</code>:</b> * * <p/> * Copies/moves administrative version control information of a source files * to administrative information of a destination file. For example, if you * have manually copied/moved a source files to a <code>target</code> one (manually means * just in the filesystem, not using version control operations) and then * would like to turn this copying/moving into a complete version control * copy or move operation, use this method that will finish all the work for * you - it will copy/move all the necessary administrative information * (kept in the source <i>.svn</i> directory) to the <code>target</code> <i>.svn</i> * directory. * <p> * In that case when you have your files copied/moved in the filesystem, you * can not perform standard (version control) copying/moving - since the * <code>target</code> already exists and the source may be already deleted. Use this * method to overcome that restriction. * * <p/> * This operation uses <code>sources</code> and <code>move</code> parameters. * If <code>move</code> is <code>true</code> then completes moving * <code>src</code> to <code>target</code>, otherwise completes copying <code>src</code> to <code>dst</code> * {@link #run()} throws {@link SVNException} if one of the following is true: * <ul> * <li><code>move = true</code> * and <code>src</code> still exists <li><code>target</code> does * not exist <li><code>target</code> is a directory <li><code>src * </code> is a directory <li><code>src</code> is not under * version control <li><code>target</code> is already under version * control <li>if <code>src</code> is copied but not scheduled * for addition, and SVNKit is not able to locate the copied * directory root for <code>src</code> * </ul> * </li> * </ul> * * @author TMate Software Ltd. * @version 1.7 * @see SvnCopySource */ public class SvnCopy extends SvnOperation<Void> { private Collection<SvnCopySource> sources = new HashSet<SvnCopySource>(); private boolean move; private boolean makeParents; private boolean failWhenDstExist; private boolean ignoreExternals; private boolean virtual; private boolean disjoint; private boolean allowMixedRevisions; private boolean metadataOnly; protected SvnCopy(SvnOperationFactory factory) { super(factory); this.sources = new HashSet<SvnCopySource>(); this.allowMixedRevisions = true; } /** * Returns operation's all copy sources, object containing information about what to copy. * * @return the copy sources of the operation, unmodifiable */ public Collection<SvnCopySource> getSources() { return Collections.unmodifiableCollection(sources); } /** * Adds copy source information to the operation * * @param source copy source information */ public void addCopySource(SvnCopySource source) { if (source != null) { this.sources.add(source); } } /** * Gets whether to do copy as move operation (delete, then add with history). * * @return <code>true</code> if move operation should be done, otherwise <code>false</code> */ public boolean isMove() { return move; } /** * Sets whether to do copy as move operation (delete, then add with history). * * @param isMove <code>true</code> if move operation should be done, otherwise <code>false</code> */ public void setMove(boolean isMove) { this.move = isMove; } /** * Gets whether to make parent folders if don't exist. * * @return <code>true</code> if non-existent parent directories should be created, otherwise <code>false</code> */ public boolean isMakeParents() { return makeParents; } /** * Sets whether to make parent folders if don't exist. * * @param isMakeParents <code>true</code> if non-existent parent directories should be created, otherwise <code>false</code> */ public void setMakeParents(boolean isMakeParents) { this.makeParents = isMakeParents; } /** * Gets whether to fail if <code>target</code> already exists. * * @return <code>true</code> if fail when <code>target</code> already exists, otherwise <code>false</code> * @see SvnRemoteCopy */ public boolean isFailWhenDstExists() { return failWhenDstExist; } /** * Sets whether to fail if <code>target</code> already exists. * * @param isFailWhenDstExist <code>true</code> if fail when <code>target</code> already exists, otherwise <code>false</code> * @see SvnRemoteCopy */ public void setFailWhenDstExists(boolean isFailWhenDstExist) { this.failWhenDstExist = isFailWhenDstExist; } /** * Returns whether to ignore externals definitions. * * @return <code>true</code> if externals definitions should be ignored, otherwise <code>false</code> */ public boolean isIgnoreExternals() { return ignoreExternals; } /** * Sets whether to ignore externals definitions. * * @param ignoreExternals <code>true</code> if externals definitions should be ignored, otherwise <code>false</code> */ public void setIgnoreExternals(boolean ignoreExternals) { this.ignoreExternals = ignoreExternals; } /** * Returns whether copy is virtual copy. * * @return <code>true</code> if it is virtual copy, otherwise <code>false</code> */ public boolean isVirtual() { return virtual; } /** * Sets whether copy is virtual copy. * * @param virtual <code>true</code> if it is virtual copy, otherwise <code>false</code> */ public void setVirtual(boolean virtual) { this.virtual = virtual; } /** * Returns whether copy is disjoint working copy. * * @return <code>true</code> if it is disjoint working copy, otherwise <code>false</code> */ public boolean isDisjoint() { return disjoint; } /** * Sets whether copy is disjoint working copy. * * @param disjoint <code>true</code> if it is disjoint working copy, otherwise <code>false</code> */ public void setDisjoint(boolean disjoint) { this.disjoint = disjoint; } /** * 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; } /** * Gets whether the coping of directories with mixed revisions is allowed * @return <code>true</code> if coping of directories with mixed revisions is allowed */ public boolean isAllowMixedRevisions() { return allowMixedRevisions; } /** * Sets whether the coping of directories with mixed revisions is allowed * * @param allowMixedRevisions <code>true</code> if coping of directories with mixed revisions is allowed */ public void setAllowMixedRevisions(boolean allowMixedRevisions) { this.allowMixedRevisions = allowMixedRevisions; } public boolean isMetadataOnly() { return metadataOnly; } public void setMetadataOnly(boolean metadataOnly) { this.metadataOnly = metadataOnly; } }