Package jenkins.scm.impl.subversion

Source Code of jenkins.scm.impl.subversion.SVNRepositoryView$ChildEntryCollector

/*
* The MIT License
*
* Copyright (c) 2013, CloudBees, Inc., Stephen Connolly.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package jenkins.scm.impl.subversion;

import com.cloudbees.plugins.credentials.common.StandardCredentials;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import hudson.scm.*;
import hudson.util.TimeUnit2;
import jenkins.model.Jenkins;
import org.mapdb.DB;
import org.mapdb.DBMaker;
import org.tmatesoft.svn.core.ISVNDirEntryHandler;
import org.tmatesoft.svn.core.SVNDirEntry;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentMap;

/**
* @author Stephen Connolly
*/
public class SVNRepositoryView {
    public static final int DIRENTS =
            SVNDirEntry.DIRENT_CREATED_REVISION | SVNDirEntry.DIRENT_KIND | SVNDirEntry.DIRENT_TIME;
    private final DB cache;
    private final SVNRepository repository;
    private final ConcurrentMap<String, NodeEntry> data;
    private final String uuid;

    public SVNRepositoryView(SVNURL repoURL, StandardCredentials credentials) throws SVNException {
        repository = SVNRepositoryFactory.create(repoURL);

        File configDir = SVNWCUtil.getDefaultConfigurationDirectory();

        ISVNAuthenticationManager sam = new SVNAuthenticationManager(configDir, null, null);

        sam.setAuthenticationProvider(new CredentialsSVNAuthenticationProviderImpl(credentials));
        SVNAuthStoreHandlerImpl.install(sam);
        sam = new FilterSVNAuthenticationManager(sam) {
            // If there's no time out, the blocking read operation may hang forever, because TCP itself
            // has no timeout. So always use some time out. If the underlying implementation gives us some
            // value (which may come from ~/.subversion), honor that, as long as it sets some timeout value.
            @Override
            public int getReadTimeout(SVNRepository repository) {
                int r = super.getReadTimeout(repository);
                if (r <= 0) {
                    r = (int) TimeUnit2.MINUTES.toMillis(1);
                }
                return r;
            }
        };
        repository.setTunnelProvider(SVNWCUtil.createDefaultOptions(true));
        repository.setAuthenticationManager(sam);
        try {
            uuid = repository.getRepositoryUUID(false);
            File cacheFile = new File(new File(Jenkins.getInstance().getRootDir(), "caches"), "svn-" + uuid + ".db");
            cacheFile.getParentFile().mkdirs();
            DB cache = null;
            while (cache == null) {
                try {
                    cache = DBMaker.newFileDB(cacheFile)
                            .cacheWeakRefEnable()
                            .make();
                } catch (Throwable t) {
                    cacheFile.delete();
                }
            }
            this.cache = cache;
            this.data = this.cache.getHashMap(credentials == null ? "data" : "data-" + credentials.getId());
            cache.commit();
        } catch (SVNException e) {
            repository.closeSession();
            throw e;
        }
    }

    public SVNRepository getRepository() {
        return repository;
    }

    public String getUuid() {
        return uuid;
    }

    public boolean isClosed() {
        return cache.isClosed();
    }

    public void close() {
        if (isClosed()) {
            return;
        }
        repository.closeSession();
        cache.close();
    }

    public SVNNodeKind checkPath(String path, long revision) throws SVNException {
        path = SVNPathUtil.getAbsolutePath(path);
        NodeEntry nodeEntry = getNodeEntry(path);
        if (nodeEntry == null || nodeEntry.getRevision() != revision) {
            try {
                SVNNodeKind svnNodeKind = repository.checkPath(path, revision);
                if (SVNNodeKind.DIR.equals(svnNodeKind)) {
                    ChildEntryCollector collector = new ChildEntryCollector();
                    long dirRev = repository.getDir(path, revision, null, DIRENTS, collector);
                    nodeEntry = new NodeEntry(dirRev, svnNodeKind, collector.getResult());
                } else {
                    nodeEntry = new NodeEntry(revision, svnNodeKind, null);
                }
                setNodeEntry(path, nodeEntry);
            } catch (SVNException e) {
                // if we have a cached result and the server is off-line, use the cache
                if (nodeEntry == null) {
                    throw e;
                }
            }
        }
        return nodeEntry.getType();
    }

