package org.tmatesoft.svn.core.internal.wc16;
import java.io.File;
import java.io.InputStream;
import java.util.*;
import org.tmatesoft.svn.core.SVNCancelException;
import org.tmatesoft.svn.core.SVNCommitInfo;
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.SVNNodeKind;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.util.SVNHashSet;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNURLUtil;
import org.tmatesoft.svn.core.internal.wc.*;
import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminArea;
import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry;
import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslator;
import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess;
import org.tmatesoft.svn.core.internal.wc2.ng.SvnNgPropertiesManager;
import org.tmatesoft.svn.core.io.ISVNEditor;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator;
import org.tmatesoft.svn.core.wc.DefaultSVNCommitHandler;
import org.tmatesoft.svn.core.wc.DefaultSVNCommitParameters;
import org.tmatesoft.svn.core.wc.ISVNCommitHandler;
import org.tmatesoft.svn.core.wc.ISVNCommitParameters;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.ISVNFileFilter;
import org.tmatesoft.svn.core.wc.ISVNOptions;
import org.tmatesoft.svn.core.wc.ISVNRepositoryPool;
import org.tmatesoft.svn.core.wc.SVNCommitItem;
import org.tmatesoft.svn.core.wc.SVNCommitPacket;
import org.tmatesoft.svn.core.wc.SVNEvent;
import org.tmatesoft.svn.core.wc.SVNEventAction;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNWCUtil;
import org.tmatesoft.svn.core.wc2.*;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* The <b>SVNCommitClient</b> class provides methods to perform operations that
* relate to committing changes to an SVN repository. These operations are
* similar to respective commands of the native SVN command line client and
* include ones which operate on working copy items as well as ones that operate
* only on a repository.
* <p>
* Here's a list of the <b>SVNCommitClient</b>'s commit-related methods matched
* against corresponing commands of the SVN command line client:
* <table cellpadding="3" cellspacing="1" border="0" width="40%" bgcolor="#999933">
* <tr bgcolor="#ADB8D9" align="left">
* <td><b>SVNKit</b></td>
* <td><b>Subversion</b></td>
* </tr>
* <tr bgcolor="#EAEAEA" align="left">
* <td>doCommit()</td>
* <td>'svn commit'</td>
* </tr>
* <tr bgcolor="#EAEAEA" align="left">
* <td>doImport()</td>
* <td>'svn import'</td>
* </tr>
* <tr bgcolor="#EAEAEA" align="left">
* <td>doDelete()</td>
* <td>'svn delete URL'</td>
* </tr>
* <tr bgcolor="#EAEAEA" align="left">
* <td>doMkDir()</td>
* <td>'svn mkdir URL'</td>
* </tr>
* </table>
*
* @version 1.3
* @author TMate Software Ltd.
* @since 1.2
* @see <a target="_top" href="http://svnkit.com/kb/examples/">Examples</a>
*/
public class SVNCommitClient16 extends SVNBasicDelegate {
private ISVNCommitHandler myCommitHandler;
private ISVNCommitParameters myCommitParameters;
/**
* Constructs and initializes an <b>SVNCommitClient</b> object with the
* specified run-time configuration and authentication drivers.
* <p>
* If <code>options</code> is <span class="javakeyword">null</span>, then
* this <b>SVNCommitClient</b> will be using a default run-time
* configuration driver which takes client-side settings from the default
* SVN's run-time configuration area but is not able to change those
* settings (read more on {@link ISVNOptions} and {@link SVNWCUtil}).
* <p>
* If <code>authManager</code> is <span class="javakeyword">null</span>,
* then this <b>SVNCommitClient</b> will be using a default authentication
* and network layers driver (see
* {@link SVNWCUtil#createDefaultAuthenticationManager()}) which uses
* server-side settings and auth storage from the default SVN's run-time
* configuration area (or system properties if that area is not found).
*
* @param authManager
* an authentication and network layers driver
* @param options
* a run-time configuration options driver
*/
public SVNCommitClient16(ISVNAuthenticationManager authManager, ISVNOptions options) {
super(authManager, options);
}
/**
* Constructs and initializes an <b>SVNCommitClient</b> object with the
* specified run-time configuration and repository pool object.
* <p/>
* If <code>options</code> is <span class="javakeyword">null</span>, then
* this <b>SVNCommitClient</b> will be using a default run-time
* configuration driver which takes client-side settings from the default
* SVN's run-time configuration area but is not able to change those
* settings (read more on {@link ISVNOptions} and {@link SVNWCUtil}).
* <p/>
* If <code>repositoryPool</code> is <span class="javakeyword">null</span>,
* then {@link org.tmatesoft.svn.core.io.SVNRepositoryFactory} will be used
* to create {@link SVNRepository repository access objects}.
*
* @param repositoryPool
* a repository pool object
* @param options
* a run-time configuration options driver
*/
public SVNCommitClient16(ISVNRepositoryPool repositoryPool, ISVNOptions options) {
super(repositoryPool, options);
}
/**
* @param handler
* @deprecated use {@link #setCommitHandler(ISVNCommitHandler)} instead
*/
public void setCommitHander(ISVNCommitHandler handler) {
myCommitHandler = handler;
}
/**
* Sets an implementation of <b>ISVNCommitHandler</b> to the commit handler
* that will be used during commit operations to handle commit log messages.
* The handler will receive a clien's log message and items (represented as
* <b>SVNCommitItem</b> objects) that will be committed. Depending on
* implementor's aims the initial log message can be modified (or something
* else) and returned back.
* <p>
* If using <b>SVNCommitClient</b> without specifying any commit handler
* then a default one will be used - {@link DefaultSVNCommitHandler}.
*
* @param handler
* an implementor's handler that will be used to handle commit
* log messages
* @see #getCommitHandler()
* @see ISVNCommitHandler
*/
public void setCommitHandler(ISVNCommitHandler handler) {
this.myCommitHandler = handler;
}
/**
* Returns the specified commit handler (if set) being in use or a default
* one (<b>DefaultSVNCommitHandler</b>) if no special implementations of
* <b>ISVNCommitHandler</b> were previously provided.
*
* @return the commit handler being in use or a default one
* @see #setCommitHander(ISVNCommitHandler)
* @see ISVNCommitHandler
* @see DefaultSVNCommitHandler
*/
public ISVNCommitHandler getCommitHandler() {
return this.myCommitHandler;
}
/**
* Sets commit parameters to use.
* <p>
* When no parameters are set {@link DefaultSVNCommitParameters default}
* ones are used.
*
* @param parameters
* commit parameters
* @see #getCommitParameters()
*/
public void setCommitParameters(ISVNCommitParameters parameters) {
this.myCommitParameters = parameters;
}
/**
* Returns commit parameters.
* <p>
* If no user parameters were previously specified, once creates and returns
* {@link DefaultSVNCommitParameters default} ones.
*
* @return commit parameters
* @see #setCommitParameters(ISVNCommitParameters)
*/
public ISVNCommitParameters getCommitParameters() {
return this.myCommitParameters;
}
/**
* Committs removing specified URL-paths from the repository. This call is
* equivalent to <code>doDelete(urls, commitMessage, null)</code>.
*
* @param urls
* an array containing URL-strings that represent repository
* locations to be removed
* @param commitMessage
* a string to be a commit log message
* @return information on a new revision as the result of the commit
* @throws SVNException
* if one of the following is true:
* <ul>
* <li>a URL does not exist
* <li>probably some of URLs refer to different repositories
* </ul>
* @see #doDelete(SVNURL[],String,SVNProperties)
*/
public SVNCommitInfo doDelete(SVNURL[] urls, String commitMessage) throws SVNException {
return doDelete(urls, commitMessage, null);
}
/**
* Deletes items from a repository.
* <p/>
* If non-<span class="javakeyword">null</span>,
* <code>revisionProperties</code> holds additional, custom revision
* properties (<code>String</code> names mapped to {@link SVNPropertyValue}
* values) to be set on the new revision. This table cannot contain any
* standard Subversion properties.
* <p/>
* {@link #getCommitHandler() Commit handler} will be asked for a commit log
* message.
* <p/>
* If the caller's {@link ISVNEventHandler event handler} is not <span
* class="javakeyword">null</span> and if the commit succeeds, the handler
* will be called with {@link SVNEventAction#COMMIT_COMPLETED} event action.
*
* @param urls
* repository urls to delete
* @param commitMessage
* commit log message
* @param revisionProperties
* custom revision properties
* @return information about the new committed revision
* @throws SVNException
* in the following cases:
* <ul>
* <li/>exception with {@link SVNErrorCode#RA_ILLEGAL_URL} error
* code - if cannot compute common root url for <code>urls
* </code> <li/>exception with {@link SVNErrorCode#FS_NOT_FOUND}
* error code - if some of <code>urls</code> does not exist
* </ul>
* @since 1.2.0, SVN 1.5.0
*/
public SVNCommitInfo doDelete(SVNURL[] urls, String commitMessage, SVNProperties revisionProperties) throws SVNException {
if (urls == null || urls.length == 0) {
return SVNCommitInfo.NULL;
}
List paths = new ArrayList();
SVNURL rootURL = SVNURLUtil.condenceURLs(urls, paths, true);
if (rootURL == null) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, "Can not compute common root URL for specified URLs");
SVNErrorManager.error(err, SVNLogType.DEFAULT);
}
if (paths.isEmpty()) {
paths.add(SVNPathUtil.tail(rootURL.getURIEncodedPath()));
rootURL = rootURL.removePathTail();
}
SVNCommitItem[] commitItems = new SVNCommitItem[paths.size()];
for (int i = 0; i < commitItems.length; i++) {
String path = (String) paths.get(i);
commitItems[i] = new SVNCommitItem(null, rootURL.appendPath(path, true), null, SVNNodeKind.NONE, SVNRevision.UNDEFINED, SVNRevision.UNDEFINED, false, true, false, false, false, false);
}
commitMessage = getCommitHandler().getCommitMessage(commitMessage, commitItems);
if (commitMessage == null) {
return SVNCommitInfo.NULL;
}
commitMessage = SVNCommitUtil.validateCommitMessage(commitMessage);
List decodedPaths = new ArrayList();
for (Iterator commitPaths = paths.iterator(); commitPaths.hasNext();) {
String path = (String) commitPaths.next();
decodedPaths.add(SVNEncodingUtil.uriDecode(path));
}
paths = decodedPaths;
SVNRepository repos = createRepository(rootURL, null, null, true);
for (Iterator commitPath = paths.iterator(); commitPath.hasNext();) {
String path = (String) commitPath.next();
SVNNodeKind kind = repos.checkPath(path, -1);
if (kind == SVNNodeKind.NONE) {
SVNURL url = rootURL.appendPath(path, false);
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_NOT_FOUND, "URL ''{0}'' does not exist", url);
SVNErrorManager.error(err, SVNLogType.DEFAULT);
}
}
commitMessage = SVNCommitUtil.validateCommitMessage(commitMessage);
SVNPropertiesManager.validateRevisionProperties(revisionProperties);
ISVNEditor commitEditor = repos.getCommitEditor(commitMessage, null, false, revisionProperties, null);
ISVNCommitPathHandler deleter = new ISVNCommitPathHandler() {
public boolean handleCommitPath(String commitPath, ISVNEditor commitEditor) throws SVNException {
commitEditor.deleteEntry(commitPath, -1);
return false;
}
};
SVNCommitInfo info;
try {
SVNCommitUtil.driveCommitEditor(deleter, paths, commitEditor, -1);
info = commitEditor.closeEdit();
} catch (SVNException e) {
try {
commitEditor.abortEdit();
} catch (SVNException inner) {
}
throw e;
}
if (info != null && info.getNewRevision() >= 0) {
dispatchEvent(SVNEventFactory.createSVNEvent(null, SVNNodeKind.NONE, null, info.getNewRevision(), SVNEventAction.COMMIT_COMPLETED, null, null, null), ISVNEventHandler.UNKNOWN);
}
return info != null ? info : SVNCommitInfo.NULL;
}
/**
* Committs a creation of a new directory/directories in the repository.
*
* @param urls
* an array containing URL-strings that represent new repository
* locations to be created
* @param commitMessage
* a string to be a commit log message
* @return information on a new revision as the result of the commit
* @throws SVNException
* if some of URLs refer to different repositories
*/
public SVNCommitInfo doMkDir(SVNURL[] urls, String commitMessage) throws SVNException {
return doMkDir(urls, commitMessage, null, false);
}
/**
* Creates directory(ies) in a repository.
* <p/>
* If <code>makeParents</code> is <span class="javakeyword">true</span>,
* creates any non-existent parent directories also.
* <p/>
* If non-<span class="javakeyword">null</span>,
* <code>revisionProperties</code> holds additional, custom revision
* properties (<code>String</code> names mapped to {@link SVNPropertyValue}
* values) to be set on the new revision. This table cannot contain any
* standard Subversion properties.
* <p/>
* {@link #getCommitHandler() Commit handler} will be asked for a commit log
* message.
* <p/>
* If the caller's {@link ISVNEventHandler event handler} is not <span
* class="javakeyword">null</span> and if the commit succeeds, the handler
* will be called with {@link SVNEventAction#COMMIT_COMPLETED} event action.
*
* @param urls
* repository locations to create
* @param commitMessage
* commit log message
* @param revisionProperties
* custom revision properties
* @param makeParents
* if <span class="javakeyword">true</span>, creates all
* non-existent parent directories
* @return information about the new committed revision
* @throws SVNException
* in the following cases:
* <ul>
* <li/>exception with {@link SVNErrorCode#RA_ILLEGAL_URL} error
* code - if cannot compute common root url for <code>urls
* </code> <li/>exception with {@link SVNErrorCode#FS_NOT_FOUND}
* error code - if some of <code>urls</code> does not exist
* </ul>
* @since 1.2.0, SVN 1.5.0
*/
public SVNCommitInfo doMkDir(SVNURL[] urls, String commitMessage, SVNProperties revisionProperties, boolean makeParents) throws SVNException {
if (makeParents) {
List allURLs = new LinkedList();
for (int i = 0; i < urls.length; i++) {
SVNURL url = urls[i];
addURLParents(allURLs, url);
}
urls = (SVNURL[]) allURLs.toArray(new SVNURL[allURLs.size()]);
}
if (urls == null || urls.length == 0) {
return SVNCommitInfo.NULL;
}
Collection paths = new SVNHashSet();
SVNURL rootURL = SVNURLUtil.condenceURLs(urls, paths, false);
if (rootURL == null) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, "Can not compute common root URL for specified URLs");
SVNErrorManager.error(err, SVNLogType.DEFAULT);
}
if (paths.isEmpty()) {
paths.add(SVNPathUtil.tail(rootURL.getURIEncodedPath()));
rootURL = rootURL.removePathTail();
}
if (paths.contains("")) {
List convertedPaths = new ArrayList();
String tail = SVNPathUtil.tail(rootURL.getURIEncodedPath());
rootURL = rootURL.removePathTail();
for (Iterator commitPaths = paths.iterator(); commitPaths.hasNext();) {
String path = (String) commitPaths.next();
if ("".equals(path)) {
convertedPaths.add(tail);
} else {
convertedPaths.add(SVNPathUtil.append(tail, path));
}
}
paths = convertedPaths;
}
List sortedPaths = new ArrayList(paths);
Collections.sort(sortedPaths, SVNPathUtil.PATH_COMPARATOR);
SVNCommitItem[] commitItems = new SVNCommitItem[sortedPaths.size()];
for (int i = 0; i < commitItems.length; i++) {
String path = (String) sortedPaths.get(i);
commitItems[i] = new SVNCommitItem(null, rootURL.appendPath(path, true), null, SVNNodeKind.DIR, SVNRevision.UNDEFINED, SVNRevision.UNDEFINED, true, false, false, false, false, false);
}
commitMessage = getCommitHandler().getCommitMessage(commitMessage, commitItems);
if (commitMessage == null) {
return SVNCommitInfo.NULL;
}
commitMessage = validateCommitMessage(commitMessage);
List decodedPaths = new ArrayList();
for (Iterator commitPaths = sortedPaths.iterator(); commitPaths.hasNext();) {
String path = (String) commitPaths.next();
decodedPaths.add(SVNEncodingUtil.uriDecode(path));
}
paths = decodedPaths;
SVNRepository repos = createRepository(rootURL, null, null, true);
commitMessage = SVNCommitUtil.validateCommitMessage(commitMessage);
SVNPropertiesManager.validateRevisionProperties(revisionProperties);
ISVNEditor commitEditor = repos.getCommitEditor(commitMessage, null, false, revisionProperties, null);
ISVNCommitPathHandler creater = new ISVNCommitPathHandler() {
public boolean handleCommitPath(String commitPath, ISVNEditor commitEditor) throws SVNException {
SVNPathUtil.checkPathIsValid(commitPath);
commitEditor.addDir(commitPath, null, -1);
return true;
}
};
SVNCommitInfo info;
try {
SVNCommitUtil.driveCommitEditor(creater, paths, commitEditor, -1);
info = commitEditor.closeEdit();
} catch (SVNException e) {
try {
commitEditor.abortEdit();
} catch (SVNException inner) {
}
throw e;
}
if (info != null && info.getNewRevision() >= 0) {
dispatchEvent(SVNEventFactory.createSVNEvent(null, SVNNodeKind.NONE, null, info.getNewRevision(), SVNEventAction.COMMIT_COMPLETED, null, null, null), ISVNEventHandler.UNKNOWN);
}
return info != null ? info : SVNCommitInfo.NULL;
}
/**
* Committs an addition of a local unversioned file or directory into the
* repository.
* <p/>
* This method is identical to
* <code>doImport(path, dstURL, commitMessage, null, true, false, SVNDepth.fromRecurse(recursive))</code>.
*
* @param path
* a local unversioned file or directory to be imported into the
* repository
* @param dstURL
* a URL-string that represents a repository location where the
* <code>path</code> will be imported
* @param commitMessage
* a string to be a commit log message
* @param recursive
* this flag is relevant only when the <code>path</code> is a
* directory: if <span class="javakeyword">true</span> then the
* entire directory tree will be imported including all child
* directories, otherwise only items located in the directory
* itself
* @return information on a new revision as the result of the commit
* @throws SVNException
* if one of the following is true:
* <ul>
* <li><code>dstURL</code> is invalid <li>the path denoted by
* <code>dstURL</code> already exists <li><code>path</code>
* contains a reserved name - <i>'.svn'</i>
* </ul>
* @deprecated use
* {@link #doImport(File,SVNURL,String,SVNProperties,boolean,boolean,SVNDepth)}
* instead
*/
public SVNCommitInfo doImport(File path, SVNURL dstURL, String commitMessage, boolean recursive) throws SVNException {
return doImport(path, dstURL, commitMessage, null, true, false, SVNDepth.fromRecurse(recursive));
}
/**
* Committs an addition of a local unversioned file or directory into the
* repository.
* <p/>
* This method is identical to
* <code>doImport(path, dstURL, commitMessage, null, useGlobalIgnores, false, SVNDepth.fromRecurse(recursive))</code>.
*
* @param path
* a local unversioned file or directory to be imported into the
* repository
* @param dstURL
* a URL-string that represents a repository location where the
* <code>path</code> will be imported
* @param commitMessage
* a string to be a commit log message
* @param useGlobalIgnores
* if <span class="javakeyword">true</span> then those paths that
* match global ignore patterns controlled by a config options
* driver (see
* {@link org.tmatesoft.svn.core.wc.ISVNOptions#getIgnorePatterns()}
* ) will not be imported, otherwise global ignore patterns are
* not used
* @param recursive
* this flag is relevant only when the <code>path</code> is a
* directory: if <span class="javakeyword">true</span> then the
* entire directory tree will be imported including all child
* directories, otherwise only items located in the directory
* itself
* @return information on a new revision as the result of the commit
* @throws SVNException
* if one of the following is true:
* <ul>
* <li><code>dstURL</code> is invalid <li>the path denoted by
* <code>dstURL</code> already exists <li><code>path</code>
* contains a reserved name - <i>'.svn'</i>
* </ul>
* @deprecated use
* {@link #doImport(File,SVNURL,String,SVNProperties,boolean,boolean,SVNDepth)}
* instead
*/
public SVNCommitInfo doImport(File path, SVNURL dstURL, String commitMessage, boolean useGlobalIgnores, boolean recursive) throws SVNException {
return doImport(path, dstURL, commitMessage, null, useGlobalIgnores, false, SVNDepth.fromRecurse(recursive));
}
/**
* Imports file or directory <code>path</code> into repository directory
* <code>dstURL</code> at HEAD revision. If some components of
* <code>dstURL</code> do not exist, then creates parent directories as
* necessary.
* <p/>
* If <code>path</code> is a directory, the contents of that directory are
* imported directly into the directory identified by <code>dstURL</code>.
* Note that the directory <code>path</code> itself is not imported -- that
* is, the base name of <code>path<code> is not part of the import.
* <p/>
* If <code>path</code> is a file, then the parent of <code>dstURL</code> is
* the directory receiving the import. The base name of <code>dstURL</code>
* is the filename in the repository. In this case if <code>dstURL</code>
* already exists, throws {@link SVNException}.
* <p/>
* If the caller's {@link ISVNEventHandler event handler} is not <span
* class="javakeyword">null</span> it will be called as the import
* progresses with {@link SVNEventAction#COMMIT_ADDED} action. If the commit
* succeeds, the handler will be called with
* {@link SVNEventAction#COMMIT_COMPLETED} event action.
* <p/>
* If non-<span class="javakeyword">null</span>,
* <code>revisionProperties</code> holds additional, custom revision
* properties (<code>String</code> names mapped to {@link SVNPropertyValue}
* values) to be set on the new revision. This table cannot contain any
* standard Subversion properties.
* <p/>
* {@link #getCommitHandler() Commit handler} will be asked for a commit log
* message.
* <p/>
* If <code>depth</code> is {@link SVNDepth#EMPTY}, imports just
* <code>path</code> and nothing below it. If {@link SVNDepth#FILES},
* imports <code>path</code> and any file children of <code>path</code>. If
* {@link SVNDepth#IMMEDIATES}, imports <code>path</code>, any file
* children, and any immediate subdirectories (but nothing underneath those
* subdirectories). If {@link SVNDepth#INFINITY}, imports <code>path</code>
* and everything under it fully recursively.
* <p/>
* If <code>useGlobalIgnores</code> is <span
* class="javakeyword">false</span>, doesn't add files or directories that
* match ignore patterns.
* <p/>
* If <code>ignoreUnknownNodeTypes</code> is <span
* class="javakeyword">false</span>, ignores files of which the node type is
* unknown, such as device files and pipes.
*
* @param path
* path to import
* @param dstURL
* import destination url
* @param commitMessage
* commit log message
* @param revisionProperties
* custom revision properties
* @param useGlobalIgnores
* whether matching against global ignore patterns should take
* place
* @param ignoreUnknownNodeTypes
* whether to ignore files of unknown node types or not
* @param depth
* tree depth to process
* @return information about the new committed revision
* @throws SVNException
* in the following cases:
* <ul>
* <li/>exception with {@link SVNErrorCode#ENTRY_NOT_FOUND}
* error code - if <code>path</code> does not exist <li/>
* exception with {@link SVNErrorCode#ENTRY_EXISTS} error code -
* if <code>dstURL</code> already exists and <code>path</code>
* is a file <li/>exception with
* {@link SVNErrorCode#CL_ADM_DIR_RESERVED} error code - if
* trying to import an item with a reserved SVN name (like
* <code>'.svn'</code> or <code>'_svn'</code>)
* </ul>
* @since 1.2.0, New in SVN 1.5.0
*/
public SVNCommitInfo doImport(File path, SVNURL dstURL, String commitMessage, SVNProperties revisionProperties, boolean useGlobalIgnores, boolean ignoreUnknownNodeTypes, SVNDepth depth) throws SVNException {
return doImport(path, dstURL, commitMessage, revisionProperties, useGlobalIgnores, ignoreUnknownNodeTypes, depth, true);
}
/**
* Imports file or directory <code>path</code> into repository directory
* <code>dstURL</code> at HEAD revision. If some components of
* <code>dstURL</code> do not exist, then creates parent directories as
* necessary.
* <p/>
* If <code>path</code> is a directory, the contents of that directory are
* imported directly into the directory identified by <code>dstURL</code>.
* Note that the directory <code>path</code> itself is not imported -- that
* is, the base name of <code>path<code> is not part of the import.
* <p/>
* If <code>path</code> is a file, then the parent of <code>dstURL</code> is
* the directory receiving the import. The base name of <code>dstURL</code>
* is the filename in the repository. In this case if <code>dstURL</code>
* already exists, throws {@link SVNException}.
* <p/>
* If the caller's {@link ISVNEventHandler event handler} is not <span
* class="javakeyword">null</span> it will be called as the import
* progresses with {@link SVNEventAction#COMMIT_ADDED} action. If the commit
* succeeds, the handler will be called with
* {@link SVNEventAction#COMMIT_COMPLETED} event action.
* <p/>
* If non-<span class="javakeyword">null</span>,
* <code>revisionProperties</code> holds additional, custom revision
* properties (<code>String</code> names mapped to {@link SVNPropertyValue}
* values) to be set on the new revision. This table cannot contain any
* standard Subversion properties.
* <p/>
* {@link #getCommitHandler() Commit handler} will be asked for a commit log
* message.
* <p/>
* If <code>depth</code> is {@link SVNDepth#EMPTY}, imports just
* <code>path</code> and nothing below it. If {@link SVNDepth#FILES},
* imports <code>path</code> and any file children of <code>path</code>. If
* {@link SVNDepth#IMMEDIATES}, imports <code>path</code>, any file
* children, and any immediate subdirectories (but nothing underneath those
* subdirectories). If {@link SVNDepth#INFINITY}, imports <code>path</code>
* and everything under it fully recursively.
* <p/>
* If <code>useGlobalIgnores</code> is <span
* class="javakeyword">false</span>, doesn't add files or directories that
* match ignore patterns.
* <p/>
* If <code>ignoreUnknownNodeTypes</code> is <span
* class="javakeyword">false</span>, ignores files of which the node type is
* unknown, such as device files and pipes.
*
* @param path
* path to import
* @param dstURL
* import destination url
* @param commitMessage
* commit log message
* @param revisionProperties
* custom revision properties
* @param useGlobalIgnores
* whether matching against global ignore patterns should take
* place
* @param ignoreUnknownNodeTypes
* whether to ignore files of unknown node types or not
* @param depth
* tree depth to process
* @param applyAutoProperties
* disable or not auto-properties application
* @return information about the new committed revision
* @throws SVNException
* in the following cases:
* <ul>
* <li/>exception with {@link SVNErrorCode#ENTRY_NOT_FOUND}
* error code - if <code>path</code> does not exist <li/>
* exception with {@link SVNErrorCode#ENTRY_EXISTS} error code -
* if <code>dstURL</code> already exists and <code>path</code>
* is a file <li/>exception with
* {@link SVNErrorCode#CL_ADM_DIR_RESERVED} error code - if
* trying to import an item with a reserved SVN name (like
* <code>'.svn'</code> or <code>'_svn'</code>)
* </ul>
* @since SVN 1.8
*/
public SVNCommitInfo doImport(File path, SVNURL dstURL, String commitMessage, SVNProperties revisionProperties, boolean useGlobalIgnores, boolean ignoreUnknownNodeTypes, SVNDepth depth, boolean applyAutoProperties)
throws SVNException {
return doImport(path, dstURL, commitMessage, revisionProperties, useGlobalIgnores, ignoreUnknownNodeTypes, depth, applyAutoProperties, null);
}
/**
* Imports file or directory <code>path</code> into repository directory
* <code>dstURL</code> at HEAD revision. If some components of
* <code>dstURL</code> do not exist, then creates parent directories as
* necessary.
* <p/>
* If <code>path</code> is a directory, the contents of that directory are
* imported directly into the directory identified by <code>dstURL</code>.
* Note that the directory <code>path</code> itself is not imported -- that
* is, the base name of <code>path<code> is not part of the import.
* <p/>
* If <code>path</code> is a file, then the parent of <code>dstURL</code> is
* the directory receiving the import. The base name of <code>dstURL</code>
* is the filename in the repository. In this case if <code>dstURL</code>
* already exists, throws {@link SVNException}.
* <p/>
* If the caller's {@link ISVNEventHandler event handler} is not <span
* class="javakeyword">null</span> it will be called as the import
* progresses with {@link SVNEventAction#COMMIT_ADDED} action. If the commit
* succeeds, the handler will be called with
* {@link SVNEventAction#COMMIT_COMPLETED} event action.
* <p/>
* If non-<span class="javakeyword">null</span>,
* <code>revisionProperties</code> holds additional, custom revision
* properties (<code>String</code> names mapped to {@link SVNPropertyValue}
* values) to be set on the new revision. This table cannot contain any
* standard Subversion properties.
* <p/>
* {@link #getCommitHandler() Commit handler} will be asked for a commit log
* message.
* <p/>
* If <code>depth</code> is {@link SVNDepth#EMPTY}, imports just
* <code>path</code> and nothing below it. If {@link SVNDepth#FILES},
* imports <code>path</code> and any file children of <code>path</code>. If
* {@link SVNDepth#IMMEDIATES}, imports <code>path</code>, any file
* children, and any immediate subdirectories (but nothing underneath those
* subdirectories). If {@link SVNDepth#INFINITY}, imports <code>path</code>
* and everything under it fully recursively.
* <p/>
* If <code>useGlobalIgnores</code> is <span
* class="javakeyword">false</span>, doesn't add files or directories that
* match ignore patterns.
* <p/>
* If <code>ignoreUnknownNodeTypes</code> is <span
* class="javakeyword">false</span>, ignores files of which the node type is
* unknown, such as device files and pipes.
*
* @param path
* path to import
* @param dstURL
* import destination url
* @param commitMessage
* commit log message
* @param revisionProperties
* custom revision properties
* @param useGlobalIgnores
* whether matching against global ignore patterns should take
* place
* @param ignoreUnknownNodeTypes
* whether to ignore files of unknown node types or not
* @param depth
* tree depth to process
* @param applyAutoProperties
* disable or not auto-properties application
* @param fileFilter
* filter to exclude or include certain files for the operation
* @return information about the new committed revision
* @throws SVNException
* in the following cases:
* <ul>
* <li/>exception with {@link SVNErrorCode#ENTRY_NOT_FOUND}
* error code - if <code>path</code> does not exist <li/>
* exception with {@link SVNErrorCode#ENTRY_EXISTS} error code -
* if <code>dstURL</code> already exists and <code>path</code>
* is a file <li/>exception with
* {@link SVNErrorCode#CL_ADM_DIR_RESERVED} error code - if
* trying to import an item with a reserved SVN name (like
* <code>'.svn'</code> or <code>'_svn'</code>)
* </ul>
* @since SVN 1.8
*/
public SVNCommitInfo doImport(File path, SVNURL dstURL, String commitMessage, SVNProperties revisionProperties, boolean useGlobalIgnores, boolean ignoreUnknownNodeTypes, SVNDepth depth, boolean applyAutoProperties, ISVNFileFilter fileFilter)
throws SVNException {
SVNRepository repos = null;
SVNFileType srcKind = SVNFileType.getType(path);
if (srcKind == SVNFileType.NONE) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_NOT_FOUND, "Path ''{0}'' does not exist", path);
SVNErrorManager.error(err, SVNLogType.WC);
}
List newPaths = new ArrayList();
SVNURL rootURL = dstURL;
repos = createRepository(rootURL, null, null, true);
SVNURL reposRoot = repos.getRepositoryRoot(true);
while (!reposRoot.equals(rootURL)) {
if (repos.checkPath("", -1) == SVNNodeKind.NONE) {
newPaths.add(SVNPathUtil.tail(rootURL.getPath()));
rootURL = rootURL.removePathTail();
repos = createRepository(rootURL, null, null, true);
} else {
break;
}
}
if (newPaths.isEmpty() && (srcKind == SVNFileType.FILE || srcKind == SVNFileType.SYMLINK)) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_EXISTS, "Path ''{0}'' already exists", dstURL);
SVNErrorManager.error(err, SVNLogType.WC);
}
if (newPaths.contains(SVNFileUtil.getAdminDirectoryName())) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CL_ADM_DIR_RESERVED, "''{0}'' is a reserved name and cannot be imported", SVNFileUtil.getAdminDirectoryName());
SVNErrorManager.error(err, SVNLogType.WC);
}
SVNCommitItem[] items = new SVNCommitItem[1];
items[0] = new SVNCommitItem(path, null, null, SVNNodeKind.NONE, SVNRevision.UNDEFINED, SVNRevision.UNDEFINED, true, false, false,
false, false, false);
items[0].setPath(path.getName());
commitMessage = getCommitHandler().getCommitMessage(commitMessage, items);
if (commitMessage == null) {
return SVNCommitInfo.NULL;
}
commitMessage = SVNCommitUtil.validateCommitMessage(commitMessage);
SVNPropertiesManager.validateRevisionProperties(revisionProperties);
Map<String, Map<String, String>> versionedAutoProperties; //pattern->properties
if (applyAutoProperties) {
versionedAutoProperties = getVersionedAutoProperties(dstURL, reposRoot);
// method above reuses repository and changes its location.
repos.setLocation(rootURL, false);
} else {
versionedAutoProperties = null;
}
ISVNEditor commitEditor = repos.getCommitEditor(commitMessage, null, false, revisionProperties, new SVNImportMediator());
String filePath = "";
if (srcKind != SVNFileType.DIRECTORY) {
filePath = (String) newPaths.remove(0);
for (int i = 0; i < newPaths.size(); i++) {
String newDir = (String) newPaths.get(i);
filePath = newDir + "/" + filePath;
}
}
Collection ignores = useGlobalIgnores ? SVNStatusEditor.getGlobalIgnores(getOptions()) : null;
checkCancelled();
boolean changed = false;
SVNCommitInfo info = null;
try {
commitEditor.openRoot(-1);
String newDirPath = null;
for (int i = newPaths.size() - 1; i >= 0; i--) {
newDirPath = newDirPath == null ? (String) newPaths.get(i) : SVNPathUtil.append(newDirPath, (String) newPaths.get(i));
commitEditor.addDir(newDirPath, null, -1);
}
changed = newPaths.size() > 0;
SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator();
if (srcKind == SVNFileType.DIRECTORY) {
changed |= importDir(deltaGenerator, path, newDirPath, useGlobalIgnores, ignoreUnknownNodeTypes, depth, versionedAutoProperties, fileFilter, commitEditor);
} else if (srcKind == SVNFileType.FILE || srcKind == SVNFileType.SYMLINK) {
if (!useGlobalIgnores || !SVNStatusEditor.isIgnored(ignores, path, "/" + path.getName())) {
changed |= importFile(deltaGenerator, path, srcKind, filePath, versionedAutoProperties, commitEditor);
}
} else if (srcKind == SVNFileType.NONE || srcKind == SVNFileType.UNKNOWN) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.NODE_UNKNOWN_KIND, "''{0}'' does not exist", path);
SVNErrorManager.error(err, SVNLogType.WC);
}
if (!changed) {
try {
commitEditor.abortEdit();
} catch (SVNException e) {
}
return SVNCommitInfo.NULL;
}
for (int i = 0; i < newPaths.size(); i++) {
commitEditor.closeDir();
}
info = commitEditor.closeEdit();
} finally {
if (!changed || info == null) {
try {
commitEditor.abortEdit();
} catch (SVNException e) {
}
}
}
if (info != null && info.getNewRevision() >= 0) {
dispatchEvent(SVNEventFactory.createSVNEvent(null, SVNNodeKind.NONE, null, info.getNewRevision(), SVNEventAction.COMMIT_COMPLETED, null, null, null), ISVNEventHandler.UNKNOWN);
}
return info != null ? info : SVNCommitInfo.NULL;
}
/**
* Committs local changes to the repository.
* <p/>
* This method is identical to
* <code>doCommit(paths, keepLocks, commitMessage, null, null, false, force, SVNDepth.fromRecurse(recursive))</code>.
*
* @param paths
* an array of local items which should be traversed to commit
* changes they have to the repository
* @param keepLocks
* if <span class="javakeyword">true</span> and there are local
* items that were locked then the commit will left them locked,
* otherwise the items will be unlocked after the commit succeeds
* @param commitMessage
* a string to be a commit log message
* @param force
* <span class="javakeyword">true</span> to force a non-recursive
* commit; if <code>recursive</code> is set to <span
* class="javakeyword">true</span> the <code>force</code> flag is
* ignored
* @param recursive
* relevant only for directory items: if <span
* class="javakeyword">true</span> then the entire directory tree
* will be committed including all child directories, otherwise
* only items located in the directory itself
* @return information on a new revision as the result of the commit
* @throws SVNException
* @deprecated use
* {@link #doCommit(File[],boolean,String,SVNProperties,String[],boolean,boolean,SVNDepth)}
* instead
*/
public SVNCommitInfo doCommit(File[] paths, boolean keepLocks, String commitMessage, boolean force, boolean recursive) throws SVNException {
return doCommit(paths, keepLocks, commitMessage, null, null, false, force, SVNDepth.getInfinityOrEmptyDepth(recursive));
}
/**
* Commits files or directories into repository.
* <p/>
* <code>paths</code> need not be canonicalized nor condensed; this method
* will take care of that. If
* <code>targets has zero elements, then do nothing and return
* immediately without error.
* <p/>
* If non-<span class="javakeyword">null</span>, <code>revisionProperties</code>
* holds additional, custom revision properties (<code>String</code> names
* mapped to {@link SVNPropertyValue} values) to be set on the new revision.
* This table cannot contain any standard Subversion properties.
* <p/>
* If the caller's {@link ISVNEventHandler event handler} is not <span
* class="javakeyword">null</span> it will be called as the commit
* progresses with any of the following actions:
* {@link SVNEventAction#COMMIT_MODIFIED},
* {@link SVNEventAction#COMMIT_ADDED},
* {@link SVNEventAction#COMMIT_DELETED},
* {@link SVNEventAction#COMMIT_REPLACED}. If the commit succeeds, the
* handler will be called with {@link SVNEventAction#COMMIT_COMPLETED} event
* action.
* <p/>
* If <code>depth</code> is {@link SVNDepth#INFINITY}, commits all changes
* to and below named targets. If <code>depth</code> is
* {@link SVNDepth#EMPTY}, commits only named targets (that is, only
* property changes on named directory targets, and property and content
* changes for named file targets). If <code>depth</code> is
* {@link SVNDepth#FILES}, behaves as above for named file targets, and for
* named directory targets, commits property changes on a named directory
* and all changes to files directly inside that directory. If
* {@link SVNDepth#IMMEDIATES}, behaves as for {@link SVNDepth#FILES}, and
* for subdirectories of any named directory target commits as though for
* {@link SVNDepth#EMPTY}.
* <p/>
* Unlocks paths in the repository, unless <code>keepLocks</code> is <span
* class="javakeyword">true</span>.
* <p/>
* <code>changelists</code> is an array of <code>String</code> changelist
* names, used as a restrictive filter on items that are committed; that is,
* doesn't commit anything unless it's a member of one of those changelists.
* After the commit completes successfully, removes changelist associations
* from the targets, unless <code>keepChangelist</code> is set. If
* <code>changelists</code> is empty (or altogether <span
* class="javakeyword">null</span>), no changelist filtering occurs.
* <p/>
* If no exception is thrown and {@link SVNCommitInfo#getNewRevision()} is
* invalid (<code><0</code>), then the commit was a no-op; nothing needed
* to be committed.
*
* @param paths
* paths to commit
* @param keepLocks
* whether to unlock or not files in the repository
* @param commitMessage
* commit log message
* @param revisionProperties
* custom revision properties
* @param changelists
* changelist names array
* @param keepChangelist
* whether to remove <code>changelists</code> or not
* @param force
* <span class="javakeyword">true</span> to force a non-recursive
* commit; if <code>depth</code> is {@link SVNDepth#INFINITY} the
* <code>force</code> flag is ignored
* @param depth
* tree depth to process
* @return information about the new committed revision
* @throws SVNException
* @since 1.2.0, New in Subversion 1.5.0
*/
public SVNCommitInfo doCommit(File[] paths, boolean keepLocks, String commitMessage, SVNProperties revisionProperties, String[] changelists, boolean keepChangelist, boolean force, SVNDepth depth)
throws SVNException {
SVNCommitPacket packet = doCollectCommitItems(paths, keepLocks, force, depth, changelists);
try {
packet = packet.removeSkippedItems();
return doCommit(packet, keepLocks, keepChangelist, commitMessage, revisionProperties);
} finally {
if (packet != null) {
packet.dispose();
}
}
}
/**
* Committs local changes made to the Working Copy items to the repository.
* <p>
* This method is identical to
* <code>doCommit(commitPacket, keepLocks, false, commitMessage, null)</code>.
* <p>
* <code>commitPacket</code> contains commit items ({@link SVNCommitItem})
* which represent local Working Copy items that were changed and are to be
* committed. Commit items are gathered into a single
* {@link SVNCommitPacket}by invoking
* {@link #doCollectCommitItems(File[],boolean,boolean,boolean)
* doCollectCommitItems()}.
*
* @param commitPacket
* a single object that contains items to be committed
* @param keepLocks
* if <span class="javakeyword">true</span> and there are local
* items that were locked then the commit will left them locked,
* otherwise the items will be unlocked after the commit succeeds
* @param commitMessage
* a string to be a commit log message
* @return information on a new revision as the result of the commit
* @throws SVNException
* @see SVNCommitItem
*/
public SVNCommitInfo doCommit(SVNCommitPacket commitPacket, boolean keepLocks, String commitMessage) throws SVNException {
return doCommit(commitPacket, keepLocks, false, commitMessage, null);
}
/**
* Commits files or directories into repository.
* <p/>
* This method is identical to
* {@link #doCommit(File[],boolean,String,SVNProperties,String[],boolean,boolean,SVNDepth)}
* except for it receives a commit packet instead of paths array. The
* aforementioned method collects commit items into a commit packet given
* working copy paths. This one accepts already collected commit items
* provided in <code>commitPacket</code>.
* <p/>
* <code>commitPacket</code> contains commit items ({@link SVNCommitItem})
* which represent local Working Copy items that are to be committed. Commit
* items are gathered in a single {@link SVNCommitPacket} by invoking either
* {@link #doCollectCommitItems(File[],boolean,boolean,SVNDepth,String[])}
* or
* {@link #doCollectCommitItems(File[],boolean,boolean,SVNDepth,boolean,String[])}.
* <p/>
* For more details on parameters, please, refer to
* {@link #doCommit(File[],boolean,String,SVNProperties,String[],boolean,boolean,SVNDepth)}.
*
* @param commitPacket
* a single object that contains items to be committed
* @param keepLocks
* if <span class="javakeyword">true</span> and there are local
* items that were locked then the commit will left them locked,
* otherwise the items will be unlocked after the commit succeeds
* @param keepChangelist
* whether to remove changelists or not
* @param commitMessage
* commit log message
* @param revisionProperties
* custom revision properties
* @return information about the new committed revision
* @throws SVNException
* @since 1.2.0, SVN 1.5.0
*/
public SVNCommitInfo doCommit(SVNCommitPacket commitPacket, boolean keepLocks, boolean keepChangelist, String commitMessage, SVNProperties revisionProperties) throws SVNException {
SVNCommitInfo[] info = doCommit(new SVNCommitPacket[] {
commitPacket
}, keepLocks, keepChangelist, commitMessage, revisionProperties);
if (info != null && info.length > 0) {
if (info[0].getErrorMessage() != null && info[0].getErrorMessage().getErrorCode() != SVNErrorCode.REPOS_POST_COMMIT_HOOK_FAILED) {
SVNErrorManager.error(info[0].getErrorMessage(), SVNLogType.DEFAULT);
}
return info[0];
}
return SVNCommitInfo.NULL;
}
/**
* Committs local changes, made to the Working Copy items, to the
* repository.
* <p>
* <code>commitPackets</code> is an array of packets that contain commit
* items (<b>SVNCommitItem</b>) which represent local Working Copy items
* that were changed and are to be committed. Commit items are gathered in a
* single <b>SVNCommitPacket</b> by invoking
* {@link #doCollectCommitItems(File[],boolean,boolean,boolean)
* doCollectCommitItems()}.
* <p>
* This allows to commit separate trees of Working Copies "belonging" to
* different repositories. One packet per one repository. If repositories
* are different (it means more than one commit will be done),
* <code>commitMessage</code> may be replaced by a commit handler to be a
* specific one for each commit.
* <p>
* This method is identical to
* <code>doCommit(commitPackets, keepLocks, false, commitMessage, null)</code>.
*
* @param commitPackets
* logically grouped items to be committed
* @param keepLocks
* if <span class="javakeyword">true</span> and there are local
* items that were locked then the commit will left them locked,
* otherwise the items will be unlocked after the commit succeeds
* @param commitMessage
* a string to be a commit log message
* @return committed information
* @throws SVNException
*/
public SVNCommitInfo[] doCommit(SVNCommitPacket[] commitPackets, boolean keepLocks, String commitMessage) throws SVNException {
return doCommit(commitPackets, keepLocks, false, commitMessage, null);
}
/**
* Commits files or directories into repository.
* <p>
* <code>commitPackets</code> is an array of packets that contain commit
* items ({@link SVNCommitItem}) which represent local Working Copy items
* that were changed and are to be committed. Commit items are gathered in a
* single {@link SVNCommitPacket}by invoking
* {@link #doCollectCommitItems(File[],boolean,boolean,SVNDepth,String[])}
* or
* {@link #doCollectCommitItems(File[],boolean,boolean,SVNDepth,boolean,String[])}.
* <p>
* This allows to commit items from separate Working Copies checked out from
* the same or different repositories. For each commit packet
* {@link #getCommitHandler() commit handler} is invoked to produce a commit
* message given the one <code>commitMessage</code> passed to this method.
* Each commit packet is committed in a separate transaction.
* <p/>
* For more details on parameters, please, refer to
* {@link #doCommit(File[],boolean,String,SVNProperties,String[],boolean,boolean,SVNDepth)}.
*
* @param commitPackets
* commit packets containing commit commit items per one commit
* @param keepLocks
* if <span class="javakeyword">true</span> and there are local
* items that were locked then the commit will left them locked,
* otherwise the items will be unlocked by the commit
* @param keepChangelist
* whether to remove changelists or not
* @param commitMessage
* a string to be a commit log message
* @param revisionProperties
* custom revision properties
* @return information about the new committed revisions
* @throws SVNException
* @since 1.2.0, SVN 1.5.0
*/
public SVNCommitInfo[] doCommit(SVNCommitPacket[] commitPackets, boolean keepLocks, boolean keepChangelist, String commitMessage, SVNProperties revisionProperties) throws SVNException {
if (commitPackets == null || commitPackets.length == 0) {
return new SVNCommitInfo[0];
}
Collection tmpFiles = null;
SVNCommitInfo info = null;
ISVNEditor commitEditor = null;
Collection infos = new ArrayList();
boolean needsSleepForTimeStamp = false;
for (int p = 0; p < commitPackets.length; p++) {
SVNCommitPacket commitPacket = commitPackets[p].removeSkippedItems();
if (commitPacket.getCommitItems().length == 0) {
continue;
}
try {
commitMessage = getCommitHandler().getCommitMessage(commitMessage, commitPacket.getCommitItems());
if (commitMessage == null) {
infos.add(SVNCommitInfo.NULL);
continue;
}
commitMessage = SVNCommitUtil.validateCommitMessage(commitMessage);
Map commitables = new TreeMap();
SVNURL baseURL = SVNCommitUtil.translateCommitables(commitPacket.getCommitItems(), commitables);
Map lockTokens = SVNCommitUtil.translateLockTokens(commitPacket.getLockTokens(), baseURL.toString());
SVNCommitItem firstItem = commitPacket.getCommitItems()[0];
SVNRepository repository = createRepository(baseURL, firstItem.getFile(), firstItem.getWCAccess(), true);
SVNCommitMediator mediator = new SVNCommitMediator(commitables);
tmpFiles = mediator.getTmpFiles();
String repositoryRoot = repository.getRepositoryRoot(true).getPath();
SVNPropertiesManager.validateRevisionProperties(revisionProperties);
commitEditor = repository.getCommitEditor(commitMessage, lockTokens, keepLocks, revisionProperties, mediator);
for (int i = 0; i < commitPacket.getCommitItems().length; i++) {
commitPacket.getCommitItems()[i].getWCAccess().setEventHandler(getEventDispatcher());
}
info = SVNCommitter.commit(mediator.getTmpFiles(), commitables, repositoryRoot, commitEditor);
Collection processedItems = new SVNHashSet();
Collection explicitCommitPaths = new SVNHashSet();
for (Iterator urls = commitables.keySet().iterator(); urls.hasNext();) {
String url = (String) urls.next();
SVNCommitItem item = (SVNCommitItem) commitables.get(url);
explicitCommitPaths.add(item.getPath());
}
for (Iterator urls = commitables.keySet().iterator(); urls.hasNext();) {
String url = (String) urls.next();
SVNCommitItem item = (SVNCommitItem) commitables.get(url);
SVNWCAccess wcAccess = item.getWCAccess();
String path = item.getPath();
SVNAdminArea dir = null;
String target = null;
try {
if (item.getKind() == SVNNodeKind.DIR) {
target = "";
dir = wcAccess.retrieve(item.getFile());
} else {
target = SVNPathUtil.tail(path);
dir = wcAccess.retrieve(item.getFile().getParentFile());
}
} catch (SVNException e) {
if (e.getErrorMessage().getErrorCode() == SVNErrorCode.WC_NOT_LOCKED) {
dir = null;
}
}
if (dir == null) {
if (hasProcessedParents(processedItems, path)) {
processedItems.add(path);
continue;
}
if (item.isDeleted() && item.getKind() == SVNNodeKind.DIR) {
File parentPath = "".equals(path) ? null : item.getFile().getParentFile();
String nameInParent = "".equals(path) ? null : SVNPathUtil.tail(path);
if (parentPath != null) {
SVNAdminArea parentDir = wcAccess.retrieve(parentPath);
if (parentDir != null) {
SVNEntry entryInParent = parentDir.getEntry(nameInParent, true);
if (entryInParent != null) {
Map attributes = new SVNHashMap();
attributes.put(SVNProperty.SCHEDULE, null);
attributes.put(SVNProperty.DELETED, Boolean.TRUE.toString());
parentDir.modifyEntry(nameInParent, attributes, true, true);
}
}
}
processedItems.add(path);
continue;
}
}
SVNEntry entry = dir.getEntry(target, true);
if (entry == null && hasProcessedParents(processedItems, path)) {
processedItems.add(path);
continue;
}
boolean recurse = false;
if (item.isAdded() && item.getCopyFromURL() != null && item.getKind() == SVNNodeKind.DIR) {
recurse = true;
}
boolean removeLock = !keepLocks && item.isLocked();
SVNProperties wcPropChanges = mediator.getWCProperties(item);
dir.commit(target, info, wcPropChanges, removeLock, recurse, !keepChangelist, explicitCommitPaths, getCommitParameters());
processedItems.add(path);
}
needsSleepForTimeStamp = true;
dispatchEvent(SVNEventFactory.createSVNEvent(null, SVNNodeKind.NONE, null, info.getNewRevision(), SVNEventAction.COMMIT_COMPLETED, null, null, null), ISVNEventHandler.UNKNOWN);
} catch (SVNException e) {
if (e instanceof SVNCancelException) {
throw e;
}
SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, e);
SVNErrorMessage err = e.getErrorMessage().wrap("Commit failed (details follow):");
infos.add(new SVNCommitInfo(-1, null, null, err));
dispatchEvent(SVNEventFactory.createErrorEvent(err, SVNEventAction.COMMIT_COMPLETED), ISVNEventHandler.UNKNOWN);
continue;
} finally {
if (info == null && commitEditor != null) {
try {
commitEditor.abortEdit();
} catch (SVNException e) {
}
}
if (tmpFiles != null) {
for (Iterator files = tmpFiles.iterator(); files.hasNext();) {
File file = (File) files.next();
file.delete();
}
}
if (commitPacket != null) {
commitPacket.dispose();
}
}
infos.add(info != null ? info : SVNCommitInfo.NULL);
}
if (needsSleepForTimeStamp) {
sleepForTimeStamp();
}
return (SVNCommitInfo[]) infos.toArray(new SVNCommitInfo[infos.size()]);
}
/**
* Collects commit items (containing detailed information on each Working
* Copy item that was changed and need to be committed to the repository)
* into a single {@link SVNCommitPacket}.
* <p/>
* This method is equivalent to
* <code>doCollectCommitItems(paths, keepLocks, force, SVNDepth.fromRecurse(recursive), null)</code>.
*
* @param paths
* an array of local items which should be traversed to collect
* information on every changed item (one <b>SVNCommitItem</b>
* per each modified local item)
* @param keepLocks
* if <span class="javakeyword">true</span> and there are local
* items that were locked then these items will be left locked
* after traversing all of them, otherwise the items will be
* unlocked
* @param force
* forces collecting commit items for a non-recursive commit
* @param recursive
* relevant only for directory items: if <span
* class="javakeyword">true</span> then the entire directory tree
* will be traversed including all child directories, otherwise
* only items located in the directory itself will be processed
* @return an <b>SVNCommitPacket</b> containing all Working Copy items
* having local modifications and represented as
* <b>SVNCommitItem</b> objects; if no modified items were found
* then {@link SVNCommitPacket#EMPTY} is returned
* @throws SVNException
* @deprecated use
* {@link #doCollectCommitItems(File[],boolean,boolean,SVNDepth,String[])}
* instead
*/
public SVNCommitPacket doCollectCommitItems(File[] paths, boolean keepLocks, boolean force, boolean recursive) throws SVNException {
SVNDepth depth = recursive ? SVNDepth.INFINITY : SVNDepth.EMPTY;
return doCollectCommitItems(paths, keepLocks, force, depth, null);
}
/**
* Collects commit items (containing detailed information on each Working
* Copy item that contains changes and need to be committed to the
* repository) into a single {@link SVNCommitPacket}. Further this commit
* packet can be passed to
* {@link #doCommit(SVNCommitPacket,boolean,boolean,String,SVNProperties)}.
* <p/>
* For more details on parameters, please, refer to
* {@link #doCommit(File[],boolean,String,SVNProperties,String[],boolean,boolean,SVNDepth)}.
*
* @param paths
* an array of local items which should be traversed to collect
* information on every changed item (one <b>SVNCommitItem</b>
* per each modified local item)
* @param keepLocks
* if <span class="javakeyword">true</span> and there are local
* items that were locked then these items will be left locked
* after traversing all of them, otherwise the items will be
* unlocked
* @param force
* forces collecting commit items for a non-recursive commit
* @param depth
* tree depth to process
* @param changelists
* changelist names array
* @return commit packet containing commit items
* @throws SVNException
* @since 1.2.0
*/
public SVNCommitPacket doCollectCommitItems(File[] paths, boolean keepLocks, boolean force, SVNDepth depth, String[] changelists) throws SVNException {
depth = depth == null ? SVNDepth.UNKNOWN : depth;
if (depth == SVNDepth.UNKNOWN) {
depth = SVNDepth.INFINITY;
}
if (paths == null || paths.length == 0) {
return SVNCommitPacket.EMPTY;
}
Collection targets = new ArrayList();
SVNStatusClient16 statusClient = new SVNStatusClient16(getRepositoryPool(), getOptions());
statusClient.setEventHandler(new ISVNEventHandler() {
public void handleEvent(SVNEvent event, double progress) throws SVNException {
}
public void checkCancelled() throws SVNCancelException {
SVNCommitClient16.this.checkCancelled();
}
});
SVNWCAccess wcAccess = SVNCommitUtil.createCommitWCAccess(paths, depth, force, targets, statusClient);
SVNAdminArea[] areas = wcAccess.getAdminAreas();
for (int i = 0; areas != null && i < areas.length; i++) {
if (areas[i] != null) {
areas[i].setCommitParameters(getCommitParameters());
}
}
try {
Map lockTokens = new SVNHashMap();
checkCancelled();
Collection changelistsSet = changelists != null ? new SVNHashSet() : null;
if (changelists != null) {
for (int j = 0; j < changelists.length; j++) {
changelistsSet.add(changelists[j]);
}
}
SVNCommitItem[] commitItems = SVNCommitUtil.harvestCommitables(wcAccess, targets, lockTokens, !keepLocks, depth, force, changelistsSet, getCommitParameters());
boolean hasModifications = false;
checkCancelled();
for (int i = 0; commitItems != null && i < commitItems.length; i++) {
SVNCommitItem commitItem = commitItems[i];
if (commitItem.isAdded() || commitItem.isDeleted() || commitItem.isContentsModified() || commitItem.isPropertiesModified() || commitItem.isCopied()) {
hasModifications = true;
break;
}
}
if (!hasModifications) {
wcAccess.close();
return SVNCommitPacket.EMPTY;
}
return new SVNCommitPacket(wcAccess, commitItems, lockTokens);
} catch (SVNException e) {
wcAccess.close();
if (e instanceof SVNCancelException) {
throw e;
}
SVNErrorMessage nestedErr = e.getErrorMessage();
SVNErrorMessage err = SVNErrorMessage.create(nestedErr.getErrorCode(), "Commit failed (details follow):");
SVNErrorManager.error(err, e, SVNLogType.DEFAULT);
return null;
}
}
/**
* Collects commit items (containing detailed information on each Working
* Copy item that was changed and need to be committed to the repository)
* into different <b>SVNCommitPacket</b>s.
* <p/>
* This method is identical to
* <code>doCollectCommitItems(paths, keepLocks, force, SVNDepth.fromRecurse(recursive), combinePackets, null)</code>.
*
* @param paths
* an array of local items which should be traversed to collect
* information on every changed item (one <b>SVNCommitItem</b>
* per each modified local item)
* @param keepLocks
* if <span class="javakeyword">true</span> and there are local
* items that were locked then these items will be left locked
* after traversing all of them, otherwise the items will be
* unlocked
* @param force
* forces collecting commit items for a non-recursive commit
* @param recursive
* relevant only for directory items: if <span
* class="javakeyword">true</span> then the entire directory tree
* will be traversed including all child directories, otherwise
* only items located in the directory itself will be processed
* @param combinePackets
* if <span class="javakeyword">true</span> then collected commit
* packets will be joined into a single one, so that to be
* committed in a single transaction
* @return an array of commit packets
* @throws SVNException
* @deprecated use
* {@link #doCollectCommitItems(File[],boolean,boolean,SVNDepth,boolean,String[])}
* instead
*/
public SVNCommitPacket[] doCollectCommitItems(File[] paths, boolean keepLocks, boolean force, boolean recursive, boolean combinePackets) throws SVNException {
SVNDepth depth = recursive ? SVNDepth.INFINITY : SVNDepth.EMPTY;
return doCollectCommitItems(paths, keepLocks, force, depth, combinePackets, null);
}
/**
* Collects commit items (containing detailed information on each Working
* Copy item that was changed and need to be committed to the repository)
* into different <code>SVNCommitPacket</code>s. This method may be
* considered as an advanced version of the
* {@link #doCollectCommitItems(File[],boolean,boolean,SVNDepth,String[])}
* method. Its main difference from the aforementioned method is that it
* provides an ability to collect commit items from different working copies
* checked out from the same repository and combine them into a single
* commit packet. This is attained via setting <code>combinePackets</code>
* into <span class="javakeyword">true</span>. However even if
* <code>combinePackets</code> is set, combining may only occur if (besides
* that the paths must be from the same repository) URLs of
* <code>paths</code> are formed of identical components, that is protocol
* name, host name, port number (if any) must match for all paths. Otherwise
* combining will not occur.
* <p/>
* Combined items will be committed in a single transaction.
* <p/>
* For details on other parameters, please, refer to
* {@link #doCommit(File[],boolean,String,SVNProperties,String[],boolean,boolean,SVNDepth)}.
*
* @param paths
* an array of local items which should be traversed to collect
* information on every changed item (one <b>SVNCommitItem</b>
* per each modified local item)
* @param keepLocks
* if <span class="javakeyword">true</span> and there are local
* items that were locked then these items will be left locked
* after traversing all of them, otherwise the items will be
* unlocked
* @param force
* forces collecting commit items for a non-recursive commit
* @param depth
* tree depth to process
* @param combinePackets
* whether combining commit packets into a single commit packet
* is allowed or not
* @param changelists
* changelist names array
* @return array of commit packets
* @throws SVNException
* in the following cases:
* <ul>
* <li/>exception with {@link SVNErrorCode#ENTRY_MISSING_URL}
* error code - if working copy root of either path has no url
* </ul>
* @since 1.2.0
*/
public SVNCommitPacket[] doCollectCommitItems(File[] paths, boolean keepLocks, boolean force, SVNDepth depth, boolean combinePackets, String[] changelists) throws SVNException {
depth = depth == null ? SVNDepth.UNKNOWN : depth;
if (depth == SVNDepth.UNKNOWN) {
depth = SVNDepth.INFINITY;
}
if (paths == null || paths.length == 0) {
return new SVNCommitPacket[0];
}
Collection packets = new ArrayList();
Map targets = new SVNHashMap();
SVNStatusClient16 statusClient = new SVNStatusClient16(getRepositoryPool(), getOptions());
statusClient.setEventHandler(new ISVNEventHandler() {
public void handleEvent(SVNEvent event, double progress) throws SVNException {
}
public void checkCancelled() throws SVNCancelException {
SVNCommitClient16.this.checkCancelled();
}
});
SVNWCAccess[] wcAccesses = SVNCommitUtil.createCommitWCAccess2(paths, depth, force, targets, statusClient);
for (int i = 0; i < wcAccesses.length; i++) {
SVNWCAccess wcAccess = wcAccesses[i];
SVNAdminArea[] areas = wcAccess.getAdminAreas();
for (int j = 0; areas != null && j < areas.length; j++) {
if (areas[j] != null) {
areas[j].setCommitParameters(getCommitParameters());
}
}
Collection targetPaths = (Collection) targets.get(wcAccess);
try {
checkCancelled();
Map lockTokens = new SVNHashMap();
Collection changelistsSet = changelists != null ? new SVNHashSet() : null;
if (changelists != null) {
for (int j = 0; j < changelists.length; j++) {
changelistsSet.add(changelists[j]);
}
}
SVNCommitItem[] commitItems = SVNCommitUtil.harvestCommitables(wcAccess, targetPaths, lockTokens, !keepLocks, depth, force, changelistsSet, getCommitParameters());
checkCancelled();
boolean hasModifications = false;
for (int j = 0; commitItems != null && j < commitItems.length; j++) {
SVNCommitItem commitItem = commitItems[j];
if (commitItem.isAdded() || commitItem.isDeleted() || commitItem.isContentsModified() || commitItem.isPropertiesModified() || commitItem.isCopied()) {
hasModifications = true;
break;
}
}
if (!hasModifications) {
wcAccess.close();
continue;
}
packets.add(new SVNCommitPacket(wcAccess, commitItems, lockTokens));
} catch (SVNException e) {
for (int j = 0; j < wcAccesses.length; j++) {
wcAccesses[j].close();
}
if (e instanceof SVNCancelException) {
throw e;
}
SVNErrorMessage nestedErr = e.getErrorMessage();
SVNErrorMessage err = SVNErrorMessage.create(nestedErr.getErrorCode(), "Commit failed (details follow):");
SVNErrorManager.error(err, e, SVNLogType.DEFAULT);
}
}
SVNCommitPacket[] packetsArray = (SVNCommitPacket[]) packets.toArray(new SVNCommitPacket[packets.size()]);
if (!combinePackets) {
return packetsArray;
}
Map repoUUIDs = new SVNHashMap();
Map locktokensMap = new SVNHashMap();
try {
for (int i = 0; i < packetsArray.length; i++) {
checkCancelled();
SVNCommitPacket packet = packetsArray[i];
File wcRoot = SVNWCUtil.getWorkingCopyRoot(packet.getCommitItems()[0].getWCAccess().getAnchor(), true);
SVNWCAccess rootWCAccess = createWCAccess();
String uuid = null;
SVNURL url = null;
try {
SVNAdminArea rootDir = rootWCAccess.open(wcRoot, false, 0);
uuid = rootDir.getEntry(rootDir.getThisDirName(), false).getUUID();
url = rootDir.getEntry(rootDir.getThisDirName(), false).getSVNURL();
} finally {
rootWCAccess.close();
}
checkCancelled();
if (uuid == null) {
if (url != null) {
SVNRepository repos = createRepository(url, wcRoot, rootWCAccess, true);
uuid = repos.getRepositoryUUID(true);
} else {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no URL", wcRoot);
SVNErrorManager.error(err, SVNLogType.WC);
}
}
uuid += url.getProtocol() + ":" + url.getHost() + ":" + url.getPort() + ":" + url.getUserInfo();
if (!repoUUIDs.containsKey(uuid)) {
repoUUIDs.put(uuid, new ArrayList());
locktokensMap.put(uuid, new SVNHashMap());
}
Collection items = (Collection) repoUUIDs.get(uuid);
Map lockTokens = (Map) locktokensMap.get(uuid);
for (int j = 0; j < packet.getCommitItems().length; j++) {
items.add(packet.getCommitItems()[j]);
}
if (packet.getLockTokens() != null) {
lockTokens.putAll(packet.getLockTokens());
}
checkCancelled();
}
packetsArray = new SVNCommitPacket[repoUUIDs.size()];
int index = 0;
for (Iterator roots = repoUUIDs.keySet().iterator(); roots.hasNext();) {
checkCancelled();
String uuid = (String) roots.next();
Collection items = (Collection) repoUUIDs.get(uuid);
Map lockTokens = (Map) locktokensMap.get(uuid);
SVNCommitItem[] itemsArray = (SVNCommitItem[]) items.toArray(new SVNCommitItem[items.size()]);
packetsArray[index++] = new SVNCommitPacket((SVNWCAccess)null, itemsArray, lockTokens);
}
} catch (SVNException e) {
for (int j = 0; j < wcAccesses.length; j++) {
wcAccesses[j].close();
}
if (e instanceof SVNCancelException) {
throw e;
}
SVNErrorMessage nestedErr = e.getErrorMessage();
SVNErrorMessage err = SVNErrorMessage.create(nestedErr.getErrorCode(), "Commit failed (details follow):");
SVNErrorManager.error(err, e, SVNLogType.DEFAULT);
}
return packetsArray;
}
private void addURLParents(List targets, SVNURL url) throws SVNException {
SVNURL parentURL = url.removePathTail();
SVNRepository repos = createRepository(parentURL, null, null, true);
SVNNodeKind kind = repos.checkPath("", SVNRepository.INVALID_REVISION);
if (kind == SVNNodeKind.NONE) {
addURLParents(targets, parentURL);
}
targets.add(url);
}
private boolean importDir(SVNDeltaGenerator deltaGenerator, File dir, String importPath, boolean useGlobalIgnores, boolean ignoreUnknownNodeTypes, SVNDepth depth, Map<String, Map<String, String>> versionedAutoProperties, ISVNFileFilter fileFilter, ISVNEditor editor)
throws SVNException {
checkCancelled();
File[] children = SVNFileListUtil.listFiles(dir);
boolean changed = false;
ISVNFileFilter commitHandlerFilter = getCommitHandler() instanceof ISVNFileFilter ? (ISVNFileFilter) getCommitHandler() : null;
Collection ignores = useGlobalIgnores ? SVNStatusEditor.getGlobalIgnores(getOptions()) : null;
for (int i = 0; children != null && i < children.length; i++) {
File file = children[i];
if (SVNFileUtil.getAdminDirectoryName().equals(file.getName())) {
SVNEvent skippedEvent = SVNEventFactory.createSVNEvent(file, SVNNodeKind.NONE, null, SVNRepository.INVALID_REVISION, SVNEventAction.SKIP, SVNEventAction.COMMIT_ADDED, null, null);
handleEvent(skippedEvent, ISVNEventHandler.UNKNOWN);
continue;
}
if (commitHandlerFilter != null && !commitHandlerFilter.accept(file)) {
continue;
}
if (fileFilter != null && !fileFilter.accept(file)) {
continue;
}
String path = importPath == null ? file.getName() : SVNPathUtil.append(importPath, file.getName());
if (useGlobalIgnores && SVNStatusEditor.isIgnored(ignores, file, "/" + path)) {
continue;
}
SVNFileType fileType = SVNFileType.getType(file);
if (fileType == SVNFileType.DIRECTORY && depth.compareTo(SVNDepth.IMMEDIATES) >= 0) {
editor.addDir(path, null, -1);
changed |= true;
SVNEvent event = SVNEventFactory.createSVNEvent(file, SVNNodeKind.DIR, null, SVNRepository.INVALID_REVISION, SVNEventAction.COMMIT_ADDED, null, null, null);
handleEvent(event, ISVNEventHandler.UNKNOWN);
SVNDepth depthBelowHere = depth;
if (depth == SVNDepth.IMMEDIATES) {
depthBelowHere = SVNDepth.EMPTY;
}
importDir(deltaGenerator, file, path, useGlobalIgnores, ignoreUnknownNodeTypes, depthBelowHere, versionedAutoProperties, fileFilter, editor);
editor.closeDir();
} else if ((fileType == SVNFileType.FILE || fileType == SVNFileType.SYMLINK) && depth.compareTo(SVNDepth.FILES) >= 0) {
changed |= importFile(deltaGenerator, file, fileType, path, versionedAutoProperties, editor);
} else if (fileType != SVNFileType.DIRECTORY && fileType != SVNFileType.FILE) {
if (ignoreUnknownNodeTypes) {
SVNEvent skippedEvent = SVNEventFactory.createSVNEvent(file, SVNNodeKind.NONE, null, SVNRepository.INVALID_REVISION, SVNEventAction.SKIP, SVNEventAction.COMMIT_ADDED, null, null);
handleEvent(skippedEvent, ISVNEventHandler.UNKNOWN);
} else {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.NODE_UNKNOWN_KIND, "Unknown or unversionable type for ''{0}''", file);
SVNErrorManager.error(err, SVNLogType.WC);
}
}
}
return changed;
}
private boolean importFile(SVNDeltaGenerator deltaGenerator, File file, SVNFileType fileType, String filePath, Map<String, Map<String, String>> versionedAutoProperties, ISVNEditor editor) throws SVNException {
if (fileType == null || fileType == SVNFileType.UNKNOWN) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.NODE_UNKNOWN_KIND, "unknown or unversionable type for ''{0}''", file);
SVNErrorManager.error(err, SVNLogType.WC);
}
editor.addFile(filePath, null, -1);
Map<String, String> matchedAutoProperties = SvnNgPropertiesManager.getMatchedAutoProperties(SVNFileUtil.getFileName(file), versionedAutoProperties);
Map autoProperties = new SVNHashMap();
if (fileType != SVNFileType.SYMLINK) {
autoProperties = SVNPropertiesManager.computeAutoProperties(getOptions(), file, autoProperties);
} else {
autoProperties.put(SVNProperty.SPECIAL, "*");
}
autoProperties.putAll(matchedAutoProperties);
String mimeTypeProperty = (String) autoProperties.get(SVNProperty.MIME_TYPE);
for (Iterator names = autoProperties.keySet().iterator(); names.hasNext();) {
String name = (String) names.next();
String value = (String) autoProperties.get(name);
if (SVNProperty.EOL_STYLE.equals(name) && value != null) {
if (SVNProperty.isBinaryMimeType(mimeTypeProperty)) {
continue;
} else if (!SVNTranslator.checkNewLines(file)) {
continue;
}
}
if (SVNProperty.CHARSET.equals(name) && value != null) {
if (SVNProperty.isBinaryMimeType(mimeTypeProperty)) {
continue;
}
try {
SVNTranslator.getCharset(value, mimeTypeProperty, filePath, getOptions());
} catch (SVNException e) {
continue;
}
}
editor.changeFileProperty(filePath, name, SVNPropertyValue.create(value));
}
SVNEvent addedEvent = SVNEventFactory.createSVNEvent(file, SVNNodeKind.FILE, mimeTypeProperty, SVNRepository.INVALID_REVISION, SVNEventAction.COMMIT_ADDED, null, null, null);
handleEvent(addedEvent, ISVNEventHandler.UNKNOWN);
String charset = SVNTranslator.getCharset((String) autoProperties.get(SVNProperty.CHARSET), mimeTypeProperty, file.getPath(), getOptions());
String eolStyle = (String) autoProperties.get(SVNProperty.EOL_STYLE);
String keywords = (String) autoProperties.get(SVNProperty.KEYWORDS);
boolean special = autoProperties.get(SVNProperty.SPECIAL) != null;
File tmpFile = null;
if (charset != null || eolStyle != null || keywords != null || special) {
byte[] eolBytes = SVNTranslator.getBaseEOL(eolStyle);
Map keywordsMap = keywords != null ? SVNTranslator.computeKeywords(keywords, null, null, null, null, null, getOptions()) : null;
tmpFile = SVNFileUtil.createTempFile("import", ".tmp");
SVNTranslator.translate(file, tmpFile, charset, eolBytes, keywordsMap, special, false);
}
File importedFile = tmpFile != null ? tmpFile : file;
InputStream is = null;
String checksum = null;
try {
is = SVNFileUtil.openFileForReading(importedFile, SVNLogType.WC);
editor.applyTextDelta(filePath, null);
checksum = deltaGenerator.sendDelta(filePath, is, editor, true);
} finally {
SVNFileUtil.closeFile(is);
SVNFileUtil.deleteFile(tmpFile);
}
editor.closeFile(filePath, checksum);
return true;
}
private static boolean hasProcessedParents(Collection paths, String path) throws SVNException {
path = SVNPathUtil.removeTail(path);
if (paths.contains(path)) {
return true;
}
if ("".equals(path)) {
return false;
}
return hasProcessedParents(paths, path);
}
static String validateCommitMessage(String message) {
if (message == null) {
return message;
}
message = message.replaceAll("\r\n", "\n");
message = message.replace('\r', '\n');
return message;
}
private Map<String, Map<String, String>> getVersionedAutoProperties(SVNURL url, SVNURL reposRoot) throws SVNException {
SVNProperties regularProperties;
SVNURL parentUrl = url.removePathTail();
if (url.equals(reposRoot)) {
return null;
}
final List<SvnInheritedProperties>[] inheritedConfigAutoProperties = new List[1];
final SvnOperationFactory operationFactory = new SvnOperationFactory();
try {
operationFactory.setRepositoryPool(getRepositoryPool());
operationFactory.setOptions(getOptions());
operationFactory.setEventHandler(getEventDispatcher());
operationFactory.setAutoDisposeRepositoryPool(false);
operationFactory.setCanceller(getEventDispatcher());
do {
SvnGetProperties getProperties = operationFactory.createGetProperties();
getProperties.setSingleTarget(SvnTarget.fromURL(parentUrl, SVNRevision.HEAD));
getProperties.setRevision(SVNRevision.HEAD);
getProperties.setDepth(SVNDepth.EMPTY);
getProperties.setTargetInheritedPropertiesReceiver(new ISvnObjectReceiver<List<SvnInheritedProperties>>() {
public void receive(SvnTarget target, List<SvnInheritedProperties> inheritedProperties) throws SVNException {
inheritedConfigAutoProperties[0] = inheritedProperties;
}
});
try {
regularProperties = getProperties.run();
break;
} catch (SVNException e) {
if (e.getErrorMessage().getErrorCode() != SVNErrorCode.RA_LOCAL_REPOS_OPEN_FAILED && e.getErrorMessage().getErrorCode() != SVNErrorCode.ENTRY_NOT_FOUND) {
throw e;
}
if (parentUrl.equals(reposRoot)) {
regularProperties = null;
break;
}
parentUrl = parentUrl.removePathTail();
}
} while (true);
Map<String, Map<String ,String>> allAutoProperties = new HashMap<String, Map<String, String>>();
if (inheritedConfigAutoProperties[0] != null) {
for (SvnInheritedProperties inheritedConfigAutoProperty : inheritedConfigAutoProperties[0]) {
SVNProperties inheritedProperties = inheritedConfigAutoProperty.getProperties();
Map<String, SVNPropertyValue> inheritedPropertiesMap = inheritedProperties.asMap();
for (Map.Entry<String, SVNPropertyValue> entry : inheritedPropertiesMap.entrySet()) {
String propertyName = entry.getKey();
if (!SVNProperty.INHERITABLE_AUTO_PROPS.equals(propertyName)) {
continue;
}
SVNPropertyValue propertyValue = entry.getValue();
allAutoProperties = SvnNgPropertiesManager.parseAutoProperties(propertyValue, allAutoProperties);
}
}
}
if (regularProperties != null) {
Map<String, SVNPropertyValue> regularPropertiesMap = regularProperties.asMap();
for (Map.Entry<String, SVNPropertyValue> entry : regularPropertiesMap.entrySet()) {
String propertyName = entry.getKey();
if (!SVNProperty.INHERITABLE_AUTO_PROPS.equals(propertyName)) {
continue;
}
SVNPropertyValue propertyValue = entry.getValue();
allAutoProperties = SvnNgPropertiesManager.parseAutoProperties(propertyValue, allAutoProperties);
}
}
return allAutoProperties;
} finally {
operationFactory.dispose();
}
}
}