Package org.tmatesoft.svn.core.internal.wc

Source Code of org.tmatesoft.svn.core.internal.wc.SVNExtendedMergeEditor$MergeTarget

/*
* ====================================================================
* Copyright (c) 2004-2009 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.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Stack;

import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.SVNMergeRangeList;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
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.SVNVersionedProperties;
import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess;
import org.tmatesoft.svn.core.io.ISVNDeltaConsumer;
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.SVNCopySource;
import org.tmatesoft.svn.core.wc.SVNEditorAction;
import org.tmatesoft.svn.core.wc.SVNStatusType;
import org.tmatesoft.svn.core.wc.SVNEventAction;
import org.tmatesoft.svn.core.wc.SVNCopyTask;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.util.SVNLogType;
import org.tmatesoft.svn.util.SVNDebugLog;

/**
* @author TMate Software Ltd.
* @version 1.3
*/
public class SVNExtendedMergeEditor extends SVNRemoteDiffEditor {

    private ISVNExtendedMergeCallback myMergeCallback;
    private SVNExtendedMergeDriver myMergeDriver;
    private SVNWCAccess myWCAccess;
    private SVNDepth myDepth;

    private SVNURL mySourceURL;
    private SVNURL myTargetURL;

    private Stack myDirectories;

    public SVNExtendedMergeEditor(SVNExtendedMergeDriver mergeDriver, ISVNExtendedMergeCallback mergeCallback, SVNAdminArea adminArea, File target, AbstractDiffCallback callback,
                                  SVNURL sourceURL, SVNRepository repos, long revision1, long revision2, boolean dryRun, SVNDepth depth, ISVNEventHandler handler,
                                  ISVNEventHandler cancelHandler) throws SVNException {
        super(adminArea, target, callback, repos, revision1, revision2, dryRun, handler, cancelHandler);

        SVNEntry rootEntry = adminArea.getEntry(adminArea.getThisDirName(), false);
        String url = rootEntry.getURL();
        myWCAccess = adminArea.getWCAccess();
        myDepth = depth;
        myTargetURL = SVNURL.parseURIEncoded(url);
        myMergeCallback = mergeCallback;
        myMergeDriver = mergeDriver;
        mySourceURL = sourceURL;

        myDirectories = new Stack();
    }

    public ISVNExtendedMergeCallback getMergeCallback() {
        return myMergeCallback;
    }

    public SVNExtendedMergeDriver getMergeDriver() {
        return myMergeDriver;
    }

    protected File getTempDirectory() throws SVNException {
        return getMergeDriver().getTempDirectory();
    }

    protected Stack getDirectories() {
        return myDirectories;
    }

    protected boolean checkDepth(File path, SVNEntry entry, SVNNodeKind kind) throws SVNException {
        if (path.equals(myTarget)) {
            return true;
        }
        boolean reportDepthAllows = checkReportDepth(path, kind);
        if (!reportDepthAllows) {
            return false;
        }
        return checkSparseWC(path, entry, kind);
    }

    private boolean checkReportDepth(File path, SVNNodeKind kind) {
        if (myDepth == SVNDepth.EMPTY) {
            return false;
        }
        if ((myDepth == SVNDepth.IMMEDIATES || myDepth == SVNDepth.FILES) && !myTarget.equals(path.getParentFile())) {
            return false;
        }
        if (myDepth == SVNDepth.FILES && kind == SVNNodeKind.DIR) {
            return false;
        }
        return true;
    }

    private boolean checkSparseWC(File path, SVNEntry entry, SVNNodeKind kind) throws SVNException {
        if (entry != null) {
            return true;
        }
        entry = myWCAccess.getEntry(path, true);
        if (entry != null) {
            return true;
        }
        File parentPath = path.getParentFile();
        SVNEntry parentEntry = myWCAccess.getEntry(parentPath, true);
        if (parentEntry != null) {
            SVNDepth parentDepth = parentEntry.getDepth();
            return checkEntryDepth(parentDepth, kind);
        }
        return walkToTarget(parentPath);
    }

