diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java index e6a3148a49c5..b92a03e998b1 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java @@ -18,13 +18,16 @@ package git4idea.repo; import com.intellij.openapi.Disposable; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsListener; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; -import git4idea.GitVcs; +import git4idea.PlatformFacade; +import git4idea.roots.GitRootProblemNotifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,23 +42,27 @@ import static git4idea.GitUtil.sortRepositories; */ public final class GitRepositoryManager extends AbstractProjectComponent implements Disposable, VcsListener { - private final GitVcs myVcs; - private final ProjectLevelVcsManager myVcsManager; + private static final Logger LOG = Logger.getInstance(GitRepositoryManager.class); + + private final @NotNull AbstractVcs myVcs; + private final @NotNull ProjectLevelVcsManager myVcsManager; + private final @NotNull PlatformFacade myPlatformFacade; private final Map myRepositories = new HashMap(); private final Set myListeners = new HashSet(); private final ReentrantReadWriteLock REPO_LOCK = new ReentrantReadWriteLock(); + @NotNull public static GitRepositoryManager getInstance(@NotNull Project project) { return ServiceManager.getService(project, GitRepositoryManager.class); } - public GitRepositoryManager(@NotNull Project project) { + public GitRepositoryManager(@NotNull Project project, @NotNull PlatformFacade platformFacade) { super(project); + myPlatformFacade = platformFacade; myVcsManager = ProjectLevelVcsManager.getInstance(myProject); - myVcs = GitVcs.getInstance(myProject); - assert myVcs != null; + myVcs = myPlatformFacade.getVcs(myProject); } @Override @@ -166,8 +173,14 @@ public final class GitRepositoryManager extends AbstractProjectComponent impleme // add GitRepositories for all roots that don't have correspondent GitRepositories yet. for (VirtualFile root : roots) { if (!myRepositories.containsKey(root)) { - GitRepository repository = createGitRepository(root); - myRepositories.put(root, repository); + if (gitRootOK(root)) { + GitRepository repository = createGitRepository(root); + myRepositories.put(root, repository); + } + else { + LOG.info("Invalid Git root: " + root); + GitRootProblemNotifier.getInstance(myProject, myPlatformFacade).rescanAndNotifyIfNeeded(); + } } } } @@ -176,6 +189,11 @@ public final class GitRepositoryManager extends AbstractProjectComponent impleme } } + private static boolean gitRootOK(@NotNull VirtualFile root) { + VirtualFile gitDir = root.findChild(".git"); + return gitDir != null && gitDir.exists(); + } + private GitRepository createGitRepository(VirtualFile root) { GitRepository repository = GitRepository.getFullInstance(root, myProject, this); for (GitRepositoryChangeListener listener : myListeners) { diff --git a/plugins/git4idea/src/git4idea/roots/GitRootProblemNotifier.java b/plugins/git4idea/src/git4idea/roots/GitRootProblemNotifier.java new file mode 100644 index 000000000000..93863825d5aa --- /dev/null +++ b/plugins/git4idea/src/git4idea/roots/GitRootProblemNotifier.java @@ -0,0 +1,155 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.roots; + +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationListener; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.VcsRootError; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Function; +import git4idea.GitVcs; +import git4idea.PlatformFacade; +import org.jetbrains.annotations.NotNull; + +import javax.swing.event.HyperlinkEvent; +import java.util.ArrayList; +import java.util.Collection; + +import static com.intellij.openapi.util.text.StringUtil.pluralize; + +/** + * Searches for Git roots problems via {@link GitRootErrorsFinder} and notifies about them. + * + * @author Kirill Likhodedov + */ +public class GitRootProblemNotifier { + + private final @NotNull Project myProject; + private final @NotNull PlatformFacade myPlatformFacade; + + public static GitRootProblemNotifier getInstance(@NotNull Project project, @NotNull PlatformFacade platformFacade) { + return new GitRootProblemNotifier(project, platformFacade); + } + + public GitRootProblemNotifier(@NotNull Project project, @NotNull PlatformFacade platformFacade) { + myProject = project; + myPlatformFacade = platformFacade; + } + + public void rescanAndNotifyIfNeeded() { + Collection errors = new GitRootErrorsFinder(myProject, myPlatformFacade).find(); + if (errors.isEmpty()) { + return; + } + + Collection unregisteredRoots = getUnregisteredRoots(errors); + Collection invalidRoots = getInvalidRoots(errors); + + String title = makeTitle(unregisteredRoots, invalidRoots); + String description = makeDescription(unregisteredRoots, invalidRoots); + + myPlatformFacade.getNotificator(myProject).notify(GitVcs.IMPORTANT_ERROR_NOTIFICATION, title, description, + NotificationType.ERROR, new NotificationListener() { + @Override + public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { + if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED && event.getDescription().equals("configure")) { + ShowSettingsUtil.getInstance().showSettingsDialog(myProject, "Version Control"); + } + } + }); + } + + @SuppressWarnings("StringConcatenationInsideStringBufferAppend") + private static String makeDescription(Collection unregisteredRoots, Collection invalidRoots) { + Function rootToString = new Function() { + @Override + public String fun(VirtualFile virtualFile) { + return FileUtil.toSystemDependentName(virtualFile.getPath()); + } + }; + + StringBuilder description = new StringBuilder(); + if (!invalidRoots.isEmpty()) { + if (invalidRoots.size() == 1) { + description.append("The directory " + invalidRoots.iterator().next() + " is registered as a Git root, " + + "but it doesn't have .git directory inside."); + } + else { + description.append("The following directories are registered as Git roots, but they don't have .git directotires inside:
" + + StringUtil.join(invalidRoots, rootToString, ", ")); + } + description.append("
"); + } + + if (!unregisteredRoots.isEmpty()) { + if (unregisteredRoots.size() == 1) { + description.append("The directory " + unregisteredRoots.iterator().next() + " is under Git, " + + "but is not registered in the Settings."); + } + else { + description.append("The following directories are roots of Git repositories, but they are not registered in the Settings:
" + + StringUtil.join(unregisteredRoots, rootToString, ", ")); + } + description.append("
"); + } + + description.append("Configure"); + + return description.toString(); + } + + private static String makeTitle(Collection unregisteredRoots, Collection invalidRoots) { + String title; + String roots = pluralize("root", invalidRoots.size()); + if (unregisteredRoots.isEmpty()) { + title = "Invalid Git " + roots; + } + else if (invalidRoots.isEmpty()) { + title = "Unregistered Git " + roots + " detected"; + } + else { + title = "Git root configuration problems"; + } + return title; + } + + @NotNull + private static Collection getUnregisteredRoots(@NotNull Collection errors) { + return filterErrorsByType(errors, VcsRootError.Type.UNREGISTERED_ROOT); + } + + @NotNull + private static Collection getInvalidRoots(@NotNull Collection errors) { + return filterErrorsByType(errors, VcsRootError.Type.EXTRA_ROOT); + } + + @NotNull + private static Collection filterErrorsByType(@NotNull Collection errors, @NotNull VcsRootError.Type type) { + Collection roots = new ArrayList(); + for (VcsRootError error : errors) { + if (error.getType() == type) { + roots.add(error.getRoot()); + } + } + return roots; + } + +}