/* * eXist Open Source Native XML Database * Copyright (C) 2009 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id:$ */ package org.exist.versioning.svn; import static org.junit.Assert.assertNotNull; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Date; import java.util.Map; import org.exist.EXistException; import org.exist.collections.Collection; import org.exist.collections.triggers.TriggerException; import org.exist.dom.BinaryDocument; import org.exist.security.PermissionDeniedException; import org.exist.security.SecurityManager; import org.exist.storage.BrokerPool; import org.exist.storage.DBBroker; import org.exist.storage.txn.TransactionException; import org.exist.storage.txn.TransactionManager; import org.exist.storage.txn.Txn; import org.exist.util.LockException; import org.exist.util.MimeType; import org.exist.xmldb.XmldbURI; 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.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.DefaultSVNOptions; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslator; import org.tmatesoft.svn.core.io.ISVNEditor; import org.tmatesoft.svn.core.io.diff.SVNDeltaProcessor; import org.tmatesoft.svn.core.io.diff.SVNDiffWindow; import org.tmatesoft.svn.core.wc.ISVNOptions; import org.tmatesoft.svn.util.SVNLogType; /** * @author <a href="mailto:shabanovd@gmail.com">Dmitriy Shabanov</a> * */ public class ExportEditor implements ISVNEditor { private XmldbURI rootPath; private Collection myRootDirectory; BrokerPool pool = null; DBBroker broker = null; TransactionManager transact = null; Txn transaction; private SVNProperties fileProperties; private Map dirProperties; private File currentTmpFile; private SVNDeltaProcessor deltaProcessor; private String currentPath; private Collection currentDirectory; private File currentFile; private ISVNOptions options; private String eolStyle = SVNProperty.EOL_STYLE_NATIVE; public ExportEditor(XmldbURI path) throws EXistException { rootPath = path; deltaProcessor = new SVNDeltaProcessor(); options = new DefaultSVNOptions(); dirProperties = new SVNHashMap(); } public void targetRevision(long revision) throws SVNException { System.out.println("targetRevision"); } public void openRoot(long revision) throws SVNException { System.out.println("openRoot"); try { pool = BrokerPool.getInstance(); assertNotNull(pool); broker = pool.get(SecurityManager.SYSTEM_USER); assertNotNull(broker); transact = pool.getTransactionManager(); assertNotNull(transact); myRootDirectory = broker.getCollection(rootPath); currentDirectory = myRootDirectory; transaction = transact.beginTransaction(); } catch (EXistException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: failed to initialize database."); throw new SVNException(err); } } public void addDir(String path, String copyFromPath, long copyFromRevision) throws SVNException { System.out.println("addDir"); currentPath = path; Collection child; try { child = broker.getOrCreateCollection(transaction, myRootDirectory.getURI().append(path)); broker.saveCollection(transaction, child); currentDirectory = child; } catch (PermissionDeniedException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: failed on permission."); throw new SVNException(err); } catch (IOException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: failed on IO."); throw new SVNException(err); } } public void openDir(String path, long revision) throws SVNException { System.out.println("openDir"); currentPath = path; currentDirectory = broker.getCollection(myRootDirectory.getURI().append(path)); } public void changeDirProperty(String name, SVNPropertyValue property) throws SVNException { //UNDERSTAND: should check path? if (SVNProperty.EXTERNALS.equals(name) && property != null) { dirProperties.put(currentPath, property.getString()); } } public void addFile(String path, String copyFromPath, long copyFromRevision) throws SVNException { System.out.println("addFile path = "+path); path = SVNEncodingUtil.uriEncode(path); //TODO: check parent for that resource. // create child resource. currentFile = SVNFileUtil.createTempFile("", ".tmp"); //prefix??? //TODO: "COPY" fileProperties = new SVNProperties(); checksum = null; } public void openFile(String path, long revision) throws SVNException { System.out.println("openFile"); } public void changeFileProperty(String path, String name, SVNPropertyValue property) throws SVNException { //UNDERSTAND: should check path? fileProperties.put(name, property); } /* ************************************* ************* text part ************* *************************************/ private String checksum; public void applyTextDelta(String path, String baseChecksum) throws SVNException { String name = SVNPathUtil.tail(path); currentTmpFile = SVNFileUtil.createTempFile(name, ".tmp"); deltaProcessor.applyTextDelta((File)null, currentTmpFile, true); } public OutputStream textDeltaChunk(String path, SVNDiffWindow diffWindow) throws SVNException { return deltaProcessor.textDeltaChunk(diffWindow); } public void textDeltaEnd(String path) throws SVNException { checksum = deltaProcessor.textDeltaEnd(); } public void closeFile(String path, String textChecksum) throws SVNException { System.out.println(" closeFile"); if (textChecksum == null) { textChecksum = fileProperties.getStringValue(SVNProperty.CHECKSUM); } String realChecksum = checksum != null ? checksum : SVNFileUtil.computeChecksum(currentTmpFile); checksum = null; if (textChecksum != null && !textChecksum.equals(realChecksum)) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CHECKSUM_MISMATCH, "Checksum mismatch for ''{0}''; expected: ''{1}'', actual: ''{2}''", new Object[] {currentFile, textChecksum, realChecksum}); SVNErrorManager.error(err, SVNLogType.WC); } try { String date = fileProperties.getStringValue(SVNProperty.COMMITTED_DATE); boolean special = fileProperties.getStringValue(SVNProperty.SPECIAL) != null; boolean binary = SVNProperty.isBinaryMimeType(fileProperties.getStringValue(SVNProperty.MIME_TYPE)); String keywords = fileProperties.getStringValue(SVNProperty.KEYWORDS); Map keywordsMap = null; // if (keywords != null) { // String url = SVNPathUtil.append(myURL, SVNEncodingUtil.uriEncode(currentPath)); // url = SVNPathUtil.append(url, SVNEncodingUtil.uriEncode(currentFile.getName())); // String author = fileProperties.getStringValue(SVNProperty.LAST_AUTHOR); // String revStr = fileProperties.getStringValue(SVNProperty.COMMITTED_REVISION); // keywordsMap = SVNTranslator.computeKeywords(keywords, url, author, date, revStr, options); // } String charset = SVNTranslator.getCharset(fileProperties.getStringValue(SVNProperty.CHARSET), currentFile.getPath(), options); byte[] eolBytes = null; if (SVNProperty.EOL_STYLE_NATIVE.equals(fileProperties.getStringValue(SVNProperty.EOL_STYLE))) { eolBytes = SVNTranslator.getEOL(eolStyle != null ? eolStyle : fileProperties.getStringValue(SVNProperty.EOL_STYLE), options); } else if (fileProperties.containsName(SVNProperty.EOL_STYLE)) { eolBytes = SVNTranslator.getEOL(fileProperties.getStringValue(SVNProperty.EOL_STYLE), options); } if (binary) { // no translation unless 'special'. charset = null; eolBytes = null; keywordsMap = null; } if (charset != null || eolBytes != null || (keywordsMap != null && !keywordsMap.isEmpty()) || special) { SVNTranslator.translate(currentTmpFile, currentFile, charset, eolBytes, keywordsMap, special, true); } else { SVNFileUtil.rename(currentTmpFile, currentFile); } boolean executable = fileProperties.getStringValue(SVNProperty.EXECUTABLE) != null; if (executable) { SVNFileUtil.setExecutable(currentFile, true); } if (!special && date != null) { currentFile.setLastModified(SVNDate.parseDate(date).getTime()); } InputStream is; try { is = new FileInputStream(currentFile); BinaryDocument doc = currentDirectory.addBinaryResource( transaction, broker, XmldbURI.create(path), is, MimeType.BINARY_TYPE.getName(), (int) currentFile.length(), new Date(), new Date()); is.close(); currentFile.delete(); } catch (FileNotFoundException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: ."); //TODO: error description throw new SVNException(err); } catch (TriggerException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: ."); //TODO: error description throw new SVNException(err); } catch (EXistException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: ."); //TODO: error description throw new SVNException(err); } catch (PermissionDeniedException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: ."); //TODO: error description throw new SVNException(err); } catch (LockException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: ."); //TODO: error description throw new SVNException(err); } catch (IOException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: ."); //TODO: error description throw new SVNException(err); } } finally { currentTmpFile.delete(); } } public void closeDir() throws SVNException { currentDirectory = broker.getCollection(currentDirectory.getParentURI()); currentPath = SVNPathUtil.removeTail(currentPath); } public void deleteEntry(String path, long revision) throws SVNException { System.out.println("deleteEntry"); } public void absentDir(String path) throws SVNException { System.out.println("absentDir"); } public void absentFile(String path) throws SVNException { System.out.println("absentFile"); } public SVNCommitInfo closeEdit() throws SVNException { System.out.println("closeEdit"); try { transact.commit(transaction); } catch (TransactionException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: failed on transaction's commit."); throw new SVNException(err); } return null; } public void abortEdit() throws SVNException { System.out.println("abortEdit"); } }