mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
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;
This commit is contained in:
@@ -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<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 protected AbstractVcs myVcs;
|
||||
|
||||
@NotNull protected final Map<VirtualFile, T> myRepositories = new HashMap<VirtualFile, T>();
|
||||
|
||||
@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<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);
|
||||
}
|
||||
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 + '}';
|
||||
}
|
||||
}
|
||||
@@ -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<T extends Repository> {
|
||||
|
||||
/**
|
||||
* 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<T> 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();
|
||||
}
|
||||
@@ -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 <T extends Repository> List<T> sortRepositories(@NotNull Collection<T> repositories) {
|
||||
List<T> repos = new ArrayList<T>(repositories);
|
||||
Collections.sort(repos, new Comparator<Repository>() {
|
||||
@Override
|
||||
public int compare(Repository o1, Repository o2) {
|
||||
return o1.getPresentableUrl().compareTo(o2.getPresentableUrl());
|
||||
}
|
||||
});
|
||||
return repos;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,8 +81,7 @@
|
||||
|
||||
<project-components>
|
||||
<component>
|
||||
<interface-class>git4idea.repo.GitRepositoryManager</interface-class>
|
||||
<implementation-class>git4idea.repo.GitRepositoryManagerImpl</implementation-class>
|
||||
<implementation-class>git4idea.repo.GitRepositoryManager</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
|
||||
@@ -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 extends RepositoryManager<GitRepository>> T getRepositoryManager(@NotNull Project project);
|
||||
|
||||
@NotNull
|
||||
GitVcsSettings getSettings(Project project);
|
||||
|
||||
@@ -685,15 +685,6 @@ public class GitUtil {
|
||||
return !manager.moreThanOneRoot();
|
||||
}
|
||||
|
||||
public static List<GitRepository> sortRepositories(@NotNull Collection<GitRepository> repositories) {
|
||||
List<GitRepository> repos = new ArrayList<GitRepository>(repositories);
|
||||
Collections.sort(repos, new Comparator<GitRepository>() {
|
||||
@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) {
|
||||
|
||||
@@ -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 <br/>");
|
||||
for (GitRepository repository : GitUtil.sortRepositories(currentBranches.keySet())) {
|
||||
for (GitRepository repository : RepositoryUtil.sortRepositories(currentBranches.keySet())) {
|
||||
sb.append(HTML_IDENT).append(code(repository.getPresentableUrl())).append("<br/>");
|
||||
}
|
||||
sb.append(DESCRIPTION_ENDING);
|
||||
|
||||
@@ -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<GitRepository> implements RepositoryManager<GitRepository> {
|
||||
|
||||
/**
|
||||
* 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<GitRepository> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<VirtualFile, GitRepository> myRepositories = new HashMap<VirtualFile, GitRepository>();
|
||||
|
||||
@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<GitRepository> 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<VirtualFile, GitRepository> repositories;
|
||||
try {
|
||||
REPO_LOCK.readLock().lock();
|
||||
repositories = new HashMap<VirtualFile, GitRepository>(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<VirtualFile, GitRepository> repositories;
|
||||
try {
|
||||
REPO_LOCK.readLock().lock();
|
||||
repositories = new HashMap<VirtualFile, GitRepository>(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, GitRepository>> 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 + '}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<GitRepository> {
|
||||
|
||||
private final List<GitRepository> myRepositories = new ArrayList<GitRepository>();
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
<interface-class>org.zmlx.hg4idea.HgRepositoryWatcher</interface-class>
|
||||
<implementation-class>org.zmlx.hg4idea.HgRepositoryWatcher</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.zmlx.hg4idea.repo.HgRepositoryManager</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
<actions>
|
||||
|
||||
@@ -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<HgTagBranch> getBranches(@NotNull Project project, @NotNull VirtualFile root) {
|
||||
HgCommandResult branchesResult = new HgTagBranchCommand(project, root).collectBranches();
|
||||
|
||||
@@ -65,6 +65,7 @@ public class HgVcs extends AbstractVcs<CommittedChangeList> {
|
||||
public static final Topic<HgUpdater> BRANCH_TOPIC = new Topic<HgUpdater>("hg4idea.branch", HgUpdater.class);
|
||||
public static final Topic<HgUpdater> REMOTE_TOPIC = new Topic<HgUpdater>("hg4idea.remote", HgUpdater.class);
|
||||
public static final Topic<HgUpdater> STATUS_TOPIC = new Topic<HgUpdater>("hg4idea.status", HgUpdater.class);
|
||||
public static final Topic<HgUpdater> UPDATE_CONFIG_TOPIC = new Topic<HgUpdater>("hg4idea.config", HgUpdater.class);
|
||||
public static final Topic<HgHideableWidget> INCOMING_OUTGOING_CHECK_TOPIC =
|
||||
new Topic<HgHideableWidget>("hg4idea.incomingcheck", HgHideableWidget.class);
|
||||
private static final Logger LOG = Logger.getInstance(HgVcs.class);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<String, String> map = execute(repo);
|
||||
String path = map.get("paths.default-push");
|
||||
if (path == null) {
|
||||
path = map.get("paths.default");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public Map<String, String> execute(VirtualFile repo) {
|
||||
@NotNull
|
||||
public Map<String, String> execute(@Nullable VirtualFile repo) {
|
||||
if (repo == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
@@ -66,5 +56,4 @@ public class HgShowConfigCommand {
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<VcsException> 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<HgRevisionNumber> branchHeadsBeforePull = new HgHeadsCommand(project, repository).execute();
|
||||
List<HgRevisionNumber> 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<HgRevisionNumber> parentsBeforeUpdate = new HgWorkingCopyRevisionsCommand(project).parents(repository);
|
||||
List<HgRevisionNumber> 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<HgRevisionNumber> branchHeadsAfterPull = new HgHeadsCommand(project, repository).execute();
|
||||
List<HgRevisionNumber> branchHeadsAfterPull = new HgHeadsCommand(project, repoRoot).execute();
|
||||
List<HgRevisionNumber> pulledBranchHeads = determinePulledBranchHeads(branchHeadsBeforePull, branchHeadsAfterPull);
|
||||
List<HgRevisionNumber> 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<HgRevisionNumber> determingRemainingOriginalBranchHeads(List<HgRevisionNumber> branchHeadsBeforePull, List<HgRevisionNumber> branchHeadsAfterPull) {
|
||||
private static List<HgRevisionNumber> determingRemainingOriginalBranchHeads(List<HgRevisionNumber> branchHeadsBeforePull,
|
||||
List<HgRevisionNumber> branchHeadsAfterPull) {
|
||||
List<HgRevisionNumber> originalBranchHeadsRemaining = new ArrayList<HgRevisionNumber>();
|
||||
for (HgRevisionNumber headAfterPull : branchHeadsAfterPull) {
|
||||
if (branchHeadsBeforePull.contains(headAfterPull)) {
|
||||
@@ -139,7 +140,8 @@ public class HgRegularUpdater implements HgUpdater {
|
||||
return originalBranchHeadsRemaining;
|
||||
}
|
||||
|
||||
private List<HgRevisionNumber> determinePulledBranchHeads(List<HgRevisionNumber> branchHeadsBeforePull, List<HgRevisionNumber> branchHeadsAfterPull) {
|
||||
private static List<HgRevisionNumber> determinePulledBranchHeads(List<HgRevisionNumber> branchHeadsBeforePull,
|
||||
List<HgRevisionNumber> branchHeadsAfterPull) {
|
||||
List<HgRevisionNumber> pulledBranchHeads = new ArrayList<HgRevisionNumber>(branchHeadsAfterPull);
|
||||
pulledBranchHeads.removeAll(branchHeadsBeforePull);
|
||||
return pulledBranchHeads;
|
||||
@@ -147,20 +149,21 @@ public class HgRegularUpdater implements HgUpdater {
|
||||
|
||||
private void abortOnMultipleLocalHeads(List<HgRevisionNumber> 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<HgRevisionNumber> 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<HgRevisionNumber> pulledRevisions = new HgMergePreviewCommand(project, newHead, parentBeforeUpdate, 1).execute(repository);
|
||||
final List<HgRevisionNumber> pulledRevisions = new HgMergePreviewCommand(project, newHead, parentBeforeUpdate, 1).execute(repoRoot);
|
||||
if (pulledRevisions == null || pulledRevisions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
HgRevisionNumber pulledRevision = pulledRevisions.get(0);
|
||||
final List<HgRevisionNumber> parentRevisions = new HgWorkingCopyRevisionsCommand(project).getRevisions(repository, "parent", null, pulledRevision, true);
|
||||
final List<HgRevisionNumber> 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<VcsException> 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<VcsException> 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<HgChange> 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<VcsException> exceptions, String possibleWarning) {
|
||||
private static void handlePossibleWarning(List<VcsException> exceptions, String possibleWarning) {
|
||||
if (!StringUtil.isEmptyOrSpaces(possibleWarning)) {
|
||||
reportWarning(exceptions, possibleWarning);
|
||||
}
|
||||
}
|
||||
|
||||
private void reportWarning(List<VcsException> exceptions, String warningMessage) {
|
||||
private static void reportWarning(List<VcsException> exceptions, String warningMessage) {
|
||||
@SuppressWarnings({"ThrowableInstanceNeverThrown"})
|
||||
VcsException warningException = new VcsException(warningMessage);
|
||||
warningException.setIsWarning(true);
|
||||
|
||||
@@ -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<String, String> 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);
|
||||
}
|
||||
}
|
||||
@@ -45,4 +45,7 @@ public interface HgRepository extends Repository {
|
||||
|
||||
@Nullable
|
||||
String getCurrentBookmark();
|
||||
|
||||
@NotNull
|
||||
HgConfig getRepositoryConfig();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository {
|
||||
@Nullable private volatile String myCurrentBookmark = null;
|
||||
@NotNull private volatile Collection<String> myBranches = Collections.emptySet();
|
||||
@NotNull private volatile Collection<String> 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;
|
||||
|
||||
@@ -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<HgRepository> implements RepositoryManager<HgRepository> {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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<Object> myUpdateQueue;
|
||||
@@ -53,10 +55,10 @@ final class HgRepositoryUpdater implements Disposable, BulkFileListener {
|
||||
|
||||
myBranchHeadsDir = VcsUtil.getVirtualFile(myRepositoryFiles.getBranchHeadsDirPath());
|
||||
|
||||
Project project = repository.getProject();
|
||||
myUpdateQueue = new QueueProcessor<Object>(new RepositoryUtil.Updater(repository), project.getDisposed());
|
||||
if (!project.isDisposed()) {
|
||||
myMessageBusConnection = project.getMessageBus().connect();
|
||||
myProject = repository.getProject();
|
||||
myUpdateQueue = new QueueProcessor<Object>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<HgTagBranch> branches = HgPusher.getBranches(myProject, repo);
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user