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.core.wc.SVNRevision; import org.tmatesoft.svn.util.SVNLogType; /** * Represents checkout operation. Checks out a working copy of <code>source</code> at revision, * looked up at {@link SvnTarget#getPegRevision()}, using <code>target</code> as the * root directory of the newly checked out working copy. * * <p/> * If source {@link SvnTarget#getPegRevision()}> is {@link SVNRevision#UNDEFINED} or invalid, then it * defaults to {@link SVNRevision#HEAD}. * * <p/> * If <code>depth</depth> is {@link SVNDepth#INFINITY}, checks out fully * recursively. Else if it is {@link SVNDepth#IMMEDIATES}, checks out * source <code>target</code> and its immediate entries (subdirectories will be * present, but will be at depth {@link SVNDepth#EMPTY} themselves); else * {@link SVNDepth#FILES}, checks out source <code>target</code> and its file entries, * but no subdirectories; else if {@link SVNDepth#EMPTY}, checks out * source <code>target</code> as an empty directory at that depth, with no entries * present. * * <p/> * If <code>depth</depth> is {@link SVNDepth#UNKNOWN}, then behave as if for * {@link SVNDepth#INFINITY}, except in the case of resuming a previous * checkout of <code>target</code> (i.e., updating), in which case uses the * depth of the existing working copy. * * <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>isAllowUnversionedObstructions</code> is <code>true</code> * then the checkout tolerates existing * unversioned items that obstruct added paths from source target. 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 checkout. Working properties * of obstructing items are set equal to the base properties. If * <code>isAllowUnversionedObstructions</code> is <code>false</code> * then the checkout will abort if there * are any unversioned obstructing items. * * <p/> * If the caller's {@link ISVNEventHandler} is non-<code>null</code>, * it is invoked as the checkout processes. * Also {@link ISVNEventHandler#checkCancelled()} will be used at various * places during the checkout to check whether the caller wants to stop the * checkout. * * <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 actually checked out from the repository. * * <p/> * {@link #run()} throws {@link org.tmatesoft.svn.core.SVNException} in the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE} * error code - if <code>target</code>'s URL refers to a file rather than a directory * <li/>exception with {@link SVNErrorCode#RA_ILLEGAL_URL} error code * - if <code>target</code>'s URL * does not exist, or if external item at the <code>revision</code> doesn't exist, * or if external item at the <code>revision</code> is not file or a directory * <li/>exception with {@link SVNErrorCode#WC_OBSTRUCTED_UPDATE} error code * - if the working copy item * is already a working copy item for a different URL * <li/>exception with {@link SVNErrorCode#WC_NODE_KIND_CHANGE} error code * - if local file is already exists with the same name that incoming added directory * <li/>exception with {@link SVNErrorCode#ENTRY_MISSING_URL} error code * - if working copy item that has no URL * </ul> * * @author TMate Software Ltd. * @version 1.7 */ public class SvnCheckout extends AbstractSvnUpdate<Long> { private SvnTarget source; private int targetWorkingCopyFormat; protected SvnCheckout(SvnOperationFactory factory) { super(factory); targetWorkingCopyFormat = -1; } /** * Gets a repository location from where a working copy will be checked out. * * @return source of repository */ public SvnTarget getSource() { return source; } /** * Sets a repository location from where a working copy will be checked out. * * @param source source of repository */ public void setSource(SvnTarget source) { this.source = source; } @Override protected void ensureArgumentsAreValid() throws SVNException { super.ensureArgumentsAreValid(); if (getRevision() == null) { setRevision(SVNRevision.UNDEFINED); } if (getSource() == null || !getSource().isURL() || getSource().getURL() == null) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.BAD_URL); SVNErrorManager.error(err, SVNLogType.WC); } if (!getRevision().isValid() && getFirstTarget() != null) { setRevision(getSource().getResolvedPegRevision()); } if (!getRevision().isValid()) { setRevision(SVNRevision.HEAD); } if (getFirstTarget() == null || getFirstTarget().getFile() == null) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.BAD_FILENAME, "Checkout destination path can not be NULL"); SVNErrorManager.error(err, SVNLogType.WC); } if (getRevision().getNumber() < 0 && getRevision().getDate() == null && getRevision() != SVNRevision.HEAD) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION); 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; } public void setTargetWorkingCopyFormat(int targetWorkingCopyFormat) { this.targetWorkingCopyFormat = targetWorkingCopyFormat; } public int getTargetWorkingCopyFormat() { return targetWorkingCopyFormat; } }