    private boolean walkToTarget(File path) throws SVNException {
        if (myTarget.equals(path)) {
            return true;
        }
        File parentPath = path.getParentFile();
        SVNEntry parentEntry = myWCAccess.getEntry(parentPath, true);
        if (parentEntry != null) {
            SVNDepth parentDepth = parentEntry.getDepth();
            return checkEntryDepth(parentDepth, SVNNodeKind.DIR);
        }
        return walkToTarget(parentPath);
    }

    private static boolean checkEntryDepth(SVNDepth parentDepth, SVNNodeKind kind) {
        if (parentDepth == SVNDepth.EMPTY) {
            return false;
        }
        if (parentDepth == SVNDepth.FILES && kind != SVNNodeKind.FILE) {
            return false;
        }
        return true;
    }

    public void deleteEntry(String path, long revision) throws SVNException {
        SVNNodeKind nodeKind = myRepos.checkPath(path, myRevision1);
        SVNAdminArea dir = retrieve(myCurrentDirectory.myWCFile, true);
        if (nodeKind != SVNNodeKind.FILE) {
            deleteEntry(path, nodeKind, dir);
            return;
        }

        long targetRevision = getTargetRevision(path);
        SVNURL[] targets = getMergeCallback().getTrueMergeTargets(getSourceURL(path), myRevision1, myRevision1, myRevision2, getTargetURL(path), targetRevision, SVNEditorAction.DELETE);

        if (targets == null) {
            deleteEntry(path, nodeKind, dir);
            return;
        }

        SVNFileInfoExt fileInfo = null;
        File expectedTarget = getFile(path);
        for (int i = 0; i < targets.length; i++) {
            SVNURL targetURL = targets[i];
            String targetPath = getPath(targetURL);
            File target = getFile(targetPath);

            if (!expectedTarget.equals(target)) {
                boolean depthAllows = checkDepth(target, null, nodeKind);
                if (!depthAllows) {
                    continue;
                }
            }

            fileInfo = getFileInfo(path, revision, SVNEditorAction.DELETE, nodeKind);
            fileInfo.addTarget(targetPath, null);
        }

        if (fileInfo != null) {
            fileInfo.delete();
        }
        myCurrentFile = null;
    }

