IDEA-110625 External system: Add git root automatically on linking external project

This commit is contained in:
Denis.Zhdanov
2013-07-16 16:55:49 +04:00
parent 258f7450cc
commit 1815ffc99f
6 changed files with 150 additions and 8 deletions

View File

@@ -24,7 +24,7 @@ import java.util.Set;
* @author Denis Zhdanov
* @since 6/13/13 7:37 PM
*/
public class ExternalSystemSettingsListenerAdapter<S extends ExternalProjectSettings> implements ExternalSystemSettingsListener<S> {
public abstract class ExternalSystemSettingsListenerAdapter<S extends ExternalProjectSettings> implements ExternalSystemSettingsListener<S> {
@Override
public void onProjectsLinked(@NotNull Collection<S> settings) {

View File

@@ -15,6 +15,8 @@
<orderEntry type="module" module-name="lang-impl" />
<orderEntry type="module" module-name="debugger-impl" />
<orderEntry type="module" module-name="execution-openapi" />
<orderEntry type="module" module-name="git4idea" />
<orderEntry type="module" module-name="vcs-api" />
</component>
</module>

View File

@@ -19,6 +19,7 @@ import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
import com.intellij.openapi.externalSystem.service.project.autoimport.ExternalSystemAutoImporter;
import com.intellij.openapi.externalSystem.service.ui.ExternalToolWindowManager;
import com.intellij.openapi.externalSystem.service.vcs.ExternalSystemVcsRegistrar;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
import com.intellij.openapi.project.Project;
@@ -49,6 +50,7 @@ public class ExternalSystemStartupActivity implements StartupActivity {
}
ExternalSystemAutoImporter.letTheMagicBegin(project);
ExternalToolWindowManager.handle(project);
ExternalSystemVcsRegistrar.handle(project);
}
};

View File

@@ -0,0 +1,134 @@
/*
* Copyright 2000-2013 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.openapi.externalSystem.service.vcs;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings;
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListenerAdapter;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsDirectoryMapping;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtilRt;
import git4idea.GitPlatformFacade;
import git4idea.GitVcs;
import git4idea.roots.GitRootDetector;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.List;
/**
* It's rather often when open-source project is backed by an external system and stored at public repo hosting
* like github, bitbucket etc. Standard actions sequence looks as below then:
* <pre>
* <ol>
* <li>Clone target repo to local machine;</li>
* <li>Execute 'import from external system' wizard;</li>
* </ol>
* </pre>
* The problem is that the ide detects unregistered vcs roots at the newly imported project and shows corresponding notification
* with suggestion to configure vcs roots for the current project. We want to simplify that in a way to not showing the notification
* but register them automatically. This class manages that.
*
* @author Denis Zhdanov
* @since 7/15/13 6:00 PM
*/
public class ExternalSystemVcsRegistrar {
@SuppressWarnings("unchecked")
public static void handle(@NotNull final Project project) {
// VCS api doesn't offer generic ability to detect and configure VCS roots at the moment(see IDEA-102703 for more details).
// That's why we have only git support here.
final Ref<GitPlatformFacade> gitFacade = new Ref<GitPlatformFacade>();
try {
gitFacade.set(ServiceManager.getService(GitPlatformFacade.class));
}
catch (Throwable e) {
// Assuming that git integration is disabled
}
if (gitFacade.get() == null) {
// Assuming that git integration is disabled
return;
}
for (final ExternalSystemManager<?, ?, ?, ?, ?> manager : ExternalSystemApiUtil.getAllManagers()) {
final AbstractExternalSystemSettings settings = manager.getSettingsProvider().fun(project);
settings.subscribe(new ExternalSystemSettingsListenerAdapter() {
@Override
public void onProjectsLinked(@NotNull final Collection linked) {
final LocalFileSystem fileSystem = LocalFileSystem.getInstance();
ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project);
for (Object o : linked) {
final ExternalProjectSettings settings = (ExternalProjectSettings)o;
// Hack into git processing.
Project projectProxy = (Project)Proxy.newProxyInstance(
getClass().getClassLoader(),
new Class[]{Project.class},
new InvocationHandler() {
@SuppressWarnings("ConstantConditions")
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("getBaseDir".equals(method.getName())) {
return fileSystem.refreshAndFindFileByPath(settings.getExternalProjectPath());
}
return method.invoke(project, args);
}
}
);
Collection<VirtualFile> roots = new GitRootDetector(projectProxy, gitFacade.get()).detect().getRoots();
if (!roots.isEmpty()) {
List<VcsDirectoryMapping> mappings = ContainerUtilRt.newArrayList(vcsManager.getDirectoryMappings());
// There is a possible case that no VCS mappings are configured for the current project. There is a single
// mapping like <Project> - <No VCS> then. We want to replace it if only one mapping to the project root dir
// has been detected then.
if (roots.size() == 1
&& mappings.size() == 1
&& StringUtil.isEmpty(mappings.get(0).getVcs())
&& roots.iterator().next().equals(project.getBaseDir()))
{
mappings.clear();
mappings.add(new VcsDirectoryMapping("", GitVcs.getKey().getName()));
}
else {
for (VirtualFile root : roots) {
mappings.add(new VcsDirectoryMapping(root.getPath(), GitVcs.getKey().getName()));
}
}
vcsManager.setDirectoryMappings(mappings);
}
}
}
});
}
}
}

View File

@@ -50,21 +50,25 @@ public class GitRootDetector {
myPlatformFacade = platformFacade;
}
@NotNull
public GitRootDetectInfo detect() {
VirtualFile projectDir = myProject.getBaseDir();
if (projectDir == null) {
return detect(myProject.getBaseDir());
}
@NotNull
public GitRootDetectInfo detect(@Nullable VirtualFile startDir) {
if (startDir == null) {
return new GitRootDetectInfo(Collections.<VirtualFile>emptyList(), false, false);
}
final Set<VirtualFile> roots = scanForRootsInsideDir(projectDir);
final Set<VirtualFile> roots = scanForRootsInsideDir(startDir);
roots.addAll(scanForRootsInContentRoots());
if (roots.contains(projectDir)) {
if (roots.contains(startDir)) {
return new GitRootDetectInfo(roots, true, false);
}
VirtualFile rootAbove = scanForSingleRootAboveDir(projectDir);
VirtualFile rootAbove = scanForSingleRootAboveDir(startDir);
if (rootAbove != null) {
roots.add(rootAbove);
return new GitRootDetectInfo(roots, true, true);

View File

@@ -16,7 +16,7 @@ public class GradleConstants {
@NonNls public static final String EXTENSION = "gradle";
@NonNls public static final String DEFAULT_SCRIPT_NAME = "build.gradle";
@NonNls public static final String SETTINGS_FILE_NAME = "setting.gradle";
@NonNls public static final String SETTINGS_FILE_NAME = "settings.gradle";
public static final String SYSTEM_DIRECTORY_PATH_KEY = "GRADLE_USER_HOME";