001: /*
002: * ====================================================================
003: * Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
004: *
005: * This software is licensed as described in the file COPYING, which
006: * you should have received as part of this distribution. The terms
007: * are also available at http://svnkit.com/license.html
008: * If newer versions of this license are posted there, you may use a
009: * newer version instead, at your option.
010: * ====================================================================
011: */
012: package org.tmatesoft.svn.core.internal.io.fs;
013:
014: import java.io.InputStream;
015: import java.util.Iterator;
016: import java.util.LinkedList;
017: import java.util.Map;
018:
019: import org.tmatesoft.svn.core.SVNErrorCode;
020: import org.tmatesoft.svn.core.SVNErrorMessage;
021: import org.tmatesoft.svn.core.SVNException;
022: import org.tmatesoft.svn.core.SVNNodeKind;
023: import org.tmatesoft.svn.core.internal.delta.SVNDeltaCombiner;
024: import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
025: import org.tmatesoft.svn.core.internal.wc.ISVNCommitPathHandler;
026: import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
027: import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
028: import org.tmatesoft.svn.core.io.ISVNEditor;
029: import org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator;
030:
031: /**
032: * @version 1.1.1
033: * @author TMate Software Ltd.
034: */
035: public class FSReplayPathHandler implements ISVNCommitPathHandler {
036:
037: private FSRoot myRoot;
038: private FSRoot myCompareRoot;
039: private Map myChangedPaths;
040: private String myBasePath;
041: private long myLowRevision;
042: private LinkedList myCopies;
043: private FSFS myOwner;
044: private SVNDeltaGenerator myDeltaGenerator;
045: private SVNDeltaCombiner myDeltaCombiner;
046:
047: public FSReplayPathHandler(FSFS owner, FSRoot root,
048: FSRoot compareRoot, Map changedPaths, String basePath,
049: long lowRevision) {
050: myRoot = root;
051: myCompareRoot = compareRoot;
052: myChangedPaths = changedPaths;
053: myBasePath = basePath;
054: myLowRevision = lowRevision;
055: myCopies = new LinkedList();
056: myOwner = owner;
057: myDeltaGenerator = new SVNDeltaGenerator();
058: myDeltaCombiner = new SVNDeltaCombiner();
059: }
060:
061: public boolean handleCommitPath(String path, ISVNEditor editor)
062: throws SVNException {
063: String absPath = !path.startsWith("/") ? "/" + path : path;
064: while (myCopies.size() > 0) {
065: CopyInfo info = (CopyInfo) myCopies.getLast();
066: if (SVNPathUtil.isAncestor(info.myPath, path)) {
067: break;
068: }
069: myCopies.removeLast();
070: }
071:
072: boolean isAdd = false;
073: boolean isDelete = false;
074:
075: FSPathChange change = (FSPathChange) myChangedPaths.get(path);
076: if (change.getChangeKind() == FSPathChangeKind.FS_PATH_CHANGE_ADD) {
077: isAdd = true;
078: } else if (change.getChangeKind() == FSPathChangeKind.FS_PATH_CHANGE_DELETE) {
079: isDelete = true;
080: } else if (change.getChangeKind() == FSPathChangeKind.FS_PATH_CHANGE_REPLACE) {
081: isAdd = true;
082: isDelete = true;
083: }
084:
085: boolean closeDir = false;
086: if (isDelete) {
087: editor.deleteEntry(path, -1);
088: }
089:
090: SVNNodeKind kind = null;
091: if (!isDelete || isAdd) {
092: kind = myRoot.checkNodeKind(absPath);
093: if (kind != SVNNodeKind.DIR && kind != SVNNodeKind.FILE) {
094: SVNErrorMessage err = SVNErrorMessage
095: .create(
096: SVNErrorCode.FS_NOT_FOUND,
097: "Filesystem path ''{0}'' is neither a file nor a directory",
098: path);
099: SVNErrorManager.error(err);
100: }
101: }
102:
103: String copyFromPath = null;
104: String realCopyFromPath = null;
105: FSRoot srcRoot = myCompareRoot;
106: String srcPath = srcRoot != null ? absPath : null;
107: boolean closeFile = false;
108: if (isAdd) {
109: FSRoot copyFromRoot = null;
110: FSRevisionNode copyfromNode = myRoot
111: .getRevisionNode(absPath);
112: copyFromPath = copyfromNode.getCopyFromPath();
113: long copyFromRevision = copyfromNode.getCopyFromRevision();
114: if (copyFromPath != null
115: && FSRepository.isValidRevision(copyFromRevision)) {
116: copyFromRoot = myOwner
117: .createRevisionRoot(copyFromRevision);
118: }
119:
120: realCopyFromPath = copyFromPath;
121:
122: if (copyFromPath != null) {
123: String relCopyFromPath = copyFromPath.substring(1);
124: boolean isWithinBasePath = "".equals(myBasePath)
125: || (relCopyFromPath.startsWith(myBasePath) && (relCopyFromPath
126: .charAt(myBasePath.length()) == '/' || relCopyFromPath
127: .length() == myBasePath.length()));
128: if (!isWithinBasePath
129: || myLowRevision > copyFromRevision) {
130: copyFromPath = null;
131: copyFromRevision = -1;
132: }
133: }
134:
135: if (kind == SVNNodeKind.DIR) {
136: if (realCopyFromPath != null && copyFromPath == null) {
137: addSubdirectory(copyFromRoot, myRoot, editor,
138: realCopyFromPath, path);
139: } else {
140: editor.addDir(path, copyFromPath, copyFromRevision);
141: }
142: closeDir = true;
143: } else {
144: editor.addFile(path, copyFromPath, copyFromRevision);
145: closeFile = true;
146: }
147:
148: if (copyFromPath != null) {
149: if (kind == SVNNodeKind.DIR) {
150: CopyInfo info = new CopyInfo(path, copyFromPath,
151: copyFromRevision);
152: myCopies.addLast(info);
153: }
154: srcRoot = copyFromRoot;
155: srcPath = copyFromPath;
156: } else {
157: if (kind == SVNNodeKind.DIR && myCopies.size() > 0) {
158: CopyInfo info = new CopyInfo(path, null, -1);
159: myCopies.addLast(info);
160: }
161: srcRoot = null;
162: srcPath = null;
163: }
164: } else if (!isDelete) {
165: if (kind == SVNNodeKind.DIR) {
166: if ("".equals(path)) {
167: editor.openRoot(-1);
168: } else {
169: editor.openDir(path, -1);
170: }
171: closeDir = true;
172: } else {
173: editor.openFile(path, -1);
174: closeFile = true;
175: }
176:
177: if (myCopies.size() > 0) {
178: CopyInfo info = (CopyInfo) myCopies.getLast();
179: if (info.myCopyFromPath != null) {
180: srcRoot = myOwner
181: .createRevisionRoot(info.myCopyFromRevision);
182: srcPath = SVNPathUtil.append(info.myCopyFromPath,
183: SVNPathUtil.pathIsChild(info.myPath, path));
184: } else {
185: srcRoot = null;
186: srcPath = null;
187: }
188: }
189: }
190:
191: if (!isDelete || isAdd) {
192: if (change.arePropertiesModified()) {
193: if (myCompareRoot != null) {
194: Map oldProps = null;
195: if (srcRoot != null) {
196: FSRevisionNode srcNode = srcRoot
197: .getRevisionNode(srcPath);
198: oldProps = srcNode.getProperties(myOwner);
199: }
200:
201: FSRevisionNode node = myRoot
202: .getRevisionNode(absPath);
203: Map newProps = node.getProperties(myOwner);
204: Map propDiff = FSRepositoryUtil.getPropsDiffs(
205: oldProps, newProps);
206: for (Iterator propNames = propDiff.keySet()
207: .iterator(); propNames.hasNext();) {
208: String propName = (String) propNames.next();
209: String propValue = (String) propDiff
210: .get(propName);
211: if (kind == SVNNodeKind.DIR) {
212: editor.changeDirProperty(propName,
213: propValue);
214: } else if (kind == SVNNodeKind.FILE) {
215: editor.changeFileProperty(path, propName,
216: propValue);
217: }
218: }
219: } else {
220: if (kind == SVNNodeKind.DIR) {
221: editor.changeDirProperty("", null);
222: } else if (kind == SVNNodeKind.FILE) {
223: editor.changeFileProperty(path, "", null);
224: }
225: }
226: }
227:
228: if (kind == SVNNodeKind.FILE
229: && (change.isTextModified() || (realCopyFromPath != null && copyFromPath == null))) {
230: String checksum = null;
231: if (myCompareRoot != null && srcRoot != null
232: && srcPath != null) {
233: FSRevisionNode node = srcRoot
234: .getRevisionNode(srcPath);
235: checksum = node.getFileChecksum();
236: }
237:
238: editor.applyTextDelta(path, checksum);
239: if (myCompareRoot != null) {
240: InputStream sourceStream = null;
241: InputStream targetStream = null;
242: try {
243: if (srcRoot != null && srcPath != null) {
244: sourceStream = srcRoot
245: .getFileStreamForPath(
246: myDeltaCombiner, srcPath);
247: } else {
248: sourceStream = SVNFileUtil.DUMMY_IN;
249: }
250: targetStream = myRoot.getFileStreamForPath(
251: myDeltaCombiner, absPath);
252: myDeltaGenerator.sendDelta(path, sourceStream,
253: 0, targetStream, editor, false);
254: } finally {
255: SVNFileUtil.closeFile(sourceStream);
256: SVNFileUtil.closeFile(targetStream);
257: }
258: }
259: }
260: }
261:
262: if (closeFile) {
263: FSRevisionNode node = myRoot.getRevisionNode(absPath);
264: editor.closeFile(path, node.getFileChecksum());
265: }
266: return closeDir;
267: }
268:
269: private void addSubdirectory(FSRoot srcRoot, FSRoot tgtRoot,
270: ISVNEditor editor, String srcPath, String path)
271: throws SVNException {
272: editor.addDir(path, null, -1);
273: FSRevisionNode node = srcRoot.getRevisionNode(srcPath);
274:
275: Map props = node.getProperties(myOwner);
276: for (Iterator propNames = props.keySet().iterator(); propNames
277: .hasNext();) {
278: String propName = (String) propNames.next();
279: String propValue = (String) props.get(propName);
280: editor.changeDirProperty(propName, propValue);
281: }
282:
283: Map entries = node.getDirEntries(myOwner);
284: for (Iterator entryNames = entries.keySet().iterator(); entryNames
285: .hasNext();) {
286: String entryName = (String) entryNames.next();
287: FSEntry entry = (FSEntry) entries.get(entryName);
288: String newPath = SVNPathUtil.append(path, entry.getName());
289:
290: if (entry.getType() == SVNNodeKind.DIR) {
291: addSubdirectory(srcRoot, tgtRoot, editor, SVNPathUtil
292: .append(srcPath, entry.getName()), newPath);
293: editor.closeDir();
294: } else if (entry.getType() == SVNNodeKind.FILE) {
295: editor.addFile(SVNPathUtil
296: .append(path, entry.getName()), null, -1);
297: String newSrcPath = SVNPathUtil.append(srcPath, entry
298: .getName());
299: FSRevisionNode srcNode = srcRoot
300: .getRevisionNode(newSrcPath);
301:
302: props = srcNode.getProperties(myOwner);
303: for (Iterator propNames = props.keySet().iterator(); propNames
304: .hasNext();) {
305: String propName = (String) propNames.next();
306: String propValue = (String) props.get(propName);
307: editor.changeFileProperty(newPath, propName,
308: propValue);
309: }
310:
311: editor.applyTextDelta(newPath, null);
312:
313: InputStream targetStream = null;
314: try {
315: targetStream = srcRoot.getFileStreamForPath(
316: myDeltaCombiner, newSrcPath);
317: myDeltaGenerator.sendDelta(newPath,
318: SVNFileUtil.DUMMY_IN, 0, targetStream,
319: editor, false);
320: } finally {
321: SVNFileUtil.closeFile(targetStream);
322: }
323: String checksum = srcNode.getFileChecksum();
324: editor.closeFile(newPath, checksum);
325: }
326:
327: }
328: }
329:
330: private class CopyInfo {
331: String myCopyFromPath;
332: long myCopyFromRevision;
333: String myPath;
334:
335: public CopyInfo(String path, String copyFromPath,
336: long copyFromRevision) {
337: myPath = path;
338: myCopyFromPath = copyFromPath;
339: myCopyFromRevision = copyFromRevision;
340: }
341: }
342: }
|