diff options
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.java | 223 |
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); + } + } + +} |