org.eclipse.egit.core.project.RepositoryFinder.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.egit.core.project.RepositoryFinder.java

Source

/*******************************************************************************
 * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
 * Copyright (C) 2007, Shawn O. Pearce <spearce@spearce.org>
 * Copyright (C) 2008, Google Inc.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/
package org.eclipse.egit.core.project;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.egit.core.CoreText;
import org.eclipse.egit.core.internal.trace.GitTraceLocation;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.util.SystemReader;

/**
 * Searches for existing Git repositories associated with a project's files.
 * <p>
 * This finder algorithm searches a project's contained files to see if any of
 * them are located within the working directory of an existing Git repository.
 * The finder searches through linked resources, as the EGit core is capable of
 * dealing with linked directories spanning multiple repositories in the same
 * project.
 * </p>
 * <p>
 * The search algorithm is exhaustive, it will find all matching repositories.
 * For the project itself as well as for each linked container within the
 * project it scans down the local filesystem trees to locate any Git
 * repositories which may be found there. It also scans up the local filesystem
 * tree to locate any Git repository which may be outside of Eclipse's
 * workspace-view of the world, but which contains the project or a linked
 * resource within the project. In short, if there is a Git repository
 * associated, it finds it.
 * </p>
 */
public class RepositoryFinder {
    private final IProject proj;

    private final Collection<RepositoryMapping> results = new ArrayList<RepositoryMapping>();
    private final Set<File> gitdirs = new HashSet<File>();

    private Set<String> ceilingDirectories = new HashSet<String>();

    /**
     * Create a new finder to locate Git repositories for a project.
     *
     * @param p
     *            the project this new finder should locate the existing Git
     *            repositories of.
     */
    public RepositoryFinder(final IProject p) {
        proj = p;
        String ceilingDirectoriesVar = SystemReader.getInstance().getenv(Constants.GIT_CEILING_DIRECTORIES_KEY);
        if (ceilingDirectoriesVar != null) {
            ceilingDirectories.addAll(Arrays.asList(ceilingDirectoriesVar.split(File.pathSeparator)));
        }
    }

    /**
     * Run the search algorithm.
     *
     * @param m
     *            a progress monitor to report feedback to; may be null.
     * @return all found {@link RepositoryMapping} instances associated with the
     *         project supplied to this instance's constructor.
     * @throws CoreException
     *             Eclipse was unable to access its workspace, and threw up on
     *             us. We're throwing it back at the caller.
     */
    public Collection<RepositoryMapping> find(IProgressMonitor m) throws CoreException {
        IProgressMonitor monitor;
        if (m == null)
            monitor = new NullProgressMonitor();
        else
            monitor = m;
        find(monitor, proj);
        return results;
    }

    private void find(final IProgressMonitor m, final IContainer c) throws CoreException {
        final IPath loc = c.getLocation();

        m.beginTask("", 101); //$NON-NLS-1$
        m.subTask(CoreText.RepositoryFinder_finding);
        try {
            if (loc != null) {
                final File fsLoc = loc.toFile();
                assert fsLoc.isAbsolute();
                final File ownCfg = configFor(fsLoc);
                final IResource[] children;

                if (ownCfg.isFile()) {
                    register(c, ownCfg.getParentFile());
                }
                if (c.isLinked() || c instanceof IProject) {
                    File p = fsLoc.getParentFile();
                    while (p != null) {
                        // TODO is this the right location?
                        if (GitTraceLocation.CORE.isActive())
                            GitTraceLocation.getTrace().trace(GitTraceLocation.CORE.getLocation(),
                                    "Looking at candidate dir: " //$NON-NLS-1$
                                            + p);
                        final File pCfg = configFor(p);
                        if (pCfg.isFile()) {
                            register(c, pCfg.getParentFile());
                        }
                        if (ceilingDirectories.contains(p.getPath()))
                            break;
                        p = p.getParentFile();
                    }
                }
                m.worked(1);

                children = c.members();
                if (children != null && children.length > 0) {
                    final int scale = 100 / children.length;
                    for (int k = 0; k < children.length; k++) {
                        final IResource o = children[k];
                        if (o instanceof IContainer && !o.getName().equals(Constants.DOT_GIT)) {
                            find(new SubProgressMonitor(m, scale), (IContainer) o);
                        } else {
                            m.worked(scale);
                        }
                    }
                }
            }
        } finally {
            m.done();
        }
    }

    private File configFor(final File fsLoc) {
        return new File(new File(fsLoc, Constants.DOT_GIT), "config"); //$NON-NLS-1$
    }

    private void register(final IContainer c, final File gitdir) {
        File f;
        try {
            f = gitdir.getCanonicalFile();
        } catch (IOException ioe) {
            f = gitdir.getAbsoluteFile();
        }
        if (gitdirs.contains(f))
            return;
        gitdirs.add(f);
        results.add(new RepositoryMapping(c, f));
    }
}