SVNWCAccess.java :  » Source-Control » tmatesoft-SVN » org » tmatesoft » svn » core » internal » wc » admin » Java Open Source

Java Open Source » Source Control » tmatesoft SVN 
tmatesoft SVN » org » tmatesoft » svn » core » internal » wc » admin » SVNWCAccess.java
/*
 * ====================================================================
 * Copyright (c) 2004-2008 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.admin;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.tmatesoft.svn.core.SVNCancelException;
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.SVNURL;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
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.SVNExternalInfo;
import org.tmatesoft.svn.core.internal.wc.SVNFileType;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.ISVNOptions;
import org.tmatesoft.svn.core.wc.SVNEvent;



/**
 * @version 1.1.1
 * @author  TMate Software Ltd.
 */
public class SVNWCAccess implements ISVNEventHandler {
    
    public static final int INFINITE_DEPTH = -1;
    
    private ISVNEventHandler myEventHandler;
    private ISVNOptions myOptions;
    private Map myAdminAreas;
    private Map myCleanupHandlers;

    private File myAnchor;

    public static SVNWCAccess newInstance(ISVNEventHandler eventHandler) {
        return new SVNWCAccess(eventHandler);
    }
    
    private SVNWCAccess(ISVNEventHandler handler) {
        myEventHandler = handler;
    }
    
    public void setEventHandler(ISVNEventHandler handler) {
        myEventHandler = handler;
    }
    
    public ISVNEventHandler getEventHandler() {
        return myEventHandler;
    }
    
    public void checkCancelled() throws SVNCancelException {
        if (myEventHandler != null) {
            myEventHandler.checkCancelled();
        }
    }

    public void handleEvent(SVNEvent event) throws SVNException {
        handleEvent(event, ISVNEventHandler.UNKNOWN);
    }
    
    public void registerCleanupHandler(SVNAdminArea area, ISVNCleanupHandler handler) {
        if (area == null || handler == null) {
            return;
        }
        if (myCleanupHandlers == null) {
            myCleanupHandlers = new HashMap();
        }
        myCleanupHandlers.put(area, handler);
    }

