Merge branch 'stable-0.8'
[egit.git] / org.eclipse.egit.core / src / org / eclipse / egit / core / project / RepositoryFinder.java
blob481f7098a688bef53c9caad04ddf02be3d53b6f8
1 /*******************************************************************************
2 * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
3 * Copyright (C) 2007, Shawn O. Pearce <spearce@spearce.org>
4 * Copyright (C) 2008, Google Inc.
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *******************************************************************************/
11 package org.eclipse.egit.core.project;
13 import java.io.File;
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Collection;
18 import java.util.HashSet;
19 import java.util.Set;
21 import org.eclipse.core.resources.IContainer;
22 import org.eclipse.core.resources.IProject;
23 import org.eclipse.core.resources.IResource;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IPath;
26 import org.eclipse.core.runtime.IProgressMonitor;
27 import org.eclipse.core.runtime.NullProgressMonitor;
28 import org.eclipse.core.runtime.SubProgressMonitor;
29 import org.eclipse.egit.core.CoreText;
30 import org.eclipse.egit.core.internal.trace.GitTraceLocation;
31 import org.eclipse.jgit.lib.Constants;
32 import org.eclipse.jgit.util.SystemReader;
34 /**
35 * Searches for existing Git repositories associated with a project's files.
36 * <p>
37 * This finder algorithm searches a project's contained files to see if any of
38 * them are located within the working directory of an existing Git repository.
39 * The finder searches through linked resources, as the EGit core is capable of
40 * dealing with linked directories spanning multiple repositories in the same
41 * project.
42 * </p>
43 * <p>
44 * The search algorithm is exhaustive, it will find all matching repositories.
45 * For the project itself as well as for each linked container within the
46 * project it scans down the local filesystem trees to locate any Git
47 * repositories which may be found there. It also scans up the local filesystem
48 * tree to locate any Git repository which may be outside of Eclipse's
49 * workspace-view of the world, but which contains the project or a linked
50 * resource within the project. In short, if there is a Git repository
51 * associated, it finds it.
52 * </p>
54 public class RepositoryFinder {
55 private final IProject proj;
57 private final Collection<RepositoryMapping> results = new ArrayList<RepositoryMapping>();
58 private final Set<File> gitdirs = new HashSet<File>();
60 private Set<String> ceilingDirectories = new HashSet<String>();
62 /**
63 * Create a new finder to locate Git repositories for a project.
65 * @param p
66 * the project this new finder should locate the existing Git
67 * repositories of.
69 public RepositoryFinder(final IProject p) {
70 proj = p;
71 String ceilingDirectoriesVar = SystemReader.getInstance().getenv(
72 Constants.GIT_CEILING_DIRECTORIES_KEY);
73 if (ceilingDirectoriesVar != null) {
74 ceilingDirectories.addAll(Arrays.asList(ceilingDirectoriesVar
75 .split(File.pathSeparator)));
79 /**
80 * Run the search algorithm.
82 * @param m
83 * a progress monitor to report feedback to; may be null.
84 * @return all found {@link RepositoryMapping} instances associated with the
85 * project supplied to this instance's constructor.
86 * @throws CoreException
87 * Eclipse was unable to access its workspace, and threw up on
88 * us. We're throwing it back at the caller.
90 public Collection<RepositoryMapping> find(IProgressMonitor m) throws CoreException {
91 if (m == null) {
92 m = new NullProgressMonitor();
94 find(m, proj);
95 return results;
98 private void find(final IProgressMonitor m, final IContainer c)
99 throws CoreException {
100 final IPath loc = c.getLocation();
102 m.beginTask("", 101); //$NON-NLS-1$
103 m.subTask(CoreText.RepositoryFinder_finding);
104 try {
105 if (loc != null) {
106 final File fsLoc = loc.toFile();
107 assert fsLoc.isAbsolute();
108 final File ownCfg = configFor(fsLoc);
109 final IResource[] children;
111 if (ownCfg.isFile()) {
112 register(c, ownCfg.getParentFile());
114 if (c.isLinked() || c instanceof IProject) {
115 File p = fsLoc.getParentFile();
116 while (p != null) {
117 // TODO is this the right location?
118 if (GitTraceLocation.CORE.isActive())
119 GitTraceLocation.getTrace().trace(
120 GitTraceLocation.CORE.getLocation(),
121 "Looking at candidate dir: " //$NON-NLS-1$
122 + p);
123 final File pCfg = configFor(p);
124 if (pCfg.isFile()) {
125 register(c, pCfg.getParentFile());
127 if (ceilingDirectories.contains(p.getPath()))
128 break;
129 p = p.getParentFile();
132 m.worked(1);
134 children = c.members();
135 if (children != null && children.length > 0) {
136 final int scale = 100 / children.length;
137 for (int k = 0; k < children.length; k++) {
138 final IResource o = children[k];
139 if (o instanceof IContainer
140 && !o.getName().equals(Constants.DOT_GIT)) {
141 find(new SubProgressMonitor(m, scale),
142 (IContainer) o);
143 } else {
144 m.worked(scale);
149 } finally {
150 m.done();
154 private File configFor(final File fsLoc) {
155 return new File(new File(fsLoc, Constants.DOT_GIT),
156 "config"); //$NON-NLS-1$
159 private void register(final IContainer c, final File gitdir) {
160 File f;
161 try {
162 f = gitdir.getCanonicalFile();
163 } catch (IOException ioe) {
164 f = gitdir.getAbsoluteFile();
166 if (gitdirs.contains(f))
167 return;
168 gitdirs.add(f);
169 results.add(new RepositoryMapping(c, f));