/* * ==================================================================== * Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://svnkit.com/license.html * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * ==================================================================== */ package org.tmatesoft.svn.core.internal.wc; import java.io.File; import java.io.OutputStream; import java.util.Map; import org.tmatesoft.svn.core.SVNCommitInfo; 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.internal.util.SVNDate; import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil; import org.tmatesoft.svn.core.internal.util.SVNHashMap; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslator; import org.tmatesoft.svn.core.io.ISVNEditor; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.io.diff.SVNDeltaProcessor; import org.tmatesoft.svn.core.io.diff.SVNDiffWindow; import org.tmatesoft.svn.core.wc.ISVNEventHandler; import org.tmatesoft.svn.core.wc.ISVNOptions; import org.tmatesoft.svn.core.wc.SVNEventAction; import org.tmatesoft.svn.util.SVNLogType; /** * @version 1.3 * @author TMate Software Ltd. */ public class SVNExportEditor implements ISVNEditor { private File myRoot; private boolean myIsForce; private String myEOLStyle; private File myCurrentDirectory; private File myCurrentFile; private File myCurrentTmpFile; private String myCurrentPath; private Map<String,String> myExternals; private SVNProperties myFileProperties; private ISVNEventHandler myEventDispatcher; private String myURL; private String myRepositoryRootUrl; private ISVNOptions myOptions; private SVNDeltaProcessor myDeltaProcessor; private boolean myIsExpandKeywords; public SVNExportEditor(ISVNEventHandler eventDispatcher, String url, File dstPath, boolean force, String eolStyle, boolean expandKeywords, String repositoryRootUrl, ISVNOptions options) { myRoot = dstPath; myIsForce = force; myEOLStyle = eolStyle; myExternals = new SVNHashMap(); myEventDispatcher = eventDispatcher; myURL = url; myDeltaProcessor = new SVNDeltaProcessor(); myOptions = options; myIsExpandKeywords = expandKeywords; myRepositoryRootUrl = repositoryRootUrl; } public Map<String,String> getCollectedExternals() { return myExternals; } public void openRoot(long revision) throws SVNException { // create root if missing or delete (if force). addDir("", null, -1); } public void addDir(String path, String copyFromPath, long copyFromRevision) throws SVNException { myCurrentDirectory = new File(myRoot, path); myCurrentPath = path; SVNFileType dirType = SVNFileType.getType(myCurrentDirectory); if (dirType == SVNFileType.FILE || dirType == SVNFileType.SYMLINK) { // export is obstructed. if (!myIsForce) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY, "''{0}'' exists and is not a directory", myCurrentDirectory); SVNErrorManager.error(err, SVNLogType.WC); } else { SVNFileUtil.deleteAll(myCurrentDirectory, myEventDispatcher); } } else if (dirType == SVNFileType.DIRECTORY && !myIsForce) { if (!"".equals(path)) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_OBSTRUCTED_UPDATE, "''{0}'' already exists", myCurrentDirectory); SVNErrorManager.error(err, SVNLogType.WC); } File[] children = SVNFileListUtil.listFiles(myCurrentDirectory); if (children != null && children.length > 0) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_OBSTRUCTED_UPDATE, "''{0}'' already exists", myCurrentDirectory); SVNErrorManager.error(err, SVNLogType.WC); } } else if (dirType == SVNFileType.NONE) { if (!myCurrentDirectory.mkdirs()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY, "Cannot create directory ''{0}''", myCurrentDirectory); SVNErrorManager.error(err, SVNLogType.WC); } } myEventDispatcher.handleEvent(SVNEventFactory.createSVNEvent(myCurrentDirectory, SVNNodeKind.DIR, null, SVNRepository.INVALID_REVISION, SVNEventAction.UPDATE_ADD, null, null, null), ISVNEventHandler.UNKNOWN); } public void changeDirProperty(String name, SVNPropertyValue value) throws SVNException { if (SVNProperty.EXTERNALS.equals(name) && value != null) { myExternals.put(myCurrentPath, value.getString()); } } public void closeDir() throws SVNException { myCurrentDirectory = myCurrentDirectory.getParentFile(); myCurrentPath = SVNPathUtil.removeTail(myCurrentPath); } public void addFile(String path, String copyFromPath, long copyFromRevision) throws SVNException { File file = new File(myRoot, path); if (!myIsForce && file.exists()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_OBSTRUCTED_UPDATE, "File ''{0}'' already exists", file); SVNErrorManager.error(err, SVNLogType.WC); } myCurrentFile = file; myFileProperties = new SVNProperties(); myChecksum = null; } public void changeFileProperty(String commitPath, String name, SVNPropertyValue value) throws SVNException { myFileProperties.put(name, value); } public void applyTextDelta(String commitPath, String baseChecksum) throws SVNException { String name = SVNPathUtil.tail(commitPath); myCurrentTmpFile = SVNFileUtil.createUniqueFile(myCurrentDirectory, name, ".tmp", false); myDeltaProcessor.applyTextDelta((File)null, myCurrentTmpFile, true); } public OutputStream textDeltaChunk(String commitPath, SVNDiffWindow diffWindow) throws SVNException { return myDeltaProcessor.textDeltaChunk(diffWindow); } private String myChecksum; public void textDeltaEnd(String commitPath) throws SVNException { myChecksum = myDeltaProcessor.textDeltaEnd(); } public void closeFile(String commitPath, String textChecksum) throws SVNException { if (textChecksum == null) { textChecksum = myFileProperties.getStringValue(SVNProperty.CHECKSUM); } if (myIsForce) { myCurrentFile.delete(); } String realChecksum = myChecksum != null ? myChecksum : SVNFileUtil.computeChecksum(myCurrentTmpFile); myChecksum = null; if (textChecksum != null && !textChecksum.equals(realChecksum)) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CHECKSUM_MISMATCH, "Checksum mismatch for ''{0}''; expected: ''{1}'', actual: ''{2}''", new Object[] {myCurrentFile, textChecksum, realChecksum}); SVNErrorManager.error(err, SVNLogType.WC); } // retranslate. if (!myIsExpandKeywords) { myFileProperties.put(SVNProperty.MIME_TYPE, "application/octet-stream"); } try { String date = myFileProperties.getStringValue(SVNProperty.COMMITTED_DATE); boolean special = myFileProperties.getStringValue(SVNProperty.SPECIAL) != null; String mimeType = myFileProperties.getStringValue(SVNProperty.MIME_TYPE); boolean binary = SVNProperty.isBinaryMimeType(mimeType); String keywords = myFileProperties.getStringValue(SVNProperty.KEYWORDS); Map keywordsMap = null; if (keywords != null) { String url = SVNPathUtil.append(myURL, SVNEncodingUtil.uriEncode(myCurrentPath)); url = SVNPathUtil.append(url, SVNEncodingUtil.uriEncode(myCurrentFile.getName())); String author = myFileProperties.getStringValue(SVNProperty.LAST_AUTHOR); String revStr = myFileProperties.getStringValue(SVNProperty.COMMITTED_REVISION); keywordsMap = SVNTranslator.computeKeywords(keywords, url, myRepositoryRootUrl, author, date, revStr, myOptions); } String charset = SVNTranslator.getCharset(myFileProperties.getStringValue(SVNProperty.CHARSET), mimeType, myCurrentFile.getPath(), myOptions); byte[] eolBytes = null; if (SVNProperty.EOL_STYLE_NATIVE.equals(myFileProperties.getStringValue(SVNProperty.EOL_STYLE))) { eolBytes = SVNTranslator.getEOL(myEOLStyle != null ? myEOLStyle : myFileProperties.getStringValue(SVNProperty.EOL_STYLE), myOptions); } else if (myFileProperties.containsName(SVNProperty.EOL_STYLE)) { eolBytes = SVNTranslator.getEOL(myFileProperties.getStringValue(SVNProperty.EOL_STYLE), myOptions); } if (binary) { // no translation unless 'special'. charset = null; eolBytes = null; keywordsMap = null; } if (charset != null || eolBytes != null || (keywordsMap != null && !keywordsMap.isEmpty()) || special) { SVNTranslator.translate(myCurrentTmpFile, myCurrentFile, charset, eolBytes, keywordsMap, special, true); } else { SVNFileUtil.rename(myCurrentTmpFile, myCurrentFile); } boolean executable = myFileProperties.getStringValue(SVNProperty.EXECUTABLE) != null; if (executable) { SVNFileUtil.setExecutable(myCurrentFile, true); } if (!special && date != null) { SVNFileUtil.setLastModified(myCurrentFile, SVNDate.parseDate(date).getTime()); } myEventDispatcher.handleEvent(SVNEventFactory.createSVNEvent(myCurrentFile, SVNNodeKind.FILE, null, SVNRepository.INVALID_REVISION, SVNEventAction.UPDATE_ADD, null, null, null), ISVNEventHandler.UNKNOWN); } finally { myCurrentTmpFile.delete(); } } public SVNCommitInfo closeEdit() throws SVNException { return null; } public void targetRevision(long revision) throws SVNException { } public void deleteEntry(String path, long revision) throws SVNException { } public void absentDir(String path) throws SVNException { } public void absentFile(String path) throws SVNException { } public void openDir(String path, long revision) throws SVNException { } public void openFile(String path, long revision) throws SVNException { } public void abortEdit() throws SVNException { } }