summaryrefslogtreecommitdiff
path: root/platform/dvcs-impl/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/dvcs-impl/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java')
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java223
1 files changed, 223 insertions, 0 deletions
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java b/platform/dvcs-impl/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java
new file mode 100644
index 000000000000..992654248e83
--- /dev/null
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java
@@ -0,0 +1,223 @@
+package com.intellij.dvcs.repo;
+
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.components.AbstractProjectComponent;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.vcs.*;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.ArrayUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * @author Nadya Zabrodina
+ */
+public abstract class AbstractRepositoryManager<T extends Repository> extends AbstractProjectComponent
+ implements Disposable, RepositoryManager<T>, VcsListener {
+
+ private static final Logger LOG = Logger.getInstance(RepositoryManager.class);
+
+ @NotNull private final ProjectLevelVcsManager myVcsManager;
+ @NotNull private final AbstractVcs myVcs;
+ @NotNull private final String myRepoDirName;
+
+ @NotNull protected final Map<VirtualFile, T> myRepositories = new HashMap<VirtualFile, T>();
+
+ @NotNull protected final ReentrantReadWriteLock REPO_LOCK = new ReentrantReadWriteLock();
+ @NotNull private final CountDownLatch myInitializationWaiter = new CountDownLatch(1);
+
+ protected AbstractRepositoryManager(@NotNull Project project, @NotNull ProjectLevelVcsManager vcsManager, @NotNull AbstractVcs vcs,
+ @NotNull String repoDirName) {
+ super(project);
+ myVcsManager = vcsManager;
+ myVcs = vcs;
+ myRepoDirName = repoDirName;
+ }
+
+ @Override
+ public void initComponent() {
+ Disposer.register(myProject, this);
+ myProject.getMessageBus().connect().subscribe(ProjectLevelVcsManager.VCS_CONFIGURATION_CHANGED, this);
+ }
+
+ @Override
+ public void dispose() {
+ try {
+ REPO_LOCK.writeLock().lock();
+ myRepositories.clear();
+ }
+ finally {
+ REPO_LOCK.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public void directoryMappingChanged() {
+ updateRepositoriesCollection();
+ }
+
+ @Override
+ @Nullable
+ public T getRepositoryForRoot(@Nullable VirtualFile root) {
+ if (root == null) {
+ return null;
+ }
+ try {
+ REPO_LOCK.readLock().lock();
+ return myRepositories.get(root);
+ }
+ finally {
+ REPO_LOCK.readLock().unlock();
+ }
+ }
+
+ @Override
+ @Nullable
+ public T getRepositoryForFile(@NotNull VirtualFile file) {
+ final VcsRoot vcsRoot = myVcsManager.getVcsRootObjectFor(file);
+ return getRepositoryForVcsRoot(vcsRoot, file.getPath());
+ }
+
+ @Override
+ public T getRepositoryForFile(@NotNull FilePath file) {
+ final VcsRoot vcsRoot = myVcsManager.getVcsRootObjectFor(file);
+ return getRepositoryForVcsRoot(vcsRoot, file.getPath());
+ }
+
+ @Nullable
+ private T getRepositoryForVcsRoot(@Nullable VcsRoot vcsRoot, @NotNull String filePath) {
+ if (vcsRoot == null) {
+ return null;
+ }
+ final AbstractVcs vcs = vcsRoot.getVcs();
+ if (!myVcs.equals(vcs)) {
+ if (vcs != null) {
+ LOG.debug(String.format("getRepositoryForFile returned non-(%s) root for file %s", myVcs.getDisplayName(), filePath));
+ }
+ return null;
+ }
+ return getRepositoryForRoot(vcsRoot.getPath());
+ }
+
+ @Override
+ @NotNull
+ public List<T> getRepositories() {
+ try {
+ REPO_LOCK.readLock().lock();
+ return RepositoryUtil.sortRepositories(myRepositories.values());
+ }
+ finally {
+ REPO_LOCK.readLock().unlock();
+ }
+ }
+
+ @Override
+ public boolean moreThanOneRoot() {
+ return myRepositories.size() > 1;
+ }
+
+ @Override
+ public void updateRepository(@Nullable VirtualFile root) {
+ T repo = getRepositoryForRoot(root);
+ if (repo != null) {
+ repo.update();
+ }
+ }
+
+ @Override
+ public void updateAllRepositories() {
+ Map<VirtualFile, T> repositories;
+ try {
+ REPO_LOCK.readLock().lock();
+ repositories = new HashMap<VirtualFile, T>(myRepositories);
+ }
+ finally {
+ REPO_LOCK.readLock().unlock();
+ }
+
+ for (VirtualFile root : repositories.keySet()) {
+ updateRepository(root);
+ }
+ }
+
+ // note: we are not calling this method during the project startup - it is called anyway by f.e the GitRootTracker
+ private void updateRepositoriesCollection() {
+ Map<VirtualFile, T> repositories;
+ try {
+ REPO_LOCK.readLock().lock();
+ repositories = new HashMap<VirtualFile, T>(myRepositories);
+ }
+ finally {
+ REPO_LOCK.readLock().unlock();
+ }
+
+ final VirtualFile[] roots = myVcsManager.getRootsUnderVcs(myVcs);
+ // remove repositories that are not in the roots anymore
+ for (Iterator<Map.Entry<VirtualFile, T>> iterator = repositories.entrySet().iterator(); iterator.hasNext(); ) {
+ if (!ArrayUtil.contains(iterator.next().getValue().getRoot(), roots)) {
+ iterator.remove();
+ }
+ }
+ // add Repositories for all roots that don't have correspondent appropriate Git or Hg Repositories yet.
+ for (VirtualFile root : roots) {
+ if (!repositories.containsKey(root)) {
+ if (isRootValid(root)) {
+ try {
+ T repository = createRepository(root);
+ repositories.put(root, repository);
+ }
+ catch (RepoStateException e) {
+ LOG.error("Couldn't initialize Repository in " + root.getPresentableUrl(), e);
+ }
+ }
+ else {
+ LOG.info("Invalid vcs root: " + root);
+ }
+ }
+ }
+
+ REPO_LOCK.writeLock().lock();
+ try {
+ myRepositories.clear();
+ myRepositories.putAll(repositories);
+ myInitializationWaiter.countDown();
+ }
+ finally {
+ REPO_LOCK.writeLock().unlock();
+ }
+ }
+
+ private boolean isRootValid(@NotNull VirtualFile root) {
+ VirtualFile vcsDir = root.findChild(myRepoDirName);
+ return vcsDir != null && vcsDir.exists();
+ }
+
+ @NotNull
+ protected abstract T createRepository(@NotNull VirtualFile root);
+
+ @Override
+ @NotNull
+ public String toString() {
+ return "RepositoryManager{myRepositories: " + myRepositories + '}';
+ }
+
+ @Override
+ public void waitUntilInitialized() {
+ try {
+ myInitializationWaiter.await();
+ }
+ catch (InterruptedException e) {
+ LOG.error(e);
+ }
+ }
+
+}