    public void handleEvent(SVNEvent event, double progress) throws SVNException {
        if (myEventHandler != null) {
            try {
                myEventHandler.handleEvent(event, progress);
            } catch (SVNException e) {
                throw e;
            } catch (Throwable th) {
                SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "Error while dispatching event: {0}", th.getMessage());
                SVNErrorManager.error(err, th);
            }
        }
    }

    public void setOptions(ISVNOptions options) {
        myOptions = options;
    }

    public ISVNOptions getOptions() {
        if (myOptions == null) {
            myOptions = new DefaultSVNOptions();
        }
        return myOptions;
    }
    
    public void setAnchor(File anchor) {
        myAnchor = anchor;
    }
    
    public File getAnchor() {
        return myAnchor;
    }

    public SVNAdminAreaInfo openAnchor(File path, boolean writeLock, int depth) throws SVNException {
        File parent = path.getParentFile();
        if (parent == null) {
            SVNAdminArea anchor = open(path, writeLock, depth);
            return new SVNAdminAreaInfo(this, anchor, anchor, "");
        }

        String name = path.getName();
        SVNAdminArea parentArea = null;
        SVNAdminArea targetArea = null; 
        SVNException parentError = null;
        
        try {
            parentArea = open(parent, writeLock, false, 0);
        } catch (SVNException svne) {
            if (writeLock && svne.getErrorMessage().getErrorCode() == SVNErrorCode.WC_LOCKED) {
                try {
                    parentArea = open(parent, false, false, 0);
                } catch (SVNException svne2) {
                    throw svne;
                }
                parentError = svne;
            } else if (svne.getErrorMessage().getErrorCode() != SVNErrorCode.WC_NOT_DIRECTORY) {
                throw svne;
            }
        }
        
        try {
            targetArea = open(path, writeLock, false, depth);
        } catch (SVNException svne) {
            if (parentArea == null || svne.getErrorMessage().getErrorCode() != SVNErrorCode.WC_NOT_DIRECTORY) {
                try {
                    close();
                } catch (SVNException svne2) {
                    //
                }
                throw svne;
            }
        }
        
        if (parentArea != null && targetArea != null) {
            SVNEntry parentEntry = null;
            SVNEntry targetEntry = null;
            SVNEntry targetInParent = null;
            try {
                targetInParent = parentArea.getEntry(name, false);
                targetEntry = targetArea.getEntry(targetArea.getThisDirName(), false);
                parentEntry = parentArea.getEntry(parentArea.getThisDirName(), false);
            } catch (SVNException svne) {
                try {
                    close();
                } catch (SVNException svne2) {
                    //
                }
                throw svne;
            }
            
            SVNURL parentURL = parentEntry != null ? parentEntry.getSVNURL() : null;
            SVNURL targetURL = targetEntry != null ? targetEntry.getSVNURL() : null;
            String encodedName = SVNEncodingUtil.uriEncode(name);
            if (targetInParent == null || (parentURL != null && targetURL != null && 
                    (!parentURL.equals(targetURL.removePathTail()) || !encodedName.equals(SVNPathUtil.tail(targetURL.getURIEncodedPath()))))) {
                if (myAdminAreas != null) {
                    myAdminAreas.remove(parent);
                }
                try {
                    doClose(parentArea, false);
                } catch (SVNException svne) {
                    try {
                        close();
                    } catch (SVNException svne2) {
                        //
                    }
                    throw svne;
                }
                parentArea = null;
            }
        }
        
        if (parentArea != null) {
            if (parentError != null && targetArea != null) {
                if (parentError.getErrorMessage().getErrorCode() == SVNErrorCode.WC_LOCKED) {
                    // try to work without 'anchor'
                    try {
                        doClose(parentArea, false);
                    } catch (SVNException svne) {
                        try {
                            close();
                        } catch (SVNException svne2) {
                            //
                        }
                        throw svne;
                    }
                    parentArea = null;
                } else {
                    try {
                        close();
                    } catch (SVNException svne) {
                        //
                    }
                    throw parentError;
                }
            }
        }

        if (targetArea == null) {
            SVNEntry targetEntry = null;
            try {
                targetEntry = parentArea.getEntry(name, false); 
            } catch (SVNException svne) {
                try {
                    close();
                } catch (SVNException svne2) {
                    //
                }
                throw svne;
            }
            if (targetEntry != null && targetEntry.isDirectory()) {
                if (myAdminAreas != null) {
                    myAdminAreas.put(path, null);
                }
            }
        }
        SVNAdminArea anchor = parentArea != null ? parentArea : targetArea;
        SVNAdminArea target = targetArea != null ? targetArea : parentArea;
        return new SVNAdminAreaInfo(this, anchor, target, parentArea == null ? "" : name);
    }

    public SVNAdminArea open(File path, boolean writeLock, int depth) throws SVNException {
        return open(path, writeLock, false, depth);
    }
    
    public SVNAdminArea open(File path, boolean writeLock, boolean stealLock, int depth) throws SVNException {
        Map tmp = new HashMap();
        SVNAdminArea area;
        try {
            area = doOpen(path, writeLock, stealLock, depth, tmp);
        } finally {
            for(Iterator paths = tmp.keySet().iterator(); paths.hasNext();) {
                Object childPath = paths.next();
                SVNAdminArea childArea = (SVNAdminArea) tmp.get(childPath);
                myAdminAreas.put(childPath, childArea);
            }
        }
        return area;
    }
    
    public SVNAdminArea probeOpen(File path, boolean writeLock, int depth) throws SVNException {
        File dir = probe(path);
        if (!path.equals(dir)) {
            depth = 0;
        }
        SVNAdminArea adminArea = null;
        try {
            adminArea = open(dir, writeLock, false, depth);
        } catch (SVNException svne) {
            SVNFileType childKind = SVNFileType.getType(path);
            SVNErrorCode errCode = svne.getErrorMessage().getErrorCode(); 
            if (!path.equals(dir) && childKind == SVNFileType.DIRECTORY && errCode == SVNErrorCode.WC_NOT_DIRECTORY) {
                SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY, "''{0}'' is not a working copy", path);
                SVNErrorManager.error(err);
            } else {
                throw svne;
            }
        }
        return adminArea;
    }
    
    public SVNAdminArea probeTry(File path, boolean writeLock, int depth) throws SVNException {
        SVNAdminArea adminArea = null;
        try {
            adminArea = probeRetrieve(path);
        } catch (SVNException svne) {
            if (svne.getErrorMessage().getErrorCode() == SVNErrorCode.WC_NOT_LOCKED) {
                try {
                    adminArea = probeOpen(path, writeLock, depth);
                } catch (SVNException svne2) {
                    if (svne2.getErrorMessage().getErrorCode() != SVNErrorCode.WC_NOT_DIRECTORY) {
                        throw svne2; 
                    }
                }
            } else {
                throw svne;
            }
        }
        return adminArea;
    }
    
    public void close() throws SVNException {
        if (myAdminAreas != null) {
            doClose(myAdminAreas, false);
            myAdminAreas.clear();
        }
        myCleanupHandlers = null;
    }
    
    public void closeAdminArea(File path) throws SVNException {
        if (myAdminAreas != null) {
            SVNAdminArea area = (SVNAdminArea) myAdminAreas.get(path);
            if (area != null) {
                doClose(area, false);
                myAdminAreas.remove(path);
            }
        }
    }
    
    private SVNAdminArea doOpen(File path, boolean writeLock, boolean stealLock, int depth, Map tmp) throws SVNException {
        // no support for 'under consturction here' - it will go to adminAreaFactory.
        tmp = tmp == null ? new HashMap() : tmp; 
        if (myAdminAreas != null) {
            SVNAdminArea existing = (SVNAdminArea) myAdminAreas.get(path);
            if (myAdminAreas.containsKey(path) && existing != null) {
                SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.WC_LOCKED, "Working copy ''{0}'' locked", path);
                SVNErrorManager.error(error);
            }
        } else {
            myAdminAreas = new HashMap();
        }
        
        SVNAdminArea area = SVNAdminAreaFactory.open(path);
        area.setWCAccess(this);
        
        if (writeLock) {
            area.lock(stealLock);
            area = SVNAdminAreaFactory.upgrade(area);
        }
        tmp.put(path, area);
        
        if (depth != 0) {
            if (depth > 0) {
                depth--;
            }
            for(Iterator entries = area.entries(false); entries.hasNext();) {
                try {
                    checkCancelled(); 
                } catch (SVNCancelException e) {
                    doClose(tmp, false);
                    throw e;
                }
                
                SVNEntry entry = (SVNEntry) entries.next();
                if (entry.getKind() != SVNNodeKind.DIR  || area.getThisDirName().equals(entry.getName())) {
                    continue;
                }
                File childPath = new File(path, entry.getName());
                try {
                    // this method will put created area into our map.
                    doOpen(childPath, writeLock, stealLock, depth, tmp);
                } catch (SVNException e) {
                    if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_NOT_DIRECTORY) {
                        doClose(tmp, false);
                        throw e;
                    }
                    // only for missing!
                    tmp.put(childPath, null);
                    continue;
                }
            }
        }
        return area;
    }
    
    private void doClose(Map adminAreas, boolean preserveLocks) throws SVNException {
        for (Iterator paths = adminAreas.keySet().iterator(); paths.hasNext();) {
            File path = (File) paths.next();
            SVNAdminArea adminArea = (SVNAdminArea) adminAreas.get(path);
            if (adminArea == null) {
                paths.remove();
                continue;
            }
            doClose(adminArea, preserveLocks);
            paths.remove();
        }
    }

    private void doClose(SVNAdminArea adminArea, boolean preserveLocks) throws SVNException {
        if (adminArea == null) {
            return;
        }
        if (myCleanupHandlers != null) {
            ISVNCleanupHandler handler = (ISVNCleanupHandler) myCleanupHandlers.remove(adminArea);
            if (handler != null) {
                handler.cleanup(adminArea);
            }
        }
        if (!preserveLocks && adminArea.isLocked()) {
            adminArea.unlock();
        }
    }

    public SVNAdminArea probeRetrieve(File path) throws SVNException {
        File dir = probe(path);
        return retrieve(dir);
    }
    
    public boolean isMissing(File path) {
        if (myAdminAreas != null) {
            return myAdminAreas.containsKey(path) && myAdminAreas.get(path) == null;
        }
        return false;
    }

    public boolean isLocked(File path) throws SVNException {
        File lockFile = new File(path, SVNFileUtil.getAdminDirectoryName());
        lockFile = new File(lockFile, "lock");
        if (SVNFileType.getType(lockFile) == SVNFileType.FILE) {
            return true;
        } else if (SVNFileType.getType(lockFile) == SVNFileType.NONE) {
            return false;
        }
        SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_LOCKED, "Lock file ''{0}'' is not a regular file", lockFile);
        SVNErrorManager.error(err);
        return false;
    }
    
    public boolean isWCRoot(File path) throws SVNException {
        SVNEntry entry = getEntry(path, false);
        if (path.getParentFile() == null && entry != null) {
            return true;
        }
        SVNAdminArea parentArea = getAdminArea(path.getParentFile());
        if (parentArea == null) {
            try {
                parentArea = probeOpen(path.getParentFile(), false, 0);
            } catch (SVNException svne) {
                return true;
            }
        }
        
        SVNEntry parentEntry = getEntry(path.getParentFile(), false);
        if (parentEntry == null) {
            return true;
        }
        
        if (parentEntry.getURL() == null) {
            SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no ancestry information", path.getParentFile());
            SVNErrorManager.error(err);
        }
        
        // what about switched paths?
        /*
        if (entry != null && entry.getURL() != null) {
            if (!entry.getURL().equals(SVNPathUtil.append(parentEntry.getURL(), SVNEncodingUtil.uriEncode(path.getName())))) {
                return true;
            }
        }*/
        entry = parentArea.getEntry(path.getName(), false);
        if (entry == null) {
            return true;
        }
        return false;
    }
    
    public SVNEntry getEntry(File path, boolean showHidden) throws SVNException {
        SVNAdminArea adminArea = getAdminArea(path);
        String entryName = null;
        if (adminArea == null) {
            adminArea = getAdminArea(path.getParentFile());
            entryName = path.getName();
        } else {
            entryName = adminArea.getThisDirName();
        }
        
        if (adminArea != null) {
            return adminArea.getEntry(entryName, showHidden);
        }
        return null;
    }
    
    public void setRepositoryRoot(File path, SVNURL reposRoot) throws SVNException {
        SVNEntry entry = getEntry(path, false);
        if (entry == null) {
            return;
        }
        SVNAdminArea adminArea = null;
        String name = null;
        if (entry.isFile()) {
            adminArea = getAdminArea(path.getParentFile());
            name = path.getName();
        } else {
            adminArea = getAdminArea(path);
            name = adminArea != null ? adminArea.getThisDirName() : null;
        }
        
        if (adminArea == null) {
            return;
        }
        if (adminArea.tweakEntry(name, null, reposRoot.toString(), -1, false)) {
            adminArea.saveEntries(false);
        }
    }
    
    public SVNAdminArea[] getAdminAreas() {
        if (myAdminAreas != null) {
            return (SVNAdminArea[]) myAdminAreas.values().toArray(new SVNAdminArea[myAdminAreas.size()]);
        }
        return new SVNAdminArea[0];
    }
    
    public SVNAdminArea retrieve(File path) throws SVNException {
        SVNAdminArea adminArea = getAdminArea(path);
        if (adminArea == null) {
            SVNEntry subEntry = null;
            try {
                SVNAdminArea dirAdminArea = getAdminArea(path.getParentFile());
                if (dirAdminArea != null) {
                    subEntry = dirAdminArea.getEntry(path.getName(), true);
                }
            } catch (SVNException svne) {
                subEntry = null;
            }
            SVNFileType type = SVNFileType.getType(path);
            if (subEntry != null) {
                if (subEntry.getKind() == SVNNodeKind.DIR && type == SVNFileType.FILE) {
                    SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_NOT_LOCKED, "Expected ''{0}'' to be a directory but found a file", path);
                    SVNErrorManager.error(err);
                } else if (subEntry.getKind() == SVNNodeKind.FILE && type == SVNFileType.DIRECTORY) {
                    SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_NOT_LOCKED, "Expected ''{0}'' to be a file but found a directory", path);
                    SVNErrorManager.error(err);
                }
            }
            File adminDir = new File(path, SVNFileUtil.getAdminDirectoryName());
            SVNFileType wcType = SVNFileType.getType(adminDir);
            
            if (type == SVNFileType.NONE) {
                SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_NOT_LOCKED, "Directory ''{0}'' is missing", path);
                SVNErrorManager.error(err);
            } else if (type == SVNFileType.DIRECTORY && wcType == SVNFileType.NONE) {
                SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_NOT_LOCKED, "Directory ''{0}'' containing working copy admin area is missing", adminDir);
                SVNErrorManager.error(err);
            } else if (type == SVNFileType.DIRECTORY && wcType == SVNFileType.DIRECTORY) {
                SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_NOT_LOCKED, "Unable to lock ''{0}''", path);
                SVNErrorManager.error(err);
            }
            SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_NOT_LOCKED, "Working copy ''{0}'' is not locked", path);
            SVNErrorManager.error(err);
        }
        return adminArea;
    }

    public static SVNExternalInfo[] parseExternals(String rootPath, String externals) {
        Collection result = new ArrayList();
        if (externals == null) {
            return (SVNExternalInfo[]) result.toArray(new SVNExternalInfo[result.size()]);
        }

        for (StringTokenizer lines = new StringTokenizer(externals, "\n\r"); lines.hasMoreTokens();) {
            String line = lines.nextToken().trim();
            if (line.length() == 0 || line.startsWith("#")) {
                continue;
            }
            String url = null;
            String path;
            long rev = -1;
            List parts = new ArrayList(4);
            for (StringTokenizer tokens = new StringTokenizer(line, " \t"); tokens
                    .hasMoreTokens();) {
                String token = tokens.nextToken().trim();
                parts.add(token);
            }
            if (parts.size() < 2) {
                continue;
            }
            path = SVNPathUtil.append(rootPath, (String) parts.get(0));
            if (path.endsWith("/")) {
                path = path.substring(0, path.length() - 1);
            }
            if (parts.size() == 2) {
                url = (String) parts.get(1);
            } else if (parts.size() == 3 && parts.get(1).toString().startsWith("-r")) {
                String revStr = parts.get(1).toString();
                revStr = revStr.substring("-r".length());
                if (!"HEAD".equals(revStr)) {
                    try {
                        rev = Long.parseLong(revStr);
                    } catch (NumberFormatException nfe) {
                        continue;
                    }
                }
                url = (String) parts.get(2);
            } else if (parts.size() == 4 && "-r".equals(parts.get(1))) {
                String revStr = parts.get(2).toString();
                if (!"HEAD".equals(revStr)) {
                    try {
                        rev = Long.parseLong(revStr);
                    } catch (NumberFormatException nfe) {
                        continue;
                    }
                }
                url = (String) parts.get(3);
            }
            if (path != null && url != null) {
                if ("".equals(rootPath) && ((String) parts.get(0)).startsWith("/")) {
                    path = "/" + path;
                }
                try {
                    url = SVNURL.parseURIEncoded(url).toString();
                } catch (SVNException e) {
                    continue;
                }
                
                try {
                    SVNExternalInfo info = new SVNExternalInfo("", null, path, SVNURL.parseURIEncoded(url), rev);
                    result.add(info);
                } catch (SVNException e) {
                }
            }
        }
        return (SVNExternalInfo[]) result.toArray(new SVNExternalInfo[result.size()]);
    }


    //analogous to retrieve_internal
    public SVNAdminArea getAdminArea(File path) {
        //internal retrieve
        SVNAdminArea adminArea = null; 
        if (myAdminAreas != null) {
            adminArea = (SVNAdminArea) myAdminAreas.get(path);
        }
        return adminArea;
    }
    
    private File probe(File path) throws SVNException {
        int wcFormat = -1;
        SVNFileType type = SVNFileType.getType(path);
        if (type == SVNFileType.DIRECTORY) {
            wcFormat = SVNAdminAreaFactory.checkWC(path, true);
        } else {
            wcFormat = 0;
        }
        
        //non wc
        if (type != SVNFileType.DIRECTORY || wcFormat == 0) {
            if ("..".equals(path.getName()) || ".".equals(path.getName())) {
                SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_BAD_PATH, "Path ''{0}'' ends in ''{1}'', which is unsupported for this operation", new Object[]{path, path.getName()});
                SVNErrorManager.error(err);
            }
            path = path.getParentFile();
        } 
        return path;
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.