diff options
Diffstat (limited to 'plugins/gradle/src/org/jetbrains/plugins')
14 files changed, 1099 insertions, 26 deletions
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/compiler/GradleBuildProcessParametersProvider.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/compiler/GradleBuildProcessParametersProvider.java new file mode 100644 index 000000000000..4337686235f5 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/compiler/GradleBuildProcessParametersProvider.java @@ -0,0 +1,93 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.compiler; + +import com.google.gson.Gson; +import com.intellij.compiler.server.BuildProcessParametersProvider; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.PathUtil; +import com.intellij.util.containers.ContainerUtil; +import groovy.lang.GroovyObject; +import org.apache.tools.ant.taskdefs.Ant; +import org.gradle.tooling.ProjectConnection; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import java.io.File; +import java.util.List; + +/** + * Adds Gradle build dependencies to the project build process' classpath. + * + * @author Vladislav.Soroka + * @since 7/22/2014 + */ +public class GradleBuildProcessParametersProvider extends BuildProcessParametersProvider { + @NotNull private final Project myProject; + + private List<String> myClasspath; + + public GradleBuildProcessParametersProvider(@NotNull Project project) { + myProject = project; + } + + @Override + @NotNull + public List<String> getClassPath() { + if (myClasspath == null) { + myClasspath = ContainerUtil.newArrayList(); + addGradleClassPath(myClasspath); + final ModuleManager moduleManager = ModuleManager.getInstance(myProject); + for (Module module : moduleManager.getModules()) { + if (ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) { + addOtherClassPath(myClasspath); + break; + } + } + } + return myClasspath; + } + + private static void addGradleClassPath(@NotNull final List<String> classpath) { + String gradleLibDirPath = null; + String gradleToolingApiJarPath = PathUtil.getJarPathForClass(ProjectConnection.class); + if (!StringUtil.isEmpty(gradleToolingApiJarPath)) { + gradleLibDirPath = PathUtil.getParentPath(gradleToolingApiJarPath); + } + if (gradleLibDirPath == null || gradleLibDirPath.isEmpty()) return; + + File gradleLibDir = new File(gradleLibDirPath); + if (!gradleLibDir.isDirectory()) return; + + File[] children = FileUtil.notNullize(gradleLibDir.listFiles()); + for (File child : children) { + if (child.isFile() && child.getName().endsWith(".jar")) { + classpath.add(child.getAbsolutePath()); + } + } + } + + private static void addOtherClassPath(@NotNull final List<String> classpath) { + classpath.add(PathUtil.getJarPathForClass(Ant.class)); + classpath.add(PathUtil.getJarPathForClass(GroovyObject.class)); + classpath.add(PathUtil.getJarPathForClass(Gson.class)); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleResourceCompilerConfigurationGenerator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleResourceCompilerConfigurationGenerator.java new file mode 100644 index 000000000000..01c5275f3828 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleResourceCompilerConfigurationGenerator.java @@ -0,0 +1,186 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.config; + +import com.intellij.compiler.server.BuildManager; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompilerMessageCategory; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.externalSystem.model.ExternalFilter; +import com.intellij.openapi.externalSystem.model.ExternalProject; +import com.intellij.openapi.externalSystem.model.ExternalSourceDirectorySet; +import com.intellij.openapi.externalSystem.model.ExternalSourceSet; +import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceType; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.CompilerModuleExtension; +import com.intellij.openapi.util.JDOMUtil; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.util.containers.FactoryMap; +import com.intellij.util.xmlb.XmlSerializer; +import org.jdom.Document; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.gradle.model.impl.*; +import org.jetbrains.plugins.gradle.service.project.data.ExternalProjectDataService; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourceCompilerConfigurationGenerator { + + private static Logger LOG = Logger.getInstance(GradleResourceCompilerConfigurationGenerator.class); + + @NotNull private final Project myProject; + @NotNull private final CompileContext myContext; + @NotNull private final Map<String, ExternalProject> myExternalProjectMap; + private final ExternalProjectDataService myExternalProjectDataService; + + public GradleResourceCompilerConfigurationGenerator(@NotNull final Project project, @NotNull final CompileContext context) { + myProject = project; + myContext = context; + myExternalProjectDataService = + (ExternalProjectDataService)ServiceManager.getService(ProjectDataManager.class).getDataService(ExternalProjectDataService.KEY); + assert myExternalProjectDataService != null; + + myExternalProjectMap = new FactoryMap<String, ExternalProject>() { + @Nullable + @Override + protected ExternalProject create(String gradleProjectPath) { + return myExternalProjectDataService.getOrImportRootExternalProject(project, GradleConstants.SYSTEM_ID, new File(gradleProjectPath)); + } + }; + } + + public void generateBuildConfiguration() { + if (!hasGradleModules()) return; + + final BuildManager buildManager = BuildManager.getInstance(); + final File projectSystemDir = buildManager.getProjectSystemDirectory(myProject); + if (projectSystemDir == null) return; + + final File gradleConfigFile = new File(projectSystemDir, GradleProjectConfiguration.CONFIGURATION_FILE_RELATIVE_PATH); + + GradleProjectConfiguration projectConfig = new GradleProjectConfiguration(); + for (Module module : myContext.getCompileScope().getAffectedModules()) { + if (!ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) continue; + + final String gradleProjectPath = module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY); + assert gradleProjectPath != null; + final ExternalProject externalRootProject = myExternalProjectMap.get(gradleProjectPath); + if (externalRootProject == null) { + myContext.addMessage(CompilerMessageCategory.ERROR, + String.format("Unable to make the module: %s, related gradle module configuration was not imported", + module.getName()), + VfsUtilCore.pathToUrl(gradleProjectPath), -1, -1); + continue; + } + + ExternalProject externalProject = myExternalProjectDataService.findExternalProject(externalRootProject, module); + if (externalProject == null) { + LOG.warn("Unable to find config for module: " + module.getName()); + continue; + } + + final CompilerModuleExtension compilerModuleExtension = CompilerModuleExtension.getInstance(module); + assert compilerModuleExtension != null; + + GradleModuleResourceConfiguration resourceConfig = new GradleModuleResourceConfiguration(); + resourceConfig.id = new ModuleVersion(externalProject.getGroup(), externalProject.getName(), externalProject.getVersion()); + resourceConfig.directory = FileUtil.toSystemIndependentName(externalProject.getProjectDir().getPath()); + + final ExternalSourceSet mainSourcesSet = externalProject.getSourceSets().get("main"); + addResources(resourceConfig.resources, mainSourcesSet, ExternalSystemSourceType.RESOURCE); + + final ExternalSourceSet testSourcesSet = externalProject.getSourceSets().get("test"); + addResources(resourceConfig.testResources, testSourcesSet, ExternalSystemSourceType.TEST_RESOURCE); + + projectConfig.moduleConfigurations.put(module.getName(), resourceConfig); + } + + final Document document = new Document(new Element("gradle-project-configuration")); + XmlSerializer.serializeInto(projectConfig, document.getRootElement()); + buildManager.runCommand(new Runnable() { + @Override + public void run() { + buildManager.clearState(myProject); + FileUtil.createIfDoesntExist(gradleConfigFile); + try { + JDOMUtil.writeDocument(document, gradleConfigFile, "\n"); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + }); + } + + private boolean hasGradleModules() { + for (Module module : myContext.getCompileScope().getAffectedModules()) { + if (ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) return true; + } + return false; + } + + private static void addResources(@NotNull List<ResourceRootConfiguration> container, + @Nullable ExternalSourceSet externalSourceSet, + @NotNull ExternalSystemSourceType sourceType) { + if (externalSourceSet == null) return; + final ExternalSourceDirectorySet directorySet = externalSourceSet.getSources().get(sourceType); + if (directorySet == null) return; + + for (File file : directorySet.getSrcDirs()) { + final String dir = file.getPath(); + final ResourceRootConfiguration rootConfiguration = new ResourceRootConfiguration(); + rootConfiguration.directory = FileUtil.toSystemIndependentName(dir); + final String target = directorySet.getOutputDir().getPath(); + rootConfiguration.targetPath = FileUtil.toSystemIndependentName(target); + + rootConfiguration.includes.clear(); + for (String include : directorySet.getIncludes()) { + rootConfiguration.includes.add(include.trim()); + } + rootConfiguration.excludes.clear(); + for (String exclude : directorySet.getExcludes()) { + rootConfiguration.excludes.add(exclude.trim()); + } + + rootConfiguration.isFiltered = !directorySet.getFilters().isEmpty(); + rootConfiguration.filters.clear(); + for (ExternalFilter filter : directorySet.getFilters()) { + final ResourceRootFilter resourceRootFilter = new ResourceRootFilter(); + resourceRootFilter.filterType = filter.getFilterType(); + resourceRootFilter.properties = filter.getPropertiesAsJsonMap(); + rootConfiguration.filters.add(resourceRootFilter); + } + + container.add(rootConfiguration); + } + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java new file mode 100644 index 000000000000..113e49a61a25 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java @@ -0,0 +1,112 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.execution; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.externalSystem.model.ExternalProject; +import com.intellij.openapi.externalSystem.model.ExternalSourceDirectorySet; +import com.intellij.openapi.externalSystem.model.ExternalSourceSet; +import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceType; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootModel; +import com.intellij.openapi.roots.OrderEnumerationHandler; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.vfs.VfsUtilCore; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.service.project.data.ExternalProjectDataService; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import java.io.File; +import java.util.Collection; + +public class GradleOrderEnumeratorHandler extends OrderEnumerationHandler { + private static final Logger LOG = Logger.getInstance(GradleOrderEnumeratorHandler.class); + + public static class FactoryImpl extends Factory { + @Override + public boolean isApplicable(@NotNull Project project) { + return true; + } + + @Override + public boolean isApplicable(@NotNull Module module) { + return ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module); + } + + @Override + public OrderEnumerationHandler createHandler(@Nullable Module module) { + return INSTANCE; + } + } + + private static final GradleOrderEnumeratorHandler INSTANCE = new GradleOrderEnumeratorHandler(); + + @Override + public boolean addCustomModuleRoots(@NotNull OrderRootType type, + @NotNull ModuleRootModel rootModel, + @NotNull Collection<String> result, + boolean includeProduction, + boolean includeTests) { + if (!type.equals(OrderRootType.CLASSES)) return false; + if (!ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, rootModel.getModule())) return false; + + final String gradleProjectPath = rootModel.getModule().getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY); + if (gradleProjectPath == null) { + LOG.error("Root project path of the Gradle project not found for " + rootModel.getModule()); + return false; + } + + final ExternalProjectDataService externalProjectDataService = + (ExternalProjectDataService)ServiceManager.getService(ProjectDataManager.class).getDataService(ExternalProjectDataService.KEY); + + assert externalProjectDataService != null; + final ExternalProject externalRootProject = + externalProjectDataService.getRootExternalProject(GradleConstants.SYSTEM_ID, new File(gradleProjectPath)); + if (externalRootProject == null) { + LOG.debug("Root external project was not yep imported for the project path: " + gradleProjectPath); + return false; + } + + ExternalProject externalProject = externalProjectDataService.findExternalProject(externalRootProject, rootModel.getModule()); + if (externalProject == null) return false; + + if (includeProduction) { + addOutputRoots(externalProject.getSourceSets().get("main"), ExternalSystemSourceType.RESOURCE, result); + } + + if (includeTests) { + addOutputRoots(externalProject.getSourceSets().get("test"), ExternalSystemSourceType.TEST_RESOURCE, result); + } + + return true; + } + + private static void addOutputRoots(@Nullable ExternalSourceSet externalSourceSet, + @NotNull ExternalSystemSourceType sourceType, + @NotNull Collection<String> result) { + if (externalSourceSet == null) return; + final ExternalSourceDirectorySet directorySet = externalSourceSet.getSources().get(sourceType); + if (directorySet == null) return; + + result.add(VfsUtilCore.pathToUrl(directorySet.getOutputDir().getAbsolutePath())); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/AbstractProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/AbstractProjectResolverExtension.java index 1d8addd31369..9603470a0878 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/AbstractProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/AbstractProjectResolverExtension.java @@ -28,6 +28,7 @@ import com.intellij.openapi.externalSystem.util.Order; import com.intellij.openapi.util.KeyValue; import com.intellij.util.Consumer; import org.gradle.tooling.model.idea.IdeaModule; +import org.gradle.tooling.model.idea.IdeaProject; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -80,6 +81,11 @@ public abstract class AbstractProjectResolverExtension implements GradleProjectR return nextResolver.createJavaProjectData(); } + @Override + public void populateProjectExtraModels(@NotNull IdeaProject gradleProject, @NotNull DataNode<ProjectData> ideProject) { + nextResolver.populateProjectExtraModels(gradleProject, ideProject); + } + @NotNull @Override public ModuleData createModule(@NotNull IdeaModule gradleModule, @NotNull ProjectData projectData) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java index 6f43559f7a11..ad7ade6a3c58 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java @@ -15,14 +15,13 @@ */ package org.jetbrains.plugins.gradle.service.project; +import com.google.gson.GsonBuilder; import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.SimpleJavaParameters; import com.intellij.externalSystem.JavaProjectData; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.externalSystem.model.DataNode; -import com.intellij.openapi.externalSystem.model.ExternalSystemException; -import com.intellij.openapi.externalSystem.model.ProjectKeys; +import com.intellij.openapi.externalSystem.model.*; import com.intellij.openapi.externalSystem.model.project.*; import com.intellij.openapi.externalSystem.model.task.TaskData; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; @@ -56,6 +55,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.model.*; import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData; +import org.jetbrains.plugins.gradle.service.project.data.ExternalProjectDataService; import org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl; import org.jetbrains.plugins.gradle.tooling.internal.init.Init; import org.jetbrains.plugins.gradle.util.GradleBundle; @@ -79,6 +79,8 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver private static final Logger LOG = Logger.getInstance("#" + BaseGradleProjectResolverExtension.class.getName()); @NotNull @NonNls private static final String UNRESOLVED_DEPENDENCY_PREFIX = "unresolved dependency - "; + private static final String MAIN_SOURCE_SET = "main"; + private static final String TEST_SOURCE_SET = "test"; @NotNull private ProjectResolverContext resolverCtx; @NotNull private final BaseProjectImportErrorHandler myErrorHandler = new BaseProjectImportErrorHandler(); @@ -120,6 +122,14 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver return javaProjectData; } + @Override + public void populateProjectExtraModels(@NotNull IdeaProject gradleProject, @NotNull DataNode<ProjectData> ideProject) { + final ExternalProject externalProject = resolverCtx.getExtraProject(ExternalProject.class); + if (externalProject != null) { + ideProject.createChild(ExternalProjectDataService.KEY, externalProject); + } + } + @NotNull @Override public ModuleData createModule(@NotNull IdeaModule gradleModule, @NotNull ProjectData projectData) { @@ -220,6 +230,8 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver File sourceCompileOutputPath = null; File testCompileOutputPath = null; + File resourceCompileOutputPath; + File testResourceCompileOutputPath; boolean inheritOutputDirs = false; ModuleData moduleData = ideModule.getData(); @@ -229,30 +241,71 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver inheritOutputDirs = moduleCompilerOutput.getInheritOutputDirs(); } + ExternalProject externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject.class); + if (externalProject != null) { + externalProject = new DefaultExternalProject(externalProject); + } + if (!inheritOutputDirs && (sourceCompileOutputPath == null || testCompileOutputPath == null)) { - ModuleExtendedModel moduleExtendedModel = resolverCtx.getExtraProject(gradleModule, ModuleExtendedModel.class); - if (moduleExtendedModel != null) { - ExtIdeaCompilerOutput output = moduleExtendedModel.getCompilerOutput(); - if (output != null) { - if (sourceCompileOutputPath == null) { - sourceCompileOutputPath = output.getMainClassesDir(); + sourceCompileOutputPath = getCompileOutputPath(externalProject, MAIN_SOURCE_SET, ExternalSystemSourceType.SOURCE); + resourceCompileOutputPath = getCompileOutputPath(externalProject, MAIN_SOURCE_SET, ExternalSystemSourceType.RESOURCE); + testCompileOutputPath = getCompileOutputPath(externalProject, TEST_SOURCE_SET, ExternalSystemSourceType.TEST); + testResourceCompileOutputPath = getCompileOutputPath(externalProject, TEST_SOURCE_SET, ExternalSystemSourceType.TEST_RESOURCE); + } + else { + resourceCompileOutputPath = sourceCompileOutputPath; + testResourceCompileOutputPath = testCompileOutputPath; + + if (externalProject != null) { + final ExternalSourceSet mainSourceSet = externalProject.getSourceSets().get(MAIN_SOURCE_SET); + if (mainSourceSet != null) { + final ExternalSourceDirectorySet resourceDirectories = mainSourceSet.getSources().get(ExternalSystemSourceType.RESOURCE); + if (resourceDirectories instanceof DefaultExternalSourceDirectorySet) { + ((DefaultExternalSourceDirectorySet)resourceDirectories).setOutputDir(sourceCompileOutputPath); } - if (testCompileOutputPath == null) { - testCompileOutputPath = output.getTestClassesDir(); + } + final ExternalSourceSet testSourceSet = externalProject.getSourceSets().get(TEST_SOURCE_SET); + if (testSourceSet != null) { + final ExternalSourceDirectorySet testResourceDirectories = testSourceSet.getSources().get(ExternalSystemSourceType.TEST_RESOURCE); + if (testResourceDirectories instanceof DefaultExternalSourceDirectorySet) { + ((DefaultExternalSourceDirectorySet)testResourceDirectories).setOutputDir(testCompileOutputPath); } } + + final DataNode<ProjectData> projectDataNode = ExternalSystemApiUtil.findParent(ideModule, ProjectKeys.PROJECT); + assert projectDataNode != null; + projectDataNode.createOrReplaceChild(ExternalProjectDataService.KEY, externalProject); } } if (sourceCompileOutputPath != null) { moduleData.setCompileOutputPath(ExternalSystemSourceType.SOURCE, sourceCompileOutputPath.getAbsolutePath()); } + if (resourceCompileOutputPath != null) { + moduleData.setCompileOutputPath(ExternalSystemSourceType.RESOURCE, resourceCompileOutputPath.getAbsolutePath()); + } if (testCompileOutputPath != null) { moduleData.setCompileOutputPath(ExternalSystemSourceType.TEST, testCompileOutputPath.getAbsolutePath()); } + if (testResourceCompileOutputPath != null) { + moduleData.setCompileOutputPath(ExternalSystemSourceType.TEST_RESOURCE, testResourceCompileOutputPath.getAbsolutePath()); + } + moduleData.setInheritProjectCompileOutputPath(inheritOutputDirs || sourceCompileOutputPath == null); } + @Nullable + private static File getCompileOutputPath(@Nullable ExternalProject externalProject, + @NotNull String sourceSetName, + @NotNull ExternalSystemSourceType sourceType) { + if (externalProject == null) return null; + final ExternalSourceSet sourceSet = externalProject.getSourceSets().get(sourceSetName); + if(sourceSet == null) return null; + + final ExternalSourceDirectorySet directorySet = sourceSet.getSources().get(sourceType); + return directorySet != null ? directorySet.getOutputDir() : null; + } + @Override public void populateModuleDependencies(@NotNull IdeaModule gradleModule, @NotNull DataNode<ModuleData> ideModule, @@ -319,17 +372,19 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver @Override public Set<Class> getExtraProjectModelClasses() { return ContainerUtil.<Class>set( - GradleBuild.class, ModuleExtendedModel.class, BuildScriptClasspathModel.class); + GradleBuild.class, ExternalProject.class, ModuleExtendedModel.class, BuildScriptClasspathModel.class); } @NotNull @Override public Set<Class> getToolingExtensionsClasses() { return ContainerUtil.<Class>set( + ExternalProject.class, // gradle-tooling-extension-api jar ProjectImportAction.class, // gradle-tooling-extension-impl jar - ModelBuildScriptClasspathBuilderImpl.class + ModelBuildScriptClasspathBuilderImpl.class, + GsonBuilder.class ); } @@ -416,6 +471,8 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver List<String> additionalEntries = ContainerUtilRt.newArrayList(); ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(GroovyObject.class)); + ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(GsonBuilder.class)); + ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(ExternalProject.class)); ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(JavaProjectData.class)); ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(LanguageLevel.class)); ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(StdModuleTypes.class)); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java index 8a2ffaae36c9..24c8e126ed3f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java @@ -199,6 +199,9 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver<Grad projectDataNode.createChild(JavaProjectData.KEY, javaProjectData); IdeaProject ideaProject = resolverCtx.getModels().getIdeaProject(); + + projectResolverChain.populateProjectExtraModels(ideaProject, projectDataNode); + DomainObjectSet<? extends IdeaModule> gradleModules = ideaProject.getModules(); if (gradleModules == null || gradleModules.isEmpty()) { throw new IllegalStateException("No modules found for the target project: " + ideaProject); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java index b727005db845..6dd201b839fb 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java @@ -27,6 +27,7 @@ import com.intellij.openapi.externalSystem.service.ParametersEnhancer; import com.intellij.openapi.util.KeyValue; import com.intellij.util.Consumer; import org.gradle.tooling.model.idea.IdeaModule; +import org.gradle.tooling.model.idea.IdeaProject; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.GradleManager; @@ -62,6 +63,8 @@ public interface GradleProjectResolverExtension extends ParametersEnhancer { @NotNull JavaProjectData createJavaProjectData(); + void populateProjectExtraModels(@NotNull IdeaProject gradleProject, @NotNull DataNode<ProjectData> ideProject); + @NotNull ModuleData createModule(@NotNull IdeaModule gradleModule, @NotNull ProjectData projectData); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleStartupActivity.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleStartupActivity.java index 81ceaa3177e2..0e5fcc12f3dc 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleStartupActivity.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleStartupActivity.java @@ -21,6 +21,11 @@ import com.intellij.ide.util.newProjectWizard.AddModuleWizard; import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationType; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompileTask; +import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; @@ -30,6 +35,8 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtilCore; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.project.MavenResourceCompilerConfigurationGenerator; +import org.jetbrains.plugins.gradle.config.GradleResourceCompilerConfigurationGenerator; import org.jetbrains.plugins.gradle.service.GradleBuildClasspathManager; import org.jetbrains.plugins.gradle.service.project.wizard.GradleProjectImportBuilder; import org.jetbrains.plugins.gradle.service.project.wizard.GradleProjectImportProvider; @@ -52,9 +59,22 @@ public class GradleStartupActivity implements StartupActivity { private static final String DO_NOT_SHOW_EVENT_DESCRIPTION = "do.not.show"; @Override - public void runActivity(@NotNull Project project) { + public void runActivity(@NotNull final Project project) { configureBuildClasspath(project); showNotificationForUnlinkedGradleProject(project); + CompilerManager.getInstance(project).addBeforeTask(new CompileTask() { + @Override + public boolean execute(CompileContext context) { + AccessToken token = ReadAction.start(); + try { + new GradleResourceCompilerConfigurationGenerator(project, context).generateBuildConfiguration(); + } + finally { + token.finish(); + } + return true; + } + }); } private static void configureBuildClasspath(@NotNull final Project project) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java index b7f94dd57122..3aa0027185bf 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java @@ -19,6 +19,7 @@ import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener; import org.gradle.tooling.ProjectConnection; import org.gradle.tooling.model.idea.IdeaModule; +import org.gradle.tooling.model.idea.IdeaProject; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.model.ProjectImportAction; @@ -93,7 +94,12 @@ public class ProjectResolverContext { } @Nullable - public <T> T getExtraProject(@NotNull IdeaModule module, Class<T> modelClazz) { + public <T> T getExtraProject(Class<T> modelClazz) { + return myModels.getExtraProject(null, modelClazz); + } + + @Nullable + public <T> T getExtraProject(@Nullable IdeaModule module, Class<T> modelClazz) { return myModels.getExtraProject(module, modelClazz); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectDataService.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectDataService.java new file mode 100644 index 000000000000..fae9ee0d88c1 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectDataService.java @@ -0,0 +1,233 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.service.project.data; + +import com.intellij.CommonBundle; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.externalSystem.model.*; +import com.intellij.openapi.externalSystem.model.project.ProjectData; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener; +import com.intellij.openapi.externalSystem.service.internal.ExternalSystemResolveProjectTask; +import com.intellij.openapi.externalSystem.service.notification.ExternalSystemNotificationManager; +import com.intellij.openapi.externalSystem.service.notification.NotificationSource; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataService; +import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; +import com.intellij.openapi.externalSystem.util.*; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ex.ProjectRootManagerEx; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.ConcurrentFactoryMap; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Collection; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/17/2014 + */ +@Order(ExternalSystemConstants.BUILTIN_SERVICE_ORDER) +public class ExternalProjectDataService implements ProjectDataService<ExternalProject, Project> { + private static final Logger LOG = Logger.getInstance(ExternalProjectDataService.class); + + @NotNull public static final Key<ExternalProject> KEY = Key.create(ExternalProject.class, ProjectKeys.TASK.getProcessingWeight() + 1); + + @NotNull private final Map<Pair<ProjectSystemId, File>, ExternalProject> myExternalRootProjects; + + @NotNull private ProjectDataManager myProjectDataManager; + + public ExternalProjectDataService(@NotNull ProjectDataManager projectDataManager) { + myProjectDataManager = projectDataManager; + myExternalRootProjects = new ConcurrentFactoryMap<Pair<ProjectSystemId, File>, ExternalProject>() { + @Nullable + @Override + protected ExternalProject create(Pair<ProjectSystemId, File> key) { + return new ExternalProjectSerializer().load(key.first, key.second); + } + + @Override + public ExternalProject put(Pair<ProjectSystemId, File> key, ExternalProject value) { + new ExternalProjectSerializer().save(value); + return super.put(key, value); + } + }; + } + + @NotNull + @Override + public Key<ExternalProject> getTargetDataKey() { + return KEY; + } + + public void importData(@NotNull final Collection<DataNode<ExternalProject>> toImport, + @NotNull final Project project, + final boolean synchronous) { + if (toImport.size() != 1) { + throw new IllegalArgumentException( + String.format("Expected to get a single external project but got %d: %s", toImport.size(), toImport)); + } + saveExternalProject(toImport.iterator().next().getData()); + } + + @Override + public void removeData(@NotNull final Collection<? extends Project> modules, @NotNull Project project, boolean synchronous) { + } + + @Nullable + public ExternalProject getOrImportRootExternalProject(@NotNull Project project, + @NotNull ProjectSystemId systemId, + @NotNull File projectRootDir) { + final ExternalProject externalProject = getRootExternalProject(systemId, projectRootDir); + return externalProject != null ? externalProject : importExternalProject(project, systemId, projectRootDir); + } + + @Nullable + private ExternalProject importExternalProject(@NotNull final Project project, + @NotNull final ProjectSystemId projectSystemId, + @NotNull final File projectRootDir) { + final Boolean result = UIUtil.invokeAndWaitIfNeeded(new Computable<Boolean>() { + @Override + public Boolean compute() { + final Ref<Boolean> result = new Ref<Boolean>(false); + if (project.isDisposed()) return false; + + final String linkedProjectPath = FileUtil.toCanonicalPath(projectRootDir.getPath()); + final ExternalProjectSettings projectSettings = + ExternalSystemApiUtil.getSettings(project, projectSystemId).getLinkedProjectSettings(linkedProjectPath); + if (projectSettings == null) { + LOG.warn("Unable to get project settings for project path: " + linkedProjectPath); + if (LOG.isDebugEnabled()) { + LOG.debug("Available projects paths: " + ContainerUtil.map( + ExternalSystemApiUtil.getSettings(project, projectSystemId).getLinkedProjectsSettings(), + new Function<ExternalProjectSettings, String>() { + @Override + public String fun(ExternalProjectSettings settings) { + return settings.getExternalProjectPath(); + } + })); + } + return false; + } + + final File projectFile = new File(linkedProjectPath); + final String projectName; + if (projectFile.isFile()) { + projectName = projectFile.getParentFile().getName(); + } + else { + projectName = projectFile.getName(); + } + + // ask a user for the project import if auto-import is disabled + if (!projectSettings.isUseAutoImport()) { + String message = String.format("Project '%s' require synchronization with %s configuration. \nImport the project?", + projectName, projectSystemId.getReadableName()); + int returnValue = Messages.showOkCancelDialog( + message, "Import Project", CommonBundle.getOkButtonText(), CommonBundle.getCancelButtonText(), Messages.getQuestionIcon() + ); + if (returnValue != Messages.OK) return false; + } + + final String title = ExternalSystemBundle.message("progress.import.text", linkedProjectPath, projectSystemId.getReadableName()); + new Task.Modal(project, title, false) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + if (project.isDisposed()) return; + + ExternalSystemNotificationManager.getInstance(project) + .clearNotifications(null, NotificationSource.PROJECT_SYNC, projectSystemId); + ExternalSystemResolveProjectTask task = + new ExternalSystemResolveProjectTask(projectSystemId, project, linkedProjectPath, false); + task.execute(indicator, ExternalSystemTaskNotificationListener.EP_NAME.getExtensions()); + if (project.isDisposed()) return; + + final Throwable error = task.getError(); + if (error != null) { + ExternalSystemNotificationManager.getInstance(project) + .processExternalProjectRefreshError(error, projectName, projectSystemId); + return; + } + final DataNode<ProjectData> projectDataDataNode = task.getExternalProject(); + if (projectDataDataNode == null) return; + + final Collection<DataNode<ExternalProject>> nodes = ExternalSystemApiUtil.findAll(projectDataDataNode, KEY); + if (nodes.size() != 1) { + throw new IllegalArgumentException( + String.format("Expected to get a single external project but got %d: %s", nodes.size(), nodes)); + } + + ProjectRootManagerEx.getInstanceEx(myProject).mergeRootsChangesDuring(new Runnable() { + @Override + public void run() { + myProjectDataManager.importData(KEY, nodes, project, true); + } + }); + + result.set(true); + } + }.queue(); + + return result.get(); + } + }); + + return result ? getRootExternalProject(projectSystemId, projectRootDir) : null; + } + + @Nullable + public ExternalProject getRootExternalProject(@NotNull ProjectSystemId systemId, @NotNull File projectRootDir) { + return myExternalRootProjects.get(Pair.create(systemId, projectRootDir)); + } + + public void saveExternalProject(@NotNull ExternalProject externalProject) { + myExternalRootProjects.put( + Pair.create(new ProjectSystemId(externalProject.getExternalSystemId()), externalProject.getProjectDir()), + new DefaultExternalProject(externalProject) + ); + } + + @Nullable + public ExternalProject findExternalProject(@NotNull ExternalProject parentProject, @NotNull Module module) { + String externalProjectId = ExternalSystemApiUtil.getExternalProjectId(module); + return externalProjectId != null ? findExternalProject(parentProject, externalProjectId) : null; + } + + @Nullable + private static ExternalProject findExternalProject(@NotNull ExternalProject parentProject, @NotNull String externalProjectId) { + if (parentProject.getQName().equals(externalProjectId)) return parentProject; + if (parentProject.getChildProjects().containsKey(externalProjectId)) { + return parentProject.getChildProjects().get(externalProjectId); + } + for (ExternalProject externalProject : parentProject.getChildProjects().values()) { + final ExternalProject project = findExternalProject(externalProject, externalProjectId); + if (project != null) return project; + } + return null; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectSerializer.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectSerializer.java new file mode 100644 index 000000000000..8828b9ef5880 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectSerializer.java @@ -0,0 +1,262 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.service.project.data; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryo.Serializer; +import com.esotericsoftware.kryo.io.Input; +import com.esotericsoftware.kryo.io.Output; +import com.esotericsoftware.kryo.serializers.CollectionSerializer; +import com.esotericsoftware.kryo.serializers.DefaultSerializers; +import com.esotericsoftware.kryo.serializers.FieldSerializer; +import com.esotericsoftware.kryo.serializers.MapSerializer; +import com.esotericsoftware.minlog.Log; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.externalSystem.model.*; +import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceType; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.StreamUtil; +import gnu.trove.THashMap; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.objenesis.strategy.StdInstantiatorStrategy; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.util.*; + +/** + * @author Vladislav.Soroka + * @since 7/15/2014 + */ +public class ExternalProjectSerializer { + private static final Logger LOG = Logger.getInstance(ExternalProjectSerializer.class); + + private final Kryo myKryo; + + public ExternalProjectSerializer() { + myKryo = new Kryo() { + @Override + public <T> T newInstance(Class<T> type) { + LOG.error("Serializing default type: " + type); + return super.newInstance(type); + } + }; + configureKryo(); + } + + private void configureKryo() { + myKryo.setAutoReset(true); + + myKryo.setRegistrationRequired(true); + Log.set(Log.LEVEL_WARN); + + myKryo.register(ArrayList.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class<Collection> type) { + return new ArrayList(); + } + }); + myKryo.register(HashMap.class, new MapSerializer() { + @Override + protected Map create(Kryo kryo, Input input, Class<Map> type) { + return new HashMap(); + } + }); + myKryo.register(HashSet.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class<Collection> type) { + return new HashSet(); + } + }); + + myKryo.register(File.class, new FileSerializer()); + myKryo.register(DefaultExternalProject.class, new FieldSerializer<DefaultExternalProject>(myKryo, DefaultExternalProject.class) { + @Override + protected DefaultExternalProject create(Kryo kryo, Input input, Class<DefaultExternalProject> type) { + return new DefaultExternalProject(); + } + }); + + myKryo.register(DefaultExternalTask.class, new FieldSerializer<DefaultExternalTask>(myKryo, DefaultExternalTask.class) { + @Override + protected DefaultExternalTask create(Kryo kryo, Input input, Class<DefaultExternalTask> type) { + return new DefaultExternalTask(); + } + }); + + myKryo.register(DefaultExternalPlugin.class, new FieldSerializer<DefaultExternalPlugin>(myKryo, DefaultExternalPlugin.class) { + @Override + protected DefaultExternalPlugin create(Kryo kryo, Input input, Class<DefaultExternalPlugin> type) { + return new DefaultExternalPlugin(); + } + }); + + myKryo.register(DefaultExternalSourceSet.class, new FieldSerializer<DefaultExternalSourceSet>(myKryo, DefaultExternalSourceSet.class) { + @Override + protected DefaultExternalSourceSet create(Kryo kryo, Input input, Class<DefaultExternalSourceSet> type) { + return new DefaultExternalSourceSet(); + } + }); + + myKryo.register( + DefaultExternalSourceDirectorySet.class, + new FieldSerializer<DefaultExternalSourceDirectorySet>(myKryo, DefaultExternalSourceDirectorySet.class) { + @Override + protected DefaultExternalSourceDirectorySet create(Kryo kryo, Input input, Class<DefaultExternalSourceDirectorySet> type) { + return new DefaultExternalSourceDirectorySet(); + } + } + ); + + myKryo.register(DefaultExternalFilter.class, new FieldSerializer<DefaultExternalFilter>(myKryo, DefaultExternalFilter.class) { + @Override + protected DefaultExternalFilter create(Kryo kryo, Input input, Class<DefaultExternalFilter> type) { + return new DefaultExternalFilter(); + } + }); + + myKryo.register(ExternalSystemSourceType.class, new DefaultSerializers.EnumSerializer(ExternalSystemSourceType.class)); + + myKryo.register(LinkedHashSet.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class<Collection> type) { + return new LinkedHashSet(); + } + }); + myKryo.register(HashSet.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class<Collection> type) { + return new HashSet(); + } + }); + myKryo.register(THashSet.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class<Collection> type) { + return new THashSet(); + } + }); + myKryo.register(Set.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class<Collection> type) { + return new HashSet(); + } + }); + myKryo.register(THashMap.class, new MapSerializer() { + @Override + protected Map create(Kryo kryo, Input input, Class<Map> type) { + return new THashMap(); + } + }); + } + + + public void save(@NotNull ExternalProject externalProject) { + Output output = null; + try { + final String externalProjectPath = externalProject.getProjectDir().getPath(); + final File configurationFile = + getProjectConfigurationFile(new ProjectSystemId(externalProject.getExternalSystemId()), externalProjectPath); + if (!FileUtil.createParentDirs(configurationFile)) return; + + output = new Output(new FileOutputStream(configurationFile)); + myKryo.writeObject(output, externalProject); + } + catch (FileNotFoundException e) { + LOG.error(e); + } + finally { + StreamUtil.closeStream(output); + } + } + + @Nullable + public ExternalProject load(@NotNull ProjectSystemId externalSystemId, File externalProjectPath) { + Input input = null; + try { + final File configurationFile = getProjectConfigurationFile(externalSystemId, externalProjectPath.getPath()); + if (!configurationFile.isFile()) return null; + + input = new Input(new FileInputStream(configurationFile)); + return myKryo.readObject(input, DefaultExternalProject.class); + } + catch (Exception e) { + LOG.error(e); + } + finally { + StreamUtil.closeStream(input); + } + + return null; + } + + private static File getProjectConfigurationFile(ProjectSystemId externalSystemId, String externalProjectPath) { + return new File(getProjectConfigurationDir(externalSystemId), Integer.toHexString(externalProjectPath.hashCode()) + "/project.dat"); + } + + private static File getProjectConfigurationDir(ProjectSystemId externalSystemId) { + return getPluginSystemDir(externalSystemId, "Projects"); + } + + private static File getPluginSystemDir(ProjectSystemId externalSystemId, String folder) { + return new File(PathManager.getSystemPath(), externalSystemId.getId().toLowerCase() + "/" + folder).getAbsoluteFile(); + } + + private static class FileSerializer extends Serializer<File> { + private final Kryo myStdKryo; + + public FileSerializer() { + myStdKryo = new Kryo(); + myStdKryo.register(File.class); + myStdKryo.setInstantiatorStrategy(new StdInstantiatorStrategy()); + } + + @Override + public void write(Kryo kryo, Output output, File object) { + myStdKryo.writeObject(output, object); + } + + @Override + public File read(Kryo kryo, Input input, Class<File> type) { + File file = myStdKryo.readObject(input, File.class); + return new File(file.getPath()); + } + } + + private static class StdSerializer<T> extends Serializer<T> { + private final Kryo myStdKryo; + + public StdSerializer(Class<T> clazz) { + myStdKryo = new Kryo(); + myStdKryo.register(clazz); + myStdKryo.setInstantiatorStrategy(new StdInstantiatorStrategy()); + } + + @Override + public void write(Kryo kryo, Output output, T object) { + myStdKryo.writeObject(output, object); + } + + @Override + public T read(Kryo kryo, Input input, Class<T> type) { + return myStdKryo.readObject(input, type); + } + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleProjectOpenProcessor.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleProjectOpenProcessor.java index 213ba84271ef..10f766cc5e34 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleProjectOpenProcessor.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleProjectOpenProcessor.java @@ -16,17 +16,26 @@ package org.jetbrains.plugins.gradle.service.project.wizard; import com.intellij.ide.util.newProjectWizard.AddModuleWizard; -import com.intellij.ide.util.projectWizard.ProjectBuilder; +import com.intellij.ide.util.projectWizard.ModuleWizardStep; import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.ide.wizard.Step; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.externalSystem.service.project.wizard.SelectExternalProjectStep; -import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.projectImport.ProjectOpenProcessorBase; import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.service.settings.GradleProjectSettingsControl; +import org.jetbrains.plugins.gradle.service.settings.GradleSystemSettingsControl; +import org.jetbrains.plugins.gradle.service.settings.ImportFromGradleControl; +import org.jetbrains.plugins.gradle.settings.DistributionType; +import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; +import org.jetbrains.plugins.gradle.settings.GradleSettings; import org.jetbrains.plugins.gradle.util.GradleConstants; +import static org.jetbrains.plugins.gradle.util.GradleEnvironment.Headless.*; /** * @author Denis Zhdanov @@ -61,24 +70,90 @@ public class GradleProjectOpenProcessor extends ProjectOpenProcessorBase<GradleP @Override protected boolean doQuickImport(VirtualFile file, WizardContext wizardContext) { - AddModuleWizard dialog = new AddModuleWizard(null, file.getPath(), new GradleProjectImportProvider(getBuilder())); + final GradleProjectImportProvider projectImportProvider = new GradleProjectImportProvider(getBuilder()); + getBuilder().setFileToImport(file.getPath()); getBuilder().prepare(wizardContext); getBuilder().getControl(null).setLinkedProjectPath(file.getPath()); - dialog.getWizardContext().setProjectBuilder(getBuilder()); - dialog.navigateToStep(new Function<Step, Boolean>() { - @Override - public Boolean fun(Step step) { - return step instanceof SelectExternalProjectStep; - } - }); - boolean result = dialog.showAndGet(); + final boolean result; + if (ApplicationManager.getApplication().isHeadlessEnvironment()) { + result = setupGradleProjectSettingsInHeadlessMode(file, projectImportProvider, wizardContext); + } + else { + AddModuleWizard dialog = new AddModuleWizard(null, file.getPath(), projectImportProvider); + dialog.getWizardContext().setProjectBuilder(getBuilder()); + dialog.navigateToStep(new Function<Step, Boolean>() { + @Override + public Boolean fun(Step step) { + return step instanceof SelectExternalProjectStep; + } + }); + result = dialog.showAndGet(); + } if (result && getBuilder().getExternalProjectNode() != null) { wizardContext.setProjectName(getBuilder().getExternalProjectNode().getData().getInternalName()); } return result; } + private boolean setupGradleProjectSettingsInHeadlessMode(VirtualFile file, + GradleProjectImportProvider projectImportProvider, + WizardContext wizardContext) { + final ModuleWizardStep[] wizardSteps = projectImportProvider.createSteps(wizardContext); + if (wizardSteps.length > 0 && wizardSteps[0] instanceof SelectExternalProjectStep) { + SelectExternalProjectStep selectExternalProjectStep = (SelectExternalProjectStep)wizardSteps[0]; + wizardContext.setProjectBuilder(getBuilder()); + try { + selectExternalProjectStep.updateStep(); + final ImportFromGradleControl importFromGradleControl = getBuilder().getControl(wizardContext.getProject()); + + GradleProjectSettingsControl gradleProjectSettingsControl = + (GradleProjectSettingsControl)importFromGradleControl.getProjectSettingsControl(); + + final GradleProjectSettings projectSettings = gradleProjectSettingsControl.getInitialSettings(); + + if (GRADLE_DISTRIBUTION_TYPE != null) { + for (DistributionType type : DistributionType.values()) { + if (type.name().equals(GRADLE_DISTRIBUTION_TYPE)) { + projectSettings.setDistributionType(type); + break; + } + } + } + if (GRADLE_HOME != null) { + projectSettings.setGradleHome(GRADLE_HOME); + } + gradleProjectSettingsControl.reset(); + + final GradleSystemSettingsControl systemSettingsControl = + (GradleSystemSettingsControl)importFromGradleControl.getSystemSettingsControl(); + assert systemSettingsControl != null; + final GradleSettings gradleSettings = systemSettingsControl.getInitialSettings(); + if (GRADLE_VM_OPTIONS != null) { + gradleSettings.setGradleVmOptions(GRADLE_VM_OPTIONS); + } + if (GRADLE_OFFLINE != null) { + gradleSettings.setOfflineWork(Boolean.parseBoolean(GRADLE_OFFLINE)); + } + String serviceDirectory = GRADLE_SERVICE_DIRECTORY; + if (GRADLE_SERVICE_DIRECTORY != null) { + gradleSettings.setServiceDirectoryPath(serviceDirectory); + } + systemSettingsControl.reset(); + + if (!selectExternalProjectStep.validate()) { + return false; + } + } + catch (ConfigurationException e) { + Messages.showErrorDialog(wizardContext.getProject(), e.getMessage(), e.getTitle()); + return false; + } + selectExternalProjectStep.updateDataModel(); + } + return true; + } + @Override public boolean lookForProjectsInDirectory() { return false; diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleSystemSettingsControl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleSystemSettingsControl.java index ffdf37c74b87..ab6454c46c99 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleSystemSettingsControl.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleSystemSettingsControl.java @@ -173,4 +173,9 @@ public class GradleSystemSettingsControl implements ExternalSystemSettingsContro public void disposeUIResources() { ExternalSystemUiUtil.disposeUi(this); } + + @NotNull + public GradleSettings getInitialSettings() { + return myInitialSettings; + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleEnvironment.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleEnvironment.java index 2c61ac6c10eb..eb780ced4d5a 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleEnvironment.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleEnvironment.java @@ -13,6 +13,18 @@ public class GradleEnvironment { @NonNls public static final boolean DISABLE_ENHANCED_TOOLING_API = Boolean.getBoolean("gradle.disable.enhanced.tooling.api"); @NonNls public static final boolean ADJUST_USER_DIR = Boolean.getBoolean("gradle.adjust.userdir"); + public static class Headless { + @NonNls public static final String GRADLE_DISTRIBUTION_TYPE = System.getProperty("idea.gradle.distributionType"); + @NonNls public static final String GRADLE_HOME = System.getProperty("idea.gradle.home"); + @NonNls public static final String GRADLE_VM_OPTIONS = System.getProperty("idea.gradle.vmOptions"); + @NonNls public static final String GRADLE_OFFLINE = System.getProperty("idea.gradle.offline"); + @NonNls public static final String GRADLE_SERVICE_DIRECTORY = System.getProperty("idea.gradle.serviceDirectory"); + + private Headless() { + } + } + + private GradleEnvironment() { } } |