From 263543889ef8da93fe9638f619e36273c65ced11 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Tue, 2 Jul 2013 16:20:37 +0400 Subject: [PATCH] RepositoryManager structure for Git and Mercurial changed and get Hg config feature implemented *RepositoryManager for git renamed and moved to dvcs common code; *RepositoryManager became generic according repository type (GitRepository or HGRepository); *RepositoryManager for mercurial implemented; *Move common implementation of RepositoryManager to AbstractRepositoryManager; *Annotations added; *HgConfig created as hg config strotage; *hgrc file changes tracked in HgRepositoryUpdater using new UPDATE_CONFIG_TOPIC; *Get defaultPath and defaultPushPath method calls changed: now using get paths from storage (HgUtil appropriate method) instead of calling mercurial showconfig command every time; --- .../dvcs/repo/AbstractRepositoryManager.java | 197 +++++++++++++++ .../intellij/dvcs/repo/RepositoryManager.java | 67 +++++ .../intellij/dvcs/repo/RepositoryUtil.java | 13 +- plugins/git4idea/src/META-INF/plugin.xml | 3 +- .../src/git4idea/GitPlatformFacade.java | 5 +- plugins/git4idea/src/git4idea/GitUtil.java | 9 - .../push/GitRejectedPushUpdateDialog.java | 3 +- .../git4idea/repo/GitRepositoryManager.java | 76 +++--- .../repo/GitRepositoryManagerImpl.java | 232 ------------------ .../test/GitTestPlatformFacade.groovy | 4 +- .../test/GitTestRepositoryManager.groovy | 5 +- plugins/hg4idea/src/META-INF/plugin.xml | 3 + .../src/org/zmlx/hg4idea/HgPusher.java | 6 - .../hg4idea/src/org/zmlx/hg4idea/HgVcs.java | 1 + .../hg4idea/command/HgOutgoingCommand.java | 8 +- .../command/HgRemoteChangesetsCommand.java | 7 +- .../hg4idea/command/HgShowConfigCommand.java | 23 +- .../provider/update/HgRegularUpdater.java | 70 +++--- .../src/org/zmlx/hg4idea/repo/HgConfig.java | 62 +++++ .../org/zmlx/hg4idea/repo/HgRepository.java | 3 + .../zmlx/hg4idea/repo/HgRepositoryFiles.java | 9 +- .../zmlx/hg4idea/repo/HgRepositoryImpl.java | 8 + .../hg4idea/repo/HgRepositoryManager.java | 42 ++++ .../hg4idea/repo/HgRepositoryUpdater.java | 19 +- .../src/org/zmlx/hg4idea/ui/HgPullDialog.java | 4 +- .../src/org/zmlx/hg4idea/ui/HgPushDialog.java | 2 +- .../src/org/zmlx/hg4idea/util/HgUtil.java | 19 ++ .../org/zmlx/hg4idea/test/HgUpdateTest.java | 3 +- 28 files changed, 540 insertions(+), 363 deletions(-) create mode 100644 platform/dvcs/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java create mode 100644 platform/dvcs/src/com/intellij/dvcs/repo/RepositoryManager.java delete mode 100644 plugins/git4idea/src/git4idea/repo/GitRepositoryManagerImpl.java create mode 100644 plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgConfig.java create mode 100644 plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryManager.java diff --git a/platform/dvcs/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java b/platform/dvcs/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java new file mode 100644 index 000000000000..329ef7e36631 --- /dev/null +++ b/platform/dvcs/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java @@ -0,0 +1,197 @@ +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.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.locks.ReentrantReadWriteLock; + +/** + * @author Nadya Zabrodina + */ +public abstract class AbstractRepositoryManager extends AbstractProjectComponent + implements Disposable, RepositoryManager, VcsListener { + + private static final Logger LOG = Logger.getInstance(RepositoryManager.class); + @NotNull private final ProjectLevelVcsManager myVcsManager; + @NotNull protected AbstractVcs myVcs; + + @NotNull protected final Map myRepositories = new HashMap(); + + @NotNull protected final ReentrantReadWriteLock REPO_LOCK = new ReentrantReadWriteLock(); + + protected AbstractRepositoryManager(@NotNull Project project, + @NotNull ProjectLevelVcsManager vcsManager) { + super(project); + myVcsManager = vcsManager; + } + + + @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", vcs.getDisplayName(), filePath)); + } + return null; + } + return getRepositoryForRoot(vcsRoot.getPath()); + } + + @Override + @NotNull + public List 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 repositories; + try { + REPO_LOCK.readLock().lock(); + repositories = new HashMap(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 repositories; + try { + REPO_LOCK.readLock().lock(); + repositories = new HashMap(myRepositories); + } + finally { + REPO_LOCK.readLock().unlock(); + } + + final VirtualFile[] roots = myVcsManager.getRootsUnderVcs(myVcs); + // remove repositories that are not in the roots anymore + for (Iterator> 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); + } + finally { + REPO_LOCK.writeLock().unlock(); + } + } + + protected abstract boolean isRootValid(@NotNull VirtualFile root); + + @NotNull + protected abstract T createRepository(@NotNull VirtualFile root); + + + @Override + @NotNull + public String toString() { + return "RepositoryManager{myRepositories: " + myRepositories + '}'; + } +} diff --git a/platform/dvcs/src/com/intellij/dvcs/repo/RepositoryManager.java b/platform/dvcs/src/com/intellij/dvcs/repo/RepositoryManager.java new file mode 100644 index 000000000000..9f0a5e2eedd8 --- /dev/null +++ b/platform/dvcs/src/com/intellij/dvcs/repo/RepositoryManager.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2011 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 com.intellij.dvcs.repo; + +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * RepositoryManager initializes and stores {@link Repository repositories} for Git or Hgroots defined in the project. + * + * @author Kirill Likhodedov + */ +public interface RepositoryManager { + + /** + * Returns the {@link Repository} which tracks the Git or Hg repository located in the given directory, + * or {@code null} if the given file is not a vcs root known to this {@link com.intellij.openapi.project.Project}. + */ + @Nullable + T getRepositoryForRoot(@Nullable VirtualFile root); + + /** + * Returns the {@link Repository} which the given file belongs to, or {@code null} if the file is not under any Git or Hg repository. + */ + @Nullable + T getRepositoryForFile(@NotNull VirtualFile file); + + /** + * Returns the {@link Repository} which the given file belongs to, or {@code null} if the file is not under any Git ot Hg repository. + */ + @Nullable + T getRepositoryForFile(@NotNull FilePath file); + + /** + * @return all repositories tracked by the manager. + */ + @NotNull + List getRepositories(); + + boolean moreThanOneRoot(); + + /** + * Synchronously updates the specified information about repository under the given root. + * + * @param root root directory of the vcs repository. + */ + void updateRepository(VirtualFile root); + + void updateAllRepositories(); +} diff --git a/platform/dvcs/src/com/intellij/dvcs/repo/RepositoryUtil.java b/platform/dvcs/src/com/intellij/dvcs/repo/RepositoryUtil.java index 1de63ab1837a..21b898837bd3 100644 --- a/platform/dvcs/src/com/intellij/dvcs/repo/RepositoryUtil.java +++ b/platform/dvcs/src/com/intellij/dvcs/repo/RepositoryUtil.java @@ -27,7 +27,7 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; -import java.util.Collection; +import java.util.*; import java.util.concurrent.Callable; /** @@ -118,4 +118,15 @@ public class RepositoryUtil { myRepository.update(); } } + + public static List sortRepositories(@NotNull Collection repositories) { + List repos = new ArrayList(repositories); + Collections.sort(repos, new Comparator() { + @Override + public int compare(Repository o1, Repository o2) { + return o1.getPresentableUrl().compareTo(o2.getPresentableUrl()); + } + }); + return repos; + } } diff --git a/plugins/git4idea/src/META-INF/plugin.xml b/plugins/git4idea/src/META-INF/plugin.xml index 2298a387ff7a..e8b122d348a9 100644 --- a/plugins/git4idea/src/META-INF/plugin.xml +++ b/plugins/git4idea/src/META-INF/plugin.xml @@ -81,8 +81,7 @@ - git4idea.repo.GitRepositoryManager - git4idea.repo.GitRepositoryManagerImpl + git4idea.repo.GitRepositoryManager diff --git a/plugins/git4idea/src/git4idea/GitPlatformFacade.java b/plugins/git4idea/src/git4idea/GitPlatformFacade.java index 4866483e09ca..d808c1b69724 100644 --- a/plugins/git4idea/src/git4idea/GitPlatformFacade.java +++ b/plugins/git4idea/src/git4idea/GitPlatformFacade.java @@ -16,9 +16,10 @@ package git4idea; import com.intellij.dvcs.DvcsPlatformFacade; +import com.intellij.dvcs.repo.RepositoryManager; import com.intellij.openapi.project.Project; import git4idea.config.GitVcsSettings; -import git4idea.repo.GitRepositoryManager; +import git4idea.repo.GitRepository; import org.jetbrains.annotations.NotNull; /** @@ -27,7 +28,7 @@ import org.jetbrains.annotations.NotNull; public interface GitPlatformFacade extends DvcsPlatformFacade { @NotNull - GitRepositoryManager getRepositoryManager(@NotNull Project project); + > T getRepositoryManager(@NotNull Project project); @NotNull GitVcsSettings getSettings(Project project); diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java index 003972686523..fec8b0b8c2c6 100644 --- a/plugins/git4idea/src/git4idea/GitUtil.java +++ b/plugins/git4idea/src/git4idea/GitUtil.java @@ -685,15 +685,6 @@ public class GitUtil { return !manager.moreThanOneRoot(); } - public static List sortRepositories(@NotNull Collection repositories) { - List repos = new ArrayList(repositories); - Collections.sort(repos, new Comparator() { - @Override public int compare(GitRepository o1, GitRepository o2) { - return o1.getPresentableUrl().compareTo(o2.getPresentableUrl()); - } - }); - return repos; - } @Nullable public static GitRemote findRemoteByName(@NotNull GitRepository repository, @Nullable String name) { diff --git a/plugins/git4idea/src/git4idea/push/GitRejectedPushUpdateDialog.java b/plugins/git4idea/src/git4idea/push/GitRejectedPushUpdateDialog.java index 8bdeb9ef5610..2a00d629b6a1 100644 --- a/plugins/git4idea/src/git4idea/push/GitRejectedPushUpdateDialog.java +++ b/plugins/git4idea/src/git4idea/push/GitRejectedPushUpdateDialog.java @@ -15,6 +15,7 @@ */ package git4idea.push; +import com.intellij.dvcs.repo.RepositoryUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.ui.components.JBLabel; @@ -128,7 +129,7 @@ class GitRejectedPushUpdateDialog extends DialogWrapper { if (allBranchesHaveTheSameName(currentBranches)) { String branchName = currentBranches.values().iterator().next().getName(); StringBuilder sb = new StringBuilder(DESCRIPTION_START + code(branchName) + " was rejected in repositories
"); - for (GitRepository repository : GitUtil.sortRepositories(currentBranches.keySet())) { + for (GitRepository repository : RepositoryUtil.sortRepositories(currentBranches.keySet())) { sb.append(HTML_IDENT).append(code(repository.getPresentableUrl())).append("
"); } sb.append(DESCRIPTION_ENDING); diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java index 5ef34fa2000a..e2f0a9c99b17 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * 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. @@ -15,53 +15,51 @@ */ package git4idea.repo; -import com.intellij.openapi.vcs.FilePath; +import com.intellij.dvcs.repo.AbstractRepositoryManager; +import com.intellij.dvcs.repo.RepositoryManager; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vfs.VirtualFile; +import git4idea.GitPlatformFacade; +import git4idea.GitUtil; +import git4idea.roots.GitRootScanner; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; /** - * GitRepositoryManager initializes and stores {@link GitRepository GitRepositories} for Git roots defined in the project. * @author Kirill Likhodedov */ -public interface GitRepositoryManager { +public class GitRepositoryManager extends AbstractRepositoryManager implements RepositoryManager { - /** - * Returns the {@link GitRepository} which tracks the Git repository located in the given directory, - * or {@code null} if the given file is not a Git root known to this {@link com.intellij.openapi.project.Project}. - */ - @Nullable - GitRepository getRepositoryForRoot(@Nullable VirtualFile root); + @NotNull private final GitPlatformFacade myPlatformFacade; - /** - * Returns the {@link GitRepository} which the given file belongs to, or {@code null} if the file is not under any Git repository. - */ - @Nullable - GitRepository getRepositoryForFile(@NotNull VirtualFile file); + public GitRepositoryManager(@NotNull Project project, @NotNull GitPlatformFacade platformFacade, + @NotNull ProjectLevelVcsManager vcsManager) { + super(project, vcsManager); + myPlatformFacade = platformFacade; + } - /** - * Returns the {@link GitRepository} which the given file belongs to, or {@code null} if the file is not under any Git repository. - */ - @Nullable - GitRepository getRepositoryForFile(@NotNull FilePath file); + @Override + public void initComponent() { + myVcs = myPlatformFacade.getVcs(myProject); + Disposer.register(myProject, this); + myProject.getMessageBus().connect().subscribe(ProjectLevelVcsManager.VCS_CONFIGURATION_CHANGED, this); + if (!ApplicationManager.getApplication().isUnitTestMode()) { + GitRootScanner.start(myProject); + } + } + + + @Override + protected boolean isRootValid(@NotNull VirtualFile root) { + VirtualFile gitDir = root.findChild(GitUtil.DOT_GIT); + return gitDir != null && gitDir.exists(); + } - /** - * @return all repositories tracked by the manager. - */ @NotNull - List getRepositories(); - - boolean moreThanOneRoot(); - - /** - * Synchronously updates the specified information about Git repository under the given root. - * @param root root directory of the Git repository. - * - */ - void updateRepository(VirtualFile root); - - void updateAllRepositories(); - + @Override + protected GitRepository createRepository(@NotNull VirtualFile root) { + return GitRepositoryImpl.getFullInstance(root, myProject, myPlatformFacade, this); + } } diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryManagerImpl.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryManagerImpl.java deleted file mode 100644 index fd913394e905..000000000000 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryManagerImpl.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * 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.repo; - -import com.intellij.dvcs.repo.RepoStateException; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.ApplicationManager; -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 git4idea.GitPlatformFacade; -import git4idea.GitUtil; -import git4idea.roots.GitRootScanner; -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.locks.ReentrantReadWriteLock; - -/** - * @author Kirill Likhodedov - */ -public class GitRepositoryManagerImpl extends AbstractProjectComponent implements Disposable, GitRepositoryManager, VcsListener { - - private static final Logger LOG = Logger.getInstance(GitRepositoryManager.class); - - @NotNull private final ProjectLevelVcsManager myVcsManager; - @NotNull private AbstractVcs myVcs; - - @NotNull private final Map myRepositories = new HashMap(); - - @NotNull private final ReentrantReadWriteLock REPO_LOCK = new ReentrantReadWriteLock(); - @NotNull private final GitPlatformFacade myPlatformFacade; - - public GitRepositoryManagerImpl(@NotNull Project project, @NotNull GitPlatformFacade platformFacade, - @NotNull ProjectLevelVcsManager vcsManager) { - super(project); - myPlatformFacade = platformFacade; - myVcsManager = vcsManager; - } - - @Override - public void initComponent() { - myVcs = myPlatformFacade.getVcs(myProject); - Disposer.register(myProject, this); - myProject.getMessageBus().connect().subscribe(ProjectLevelVcsManager.VCS_CONFIGURATION_CHANGED, this); - if (!ApplicationManager.getApplication().isUnitTestMode()) { - GitRootScanner.start(myProject); - } - } - - @Override - public void dispose() { - try { - REPO_LOCK.writeLock().lock(); - myRepositories.clear(); - } - finally { - REPO_LOCK.writeLock().unlock(); - } - } - - @Override - public void directoryMappingChanged() { - updateRepositoriesCollection(); - } - - @Override - @Nullable - public GitRepository 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 GitRepository getRepositoryForFile(@NotNull VirtualFile file) { - final VcsRoot vcsRoot = myVcsManager.getVcsRootObjectFor(file); - return getRepositoryForVcsRoot(vcsRoot, file.getPath()); - } - - @Override - public GitRepository getRepositoryForFile(@NotNull FilePath file) { - final VcsRoot vcsRoot = myVcsManager.getVcsRootObjectFor(file); - return getRepositoryForVcsRoot(vcsRoot, file.getPath()); - } - - @Nullable - private GitRepository getRepositoryForVcsRoot(VcsRoot vcsRoot, 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-Git (%s) root for file %s", vcs.getDisplayName(), filePath)); - } - return null; - } - return getRepositoryForRoot(vcsRoot.getPath()); - } - - @Override - @NotNull - public List getRepositories() { - try { - REPO_LOCK.readLock().lock(); - return GitUtil.sortRepositories(myRepositories.values()); - } - finally { - REPO_LOCK.readLock().unlock(); - } - } - - @Override - public boolean moreThanOneRoot() { - return myRepositories.size() > 1; - } - - @Override - public void updateRepository(VirtualFile root) { - GitRepository repo = getRepositoryForRoot(root); - if (repo != null) { - repo.update(); - } - } - - @Override - public void updateAllRepositories() { - Map repositories; - try { - REPO_LOCK.readLock().lock(); - repositories = new HashMap(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 the GitRootTracker - private void updateRepositoriesCollection() { - Map repositories; - try { - REPO_LOCK.readLock().lock(); - repositories = new HashMap(myRepositories); - } - finally { - REPO_LOCK.readLock().unlock(); - } - - final VirtualFile[] roots = myVcsManager.getRootsUnderVcs(myVcs); - // remove repositories that are not in the roots anymore - for (Iterator> iterator = repositories.entrySet().iterator(); iterator.hasNext(); ) { - if (!ArrayUtil.contains(iterator.next().getValue().getRoot(), roots)) { - iterator.remove(); - } - } - // add GitRepositories for all roots that don't have correspondent GitRepositories yet. - for (VirtualFile root : roots) { - if (!repositories.containsKey(root)) { - if (gitRootOK(root)) { - try { - GitRepository repository = createGitRepository(root); - repositories.put(root, repository); - } - catch (RepoStateException e) { - LOG.error("Couldn't initialize GitRepository in " + root.getPresentableUrl(), e); - } - } - else { - LOG.info("Invalid Git root: " + root); - } - } - } - - REPO_LOCK.writeLock().lock(); - try { - myRepositories.clear(); - myRepositories.putAll(repositories); - } - finally { - REPO_LOCK.writeLock().unlock(); - } - } - - private static boolean gitRootOK(@NotNull VirtualFile root) { - VirtualFile gitDir = root.findChild(GitUtil.DOT_GIT); - return gitDir != null && gitDir.exists(); - } - - private GitRepository createGitRepository(VirtualFile root) { - return GitRepositoryImpl.getFullInstance(root, myProject, myPlatformFacade, this); - } - - @Override - public String toString() { - return "GitRepositoryManager{myRepositories: " + myRepositories + '}'; - } - -} diff --git a/plugins/git4idea/testFramework/git4idea/test/GitTestPlatformFacade.groovy b/plugins/git4idea/testFramework/git4idea/test/GitTestPlatformFacade.groovy index d22c9499739f..07f4a33c5aab 100644 --- a/plugins/git4idea/testFramework/git4idea/test/GitTestPlatformFacade.groovy +++ b/plugins/git4idea/testFramework/git4idea/test/GitTestPlatformFacade.groovy @@ -24,9 +24,7 @@ import git4idea.GitPlatformFacade import git4idea.Notificator import git4idea.config.GitVcsApplicationSettings import git4idea.config.GitVcsSettings -import git4idea.repo.GitRepositoryManager import org.jetbrains.annotations.NotNull - /** * * @author Kirill Likhodedov @@ -85,7 +83,7 @@ class GitTestPlatformFacade extends DvcsTestPlatformFacade implements GitPlatfor @NotNull @Override - public GitRepositoryManager getRepositoryManager(@NotNull Project project) { + public GitTestRepositoryManager getRepositoryManager(@NotNull Project project) { return myRepositoryManager; } diff --git a/plugins/git4idea/testFramework/git4idea/test/GitTestRepositoryManager.groovy b/plugins/git4idea/testFramework/git4idea/test/GitTestRepositoryManager.groovy index 6bb237d7d4ba..4d6d89ef3b35 100644 --- a/plugins/git4idea/testFramework/git4idea/test/GitTestRepositoryManager.groovy +++ b/plugins/git4idea/testFramework/git4idea/test/GitTestRepositoryManager.groovy @@ -14,16 +14,17 @@ * limitations under the License. */ package git4idea.test + +import com.intellij.dvcs.repo.RepositoryManager import com.intellij.openapi.vcs.FilePath import com.intellij.openapi.vfs.VirtualFile import git4idea.repo.GitRepository -import git4idea.repo.GitRepositoryManager import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.Nullable /** * @author Kirill Likhodedov */ -public class GitTestRepositoryManager implements GitRepositoryManager { +public class GitTestRepositoryManager implements RepositoryManager { private final List myRepositories = new ArrayList(); diff --git a/plugins/hg4idea/src/META-INF/plugin.xml b/plugins/hg4idea/src/META-INF/plugin.xml index 92efe818f74e..7f1fccb91189 100644 --- a/plugins/hg4idea/src/META-INF/plugin.xml +++ b/plugins/hg4idea/src/META-INF/plugin.xml @@ -28,6 +28,9 @@ org.zmlx.hg4idea.HgRepositoryWatcher org.zmlx.hg4idea.HgRepositoryWatcher + + org.zmlx.hg4idea.repo.HgRepositoryManager + diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java index 1ddff9b62423..16f4ee3de205 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java @@ -26,7 +26,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.action.HgCommandResultNotifier; import org.zmlx.hg4idea.command.HgPushCommand; -import org.zmlx.hg4idea.command.HgShowConfigCommand; import org.zmlx.hg4idea.command.HgTagBranch; import org.zmlx.hg4idea.command.HgTagBranchCommand; import org.zmlx.hg4idea.execution.HgCommandResult; @@ -91,11 +90,6 @@ public class HgPusher { }); } - public static String getDefaultPushPath(@NotNull Project project, @NotNull VirtualFile repo) { - final HgShowConfigCommand configCommand = new HgShowConfigCommand(project); - return configCommand.getDefaultPushPath(repo); - } - @NotNull public static List getBranches(@NotNull Project project, @NotNull VirtualFile root) { HgCommandResult branchesResult = new HgTagBranchCommand(project, root).collectBranches(); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java index ad44f7800327..24f9c68f9480 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java @@ -65,6 +65,7 @@ public class HgVcs extends AbstractVcs { public static final Topic BRANCH_TOPIC = new Topic("hg4idea.branch", HgUpdater.class); public static final Topic REMOTE_TOPIC = new Topic("hg4idea.remote", HgUpdater.class); public static final Topic STATUS_TOPIC = new Topic("hg4idea.status", HgUpdater.class); + public static final Topic UPDATE_CONFIG_TOPIC = new Topic("hg4idea.config", HgUpdater.class); public static final Topic INCOMING_OUTGOING_CHECK_TOPIC = new Topic("hg4idea.incomingcheck", HgHideableWidget.class); private static final Logger LOG = Logger.getInstance(HgVcs.class); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java index cc045d2affd7..64f155064ead 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java @@ -14,6 +14,8 @@ package org.zmlx.hg4idea.command; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.util.HgUtil; public class HgOutgoingCommand extends HgRemoteChangesetsCommand { @@ -21,8 +23,8 @@ public class HgOutgoingCommand extends HgRemoteChangesetsCommand { super(project, "outgoing"); } - protected String getRepositoryUrl(VirtualFile repo) { - return new HgShowConfigCommand(project).getDefaultPushPath(repo); + @Nullable + protected String getRepositoryUrl(VirtualFile root) { + return HgUtil.getRepositoryDefaultPushPath(project, root); } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java index 118d23a63855..9767be438948 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java @@ -22,12 +22,14 @@ import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgProjectSettings; import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.action.HgCommandResultNotifier; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.util.HgErrorUtil; +import org.zmlx.hg4idea.util.HgUtil; import javax.swing.event.HyperlinkEvent; import java.util.List; @@ -54,8 +56,9 @@ public abstract class HgRemoteChangesetsCommand extends HgChangesetsCommand { return true; } - protected String getRepositoryUrl(VirtualFile repo) { - return new HgShowConfigCommand(project).getDefaultPath(repo); + @Nullable + protected String getRepositoryUrl(VirtualFile root) { + return HgUtil.getRepositoryDefaultPath(project, root); } @Override diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgShowConfigCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgShowConfigCommand.java index 06ac78b26417..e444485f8602 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgShowConfigCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgShowConfigCommand.java @@ -15,6 +15,8 @@ package org.zmlx.hg4idea.command; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.execution.HgCommandResult; @@ -25,26 +27,14 @@ import java.util.Map; public class HgShowConfigCommand { - private final Project project; + @NotNull private final Project project; - public HgShowConfigCommand(Project project) { + public HgShowConfigCommand(@NotNull Project project) { this.project = project; } - public String getDefaultPath(VirtualFile repo) { - return execute(repo).get("paths.default"); - } - - public String getDefaultPushPath(VirtualFile repo) { - final Map map = execute(repo); - String path = map.get("paths.default-push"); - if (path == null) { - path = map.get("paths.default"); - } - return path; - } - - public Map execute(VirtualFile repo) { + @NotNull + public Map execute(@Nullable VirtualFile repo) { if (repo == null) { return Collections.emptyMap(); } @@ -66,5 +56,4 @@ public class HgShowConfigCommand { } return options; } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java index e44b38859763..6cf3bcadf500 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java @@ -26,6 +26,7 @@ import org.zmlx.hg4idea.*; import org.zmlx.hg4idea.command.*; import org.zmlx.hg4idea.execution.HgCommandException; import org.zmlx.hg4idea.execution.HgCommandResult; +import org.zmlx.hg4idea.util.HgUtil; import java.util.ArrayList; import java.util.List; @@ -36,13 +37,13 @@ import static org.zmlx.hg4idea.HgErrorHandler.ensureSuccess; public class HgRegularUpdater implements HgUpdater { private final Project project; - @NotNull private final VirtualFile repository; + @NotNull private final VirtualFile repoRoot; @NotNull private final UpdateConfiguration updateConfiguration; private static final Logger LOG = Logger.getInstance(HgRegularUpdater.class); public HgRegularUpdater(Project project, @NotNull VirtualFile repository, @NotNull UpdateConfiguration configuration) { this.project = project; - this.repository = repository; + this.repoRoot = repository; this.updateConfiguration = configuration; } @@ -64,20 +65,19 @@ public class HgRegularUpdater implements HgUpdater { public boolean update(final UpdatedFiles updatedFiles, ProgressIndicator indicator, List warnings) throws VcsException { - indicator.setText(HgVcsMessages.message("hg4idea.progress.updating", repository.getPath())); + indicator.setText(HgVcsMessages.message("hg4idea.progress.updating", repoRoot.getPath())); - HgShowConfigCommand configCommand = new HgShowConfigCommand(project); - String defaultPath = configCommand.getDefaultPath(repository); + String defaultPath = HgUtil.getRepositoryDefaultPath(project, repoRoot); if (StringUtil.isEmptyOrSpaces(defaultPath)) { - throw new VcsException(HgVcsMessages.message("hg4idea.warning.no-default-update-path", repository.getPath())); + throw new VcsException(HgVcsMessages.message("hg4idea.warning.no-default-update-path", repoRoot.getPath())); } - List branchHeadsBeforePull = new HgHeadsCommand(project, repository).execute(); + List branchHeadsBeforePull = new HgHeadsCommand(project, repoRoot).execute(); if (branchHeadsBeforePull.size() > 1) { - reportWarning(warnings, HgVcsMessages.message("hg4idea.update.warning.multipleHeadsBeforeUpdate", repository.getPath())); + reportWarning(warnings, HgVcsMessages.message("hg4idea.update.warning.multipleHeadsBeforeUpdate", repoRoot.getPath())); } //TODO perhaps report a warning in this case ? @@ -89,7 +89,7 @@ public class HgRegularUpdater implements HgUpdater { // } if (shouldPull()) { - boolean pullResult = pull(repository, indicator); + boolean pullResult = pull(repoRoot, indicator); if (!pullResult) { return false; } @@ -97,14 +97,14 @@ public class HgRegularUpdater implements HgUpdater { if (shouldUpdate()) { - List parentsBeforeUpdate = new HgWorkingCopyRevisionsCommand(project).parents(repository); + List parentsBeforeUpdate = new HgWorkingCopyRevisionsCommand(project).parents(repoRoot); if (parentsBeforeUpdate.size() > 1) { - throw new VcsException(HgVcsMessages.message("hg4idea.update.error.uncommittedMerge", repository.getPath())); + throw new VcsException(HgVcsMessages.message("hg4idea.update.error.uncommittedMerge", repoRoot.getPath())); } indicator.setText2(HgVcsMessages.message("hg4idea.progress.countingHeads")); - List branchHeadsAfterPull = new HgHeadsCommand(project, repository).execute(); + List branchHeadsAfterPull = new HgHeadsCommand(project, repoRoot).execute(); List pulledBranchHeads = determinePulledBranchHeads(branchHeadsBeforePull, branchHeadsAfterPull); List remainingOriginalBranchHeads = determingRemainingOriginalBranchHeads(branchHeadsBeforePull, branchHeadsAfterPull); @@ -113,14 +113,14 @@ public class HgRegularUpdater implements HgUpdater { abortOnMultiplePulledHeads(pulledBranchHeads); abortOnMultipleLocalHeads(remainingOriginalBranchHeads); - HgCommandResult mergeResult = doMerge(updatedFiles, indicator, warnings, pulledBranchHeads.get(0)); + HgCommandResult mergeResult = doMerge(updatedFiles, indicator, pulledBranchHeads.get(0)); if (shouldCommitAfterMerge()) { commitOrWarnAboutConflicts(warnings, mergeResult); } } else { //in case of multiple heads the update will report the appropriate error - update(repository, indicator, updatedFiles, warnings); + update(repoRoot, indicator, updatedFiles, warnings); } //any kind of update could have resulted in merges and merge conflicts, so run the resolver @@ -129,7 +129,8 @@ public class HgRegularUpdater implements HgUpdater { return true; } - private List determingRemainingOriginalBranchHeads(List branchHeadsBeforePull, List branchHeadsAfterPull) { + private static List determingRemainingOriginalBranchHeads(List branchHeadsBeforePull, + List branchHeadsAfterPull) { List originalBranchHeadsRemaining = new ArrayList(); for (HgRevisionNumber headAfterPull : branchHeadsAfterPull) { if (branchHeadsBeforePull.contains(headAfterPull)) { @@ -139,7 +140,8 @@ public class HgRegularUpdater implements HgUpdater { return originalBranchHeadsRemaining; } - private List determinePulledBranchHeads(List branchHeadsBeforePull, List branchHeadsAfterPull) { + private static List determinePulledBranchHeads(List branchHeadsBeforePull, + List branchHeadsAfterPull) { List pulledBranchHeads = new ArrayList(branchHeadsAfterPull); pulledBranchHeads.removeAll(branchHeadsBeforePull); return pulledBranchHeads; @@ -147,20 +149,21 @@ public class HgRegularUpdater implements HgUpdater { private void abortOnMultipleLocalHeads(List originalBranchHeadsRemaining) throws VcsException { if (originalBranchHeadsRemaining.size() != 1) { - throw new VcsException(HgVcsMessages.message("hg4idea.update.error.merge.multipleLocalHeads", repository.getPath())); + throw new VcsException(HgVcsMessages.message("hg4idea.update.error.merge.multipleLocalHeads", repoRoot.getPath())); } } private void abortOnMultiplePulledHeads(List newBranchHeadsAfterPull) throws VcsException { if (newBranchHeadsAfterPull.size() != 1) { - throw new VcsException(HgVcsMessages.message("hg4idea.update.error.merge.multipleRemoteHeads", newBranchHeadsAfterPull.size(), repository.getPath())); + throw new VcsException(HgVcsMessages.message("hg4idea.update.error.merge.multipleRemoteHeads", newBranchHeadsAfterPull.size(), + repoRoot.getPath())); } } private void updateToPulledHead(VirtualFile repo, UpdatedFiles updatedFiles, HgRevisionNumber newHead, ProgressIndicator indicator) { indicator.setText2(HgVcsMessages.message("hg4idea.update.progress.updating.to.pulled.head")); HgRevisionNumber parentBeforeUpdate = new HgWorkingCopyRevisionsCommand(project).firstParent(repo); - HgUpdateCommand updateCommand = new HgUpdateCommand(project, repository); + HgUpdateCommand updateCommand = new HgUpdateCommand(project, repoRoot); updateCommand.setRevision(newHead.getChangeset()); updateCommand.setClean(true); updateCommand.execute(); @@ -171,12 +174,12 @@ public class HgRegularUpdater implements HgUpdater { private @Nullable HgRevisionNumber findCommonParent(HgRevisionNumber newHead, HgRevisionNumber parentBeforeUpdate) { // hg log -r 0:source --prune dest --limit 1 - final List pulledRevisions = new HgMergePreviewCommand(project, newHead, parentBeforeUpdate, 1).execute(repository); + final List pulledRevisions = new HgMergePreviewCommand(project, newHead, parentBeforeUpdate, 1).execute(repoRoot); if (pulledRevisions == null || pulledRevisions.isEmpty()) { return null; } HgRevisionNumber pulledRevision = pulledRevisions.get(0); - final List parentRevisions = new HgWorkingCopyRevisionsCommand(project).getRevisions(repository, "parent", null, pulledRevision, true); + final List parentRevisions = new HgWorkingCopyRevisionsCommand(project).getRevisions(repoRoot, "parent", null, pulledRevision, true); if (parentRevisions.isEmpty()) { return null; } @@ -186,45 +189,46 @@ public class HgRegularUpdater implements HgUpdater { private void commitOrWarnAboutConflicts(List exceptions, HgCommandResult mergeResult) throws VcsException { if (mergeResult.getExitValue() == 0) { //operation successful and no conflicts try { - new HgCommitCommand(project, repository, "Automated merge").execute(); + new HgCommitCommand(project, repoRoot, "Automated merge").execute(); } catch (HgCommandException e) { throw new VcsException(e); } } else { - reportWarning(exceptions, HgVcsMessages.message("hg4idea.update.warning.merge.conflicts", repository.getPath())); + reportWarning(exceptions, HgVcsMessages.message("hg4idea.update.warning.merge.conflicts", repoRoot.getPath())); } } - private HgCommandResult doMerge(UpdatedFiles updatedFiles, ProgressIndicator indicator, List exceptions, HgRevisionNumber headToMerge) throws VcsException { + private HgCommandResult doMerge(UpdatedFiles updatedFiles, + ProgressIndicator indicator, + HgRevisionNumber headToMerge) throws VcsException { indicator.setText2(HgVcsMessages.message("hg4idea.update.progress.merging")); - HgMergeCommand mergeCommand = new HgMergeCommand(project, repository); + HgMergeCommand mergeCommand = new HgMergeCommand(project, repoRoot); //do not explicitly set the revision, that way mercurial itself checks that there are exactly //two heads in this branch // mergeCommand.setRevision(headToMerge.getRevision()); - HgCommandResult mergeResult = new HgHeadMerger(project, mergeCommand).merge(repository, updatedFiles, headToMerge); - return mergeResult; + return new HgHeadMerger(project, mergeCommand).merge(repoRoot, updatedFiles, headToMerge); } private void abortOnLocalChanges() throws VcsException { if (getLocalChanges().size() != 0) { - throw new VcsException(HgVcsMessages.message("hg4idea.update.error.localchanges", repository.getPath())); + throw new VcsException(HgVcsMessages.message("hg4idea.update.error.localchanges", repoRoot.getPath())); } } private void resolvePossibleConflicts(final UpdatedFiles updatedFiles) { - new HgConflictResolver(project, updatedFiles).resolve(repository); + new HgConflictResolver(project, updatedFiles).resolve(repoRoot); } private Set getLocalChanges() { HgStatusCommand statusCommand = new HgStatusCommand.Builder(true).unknown(false).ignored(false).build(project); - return statusCommand.execute(repository); + return statusCommand.execute(repoRoot); } private boolean pull(VirtualFile repo, ProgressIndicator indicator) throws VcsException { indicator.setText2(HgVcsMessages.message("hg4idea.progress.pull.with.update")); HgPullCommand hgPullCommand = new HgPullCommand(project, repo); - final String defaultPath = new HgShowConfigCommand(project).getDefaultPath(repo); + final String defaultPath = HgUtil.getRepositoryDefaultPath(project, repo); hgPullCommand.setSource(defaultPath); hgPullCommand.setUpdate(false); hgPullCommand.setRebase(false); @@ -244,13 +248,13 @@ public class HgRegularUpdater implements HgUpdater { addUpdatedFiles(repo, updatedFiles, parentBeforeUpdate, parentAfterUpdate); } - private void handlePossibleWarning(List exceptions, String possibleWarning) { + private static void handlePossibleWarning(List exceptions, String possibleWarning) { if (!StringUtil.isEmptyOrSpaces(possibleWarning)) { reportWarning(exceptions, possibleWarning); } } - private void reportWarning(List exceptions, String warningMessage) { + private static void reportWarning(List exceptions, String warningMessage) { @SuppressWarnings({"ThrowableInstanceNeverThrown"}) VcsException warningException = new VcsException(warningMessage); warningException.setIsWarning(true); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgConfig.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgConfig.java new file mode 100644 index 000000000000..eb558b55f3e8 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgConfig.java @@ -0,0 +1,62 @@ +package org.zmlx.hg4idea.repo; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.HgUpdater; +import org.zmlx.hg4idea.HgVcs; +import org.zmlx.hg4idea.command.HgShowConfigCommand; + +import java.util.Collections; +import java.util.Map; + +/** + * @author Nadya Zabrodina + */ +public class HgConfig implements HgUpdater { + + @NotNull private VirtualFile myRepo; + @NotNull private Project myProject; + @NotNull private Map myConfigMap = Collections.emptyMap(); + + + public HgConfig(@NotNull Project project, @NotNull VirtualFile repo) { + myProject = project; + myRepo = repo; + update(myProject, myRepo); + myProject.getMessageBus().connect().subscribe(HgVcs.UPDATE_CONFIG_TOPIC, this); + } + + + @Override + public void update(@NotNull Project project, @Nullable VirtualFile root) { + // todo: may be should change showconfigCommand to parse hgrc file + // but default values for extension and repository root are not included in hgrc, so perform showconfig is better + // in windows configuration Mercurial.ini file may be used instead of hgrc + myConfigMap = new HgShowConfigCommand(myProject).execute(myRepo); + } + + @Nullable + public String getDefaultPath() { + return myConfigMap.get("paths.default"); + } + + @Nullable + public String getDefaultPushPath() { + String path = myConfigMap.get("paths.default-push"); + if (path == null) { + path = myConfigMap.get("paths.default"); + } + return path; + } + + @Nullable + public String getNamedConfig(@Nullable String configName) { + if (StringUtil.isEmptyOrSpaces(configName)) { + return null; + } + return myConfigMap.get(configName); + } +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java index 13e639c21eba..655b68100144 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java @@ -45,4 +45,7 @@ public interface HgRepository extends Repository { @Nullable String getCurrentBookmark(); + + @NotNull + HgConfig getRepositoryConfig(); } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryFiles.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryFiles.java index 0694ad7bbc94..16cc5e2fb5a3 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryFiles.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryFiles.java @@ -37,6 +37,7 @@ public class HgRepositoryFiles { public static final String BRANCH = "branch"; public static final String BOOKMARKS = "bookmarks"; public static final String CURRENT_BOOKMARK = "bookmarks.current"; + public static final String CONFIG_HGRC = "hgrc"; @NotNull private final String myBranchHeadsPath; @@ -45,6 +46,7 @@ public class HgRepositoryFiles { @NotNull private final String myBranchPath; @NotNull private final String myBookmarksPath; @NotNull private final String myCurrentBookmarkPath; + @NotNull private final String myConfigHgrcPath; @NotNull public static HgRepositoryFiles getInstance(@NotNull VirtualFile hgDir) { @@ -57,7 +59,8 @@ public class HgRepositoryFiles { myBranchPath = hgDir.getPath() + slash(BRANCH); myMergePath = hgDir.getPath() + slash(MERGE); myBookmarksPath = hgDir.getPath() + slash(BOOKMARKS); - myCurrentBookmarkPath = hgDir.getPath()+slash(CURRENT_BOOKMARK); + myCurrentBookmarkPath = hgDir.getPath() + slash(CURRENT_BOOKMARK); + myConfigHgrcPath = hgDir.getPath() + slash(CONFIG_HGRC); } @NotNull @@ -97,4 +100,8 @@ public class HgRepositoryFiles { public boolean isCurrentBookmarksFile(String filePath) { return filePath.equals(myCurrentBookmarkPath); } + + public boolean isConfigHgrcFile(String filePath) { + return filePath.equals(myConfigHgrcPath); + } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java index 4bd600d4d242..0b6fb08ef9c8 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java @@ -44,6 +44,7 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository { @Nullable private volatile String myCurrentBookmark = null; @NotNull private volatile Collection myBranches = Collections.emptySet(); @NotNull private volatile Collection myBookmarks = Collections.emptySet(); + @NotNull private volatile HgConfig myConfig; private boolean myIsFresh = true; @@ -56,6 +57,7 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository { myState = State.NORMAL; myCurrentRevision = null; myReader = new HgRepositoryReader(VfsUtilCore.virtualToIoFile(myHgDir)); + myConfig = new HgConfig(project, rootDir); update(); } @@ -103,6 +105,12 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository { return myCurrentBookmark; } + @NotNull + @Override + public HgConfig getRepositoryConfig() { + return myConfig; + } + @Override public boolean isFresh() { return myIsFresh; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryManager.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryManager.java new file mode 100644 index 000000000000..28fe95d45fe3 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryManager.java @@ -0,0 +1,42 @@ +package org.zmlx.hg4idea.repo; + +import com.intellij.dvcs.repo.AbstractRepositoryManager; +import com.intellij.dvcs.repo.RepositoryManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.zmlx.hg4idea.HgVcs; +import org.zmlx.hg4idea.util.HgUtil; + +/** + * @author Nadya Zabrodina + */ +public class HgRepositoryManager extends AbstractRepositoryManager implements RepositoryManager { + + public HgRepositoryManager(@NotNull Project project, + @NotNull ProjectLevelVcsManager vcsManager) { + super(project, vcsManager); + } + + @Override + public void initComponent() { + myVcs = HgVcs.getInstance(myProject); + Disposer.register(myProject, this); + myProject.getMessageBus().connect().subscribe(ProjectLevelVcsManager.VCS_CONFIGURATION_CHANGED, this); + } + + + @Override + protected boolean isRootValid(@NotNull VirtualFile root) { + VirtualFile hgDir = root.findChild(HgUtil.DOT_HG); + return hgDir != null && hgDir.exists(); + } + + @NotNull + @Override + protected HgRepository createRepository(@NotNull VirtualFile root) { + return HgRepositoryImpl.getFullInstance(root, myProject, this); + } +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryUpdater.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryUpdater.java index 839aae7ed3f2..b29cb2738caf 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryUpdater.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryUpdater.java @@ -28,6 +28,7 @@ import com.intellij.util.messages.MessageBusConnection; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.HgVcs; import java.util.List; @@ -37,6 +38,7 @@ import java.util.List; * @author Nadya Zabrodina */ final class HgRepositoryUpdater implements Disposable, BulkFileListener { + @NotNull private Project myProject; @NotNull private final HgRepositoryFiles myRepositoryFiles; @Nullable private final MessageBusConnection myMessageBusConnection; @NotNull private final QueueProcessor myUpdateQueue; @@ -53,10 +55,10 @@ final class HgRepositoryUpdater implements Disposable, BulkFileListener { myBranchHeadsDir = VcsUtil.getVirtualFile(myRepositoryFiles.getBranchHeadsDirPath()); - Project project = repository.getProject(); - myUpdateQueue = new QueueProcessor(new RepositoryUtil.Updater(repository), project.getDisposed()); - if (!project.isDisposed()) { - myMessageBusConnection = project.getMessageBus().connect(); + myProject = repository.getProject(); + myUpdateQueue = new QueueProcessor(new RepositoryUtil.Updater(repository), myProject.getDisposed()); + if (!myProject.isDisposed()) { + myMessageBusConnection = myProject.getMessageBus().connect(); myMessageBusConnection.subscribe(VirtualFileManager.VFS_CHANGES, this); } else { @@ -88,6 +90,7 @@ final class HgRepositoryUpdater implements Disposable, BulkFileListener { boolean mergeFileChanged = false; boolean bookmarksFileChanged = false; boolean currentBookmarkFileChanged = false; + boolean configHgrcChanged = false; for (VFileEvent event : events) { String filePath = event.getPath(); if (filePath == null) { @@ -109,11 +112,17 @@ final class HgRepositoryUpdater implements Disposable, BulkFileListener { else if (myRepositoryFiles.isCurrentBookmarksFile(filePath)) { currentBookmarkFileChanged = true; } - } + else if (myRepositoryFiles.isConfigHgrcFile(filePath)) { + configHgrcChanged = true; + } + } if (branchHeadsChanged || branchFileChanged || mergeFileChanged || bookmarksFileChanged || currentBookmarkFileChanged) { myUpdateQueue.add(DUMMY_UPDATE_OBJECT); } + if (configHgrcChanged) { + myProject.getMessageBus().syncPublisher(HgVcs.UPDATE_CONFIG_TOPIC).update(myProject, null); + } } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPullDialog.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPullDialog.java index 8d1f2b00df77..f2412d9f613d 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPullDialog.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPullDialog.java @@ -24,7 +24,6 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgRememberedInputs; -import org.zmlx.hg4idea.command.HgShowConfigCommand; import org.zmlx.hg4idea.util.HgUtil; import javax.swing.*; @@ -101,8 +100,7 @@ public class HgPullDialog extends DialogWrapper { @Override public void run() { VirtualFile repo = hgRepositorySelector.getRepository(); - HgShowConfigCommand configCommand = new HgShowConfigCommand(project); - final String defaultPath = configCommand.getDefaultPath(repo); + final String defaultPath = HgUtil.getRepositoryDefaultPath(project,repo); if (!StringUtil.isEmptyOrSpaces(defaultPath)) { UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPushDialog.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPushDialog.java index a76c7872391c..6e11818a2005 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPushDialog.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPushDialog.java @@ -133,7 +133,7 @@ public class HgPushDialog extends DialogWrapper { @Override public void run() { final VirtualFile repo = hgRepositorySelectorComponent.getRepository(); - final String defaultPath = HgPusher.getDefaultPushPath(myProject, repo); + final String defaultPath = HgUtil.getRepositoryDefaultPushPath(myProject, repo); final List branches = HgPusher.getBranches(myProject, repo); ApplicationManager.getApplication().invokeLater(new Runnable() { @Override diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java index 0f355b2b4271..cdee4c504187 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java @@ -13,6 +13,7 @@ package org.zmlx.hg4idea.util; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -44,6 +45,7 @@ import org.zmlx.hg4idea.command.HgStatusCommand; import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand; import org.zmlx.hg4idea.provider.HgChangeProvider; import org.zmlx.hg4idea.repo.HgRepository; +import org.zmlx.hg4idea.repo.HgRepositoryManager; import java.awt.*; import java.io.*; @@ -548,4 +550,21 @@ public abstract class HgUtil { } return branchText + repository.getCurrentBranch(); } + + @NotNull + public static HgRepositoryManager getRepositoryManager(@NotNull Project project) { + return ServiceManager.getService(project, HgRepositoryManager.class); + } + + @Nullable + public static String getRepositoryDefaultPath(@NotNull Project project, @NotNull VirtualFile root) { + HgRepository hgRepository = getRepositoryManager(project).getRepositoryForRoot(root); + return hgRepository != null ? hgRepository.getRepositoryConfig().getDefaultPath() : null; + } + + @Nullable + public static String getRepositoryDefaultPushPath(@NotNull Project project, @NotNull VirtualFile root) { + HgRepository hgRepository = getRepositoryManager(project).getRepositoryForRoot(root); + return hgRepository != null ? hgRepository.getRepositoryConfig().getDefaultPushPath() : null; + } } diff --git a/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgUpdateTest.java b/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgUpdateTest.java index 4c00183d22d8..8ab8cd367763 100644 --- a/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgUpdateTest.java +++ b/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgUpdateTest.java @@ -25,6 +25,7 @@ import org.zmlx.hg4idea.HgFileStatusEnum; import org.zmlx.hg4idea.HgRevisionNumber; import org.zmlx.hg4idea.command.*; import org.zmlx.hg4idea.provider.update.HgRegularUpdater; +import org.zmlx.hg4idea.util.HgUtil; import java.io.File; import java.io.IOException; @@ -58,7 +59,7 @@ public class HgUpdateTest extends HgCollaborativeTest { //do a simple pull without an update HgPullCommand pull = new HgPullCommand(myProject, projectRepoVirtualFile); - pull.setSource(new HgShowConfigCommand(myProject).getDefaultPath(projectRepoVirtualFile)); + pull.setSource(HgUtil.getRepositoryDefaultPath(myProject, projectRepoVirtualFile)); pull.setUpdate(false); pull.execute();