    private File getCopySourcePath(SVNCopySource source) {
        if (source == null) {
            return null;
        }
        if (!source.isURL()) {
            return source.getFile();
        }
        File target = null;
        String sPath = SVNPathUtil.getPathAsChild(mySourceURL.getPath(), source.getURL().getPath());
        String tPath = SVNPathUtil.getPathAsChild(myTargetURL.getPath(), source.getURL().getPath());
        if (sPath != null) {
            target = getFile(sPath);
        } else if (tPath != null) {
            target = getFile(tPath);
        } else {
            SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, "merge ext: Neither merge source URL nor merge target URL are not ancestors of copy source URL");
        }
        return target;
    }

    private SVNURL getCopySourceURL(SVNCopySource source) throws SVNException {
        if (source == null) {
            return null;
        }
        if (source.isURL()) {
            return source.getURL();
        }
        String relativePath = SVNPathUtil.getPathAsChild(myTarget.getAbsolutePath(), source.getFile().getAbsolutePath());
        if (relativePath == null) {
            SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, "merge ext: illegal file path passed as copy source");
            return null;
        }
        return myTargetURL.appendPath(relativePath, false);
    }

    private void deletePath(File file) throws SVNException {
        if (file == null) {
            return;
        }
        String path = getPath(file);
        SVNStatusType type = SVNStatusType.INAPPLICABLE;
        SVNEventAction action = SVNEventAction.SKIP;
        SVNEventAction expectedAction = SVNEventAction.UPDATE_DELETE;

        SVNEntry entry = myWCAccess.getEntry(file, false);
        if (entry == null) {
            return;
        }
        SVNNodeKind nodeKind = entry.getKind();
        SVNAdminArea dir = retrieve(myCurrentDirectory.myWCFile, true);

        if (dir != null) {
            if (nodeKind == SVNNodeKind.FILE) {
                SVNVersionedProperties baseProperties = dir.getBaseProperties(file.getName());
                String baseType = baseProperties.getStringPropertyValue(SVNProperty.MIME_TYPE);
                File baseFile = dir.getBaseFile(file.getName(), false);
                SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, "merge ext: del " + path);
                type = getDiffCallback().fileDeleted(path, baseFile, null, baseType, null, baseProperties.asMap(), null);
            } else if (nodeKind == SVNNodeKind.DIR) {
                SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, "merge ext: attempt to delete directory " + path + " skipped");
            }
            if (type != SVNStatusType.MISSING && type != SVNStatusType.OBSTRUCTED) {
                action = SVNEventAction.UPDATE_DELETE;
                if (myIsDryRun) {
                    getDiffCallback().addDeletedPath(path);
                }
            }
        }
        addDeletedPath(path, nodeKind, type, action, expectedAction);
    }

    protected void addDeletedPath(String path, SVNNodeKind nodeKind, SVNStatusType type, SVNEventAction action, SVNEventAction expectedAction) {
        if (myEventHandler != null) {
            File deletedFile = getFile(path);
            KindActionState kas = (KindActionState) myDeletedPaths.get(deletedFile);
            if (kas != null) {
                if (action == SVNEventAction.SKIP && (kas.myAction == SVNEventAction.UPDATE_DELETE || kas.myAction == SVNEventAction.SKIP)) {
                    return;
                }
            }
        }
        super.addDeletedPath(path, nodeKind, type, action, expectedAction, false);
    }

    public void addFile(String path, String copyFromPath, long copyFromRevision) throws SVNException {
        SVNURL url = getSourceURL(path);
        SVNURL expectedTargetURL = getTargetURL(path);
        long targetRevision = getTargetRevision(path);
        SVNURL[] mergeURLs = getMergeCallback().getTrueMergeTargets(url, Math.max(myRevision1, myRevision2), myRevision1, myRevision2, expectedTargetURL, targetRevision, SVNEditorAction.ADD);

        if (mergeURLs == null) {
            super.addFile(path, copyFromPath, copyFromRevision);
            return;
        }

        for (int i = 0; i < mergeURLs.length; i++) {
            SVNURL targetURL = mergeURLs[i];
            String targetPath = getPath(targetURL);
            File target = getFile(targetPath);


            if (!expectedTargetURL.equals(targetURL)) {
                boolean depthAllows = checkDepth(target, null, SVNNodeKind.FILE);
                if (!depthAllows) {
                    continue;
                }
            }

            SVNURL[] mergeSources = new SVNURL[2];
            SVNMergeRangeList remainingRanges = getMergeDriver().calculateRemainingRanges(target, url, mergeSources);
            boolean mergeInfoConflicts = getMergeDriver().mergeInfoConflicts(remainingRanges, target);
            SVNCopyTask copyTask = getMergeCallback().getTargetCopySource(url, Math.max(myRevision1, myRevision2), myRevision1, myRevision2, targetURL, targetRevision);
            SVNCopySource copySource = copyTask == null ? null : copyTask.getCopySource();
            copySource = processCopySource(copySource, targetRevision);
            boolean deleteSource = copyTask != null && copyTask.isMove();

            if (deleteSource) {
                File deleteTarget = getCopySourcePath(copySource);
                boolean depthAllows = checkDepth(deleteTarget, null, SVNNodeKind.FILE);
                if (depthAllows) {
                    deletePath(deleteTarget);
                }
            }

            SVNEntry targetEntry = myWCAccess.getEntry(target, true);
            boolean targetExists = targetEntry != null && !targetEntry.isScheduledForDeletion();
            boolean applyDelta;

            if (targetExists) {
                getMergeDriver().addMergeSource(path, mergeSources, target, remainingRanges, mergeInfoConflicts, copySource);
                applyDelta = false;
            } else {
                applyDelta = true;
            }

            if (applyDelta) {
                SVNFileInfoExt fileInfo = getFileInfo(path, -1, SVNEditorAction.ADD, null);
                fileInfo.addTarget(targetPath, copySource);
            }
        }
    }

    public void openFile(String path, long revision) throws SVNException {
        SVNURL url = getSourceURL(path);
        SVNURL expectedTargetURL = getTargetURL(path);
        long targetRevision = getTargetRevision(path);
        SVNURL[] mergeURLs = getMergeCallback().getTrueMergeTargets(url, Math.max(myRevision1, myRevision2), myRevision1, myRevision2, getTargetURL(path), targetRevision, SVNEditorAction.MODIFY);

        if (mergeURLs == null) {
            super.openFile(path, revision);
            return;
        }

        for (int i = 0; i < mergeURLs.length; i++) {
            SVNURL targetURL = mergeURLs[i];
            String targetPath = getPath(targetURL);
            File target = getFile(targetPath);

            if (!expectedTargetURL.equals(targetURL)) {
                boolean depthAllows = checkDepth(target, null, SVNNodeKind.FILE);
                if (!depthAllows) {
                    continue;
                }
            }

            SVNURL[] mergeSources = new SVNURL[2];
            SVNMergeRangeList remainingRanges = getMergeDriver().calculateRemainingRanges(target, url, mergeSources);
            boolean mergeInfoConflicts = getMergeDriver().mergeInfoConflicts(remainingRanges, target);
            SVNCopyTask copyTask = getMergeCallback().getTargetCopySource(url, Math.max(myRevision1, myRevision2), myRevision1, myRevision2, targetURL, targetRevision);
            SVNCopySource copySource = copyTask == null ? null : copyTask.getCopySource();
            copySource = processCopySource(copySource, targetRevision);
            boolean deleteSource = copyTask != null && copyTask.isMove();

            if (deleteSource) {
                File deleteTarget = getCopySourcePath(copySource);
                boolean depthAllows = checkDepth(deleteTarget, null, SVNNodeKind.FILE);
                if (depthAllows) {
                    deletePath(deleteTarget);
                }
            }

            SVNEntry targetEntry = myWCAccess.getEntry(target, true);
            boolean targetExists = targetEntry != null && !targetEntry.isScheduledForDeletion();
            boolean applyDelta;

            if (targetExists) {
                if (mergeInfoConflicts) {
                    getMergeDriver().addMergeSource(path, mergeSources, target, remainingRanges, true, copySource);
                    applyDelta = false;
                } else {
                    applyDelta = true;
                }
            } else {
                if (copySource != null) {
                    getMergeDriver().copy(copySource, target, false);
                }
                applyDelta = true;
            }

            if (applyDelta) {
                SVNFileInfoExt fileInfo = getFileInfo(path, revision, SVNEditorAction.MODIFY, null);
                fileInfo.addTarget(targetPath, copySource);
            }
        }
    }

    private SVNCopySource processCopySource(SVNCopySource copySource, long targetRevision) throws SVNException {
        if (copySource == null) {
            return null;
        }
        if (copySource.isURL() && (copySource.getRevision() != null && copySource.getRevision().getID() == 10)) {
            return copySource;
        }

        SVNRevision pegRevision;
        SVNRevision revision;
        try {
            pegRevision = processCopySourceRevision(copySource.getPegRevision(), copySource, targetRevision);
            revision = processCopySourceRevision(copySource.getRevision(), copySource, targetRevision);
        } catch (SVNException e) {
            SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, "merge ext: Error while fetching copy source revision");
            return null;
        }

        SVNURL url = copySource.getURL();
        if (url == null) {
            url = getCopySourceURL(copySource);
            if (url == null) {
                return null;
            }
        }
        return new SVNCopySource(pegRevision, revision, url);
    }

    private SVNRevision processCopySourceRevision(SVNRevision revision, SVNCopySource copySource, long targetRevision) throws SVNException {
        if (revision.getID() == 10) {
            return revision;
        }
        if (revision == SVNRevision.WORKING || revision == SVNRevision.BASE) {
            return SVNRevision.create(targetRevision);
        }
        return SVNRevision.create(getMergeDriver().getRevision(copySource));
    }

    private long getTargetRevision(String path) throws SVNException {
        File file = getFile(path);
        SVNEntry entry = myWCAccess.getEntry(file, true);
        return calculateTargetRevision(myWCAccess, entry, file);
    }

    public void openDir(String path, long revision) throws SVNException {
        super.openDir(path, revision);
        processDir(path, false);
    }

    public void addDir(String path, String copyFromPath, long copyFromRevision) throws SVNException {
        super.addDir(path, copyFromPath, copyFromRevision);
        processDir(path, true);
    }

    private void processDir(String path, boolean remoteAdd) throws SVNException {
        File dir = getFile(path);
        SVNEntry dirEntry = myWCAccess.getEntry(dir, true);

        long dirRevision = calculateTargetRevision(myWCAccess, dirEntry, dir);
        boolean skipped = dirEntry == null;
        boolean added = dirEntry != null && (dirEntry.isScheduledForAddition() || dirEntry.isScheduledForReplacement());

        if (skipped || added) {
            SVNDirectoryInfoExt dirInfo = new SVNDirectoryInfoExt(dirRevision);
            dirInfo.myAdded = added;
            dirInfo.myRemotelyAdded = remoteAdd;
            dirInfo.mySkipped = skipped;
            getDirectories().push(dirInfo);
        }
    }

    private long calculateTargetRevision(SVNWCAccess access, SVNEntry entry, File path) throws SVNException {
        long targetRevision;
        if (entry == null) {
            if (getDirectories().empty()) {
                SVNEntry parentEntry = access.getEntry(path.getParentFile(), true);
                checkParentEntry(path, parentEntry);
                targetRevision = parentEntry.getRevision();
            } else {
                SVNDirectoryInfoExt parentDirInfo = (SVNDirectoryInfoExt) getDirectories().peek();
                targetRevision = parentDirInfo.myRevision;
            }
        } else {
            targetRevision = entry.getRevision();
            if (entry.isScheduledForAddition() || entry.isScheduledForReplacement()) {
                if (getDirectories().empty()) {
                    SVNEntry parentEntry = access.getEntry(path.getParentFile(), true);
                    checkParentEntry(path, parentEntry);
                    targetRevision = parentEntry.getRevision();
                } else {
                    SVNDirectoryInfoExt parentDirInfo = (SVNDirectoryInfoExt) getDirectories().peek();
                    targetRevision = parentDirInfo.myRevision;
                }
            }
        }
        return targetRevision;
    }

    private static void checkParentEntry(File path, SVNEntry parentEntry) throws SVNException {
        if (parentEntry == null) {
            SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.ENTRY_NOT_FOUND, "Parent directory of ''{0}'' is unexpectedly unversioned", path);
            SVNErrorManager.error(error, SVNLogType.WC);
        }
        if (parentEntry.isScheduledForAddition() || parentEntry.isScheduledForReplacement()) {
            SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.ENTRY_ATTRIBUTE_INVALID, "Parent directory of ''{0}'' unexpectedly scheduled for ''{1}''", new Object[]{path, parentEntry.getSchedule()});
            SVNErrorManager.error(error, SVNLogType.WC);
        }
    }

    public void closeDir() throws SVNException {
        super.closeDir();

        if (!getDirectories().empty()) {
            getDirectories().pop();
        }
    }

    private SVNFileInfoExt getFileInfo(String path, long revision, SVNEditorAction action, SVNNodeKind kind) throws SVNException {
        if (myCurrentFile == null) {
            myCurrentFile = createFileInfo(path, action, kind);
            if (action == SVNEditorAction.ADD) {
                myCurrentFile.myBaseProperties = new SVNProperties();
                myCurrentFile.myBaseFile = SVNFileUtil.createUniqueFile(getTempDirectory(), ".diff", ".tmp", false);
            } else if (action == SVNEditorAction.MODIFY) {
                myCurrentFile.loadFromRepository(revision);
            }
        }
        return (SVNFileInfoExt) myCurrentFile;
    }

    public void changeFileProperty(String commitPath, String name, SVNPropertyValue value) throws SVNException {
        if (myCurrentFile == null) {
            return;
        }
        myCurrentFile.myPropertyDiff.put(name, value);
    }

    public void applyTextDelta(String commitPath, String baseChecksum) throws SVNException {
        if (myCurrentFile == null) {
            return;
        }
        if (myCurrentFile instanceof SVNFileInfoExt) {
            SVNFileInfoExt fileInfo = (SVNFileInfoExt) myCurrentFile;
            fileInfo.applyTextDelta(commitPath, baseChecksum);
        } else {
            super.applyTextDelta(commitPath, baseChecksum);
        }
    }

    public OutputStream textDeltaChunk(String commitPath, SVNDiffWindow diffWindow) throws SVNException {
        if (myCurrentFile == null) {
            return SVNFileUtil.DUMMY_OUT;
        }
        if (myCurrentFile instanceof SVNFileInfoExt) {
            SVNFileInfoExt fileInfo = (SVNFileInfoExt) myCurrentFile;
            return fileInfo.textDeltaChunk(commitPath, diffWindow);
        }
        return super.textDeltaChunk(commitPath, diffWindow);
    }

    public void textDeltaEnd(String commitPath) throws SVNException {
        if (myCurrentFile == null) {
            return;
        }
        if (myCurrentFile instanceof SVNFileInfoExt) {
            SVNFileInfoExt fileInfo = (SVNFileInfoExt) myCurrentFile;
            fileInfo.textDeltaEnd(commitPath);
        } else {
            super.textDeltaEnd(commitPath);
        }
    }

    public void closeFile(String commitPath, String textChecksum) throws SVNException {
        if (myCurrentFile == null) {
            return;
        }
        if (myCurrentFile instanceof SVNFileInfoExt) {
            SVNFileInfoExt fileInfo = (SVNFileInfoExt) myCurrentFile;
            fileInfo.close();
        } else {
            super.closeFile(commitPath, textChecksum);
        }
        myCurrentFile = null;
    }

    private SVNURL getSourceURL(String path) throws SVNException {
        return mySourceURL.appendPath(path, false);
    }

    private SVNURL getTargetURL(String path) throws SVNException {
        return myTargetURL.appendPath(path, false);
    }

    private File getFile(String path) {
        return new File(myTarget, path);
    }

    private String getPath(SVNURL target) {
        return SVNPathUtil.getRelativePath(myTargetURL.getPath(), target.getPath());
    }

    private String getPath(File path) {
        return SVNPathUtil.getRelativePath(myTarget.getAbsolutePath(), path.getAbsolutePath());
    }

    protected SVNFileInfoExt createFileInfo(String path, SVNEditorAction action, SVNNodeKind kind) {
        return new SVNFileInfoExt(path, action == SVNEditorAction.ADD, action, kind);
    }

    protected class SVNDirectoryInfoExt {

        protected long myRevision;
        protected boolean myAdded;
        protected boolean myRemotelyAdded;
        protected boolean mySkipped;

        public SVNDirectoryInfoExt(long revision) {
            myRevision = revision;
        }
    }

    protected class SVNFileInfoExt extends SVNFileInfo implements ISVNDeltaConsumer {

        protected SVNEditorAction myAction;
        protected Collection myTargets;
        protected SVNNodeKind myKind;
        protected boolean myIsLoaded;

        protected SVNFileInfoExt(String path, boolean added, SVNEditorAction action, SVNNodeKind nodeKind) {
            super(path, added);
            myAction = action;
            myKind = nodeKind;
        }

        public void loadFromRepository(long revision) throws SVNException {
            if (!myIsLoaded) {
                super.loadFromRepository(revision);
                myIsLoaded = true;
            }
        }

        protected SVNNodeKind getNodeKind() throws SVNException {
            if (myKind == null) {
                myKind = myRepos.checkPath(myRepositoryPath, myRevision1);
            }
            return myKind;
        }

        protected Collection getTargets() {
            if (myTargets == null) {
                myTargets = new ArrayList();
            }
            return myTargets;
        }

        protected void addTarget(String targetPath, SVNCopySource copySource) {
            SVNDeltaProcessor processor;
            if (myAction == SVNEditorAction.DELETE) {
                processor = null;
            } else {
                processor = getTargets().size() == 0 ? myDeltaProcessor : new SVNDeltaProcessor();
            }
            MergeTarget target = new MergeTarget(targetPath, processor, copySource);
            SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, "ext merge: " + target.toString());
            getTargets().add(target);
        }

        public void applyTextDelta(String path, String baseChecksum) throws SVNException {
            if (myTargets == null || myTargets.isEmpty()) {
                return;
            }
            for (Iterator iterator = getTargets().iterator(); iterator.hasNext();) {
                MergeTarget target = (MergeTarget) iterator.next();
                target.applyTextDelta(path, baseChecksum);
            }
        }

        public OutputStream textDeltaChunk(String path, SVNDiffWindow diffWindow) throws SVNException {
            if (myTargets == null || myTargets.isEmpty()) {
                return SVNFileUtil.DUMMY_OUT;
            }
            for (Iterator iterator = getTargets().iterator(); iterator.hasNext();) {
                MergeTarget target = (MergeTarget) iterator.next();
                target.textDeltaChunk(path, diffWindow);
            }
            return SVNFileUtil.DUMMY_OUT;
        }

        public void textDeltaEnd(String path) throws SVNException {
            if (myTargets == null || myTargets.isEmpty()) {
                return;
            }
            for (Iterator iterator = getTargets().iterator(); iterator.hasNext();) {
                MergeTarget target = (MergeTarget) iterator.next();
                target.textDeltaEnd(path);
            }
        }

        protected void close() throws SVNException {
            if (myTargets == null || myTargets.isEmpty()) {
                return;
            }
            for (Iterator iterator = getTargets().iterator(); iterator.hasNext();) {
                MergeTarget target = (MergeTarget) iterator.next();
                target.close();
            }
        }

        protected void delete() throws SVNException {
            if (myTargets == null || myTargets.isEmpty()) {
                return;
            }
            for (Iterator iterator = getTargets().iterator(); iterator.hasNext();) {
                MergeTarget target = (MergeTarget) iterator.next();
                target.delete();
            }
        }
    }

    protected class MergeTarget implements ISVNDeltaConsumer {

        private SVNDeltaProcessor myTargetProcessor;
        private String myPath;
        private File myWCFile;
        private File myFile;
        private SVNCopySource myCopySource;

        public MergeTarget(String path, SVNDeltaProcessor targetProcessor, SVNCopySource copySource) {
            myPath = path;
            myWCFile = myTarget == null ? null : new File(myTarget, path);
            myTargetProcessor = targetProcessor;
            myCopySource = copySource;
        }

        private SVNDeltaProcessor getDeltaProcessor() {
            return myTargetProcessor;
        }

        public void applyTextDelta(String path, String baseChecksum) throws SVNException {
            SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, "ext merge: apply delta " + myPath);
            SVNAdminArea dir;
            try {
                dir = retrieveParent(myWCFile, true);
            } catch (SVNException e) {
                dir = null;
            }
            myFile = createTempFile(dir, SVNPathUtil.tail(myPath));
            getDeltaProcessor().applyTextDelta(myCurrentFile.myBaseFile, myFile, false);
        }

        public OutputStream textDeltaChunk(String path, SVNDiffWindow diffWindow) throws SVNException {
            SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, "ext merge: delta chunk " + myPath);
            return getDeltaProcessor().textDeltaChunk(diffWindow);
        }

        public void textDeltaEnd(String path) throws SVNException {
            SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, "ext merge: delta end " + myPath);
            getDeltaProcessor().textDeltaEnd();
        }

        protected void close() throws SVNException {
            SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, "ext merge: close " + myPath);
            closeFile(myPath, myCurrentFile.myIsAdded, myWCFile, myFile, myCurrentFile.myPropertyDiff, myCurrentFile.myBaseProperties,
                    myCurrentFile.myBaseFile, null);

            if (myCopySource == null) {
                return;
            }

            SVNEntry targetEntry = myWCAccess.getEntry(myWCFile, false);
            if (targetEntry != null) {
                SVNURL copyFromLocation = targetEntry.getCopyFromSVNURL();
                long copyFromRevision = targetEntry.getCopyFromRevision();

                SVNURL sourceURL = myCopySource.getURL();
                long sourceRevision = myCopySource.getRevision().getNumber();
                if (copyFromLocation == null || !copyFromLocation.equals(sourceURL) || copyFromRevision != sourceRevision) {
                    getMergeDriver().copy(myCopySource, myWCFile, true);
                }
            }
        }

        protected void delete() throws SVNException {
            SVNStatusType type = SVNStatusType.INAPPLICABLE;
            SVNEventAction action = SVNEventAction.SKIP;
            SVNEventAction expectedAction = SVNEventAction.UPDATE_DELETE;

            SVNFileInfoExt fileInfo = (SVNFileInfoExt) myCurrentFile;
            final SVNNodeKind nodeKind = fileInfo.getNodeKind();

            SVNAdminArea dir = retrieveParent(myWCFile, true);
            if (myAdminArea == null || dir != null) {
                if (nodeKind == SVNNodeKind.FILE) {
                    fileInfo.loadFromRepository(myRevision1);
                    String baseType = fileInfo.myBaseProperties.getStringValue(SVNProperty.MIME_TYPE);
                    SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, "merge ext: del " + myPath);
                    type = getDiffCallback().fileDeleted(myPath, fileInfo.myBaseFile, null, baseType, null, fileInfo.myBaseProperties, null);
                } else if (nodeKind == SVNNodeKind.DIR) {
                    SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, "merge ext: attempt to delete directory skipped");
                }
                if (type != SVNStatusType.MISSING && type != SVNStatusType.OBSTRUCTED) {
                    action = SVNEventAction.UPDATE_DELETE;
                    if (myIsDryRun) {
                        getDiffCallback().addDeletedPath(myPath);
                    }
                }
            }
            addDeletedPath(myPath, nodeKind, type, action, expectedAction);
        }

        public String toString() {
            StringBuffer buffer = new StringBuffer();
            buffer.append("[merge target: path = ");
            buffer.append(myPath);
            buffer.append("; wc file = ");
            buffer.append(myWCFile);
            buffer.append("; file = ");
            buffer.append(myFile);
            buffer.append("; base file = ");
            buffer.append(myCurrentFile.myBaseFile);
            buffer.append("; copyFromURL = ");
            buffer.append(myCopySource == null ? null : myCopySource.getURL());
            buffer.append("; copyFromRevision = ");
            buffer.append(myCopySource == null ? "unknown" : String.valueOf(myCopySource.getRevision()));
            buffer.append("]");
            return buffer.toString();
        }
    }
}
TOP

Related Classes of org.tmatesoft.svn.core.internal.wc.SVNExtendedMergeEditor$MergeTarget

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.