Merge remote-tracking branch 'origin/master'

This commit is contained in:
Alexander Lobas
2012-04-20 13:33:50 +04:00
17 changed files with 309 additions and 28 deletions
@@ -25,6 +25,7 @@ import com.intellij.openapi.vfs.newvfs.ManagingFS;
import com.intellij.openapi.vfs.newvfs.NewVirtualFileSystem;
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent;
import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl;
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
import com.intellij.testFramework.PlatformLangTestCase;
import com.intellij.testFramework.PlatformTestUtil;
@@ -325,7 +326,15 @@ public class LocalFileSystemTest extends PlatformLangTestCase {
public void testWindowsVirtualDirectory() throws Exception {
if (!SystemInfo.isWindows) return;
File file = new File("c:\\Documents and Settings\\desktop.ini");
VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
String parent = FileUtil.toSystemIndependentName(file.getParent());
VirtualDirectoryImpl.allowRootAccess(parent);
VirtualFile virtualFile;
try {
virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
}
finally {
VirtualDirectoryImpl.disallowRootAccess(parent);
}
if (virtualFile == null) {
System.out.println("NO LUCK: " + file);
return;
@@ -365,6 +365,9 @@ public class GitBranch extends GitReference {
if (branch.startsWith(REFS_HEADS_PREFIX)) {
branch = branch.substring(REFS_HEADS_PREFIX.length());
}
else if (branch.startsWith(REFS_REMOTES_PREFIX)) {
branch = branch.substring(REFS_REMOTES_PREFIX.length());
}
boolean remoteFlag;
if (!".".equals(remote)) {
branch = remote + "/" + branch;
@@ -15,6 +15,7 @@
*/
package git4idea;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
@@ -27,6 +28,7 @@ import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import git4idea.repo.GitRepositoryManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* IntelliJ code provides a lot of statical bindings to the interested pieces of data. For example we need to execute code
@@ -80,4 +82,8 @@ public interface PlatformFacade {
@NotNull
GitRepositoryManager getRepositoryManager(@NotNull Project project);
@Nullable
IdeaPluginDescriptor getPluginByClassName(@NotNull String name);
}
@@ -15,6 +15,8 @@
*/
package git4idea;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.ServiceManager;
@@ -29,6 +31,7 @@ import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import git4idea.repo.GitRepositoryManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Kirill Likhodedov
@@ -100,6 +103,12 @@ public class PlatformFacadeImpl implements PlatformFacade {
return ServiceManager.getService(project, GitRepositoryManager.class);
}
@Nullable
@Override
public IdeaPluginDescriptor getPluginByClassName(@NotNull String name) {
return PluginManager.getPlugin(PluginManager.getPluginByClassName(name));
}
@NotNull
@Override
public AbstractVcs getVcs(@NotNull Project project) {
@@ -146,7 +146,11 @@ git.vcs.config.convert.tooltip=<html>Specify what to do if line separators in a
git.vcs.config.path.label=Path to &Git Executable:
git.vcs.config.ssh.mode.idea=Built-in
git.vcs.config.ssh.mode.native=Native
git.vcs.config.ssh.mode.tooltip=<html>Specify which version of SSH to be used with Git.<ul><li><b>Native</b> means that the native SSH will be used.</li><li><b>{0} SSH</b> means that the implementation provided by the {0} will be used.</li></ul>The native implementation might cause hangups on some platforms. In native case, you also might need to configure <em>ssh-askpass</em> for your platform to receive GUI prompts for passwords.</html>
git.vcs.config.ssh.mode.tooltip=<html>Specify the version of SSH to be used with Git.\
<ul><li><b>Native</b> means that the native SSH will be used.</li>\
<li><b>Built-in</b> means that the implementation provided by {0} will be used.</li></ul>\
The native implementation might cause hangups on some platforms. \
In native case, you also might need to configure <em>ssh-askpass</em> for your platform to receive GUI prompts for passwords.</html>
git.vcs.config.ssh.mode=&SSH Executable:
git.vcs.config.test.label=Test
git.vcs.config.test=&Test
@@ -16,9 +16,9 @@
package git4idea.repo;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import git4idea.PlatformFacade;
import org.ini4j.Ini;
import org.ini4j.Profile;
import org.jetbrains.annotations.NotNull;
@@ -51,11 +51,13 @@ public class GitConfig {
private static final Logger LOG = Logger.getInstance(GitConfig.class);
private static final Pattern REMOTE_SECTION = Pattern.compile("remote \"(.*)\"");
private static final Pattern REMOTE_SECTION = Pattern.compile("(?:svn-)?remote \"(.*)\"");
private static final Pattern URL_SECTION = Pattern.compile("url \"(.*)\"");
private static final Pattern BRANCH_INFO_SECTION = Pattern.compile("branch \"(.*)\"");
private static final Pattern BRANCH_COMMON_PARAMS_SECTION = Pattern.compile("branch");
private static final String DOT_REMOTE = "."; // used in git-svn "remote = . "
private final Collection<GitRemote> myRemotes;
private final Collection<GitBranchTrackInfo> myBranchTrackInfos;
@@ -102,7 +104,7 @@ public class GitConfig {
* If it has valid format in general, but some sections are invalid, it skips invalid sections, but reports an error.
*/
@NotNull
static GitConfig read(@NotNull File configFile) {
static GitConfig read(@NotNull PlatformFacade platformFacade, @NotNull File configFile) {
Ini ini = new Ini();
ini.getConfig().setMultiOption(true); // duplicate keys (e.g. url in [remote])
ini.getConfig().setTree(false); // don't need tree structure: it corrupts url in section name (e.g. [url "http://github.com/"]
@@ -114,7 +116,7 @@ public class GitConfig {
return new GitConfig(Collections.<GitRemote>emptyList(), Collections.<GitBranchTrackInfo>emptyList());
}
IdeaPluginDescriptor plugin = PluginManager.getPlugin(PluginManager.getPluginByClassName(GitConfig.class.getName()));
IdeaPluginDescriptor plugin = platformFacade.getPluginByClassName(GitConfig.class.getName());
ClassLoader classLoader = plugin == null ? null : plugin.getPluginClassLoader(); // null if IDEA is started from IDEA
Collection<GitRemote> gitRemotes = parseRemotes(ini, classLoader);
@@ -161,17 +163,21 @@ public class GitConfig {
final String remoteBranch = (merge ? mergeName : rebaseName);
GitRemote branchRemote = null;
for (GitRemote remote : remotes) {
if (remote.getName().equals(remoteName)) {
branchRemote = remote;
break;
if (DOT_REMOTE.equals(remoteName)) {
branchRemote = GitRemote.DOT;
}
else {
for (GitRemote remote : remotes) {
if (remote.getName().equals(remoteName)) {
branchRemote = remote;
break;
}
}
if (branchRemote == null) {
LOG.info("No remote found with name " + remoteName);
return null;
}
}
if (branchRemote == null) {
LOG.info("No remote found with name " + remoteName);
return null;
}
assert remoteBranch != null; // this is checked in StringUtil.isEmptyOrSpaces
return new GitBranchTrackInfo(branchName, branchRemote, remoteBranch, merge);
}
@@ -198,7 +204,7 @@ public class GitConfig {
String sectionName = stringSectionEntry.getKey();
Profile.Section section = stringSectionEntry.getValue();
if (sectionName.startsWith("remote")) {
if (sectionName.startsWith("remote") || sectionName.startsWith("svn-remote")) {
Remote remote = parseRemoteSection(sectionName, section, classLoader);
if (remote != null) {
remotes.add(remote);
@@ -401,8 +407,8 @@ public class GitConfig {
}
private interface RemoteBean {
@Nullable String[] getFetch();
@Nullable String[] getPush();
@Nullable String[] getFetch();
@Nullable String[] getPush();
@Nullable String[] getUrl();
@Nullable String[] getPushUrl();
}
@@ -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.
@@ -19,6 +19,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
@@ -59,6 +60,15 @@ import java.util.List;
*/
public final class GitRemote implements Comparable<GitRemote> {
/**
* This is a special instance of GitRemote used in typical git-svn configurations like:
* [branch "trunk"]
* remote = .
* merge = refs/remotes/git-svn
*/
public static final GitRemote DOT = new GitRemote(".", Collections.singletonList("."), Collections.<String>emptyList(),
Collections.<String>emptyList(), Collections.<String>emptyList());
private final String myName;
private final List<String> myUrls;
private final Collection<String> myPushUrls;
@@ -16,6 +16,7 @@
package git4idea.repo;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VfsUtil;
@@ -26,6 +27,7 @@ import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.MessageBusConnection;
import git4idea.GitBranch;
import git4idea.GitUtil;
import git4idea.PlatformFacade;
import git4idea.branch.GitBranchesCollection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -231,7 +233,7 @@ public class GitRepositoryImpl implements GitRepository, Disposable {
private void updateConfig() {
File configFile = new File(VfsUtil.virtualToIoFile(myGitDir), "config");
myConfig = GitConfig.read(configFile);
myConfig = GitConfig.read(ServiceManager.getService(PlatformFacade.class), configFile);
}
/**
@@ -19,6 +19,7 @@ import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
@@ -171,6 +172,7 @@ public class GitUnstashDialog extends DialogWrapper {
if (Messages.YES == Messages.showYesNoDialog(GitUnstashDialog.this.getContentPane(),
GitBundle.message("git.unstash.drop.confirmation.message", stash.getStash(), stash.getMessage()),
GitBundle.message("git.unstash.drop.confirmation.title", stash.getStash()), Messages.getQuestionIcon())) {
final ModalityState current = ModalityState.current();
ProgressManager.getInstance().run(new Task.Modal(myProject, "Removing stash " + stash.getStash(), false) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
@@ -185,7 +187,7 @@ public class GitUnstashDialog extends DialogWrapper {
public void run() {
GitUIUtil.showOperationError(myProject, ex, h.printableCommandLine());
}
});
}, current);
}
}
});
@@ -0,0 +1,69 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
packedGitWindowSize = 16m
packedGitLimit = 128m
[svn-remote "svn"]
url = svn+ssh://user@cvs.host/SVN/project/trunk/sourcecode
fetch = :refs/remotes/git-svn
[svn-remote "170"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_170_branch
fetch = :refs/remotes/170
[svn-remote "1702"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_1702_branch
fetch = :refs/remotes/1702
[svn-remote "1701"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_1701_branch
fetch = :refs/remotes/1701
[svn-remote "166"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_166_branch
fetch = :refs/remotes/166
[svn-remote "165"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_165_branch
fetch = :refs/remotes/165
[svn-remote "168"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_168_branch
fetch = :refs/remotes/168
[svn-remote "169"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_169_branch
fetch = :refs/remotes/169
[svn-remote "170_GA"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_170_GA_branch
fetch = :refs/remotes/170_GA
[svn-remote "UPDM_2"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UPDM_20_branch
fetch = :refs/remotes/UPDM_2
[gui]
wmstate = normal
geometry = 907x745+1421+65 510 188
matchtrackingbranch = true
[remote "h10"]
url = /opt/repo
fetch = +refs/heads/*:refs/remotes/h10/*
[pack]
threads = 2
deltaCacheSize = 1
windowMemory = 512m
[branch "trunk"]
remote = .
merge = refs/remotes/git-svn
[merge]
renameLimit = 999999
[branch "trunk2"]
remote = .
merge = refs/remotes/git-svn
[branch]
autosetupmerge = true
@@ -0,0 +1,3 @@
b5 Example of git-svn config
Inspired by IDEA-83764
Several svn-remotes defined for different svn branches.
@@ -0,0 +1,12 @@
BRANCH
trunk
. .
refs/remotes/git-svn
refs/remotes/git-svn
merge
BRANCH
trunk2
. .
refs/remotes/git-svn
refs/remotes/git-svn
merge
@@ -0,0 +1,69 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
packedGitWindowSize = 16m
packedGitLimit = 128m
[svn-remote "svn"]
url = svn+ssh://user@cvs.host/SVN/project/trunk/sourcecode
fetch = :refs/remotes/git-svn
[svn-remote "170"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_170_branch
fetch = :refs/remotes/170
[svn-remote "1702"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_1702_branch
fetch = :refs/remotes/1702
[svn-remote "1701"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_1701_branch
fetch = :refs/remotes/1701
[svn-remote "166"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_166_branch
fetch = :refs/remotes/166
[svn-remote "165"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_165_branch
fetch = :refs/remotes/165
[svn-remote "168"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_168_branch
fetch = :refs/remotes/168
[svn-remote "169"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_169_branch
fetch = :refs/remotes/169
[svn-remote "170_GA"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_170_GA_branch
fetch = :refs/remotes/170_GA
[svn-remote "UPDM_2"]
url = svn+ssh://user@cvs.host/SVN/project/branches/MD_UPDM_20_branch
fetch = :refs/remotes/UPDM_2
[gui]
wmstate = normal
geometry = 907x745+1421+65 510 188
matchtrackingbranch = true
[remote "h10"]
url = /opt/repo
fetch = +refs/heads/*:refs/remotes/h10/*
[pack]
threads = 2
deltaCacheSize = 1
windowMemory = 512m
[branch "trunk"]
remote = .
merge = refs/remotes/git-svn
[merge]
renameLimit = 999999
[branch "trunk2"]
remote = .
merge = refs/remotes/git-svn
[branch]
autosetupmerge = true
@@ -0,0 +1,3 @@
r11 Example of git-svn config
Inspired by IDEA-83764
Several svn-remotes defined for different svn branches.
@@ -0,0 +1,66 @@
REMOTE
svn
svn+ssh://user@cvs.host/SVN/project/trunk/sourcecode
svn+ssh://user@cvs.host/SVN/project/trunk/sourcecode
:refs/remotes/git-svn
:refs/remotes/git-svn
REMOTE
170
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_170_branch
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_170_branch
:refs/remotes/170
:refs/remotes/170
REMOTE
1702
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_1702_branch
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_1702_branch
:refs/remotes/1702
:refs/remotes/1702
REMOTE
1701
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_1701_branch
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_1701_branch
:refs/remotes/1701
:refs/remotes/1701
REMOTE
166
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_166_branch
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_166_branch
:refs/remotes/166
:refs/remotes/166
REMOTE
165
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_165_branch
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_165_branch
:refs/remotes/165
:refs/remotes/165
REMOTE
168
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_168_branch
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_168_branch
:refs/remotes/168
:refs/remotes/168
REMOTE
169
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_169_branch
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_169_branch
:refs/remotes/169
:refs/remotes/169
REMOTE
170_GA
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_170_GA_branch
svn+ssh://user@cvs.host/SVN/project/branches/MD_UML_170_GA_branch
:refs/remotes/170_GA
:refs/remotes/170_GA
REMOTE
UPDM_2
svn+ssh://user@cvs.host/SVN/project/branches/MD_UPDM_20_branch
svn+ssh://user@cvs.host/SVN/project/branches/MD_UPDM_20_branch
:refs/remotes/UPDM_2
:refs/remotes/UPDM_2
REMOTE
h10
/opt/repo
/opt/repo
+refs/heads/*:refs/remotes/h10/*
+refs/heads/*:refs/remotes/h10/*
@@ -17,6 +17,7 @@ package git4idea.repo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import git4idea.test.GitTestPlatformFacade;
import git4idea.test.GitTestUtil;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -47,13 +48,13 @@ public class GitConfigTest {
@Test(dataProvider = "remote")
public void testRemotes(String testName, File configFile, File resultFile) throws IOException {
GitConfig config = GitConfig.read(configFile);
GitConfig config = GitConfig.read(new GitTestPlatformFacade(), configFile);
GitTestUtil.assertEqualCollections(config.getRemotes(), readRemoteResults(resultFile));
}
@Test(dataProvider = "branch")
public void testBranches(String testName, File configFile, File resultFile) throws IOException {
GitConfig config = GitConfig.read(configFile);
GitConfig config = GitConfig.read(new GitTestPlatformFacade(), configFile);
GitTestUtil.assertEqualCollections(config.getBranchTrackInfos(), readBranchResults(resultFile));
}
@@ -78,9 +79,8 @@ public class GitConfigTest {
private static GitRemote getRemote(String remoteString) {
String[] remoteInfo = remoteString.split(" ");
return new GitRemote(getOrEmpty(remoteInfo, 0), Collections.singletonList(getOrEmpty(remoteInfo, 1)),
Collections.singletonList(getOrEmpty(remoteInfo, 2)), Collections.singletonList(getOrEmpty(remoteInfo, 3)),
Collections.singletonList(getOrEmpty(remoteInfo, 4)));
return new GitRemote(remoteInfo[0], getSingletonOrEmpty(remoteInfo, 1), getSingletonOrEmpty(remoteInfo, 2),
getSingletonOrEmpty(remoteInfo, 3), getSingletonOrEmpty(remoteInfo, 4));
}
private static Set<GitRemote> readRemoteResults(File resultFile) throws IOException {
@@ -110,8 +110,8 @@ public class GitConfigTest {
return Arrays.asList(line.split(" "));
}
private static String getOrEmpty(String[] array, int i) {
return array.length < i + 1 ? "" : array[i];
private static List<String> getSingletonOrEmpty(String[] array, int i) {
return array.length < i + 1 ? Collections.<String>emptyList() : Collections.singletonList(array[i]);
}
}
@@ -15,6 +15,7 @@
*/
package git4idea.test;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.mock.MockLocalFileSystem;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.project.Project;
@@ -32,6 +33,7 @@ import git4idea.PlatformFacade;
import git4idea.repo.GitRepositoryManager;
import git4idea.tests.TestDialogManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
*
@@ -137,6 +139,12 @@ public class GitTestPlatformFacade implements PlatformFacade {
return myRepositoryManager;
}
@Nullable
@Override
public IdeaPluginDescriptor getPluginByClassName(@NotNull String name) {
return null;
}
@NotNull
@Override
public AbstractVcs getVcs(@NotNull Project project) {