package org.tmatesoft.svn.core.wc2; import java.io.File; import java.util.ArrayList; import java.util.Collection; import org.tmatesoft.svn.core.SVNCommitInfo; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; import org.tmatesoft.svn.core.wc.DefaultSVNCommitParameters; import org.tmatesoft.svn.core.wc.ISVNEventHandler; import org.tmatesoft.svn.core.wc.ISVNExternalsHandler; import org.tmatesoft.svn.core.wc.ISVNRepositoryPool; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.hooks.ISvnExternalsHandler; /** * Represents copy to repository operation. * Copies each source in <code>sources</code> to operation's <code>target</code> destination. * <code>Target</code> should represent repository URL. * * <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 * <code>target</code>. * * <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/> * {@link ISVNAuthenticationManager Authentication manager} (whether * provided directly through the appropriate constructor or in an * {@link ISVNRepositoryPool} instance) and {@link #getCommitHandler() * commit handler} are used to immediately attempt to commit the copy action * in the repository. * * <p/> * If the caller's {@link ISVNEventHandler} is non-<code>null</code>, invokes it for each item added at the * new location. * * <p/> * When performing a wc-to-url copy (tagging|branching from a working copy) * it's possible to fix revisions of external working copies (if any) which * are located within the working copy being copied. For example, imagine * you have a working copy and on one of its subdirectories you set an * <code>"svn:externals"</code> property which does not contain * a revision number. Suppose you have made a tag from your working copy and * in some period of time a user checks out that tag. It could have happened * that the external project has evolved since the tag creation moment and * the tag version is no more compatible with it. So, the user has a broken * project since it will not compile because of the API incompatibility * between the two versions of the external project: the HEAD one and the * one existed in the moment of the tag creation. That is why it appears * useful to fix externals revisions during a wc-to-url copy. To enable * externals revision fixing a user should implement * {@link ISVNExternalsHandler}. The user's implementation * {@link ISVNExternalsHandler#handleExternal(File,SVNURL,SVNRevision,SVNRevision,String,SVNRevision)} * method will be called on every external that will be met in the working * copy. If the user's implementation returns non-<code>null</code> * external revision, it's compared with the * revisions fetched from the external definition. If they are different, * the user's revision will be written in the external definition of the * tag. Otherwise if the returned revision is equal to the revision from the * external definition or if the user's implementation returns <code>null</code> * for that external, it will be skipped (i.e. left as is, unprocessed). * * <p/> * Note: this routine requires repository access. * * {@link #run()} returns {@link SVNCommitInfo} commit information information about the new committed revision. * * @author TMate Software Ltd. * @version 1.7 */ public class SvnRemoteCopy extends AbstractSvnCommit { private boolean move; private boolean makeParents; private boolean failWhenDstExists; private ISvnExternalsHandler externalsHandler; private ISvnCommitParameters commitParameters; private boolean disableLocalModifications; private Collection<SvnCopySource> sources; protected SvnRemoteCopy(SvnOperationFactory factory) { super(factory); sources = new ArrayList<SvnCopySource>(); } /** * 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 move <code>true</code> if move operation should be done, otherwise <code>false</code> */ public void setMove(boolean move) { this.move = move; } /** * 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 makeParents <code>true</code> if non-existent parent directories should be created, otherwise <code>false</code> */ public void setMakeParents(boolean makeParents) { this.makeParents = makeParents; } /** * Sets whether to disable local modifications. * * @return <code>true</code> if local modifications are disabled, otherwise <code>false</code> * @see #setDisableLocalModifications(boolean) */ public boolean isDisableLocalModifications() { return disableLocalModifications; } /** * Sets whether to disable local modifications. * If <code>true</code> and any local modification is found, * {@link #run()} method throws {@link SVNException} exception with {@link SVNErrorCode#ILLEGAL_TARGET} code. * * @param disableLocalModifications <code>true</code> if local modifications are disabled, otherwise <code>false</code> */ public void setDisableLocalModifications(boolean disableLocalModifications) { this.disableLocalModifications = disableLocalModifications; } /** * Returns all operation's sources. * * @return sources of the operation * @see SvnRemoteCopy */ public Collection<SvnCopySource> getSources() { return sources; } /** * And one source to the operation's sources. * * @param source source of the operation * @see SvnRemoteCopy */ public void addCopySource(SvnCopySource source) { if (source != null) { this.sources.add(source); } } /** * 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 failWhenDstExists; } /** * Sets whether to fail if <code>target</code> already exists. * * @param failWhenDstExists <code>true</code> if fail when <code>target</code> already exists, otherwise <code>false</code> * @see SvnRemoteCopy */ public void setFailWhenDstExists(boolean failWhenDstExists) { this.failWhenDstExists = failWhenDstExists; } /** * Runs copy operation. * * @return {@link SVNCommitInfo} commit information information about the new committed revision. */ @Override public SVNCommitInfo run() throws SVNException { return super.run(); } /** * Gets operation's externals handler. * * @return externals handler of the operation * @see SvnRemoteCopy */ public ISvnExternalsHandler getExternalsHandler() { return externalsHandler; } /** * Sets operation's externals handler. * * @param externalsHandler externals handler of the operation * @see SvnRemoteCopy */ public void setExternalsHandler(ISvnExternalsHandler externalsHandler) { this.externalsHandler = externalsHandler; } /** * Returns operation's parameters of the commit. * If no user parameters were previously specified, once creates and returns * {@link DefaultSVNCommitParameters default} ones. * * @return commit parameters of the operation * @see ISvnCommitParameters */ public ISvnCommitParameters getCommitParameters() { return commitParameters; } /** * Sets operation's parameters of the commit. * When no parameters are set {@link DefaultSVNCommitParameters default}ones * are used. * * @param commitParameters commit parameters of the operation * @see ISvnCommitParameters */ public void setCommitParameters(ISvnCommitParameters commitParameters) { this.commitParameters = commitParameters; } /** * 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 false; } @Override protected File getOperationalWorkingCopy() { SvnCopySource firstSource = getSources().iterator().next(); if (firstSource.getSource().isLocal()) { return firstSource.getSource().getFile(); } return null; } }