    @CheckForNull
    private NodeEntry getNodeEntry(String path) {
        try {
            return data.get(path);
        } catch (Throwable t) {
            // ignore, it's only a cache
            return null;
        }
    }

    private void setNodeEntry(String path, NodeEntry nodeEntry) {
        try {
            data.put(path, nodeEntry);
            cache.commit();
        } catch (Throwable t) {
            // ignore, it's only a cache
        }
    }

    public long getLatestRevision() throws SVNException {
        return repository.getLatestRevision();
    }

    public NodeEntry getNode(String path, long revision) throws SVNException {
        path = SVNPathUtil.getAbsolutePath(path);
        NodeEntry nodeEntry = getNodeEntry(path);
        if (nodeEntry == null || nodeEntry.getRevision() != revision) {
            try {
                SVNNodeKind svnNodeKind = repository.checkPath(path, revision);
                if (revision == -1) {
                    if (SVNNodeKind.DIR.equals(svnNodeKind)) {
                        ChildEntryCollector collector = new ChildEntryCollector();
                        long dirRev = repository.getDir(path, revision, null, DIRENTS, collector);
                        nodeEntry = new NodeEntry(dirRev, svnNodeKind, collector.getResult());
                    } else if (SVNNodeKind.FILE.equals(svnNodeKind)) {
                        long fileRev = repository.getFile(path, revision, null, null);
                        nodeEntry = new NodeEntry(fileRev, svnNodeKind, null);
                    } else {
                        nodeEntry = new NodeEntry(revision, svnNodeKind, null);
                    }
                } else {
                    nodeEntry = new NodeEntry(revision, svnNodeKind, null);
                }
                if (!nodeEntry.getType().equals(SVNNodeKind.DIR)) {
                    setNodeEntry(path, nodeEntry);
                }
            } catch (SVNException e) {
                // if we have a cached result and the server is off-line, use the cache
                if (nodeEntry == null) {
                    throw e;
                }
            }
        }
        if (nodeEntry.getType().equals(SVNNodeKind.DIR) && nodeEntry.getChildren() == null) {
            // if the cached result does not have a list of children and the server is off-line, bomb out
            ChildEntryCollector collector = new ChildEntryCollector();
            long dirRev = repository.getDir(path, revision, null, DIRENTS, collector);
            nodeEntry = new NodeEntry(dirRev, nodeEntry.getType(), collector.getResult());
            setNodeEntry(path, nodeEntry);
        }
        return nodeEntry;
    }

    public static class NodeEntry implements Serializable {
        private final long revision;
        private final SVNNodeKind type;
        private final ChildEntry[] children;

        public NodeEntry(long revision, SVNNodeKind type, ChildEntry[] children) {
            this.revision = revision;
            this.type = type;
            this.children = children;
        }

        public SVNNodeKind getType() {
            return type;
        }

        public long getRevision() {
            return revision;
        }

        public ChildEntry[] getChildren() {
            return children;
        }
    }

    public static class ChildEntry implements Serializable {
        private final long revision;
        private final SVNNodeKind type;
        private final String name;
        private final long lastModified;

        public ChildEntry(long revision, long lastModified, SVNNodeKind type, String name) {
            this.revision = revision;
            this.type = type;
            this.name = name;
            this.lastModified = lastModified;
        }

        public SVNNodeKind getType() {
            return type;
        }

        public long getRevision() {
            return revision;
        }

        public String getName() {
            return name;
        }

        public long getLastModified() {
            return lastModified;
        }
    }

    private static class ChildEntryCollector implements ISVNDirEntryHandler {
        private final List<ChildEntry> children = new ArrayList<ChildEntry>();

        public void handleDirEntry(SVNDirEntry entry) throws SVNException {
            children.add(
                    new ChildEntry(entry.getRevision(), entry.getDate().getTime(), entry.getKind(), entry.getName()));
        }

        public ChildEntry[] getResult() {
            return children.toArray(new ChildEntry[children.size()]);
        }
    }
}
TOP

Related Classes of jenkins.scm.impl.subversion.SVNRepositoryView$ChildEntryCollector

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.