From 8ffd4359836a426c99d23e024246ab0c674682dc Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Wed, 30 Jul 2014 19:35:45 +0400 Subject: [PATCH] IDEA-127046 Gradle: processing resources --- build/scripts/layouts.gant | 5 + .../externalSystem/model/DataNode.java | 12 + .../model/DefaultExternalFilter.java | 62 +++++ .../model/DefaultExternalPlugin.java | 46 +++ .../model/DefaultExternalProject.java | 243 ++++++++++++++++ .../DefaultExternalSourceDirectorySet.java | 124 +++++++++ .../model/DefaultExternalSourceSet.java | 66 +++++ .../model/DefaultExternalTask.java | 86 ++++++ .../externalSystem/model/ExternalFilter.java | 34 +++ .../externalSystem/model/ExternalPlugin.java | 30 ++ .../externalSystem/model/ExternalProject.java | 87 ++++++ .../model/ExternalSourceDirectorySet.java | 46 +++ .../model/ExternalSourceSet.java | 39 +++ .../externalSystem/model/ExternalTask.java | 36 +++ .../project/ExternalSystemSourceType.java | 70 +++-- .../project/IExternalSystemSourceType.java | 32 +++ .../util/ExternalSystemApiUtil.java | 5 + .../util/ExternalSystemConstants.java | 1 + .../external-system-impl.iml | 2 + .../project/ProjectStructureServices.java | 42 --- .../project/manage/ModuleDataService.java | 1 + .../project/manage/ProjectDataManager.java | 21 +- .../util/ExternalProjectSerializer.java | 262 ++++++++++++++++++ .../test/ExternalSystemTestCase.java | 137 ++++++++- .../roots/OrderEnumerationHandler.java | 9 + .../roots/impl/OrderEnumeratorBase.java | 32 +++ .../roots/impl/OrderRootsEnumeratorImpl.java | 1 + plugins/gradle/gradle.iml | 3 + .../gradle/jps-plugin/gradle-jps-plugin.iml | 44 +++ ...jps.gradle.model.JpsGradleExtensionService | 16 ++ ...g.jetbrains.jps.incremental.BuilderService | 16 ++ ...JavaDependenciesEnumerationHandler$Factory | 16 ++ ....serialization.JpsModelSerializerExtension | 16 ++ .../compiler/ChainingFilterTransformer.java | 111 ++++++++ .../gradle/compiler/GradleBuilderService.java | 44 +++ .../compiler/GradleResourceFileProcessor.java | 94 +++++++ .../compiler/GradleResourcesBuilder.java | 128 +++++++++ .../model/JpsGradleExtensionService.java | 49 ++++ .../model/JpsGradleModuleExtension.java | 25 ++ .../jps/gradle/model/impl/FilePattern.java | 38 +++ .../GradleModuleResourceConfiguration.java | 81 ++++++ .../impl/GradleProjectConfiguration.java | 35 +++ .../model/impl/GradleResourceFileFilter.java | 81 ++++++ .../impl/GradleResourceRootDescriptor.java | 88 ++++++ .../model/impl/GradleResourcesTarget.java | 161 +++++++++++ .../model/impl/GradleResourcesTargetType.java | 78 ++++++ ...sGradleDependenciesEnumerationHandler.java | 57 ++++ .../impl/JpsGradleExtensionServiceImpl.java | 136 +++++++++ .../JpsGradleModelSerializationExtension.java | 59 ++++ .../impl/JpsGradleModuleExtensionImpl.java | 43 +++ .../jps/gradle/model/impl/ModuleVersion.java | 64 +++++ .../model/impl/ResourceRootConfiguration.java | 59 ++++ .../gradle/model/impl/ResourceRootFilter.java | 75 +++++ .../src/META-INF/gradle-maven-integration.xml | 1 - plugins/gradle/src/META-INF/plugin.xml | 6 + .../GradleBuildProcessParametersProvider.java | 93 +++++++ ...esourceCompilerConfigurationGenerator.java | 186 +++++++++++++ .../GradleOrderEnumeratorHandler.java | 114 ++++++++ .../AbstractProjectResolverExtension.java | 6 + .../BaseGradleProjectResolverExtension.java | 83 +++++- .../project/GradleProjectResolver.java | 3 + .../GradleProjectResolverExtension.java | 3 + .../project/GradleStartupActivity.java | 22 +- .../project/ProjectResolverContext.java | 8 +- .../data/ExternalProjectDataService.java | 233 ++++++++++++++++ .../compiler/GradleCompilingTestCase.java | 89 ++++++ .../compiler/GradleResourceFilteringTest.java | 132 +++++++++ .../GradleResourceProcessingTest.java | 176 ++++++++++++ .../gradle/model/ModuleExtendedModel.java | 3 + .../gradle/model/ProjectImportAction.java | 51 ++-- .../gradle/tooling/ErrorMessageBuilder.java | 12 +- .../gradle-tooling-extension-impl.iml | 1 + ...plugins.gradle.tooling.ModelBuilderService | 1 + .../builder/ExternalProjectBuilderImpl.groovy | 231 +++++++++++++++ 74 files changed, 4484 insertions(+), 118 deletions(-) create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalFilter.java create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalPlugin.java create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalProject.java create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceDirectorySet.java create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceSet.java create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalTask.java create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalFilter.java create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalPlugin.java create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalProject.java create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceDirectorySet.java create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceSet.java create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalTask.java create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/model/project/IExternalSystemSourceType.java delete mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureServices.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalProjectSerializer.java create mode 100644 plugins/gradle/jps-plugin/gradle-jps-plugin.iml create mode 100644 plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.gradle.model.JpsGradleExtensionService create mode 100644 plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService create mode 100644 plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.java.impl.JpsJavaDependenciesEnumerationHandler$Factory create mode 100644 plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.serialization.JpsModelSerializerExtension create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/ChainingFilterTransformer.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleBuilderService.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourceFileProcessor.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourcesBuilder.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleExtensionService.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleModuleExtension.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/FilePattern.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleModuleResourceConfiguration.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleProjectConfiguration.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceFileFilter.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceRootDescriptor.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTarget.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTargetType.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleDependenciesEnumerationHandler.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleExtensionServiceImpl.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModelSerializationExtension.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModuleExtensionImpl.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ModuleVersion.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootConfiguration.java create mode 100644 plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootFilter.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/compiler/GradleBuildProcessParametersProvider.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleResourceCompilerConfigurationGenerator.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectDataService.java create mode 100644 plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleCompilingTestCase.java create mode 100644 plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceFilteringTest.java create mode 100644 plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceProcessingTest.java create mode 100644 plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index b0315724e8e7..ed22dfed5f99 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -336,6 +336,10 @@ public def layoutCommunityPlugins(String home) { } layoutPlugin("gradle") { + jar("gradle-jps-plugin.jar") { + module("gradle-jps-plugin") + } + jar("gradle-tooling-extension-api.jar") { module("gradle-tooling-extension-api") } @@ -753,6 +757,7 @@ def layoutJps(String home, String targetDir, String buildNumber, Closure additio jar("maven-jps-plugin.jar") { module("maven-jps-plugin") } + jar("gradle-jps-plugin.jar") { module("gradle-jps-plugin") } fileset(dir: "$home/plugins/maven/maven3-server-impl/lib/maven3/lib") {include(name: "plexus-utils-*.jar")} jar("eclipse-jps-plugin.jar") { diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DataNode.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DataNode.java index 4efac184c2ee..10fc11acbf5f 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DataNode.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DataNode.java @@ -68,6 +68,18 @@ public class DataNode implements Serializable { return result; } + @NotNull + public DataNode createOrReplaceChild(@NotNull Key key, @NotNull T data) { + for (Iterator> iterator = myChildren.iterator(); iterator.hasNext(); ) { + DataNode child = iterator.next(); + if (child.getKey().equals(key)) { + iterator.remove(); + break; + } + } + return createChild(key, data); + } + @NotNull public Key getKey() { return myKey; diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalFilter.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalFilter.java new file mode 100644 index 000000000000..6bc9cf9aed94 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalFilter.java @@ -0,0 +1,62 @@ +/* + * 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 com.intellij.openapi.externalSystem.model; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Vladislav.Soroka + * @since 7/22/2014 + */ +public class DefaultExternalFilter implements ExternalFilter { + private static final long serialVersionUID = 1L; + + @NotNull + private String myFilterType; + @NotNull + private String myPropertiesAsJsonMap; + + public DefaultExternalFilter() { + myPropertiesAsJsonMap = ""; + myFilterType = ""; + } + + + public DefaultExternalFilter(ExternalFilter filter) { + myPropertiesAsJsonMap = filter.getPropertiesAsJsonMap(); + myFilterType = filter.getFilterType(); + } + + @NotNull + @Override + public String getFilterType() { + return myFilterType; + } + + public void setFilterType(@NotNull String filterType) { + myFilterType = filterType; + } + + @Override + @NotNull + public String getPropertiesAsJsonMap() { + return myPropertiesAsJsonMap; + } + + public void setPropertiesAsJsonMap(@NotNull String propertiesAsJsonMap) { + myPropertiesAsJsonMap = propertiesAsJsonMap; + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalPlugin.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalPlugin.java new file mode 100644 index 000000000000..8b7991b1d88c --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalPlugin.java @@ -0,0 +1,46 @@ +/* + * 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 com.intellij.openapi.externalSystem.model; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Vladislav.Soroka + * @since 7/16/2014 + */ +public class DefaultExternalPlugin implements ExternalPlugin { + private static final long serialVersionUID = 1L; + + @NotNull + private String myId; + + public DefaultExternalPlugin() { + } + + public DefaultExternalPlugin(ExternalPlugin plugin) { + myId = plugin.getId(); + } + + @NotNull + @Override + public String getId() { + return myId; + } + + public void setId(@NotNull String id) { + myId = id; + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalProject.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalProject.java new file mode 100644 index 000000000000..cecb9ad33c12 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalProject.java @@ -0,0 +1,243 @@ +/* + * 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 com.intellij.openapi.externalSystem.model; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/14/2014 + */ +public class DefaultExternalProject implements ExternalProject { + + private static final long serialVersionUID = 1L; + + @NotNull + private String myName; + @NotNull + private String myQName; + @Nullable + private String myDescription; + @NotNull + private String myGroup; + @NotNull + private String myVersion; + @NotNull + private Map myChildProjects; + @NotNull + private File myProjectDir; + @NotNull + private File myBuildDir; + @Nullable + private File myBuildFile; + @NotNull + private Map myTasks; + @NotNull + private Map myProperties; + @NotNull + private Map mySourceSets; + @NotNull + private String myExternalSystemId; + @NotNull + private Map myPlugins; + + public DefaultExternalProject() { + myChildProjects = new HashMap(); + myTasks = new HashMap(); + myProperties = new HashMap(); + mySourceSets = new HashMap(); + myPlugins = new HashMap(); + } + + public DefaultExternalProject(@NotNull ExternalProject externalProject) { + this(); + myName = externalProject.getName(); + myQName = externalProject.getQName(); + myVersion = externalProject.getVersion(); + myGroup = externalProject.getGroup(); + myDescription = externalProject.getDescription(); + myProjectDir = externalProject.getProjectDir(); + myBuildDir = externalProject.getBuildDir(); + myBuildFile = externalProject.getBuildFile(); + myExternalSystemId = externalProject.getExternalSystemId(); + + for (Map.Entry entry : externalProject.getChildProjects().entrySet()) { + myChildProjects.put(entry.getKey(), new DefaultExternalProject(entry.getValue())); + } + + for (Map.Entry entry : externalProject.getTasks().entrySet()) { + myTasks.put(entry.getKey(), new DefaultExternalTask(entry.getValue())); + } + for (Map.Entry entry : externalProject.getSourceSets().entrySet()) { + mySourceSets.put(entry.getKey(), new DefaultExternalSourceSet(entry.getValue())); + } + for (Map.Entry entry : externalProject.getPlugins().entrySet()) { + myPlugins.put(entry.getKey(), new DefaultExternalPlugin(entry.getValue())); + } + } + + + @NotNull + @Override + public String getExternalSystemId() { + return myExternalSystemId; + } + + public void setExternalSystemId(@NotNull String externalSystemId) { + myExternalSystemId = externalSystemId; + } + + @NotNull + @Override + public String getName() { + return myName; + } + + public void setName(@NotNull String name) { + myName = name; + } + + @NotNull + @Override + public String getQName() { + return myQName; + } + + public void setQName(@NotNull String QName) { + myQName = QName; + } + + @Nullable + @Override + public String getDescription() { + return myDescription; + } + + public void setDescription(@Nullable String description) { + myDescription = description; + } + + @NotNull + @Override + public String getGroup() { + return myGroup; + } + + public void setGroup(@NotNull String group) { + myGroup = group; + } + + @NotNull + @Override + public String getVersion() { + return myVersion; + } + + public void setVersion(@NotNull String version) { + myVersion = version; + } + + @NotNull + @Override + public Map getChildProjects() { + return myChildProjects; + } + + public void setChildProjects(@NotNull Map childProjects) { + myChildProjects = childProjects; + } + + @NotNull + @Override + public File getProjectDir() { + return myProjectDir; + } + + public void setProjectDir(@NotNull File projectDir) { + myProjectDir = projectDir; + } + + @NotNull + @Override + public File getBuildDir() { + return myBuildDir; + } + + public void setBuildDir(@NotNull File buildDir) { + myBuildDir = buildDir; + } + + @Nullable + @Override + public File getBuildFile() { + return myBuildFile; + } + + public void setBuildFile(@Nullable File buildFile) { + myBuildFile = buildFile; + } + + @NotNull + @Override + public Map getTasks() { + return myTasks; + } + + public void setTasks(@NotNull Map tasks) { + myTasks = tasks; + } + + @NotNull + @Override + public Map getPlugins() { + return myPlugins; + } + + public void setPlugins(@NotNull Map plugins) { + myPlugins = plugins; + } + + @NotNull + @Override + public Map getProperties() { + return myProperties; + } + + public void setProperties(@NotNull Map properties) { + myProperties = properties; + } + + @Nullable + @Override + public Object getProperty(String name) { + return myProperties.get(name); + } + + @NotNull + @Override + public Map getSourceSets() { + return mySourceSets; + } + + public void setSourceSets(@NotNull Map sourceSets) { + mySourceSets = sourceSets; + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceDirectorySet.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceDirectorySet.java new file mode 100644 index 000000000000..d6a8d7aa6291 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceDirectorySet.java @@ -0,0 +1,124 @@ +/* + * 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 com.intellij.openapi.externalSystem.model; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Vladislav.Soroka + * @since 7/14/2014 + */ +public class DefaultExternalSourceDirectorySet implements ExternalSourceDirectorySet { + private static final long serialVersionUID = 1L; + + @NotNull + private String myName; + @NotNull + private Set mySrcDirs; + @NotNull + private File myOutputDir; + @NotNull + private Set myExcludes; + @NotNull + private Set myIncludes; + @NotNull + private List myFilters; + + public DefaultExternalSourceDirectorySet() { + mySrcDirs = new HashSet(); + myExcludes = new HashSet(); + myIncludes = new HashSet(); + myFilters = new ArrayList(); + } + + public DefaultExternalSourceDirectorySet(ExternalSourceDirectorySet sourceDirectorySet) { + this(); + myName = sourceDirectorySet.getName(); + mySrcDirs = new HashSet(sourceDirectorySet.getSrcDirs()); + myOutputDir = sourceDirectorySet.getOutputDir(); + myExcludes = new HashSet(sourceDirectorySet.getExcludes()); + myIncludes = new HashSet(sourceDirectorySet.getIncludes()); + for (ExternalFilter filter : sourceDirectorySet.getFilters()) { + myFilters.add(new DefaultExternalFilter(filter)); + } + } + + @NotNull + @Override + public String getName() { + return myName; + } + + public void setName(@NotNull String name) { + myName = name; + } + + @NotNull + @Override + public Set getSrcDirs() { + return mySrcDirs; + } + + public void setSrcDirs(@NotNull Set srcDirs) { + mySrcDirs = srcDirs; + } + + @NotNull + @Override + public File getOutputDir() { + return myOutputDir; + } + + @NotNull + @Override + public Set getIncludes() { + return myIncludes; + } + + public void setIncludes(@NotNull Set includes) { + myIncludes = includes; + } + + @NotNull + @Override + public Set getExcludes() { + return myExcludes; + } + + public void setExcludes(@NotNull Set excludes) { + myExcludes = excludes; + } + + @NotNull + @Override + public List getFilters() { + return myFilters; + } + + public void setFilters(@NotNull List filters) { + myFilters = filters; + } + + public void setOutputDir(@NotNull File outputDir) { + myOutputDir = outputDir; + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceSet.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceSet.java new file mode 100644 index 000000000000..19d692dd1985 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceSet.java @@ -0,0 +1,66 @@ +/* + * 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 com.intellij.openapi.externalSystem.model; + +import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceType; +import com.intellij.openapi.externalSystem.model.project.IExternalSystemSourceType; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/14/2014 + */ +public class DefaultExternalSourceSet implements ExternalSourceSet { + private static final long serialVersionUID = 1L; + + private String myName; + private Map mySources; + + public DefaultExternalSourceSet() { + mySources = new HashMap(); + } + + public DefaultExternalSourceSet(ExternalSourceSet sourceSet) { + this(); + myName = sourceSet.getName(); + for (Map.Entry entry : sourceSet.getSources().entrySet()) { + mySources.put(ExternalSystemSourceType.from(entry.getKey()), new DefaultExternalSourceDirectorySet(entry.getValue())); + } + } + + @NotNull + @Override + public String getName() { + return myName; + } + + public void setName(String name) { + myName = name; + } + + @NotNull + @Override + public Map getSources() { + return mySources; + } + + public void setSources(Map sources) { + mySources = sources; + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalTask.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalTask.java new file mode 100644 index 000000000000..e9392eb52e84 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalTask.java @@ -0,0 +1,86 @@ +/* + * 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 com.intellij.openapi.externalSystem.model; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 7/14/2014 + */ +public class DefaultExternalTask implements ExternalTask { + private static final long serialVersionUID = 1L; + + @NotNull + private String myName; + @NotNull + private String myQName; + @Nullable + private String myDescription; + @Nullable + private String myGroup; + + public DefaultExternalTask() { + } + + public DefaultExternalTask(ExternalTask externalTask) { + myName = externalTask.getName(); + myQName = externalTask.getQName(); + myDescription = externalTask.getDescription(); + myGroup = externalTask.getGroup(); + } + + @NotNull + @Override + public String getName() { + return myName; + } + + public void setName(@NotNull String name) { + myName = name; + } + + @NotNull + @Override + public String getQName() { + return myQName; + } + + public void setQName(@NotNull String QName) { + myQName = QName; + } + + @Nullable + @Override + public String getDescription() { + return myDescription; + } + + public void setDescription(@Nullable String description) { + myDescription = description; + } + + @Nullable + @Override + public String getGroup() { + return myGroup; + } + + public void setGroup(@Nullable String group) { + myGroup = group; + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalFilter.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalFilter.java new file mode 100644 index 000000000000..98fc003cb645 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalFilter.java @@ -0,0 +1,34 @@ +/* + * 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 com.intellij.openapi.externalSystem.model; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.Serializable; +import java.util.Map; +import java.util.Set; + +/** + * @author Vladislav.Soroka + * @since 7/14/2014 + */ +public interface ExternalFilter extends Serializable { + @NotNull + String getFilterType(); + @NotNull + String getPropertiesAsJsonMap(); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalPlugin.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalPlugin.java new file mode 100644 index 000000000000..edd3db771b3f --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalPlugin.java @@ -0,0 +1,30 @@ +/* + * 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 com.intellij.openapi.externalSystem.model; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.Serializable; + +/** + * @author Vladislav.Soroka + * @since 7/14/2014 + */ +public interface ExternalPlugin extends Serializable { + @NotNull + String getId(); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalProject.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalProject.java new file mode 100644 index 000000000000..6df2d413d0fd --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalProject.java @@ -0,0 +1,87 @@ +/* + * 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 com.intellij.openapi.externalSystem.model; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.Serializable; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/14/2014 + */ +public interface ExternalProject extends Serializable { + + @NotNull + String getExternalSystemId(); + + @NotNull + String getName(); + + @NotNull + String getQName(); + + @Nullable + String getDescription(); + + @NotNull + String getGroup(); + + @NotNull + String getVersion(); + + @NotNull + Map getChildProjects(); + + @NotNull + File getProjectDir(); + + @NotNull + File getBuildDir(); + + @Nullable + File getBuildFile(); + + @NotNull + Map getTasks(); + + //@NotNull + //Map getConfigurations(); + + //@NotNull + //List getRepositories(); + + //@NotNull + //List getDependencies(); + + @NotNull + Map getPlugins(); + + //@NotNull + //ExternalProjectBuild getBuild(); + + @NotNull + Map getProperties(); + + @Nullable + Object getProperty(String name); + + @NotNull + Map getSourceSets(); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceDirectorySet.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceDirectorySet.java new file mode 100644 index 000000000000..70f0bed3d177 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceDirectorySet.java @@ -0,0 +1,46 @@ +/* + * 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 com.intellij.openapi.externalSystem.model; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.Serializable; +import java.util.List; +import java.util.Set; + +/** + * @author Vladislav.Soroka + * @since 7/14/2014 + */ +public interface ExternalSourceDirectorySet extends Serializable { + @NotNull + String getName(); + + @NotNull + Set getSrcDirs(); + + @NotNull + File getOutputDir(); + + @NotNull + Set getExcludes(); + @NotNull + Set getIncludes(); + + @NotNull + List getFilters(); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceSet.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceSet.java new file mode 100644 index 000000000000..b23c07bbafa6 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceSet.java @@ -0,0 +1,39 @@ +/* + * 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 com.intellij.openapi.externalSystem.model; + +import com.intellij.openapi.externalSystem.model.project.IExternalSystemSourceType; +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/14/2014 + */ +public interface ExternalSourceSet extends Serializable { + @NotNull + String getName(); + //@NotNull + //ClasspathContainer getCompileClasspath(); + + //@NotNull + //ClasspathContainer getRuntimeClasspath(); + + @NotNull + Map getSources(); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalTask.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalTask.java new file mode 100644 index 000000000000..b4c61c662acc --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalTask.java @@ -0,0 +1,36 @@ +/* + * 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 com.intellij.openapi.externalSystem.model; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.Serializable; + +/** + * @author Vladislav.Soroka + * @since 7/14/2014 + */ +public interface ExternalTask extends Serializable { + @NotNull + String getName(); + @NotNull + String getQName(); + @Nullable + String getDescription(); + @Nullable + String getGroup(); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/project/ExternalSystemSourceType.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/project/ExternalSystemSourceType.java index ffe8a52d4a06..0e112b1c2b14 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/project/ExternalSystemSourceType.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/project/ExternalSystemSourceType.java @@ -1,52 +1,62 @@ package com.intellij.openapi.externalSystem.model.project; -import org.jetbrains.annotations.NotNull; - -import java.io.Serializable; - /** * Enumerates module source types. * * @author Denis Zhdanov * @since 8/10/11 5:21 PM */ -public class ExternalSystemSourceType implements Serializable { +public enum ExternalSystemSourceType implements IExternalSystemSourceType { - @NotNull public static final ExternalSystemSourceType SOURCE = new ExternalSystemSourceType("SOURCE"); - @NotNull public static final ExternalSystemSourceType TEST = new ExternalSystemSourceType("TEST"); - @NotNull public static final ExternalSystemSourceType EXCLUDED = new ExternalSystemSourceType("EXCLUDED"); - @NotNull public static final ExternalSystemSourceType SOURCE_GENERATED = new ExternalSystemSourceType("SOURCE_GENERATED"); - @NotNull public static final ExternalSystemSourceType TEST_GENERATED = new ExternalSystemSourceType("TEST_GENERATED"); - @NotNull public static final ExternalSystemSourceType RESOURCE = new ExternalSystemSourceType("RESOURCE"); - @NotNull public static final ExternalSystemSourceType TEST_RESOURCE = new ExternalSystemSourceType("TEST_RESOURCE"); - - private static final long serialVersionUID = 1L; + SOURCE(false, false, false, false), + TEST(true, false, false, false), + EXCLUDED(false, false, false, true), + SOURCE_GENERATED(true, true, false, false), + TEST_GENERATED(true, true, false, false), + RESOURCE(false, false, true, false), + TEST_RESOURCE(true, false, true, false); - @NotNull private final String myId; + private final boolean isTest; + private final boolean isGenerated; + private final boolean isResource; + private final boolean isExcluded; - public ExternalSystemSourceType(@NotNull String id) { - myId = id; + ExternalSystemSourceType(boolean test, boolean generated, boolean resource, boolean excluded) { + isTest = test; + isGenerated = generated; + isResource = resource; + isExcluded = excluded; } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ExternalSystemSourceType type = (ExternalSystemSourceType)o; - - if (!myId.equals(type.myId)) return false; - - return true; + public boolean isTest() { + return isTest; } @Override - public int hashCode() { - return myId.hashCode(); + public boolean isGenerated() { + return isGenerated; } @Override - public String toString() { - return myId; + public boolean isResource() { + return isResource; + } + + @Override + public boolean isExcluded() { + return isExcluded; + } + + public static ExternalSystemSourceType from(IExternalSystemSourceType sourceType) { + for (ExternalSystemSourceType systemSourceType : ExternalSystemSourceType.values()) { + if (systemSourceType.isGenerated == sourceType.isGenerated() && + systemSourceType.isResource == sourceType.isResource() && + systemSourceType.isTest == sourceType.isTest() && + systemSourceType.isExcluded == sourceType.isExcluded()) { + return systemSourceType; + } + } + throw new IllegalArgumentException("Invalid source type: " + sourceType); } } diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/project/IExternalSystemSourceType.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/project/IExternalSystemSourceType.java new file mode 100644 index 000000000000..2ad8821b06cd --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/project/IExternalSystemSourceType.java @@ -0,0 +1,32 @@ +/* + * 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 com.intellij.openapi.externalSystem.model.project; + +import java.io.Serializable; + +/** + * @author Vladislav.Soroka + * @since 7/17/2014 + */ +public interface IExternalSystemSourceType extends Serializable { + boolean isTest(); + + boolean isGenerated(); + + boolean isResource(); + + boolean isExcluded(); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java index a6cfc65eb759..fd3493447ced 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java @@ -681,4 +681,9 @@ public class ExternalSystemApiUtil { public static String getExternalProjectPath(@Nullable Module module) { return module != null ? module.getOptionValue(ExternalSystemConstants.LINKED_PROJECT_PATH_KEY) : null; } + + @Nullable + public static String getExternalProjectId(@Nullable Module module) { + return module != null ? module.getOptionValue(ExternalSystemConstants.LINKED_PROJECT_ID_KEY) : null; + } } diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemConstants.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemConstants.java index 283067810bb0..160c95938378 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemConstants.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemConstants.java @@ -27,6 +27,7 @@ public class ExternalSystemConstants { @NonNls @NotNull public static final String EXTERNAL_SYSTEM_ID_KEY = "external.system.id"; @NonNls @NotNull public static final String LINKED_PROJECT_PATH_KEY = "external.linked.project.path"; @NonNls @NotNull public static final String ROOT_PROJECT_PATH_KEY = "external.root.project.path"; + @NonNls @NotNull public static final String LINKED_PROJECT_ID_KEY = "external.linked.project.id"; @NonNls @NotNull public static final String EXTERNAL_SYSTEM_MODULE_GROUP_KEY = "external.system.module.group"; @NonNls @NotNull public static final String EXTERNAL_SYSTEM_MODULE_VERSION_KEY = "external.system.module.version"; diff --git a/platform/external-system-impl/external-system-impl.iml b/platform/external-system-impl/external-system-impl.iml index aa68fdc4d7b6..a59eae8eea21 100644 --- a/platform/external-system-impl/external-system-impl.iml +++ b/platform/external-system-impl/external-system-impl.iml @@ -24,6 +24,8 @@ + + diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureServices.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureServices.java deleted file mode 100644 index 1e6dadd0d3b8..000000000000 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureServices.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.intellij.openapi.externalSystem.service.project; - -import org.jetbrains.annotations.NotNull; - -/** - * Facades all services necessary for the 'sync project changes' processing. - *

- * Thread-safe. - * - * @author Denis Zhdanov - * @since 2/14/12 1:26 PM - */ -public class ProjectStructureServices { - - @NotNull private final ProjectStructureHelper myProjectStructureHelper; - @NotNull private final PlatformFacade myPlatformFacade; - @NotNull private final ExternalLibraryPathTypeMapper myLibraryPathTypeMapper; - - public ProjectStructureServices(@NotNull ProjectStructureHelper projectStructureHelper, - @NotNull PlatformFacade platformFacade, - @NotNull ExternalLibraryPathTypeMapper mapper) - { - myProjectStructureHelper = projectStructureHelper; - myPlatformFacade = platformFacade; - myLibraryPathTypeMapper = mapper; - } - - @NotNull - public ProjectStructureHelper getProjectStructureHelper() { - return myProjectStructureHelper; - } - - @NotNull - public PlatformFacade getPlatformFacade() { - return myPlatformFacade; - } - - @NotNull - public ExternalLibraryPathTypeMapper getLibraryPathTypeMapper() { - return myLibraryPathTypeMapper; - } -} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDataService.java index 4b1e3b13a22f..32919794eca4 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDataService.java @@ -274,6 +274,7 @@ public class ModuleDataService implements ProjectDataService module.putUserData(MODULE_DATA_KEY, moduleData); module.setOption(ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY, moduleData.getOwner().toString()); + module.setOption(ExternalSystemConstants.LINKED_PROJECT_ID_KEY, moduleData.getId()); module.setOption(ExternalSystemConstants.LINKED_PROJECT_PATH_KEY, moduleData.getLinkedExternalProjectPath()); final ProjectData projectData = moduleDataNode.getData(ProjectKeys.PROJECT); module.setOption(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY, projectData != null ? projectData.getLinkedExternalProjectPath() : ""); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java index 6575ffb107f0..c2dcfe57b010 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java @@ -25,6 +25,7 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.containers.Stack; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.List; @@ -40,8 +41,10 @@ public class ProjectDataManager { private static final Logger LOG = Logger.getInstance("#" + ProjectDataManager.class.getName()); - @NotNull private final NotNullLazyValue, List>>> myServices = - new NotNullLazyValue, List>>>() { + @NotNull private final NotNullLazyValue, List>>> myServices; + + public ProjectDataManager() { + myServices = new NotNullLazyValue, List>>>() { @NotNull @Override protected Map, List>> compute() { @@ -57,10 +60,22 @@ public class ProjectDataManager { for (List> services : result.values()) { ExternalSystemApiUtil.orderAwareSort(services); } - return result; } }; + } + + @Nullable + public List> getDataServices(Key key) { + return myServices.getValue().get(key); + } + + @Nullable + public ProjectDataService getDataService(Key key) { + final List> dataServices = myServices.getValue().get(key); + assert dataServices == null || dataServices.isEmpty() || dataServices.size() == 1; + return ContainerUtil.getFirstItem(dataServices); + } @SuppressWarnings("unchecked") public void importData(@NotNull Collection> nodes, @NotNull Project project, boolean synchronous) { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalProjectSerializer.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalProjectSerializer.java new file mode 100644 index 000000000000..0a863ed08852 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/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 com.intellij.openapi.externalSystem.util; + +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 newInstance(Class 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 type) { + return new ArrayList(); + } + }); + myKryo.register(HashMap.class, new MapSerializer() { + @Override + protected Map create(Kryo kryo, Input input, Class type) { + return new HashMap(); + } + }); + myKryo.register(HashSet.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class type) { + return new HashSet(); + } + }); + + myKryo.register(File.class, new FileSerializer()); + myKryo.register(DefaultExternalProject.class, new FieldSerializer(myKryo, DefaultExternalProject.class) { + @Override + protected DefaultExternalProject create(Kryo kryo, Input input, Class type) { + return new DefaultExternalProject(); + } + }); + + myKryo.register(DefaultExternalTask.class, new FieldSerializer(myKryo, DefaultExternalTask.class) { + @Override + protected DefaultExternalTask create(Kryo kryo, Input input, Class type) { + return new DefaultExternalTask(); + } + }); + + myKryo.register(DefaultExternalPlugin.class, new FieldSerializer(myKryo, DefaultExternalPlugin.class) { + @Override + protected DefaultExternalPlugin create(Kryo kryo, Input input, Class type) { + return new DefaultExternalPlugin(); + } + }); + + myKryo.register(DefaultExternalSourceSet.class, new FieldSerializer(myKryo, DefaultExternalSourceSet.class) { + @Override + protected DefaultExternalSourceSet create(Kryo kryo, Input input, Class type) { + return new DefaultExternalSourceSet(); + } + }); + + myKryo.register( + DefaultExternalSourceDirectorySet.class, + new FieldSerializer(myKryo, DefaultExternalSourceDirectorySet.class) { + @Override + protected DefaultExternalSourceDirectorySet create(Kryo kryo, Input input, Class type) { + return new DefaultExternalSourceDirectorySet(); + } + } + ); + + myKryo.register(DefaultExternalFilter.class, new FieldSerializer(myKryo, DefaultExternalFilter.class) { + @Override + protected DefaultExternalFilter create(Kryo kryo, Input input, Class 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 type) { + return new LinkedHashSet(); + } + }); + myKryo.register(HashSet.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class type) { + return new HashSet(); + } + }); + myKryo.register(THashSet.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class type) { + return new THashSet(); + } + }); + myKryo.register(Set.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class type) { + return new HashSet(); + } + }); + myKryo.register(THashMap.class, new MapSerializer() { + @Override + protected Map create(Kryo kryo, Input input, Class 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 { + 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 type) { + File file = myStdKryo.readObject(input, File.class); + return new File(file.getPath()); + } + } + + private static class StdSerializer extends Serializer { + private final Kryo myStdKryo; + + public StdSerializer(Class 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 type) { + return myStdKryo.readObject(input, type); + } + } +} diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestCase.java b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestCase.java index 22ec927eb30d..770578ae44f5 100644 --- a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestCase.java +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestCase.java @@ -15,24 +15,41 @@ */ package com.intellij.openapi.externalSystem.test; +import com.intellij.compiler.CompilerTestUtil; +import com.intellij.compiler.CompilerWorkspaceConfiguration; +import com.intellij.compiler.artifacts.ArtifactsTestUtil; +import com.intellij.compiler.impl.ModuleCompileScope; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompileScope; +import com.intellij.openapi.compiler.CompileStatusNotification; +import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl; +import com.intellij.openapi.roots.ModuleRootModificationUtil; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.packaging.impl.compiler.ArtifactCompileScope; import com.intellij.testFramework.IdeaTestCase; +import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; +import com.intellij.util.concurrency.Semaphore; +import com.intellij.util.io.TestFileSystemItem; import com.intellij.util.ui.UIUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; @@ -40,6 +57,7 @@ import org.jetbrains.annotations.NotNull; import org.junit.After; import org.junit.Before; +import javax.swing.*; import java.awt.*; import java.io.File; import java.io.IOException; @@ -129,11 +147,11 @@ public abstract class ExternalSystemTestCase extends UsefulTestCase { @Override public void tearDown() throws Exception { try { - myProject = null; - UIUtil.invokeAndWaitIfNeeded(new Runnable() { + edt(new Runnable() { @Override public void run() { try { + CompilerTestUtil.disableExternalCompiler(myProject); tearDownFixtures(); } catch (Exception e) { @@ -141,6 +159,7 @@ public abstract class ExternalSystemTestCase extends UsefulTestCase { } } }); + myProject = null; if (!FileUtil.delete(myTestDir) && myTestDir.exists()) { System.err.println("Cannot delete " + myTestDir); //printDirectoryContent(myDir); @@ -319,7 +338,11 @@ public abstract class ExternalSystemTestCase extends UsefulTestCase { protected VirtualFile createProjectSubFile(String relativePath) throws IOException { File f = new File(getProjectPath(), relativePath); FileUtil.ensureExists(f.getParentFile()); - f.createNewFile(); + FileUtil.ensureCanCreateFile(f); + final boolean created = f.createNewFile(); + if(!created) { + throw new AssertionError("Unable to create the project sub file: " + f.getAbsolutePath()); + } return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(f); } @@ -329,6 +352,114 @@ public abstract class ExternalSystemTestCase extends UsefulTestCase { return file; } + + protected void compileModules(final String... moduleNames) { + compile(createModulesCompileScope(moduleNames)); + } + + protected void buildArtifacts(String... artifactNames) { + compile(createArtifactsScope(artifactNames)); + } + + private void compile(final CompileScope scope) { + edt(new Runnable() { + @Override + public void run() { + for (Module module : scope.getAffectedModules()) { + setupJdkForModule(module.getName()); + } + } + }); + + CompilerWorkspaceConfiguration.getInstance(myProject).CLEAR_OUTPUT_DIRECTORY = true; + + final Semaphore semaphore = new Semaphore(); + semaphore.down(); + edt(new Runnable() { + @Override + public void run() { + CompilerTestUtil.enableExternalCompiler(); + CompilerManager.getInstance(myProject).make(scope, new CompileStatusNotification() { + @Override + public void finished(boolean aborted, int errors, int warnings, CompileContext compileContext) { + //assertFalse(aborted); + //assertEquals(collectMessages(compileContext, CompilerMessageCategory.ERROR), 0, errors); + //assertEquals(collectMessages(compileContext, CompilerMessageCategory.WARNING), 0, warnings); + semaphore.up(); + } + }); + } + }); + while (!semaphore.waitFor(100)) { + if (SwingUtilities.isEventDispatchThread()) { + UIUtil.dispatchAllInvocationEvents(); + } + } + if (SwingUtilities.isEventDispatchThread()) { + UIUtil.dispatchAllInvocationEvents(); + } + } + + private CompileScope createModulesCompileScope(final String[] moduleNames) { + final List modules = new ArrayList(); + for (String name : moduleNames) { + modules.add(getModule(name)); + } + return new ModuleCompileScope(myProject, modules.toArray(new Module[modules.size()]), false); + } + + private CompileScope createArtifactsScope(String[] artifactNames) { + List artifacts = new ArrayList(); + for (String name : artifactNames) { + artifacts.add(ArtifactsTestUtil.findArtifact(myProject, name)); + } + return ArtifactCompileScope.createArtifactsScope(myProject, artifacts); + } + + protected Sdk setupJdkForModule(final String moduleName) { + final Sdk sdk = true ? JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk() : createJdk("Java 1.5"); + ModuleRootModificationUtil.setModuleSdk(getModule(moduleName), sdk); + return sdk; + } + + protected static Sdk createJdk(String versionName) { + return IdeaTestUtil.getMockJdk17(versionName); + } + + protected Module getModule(final String name) { + AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock(); + try { + Module m = ModuleManager.getInstance(myProject).findModuleByName(name); + assertNotNull("Module " + name + " not found", m); + return m; + } + finally { + accessToken.finish(); + } + } + + protected void assertExplodedLayout(String artifactName, String expected) { + assertJarLayout(artifactName + " exploded", expected); + } + + protected void assertJarLayout(String artifactName, String expected) { + ArtifactsTestUtil.assertLayout(myProject, artifactName, expected); + } + + protected void assertArtifactOutputPath(final String artifactName, final String expected) { + ArtifactsTestUtil.assertOutputPath(myProject, artifactName, expected); + } + + protected void assertArtifactOutputFileName(final String artifactName, final String expected) { + ArtifactsTestUtil.assertOutputFileName(myProject, artifactName, expected); + } + + protected void assertArtifactOutput(String artifactName, TestFileSystemItem fs) { + final String outputPath = ArtifactsTestUtil.findArtifact(myProject, artifactName).getOutputPath(); + assert outputPath != null; + fs.assertDirectoryEqual(new File(outputPath)); + } + private static void setFileContent(final VirtualFile file, final String content, final boolean advanceStamps) throws IOException { new WriteAction() { @Override diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/OrderEnumerationHandler.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/OrderEnumerationHandler.java index 83984e11a80b..7a62c35d0390 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/OrderEnumerationHandler.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/OrderEnumerationHandler.java @@ -18,6 +18,7 @@ package com.intellij.openapi.roots; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -65,4 +66,12 @@ public abstract class OrderEnumerationHandler { @NotNull Collection urls) { return false; } + + public boolean addCustomModuleRoots(@NotNull OrderRootType type, + @NotNull ModuleRootModel rootModel, + @NotNull Collection result, + boolean includeProduction, + boolean includeTests) { + return false; + } } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/OrderEnumeratorBase.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/OrderEnumeratorBase.java index 61a6aee9315b..b13df0560292 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/OrderEnumeratorBase.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/OrderEnumeratorBase.java @@ -356,6 +356,38 @@ abstract class OrderEnumeratorBase extends OrderEnumerator implements OrderEnume return false; } + boolean addCustomRootsForModule(OrderRootType type, + ModuleRootModel rootModel, + Collection result, + boolean includeProduction, + boolean includeTests) { + for (OrderEnumerationHandler handler : myCustomHandlers) { + final List urls = new ArrayList(); + final boolean added = handler.addCustomModuleRoots(type, rootModel, urls, includeProduction, includeTests); + for (String url : urls) { + ContainerUtil.addIfNotNull(VirtualFileManager.getInstance().findFileByUrl(url), result); + } + + if (added) return true; + } + return false; + } + + boolean addCustomRootUrlsForModule(OrderRootType type, + ModuleRootModel rootModel, + Collection result, + boolean includeProduction, + boolean includeTests) { + for (OrderEnumerationHandler handler : myCustomHandlers) { + final List urls = new ArrayList(); + final boolean added = handler.addCustomModuleRoots(type, rootModel, urls, includeProduction, includeTests); + result.addAll(urls); + + if (added) return true; + } + return false; + } + @Override public boolean isRuntimeOnly() { return myRuntimeOnly; diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/OrderRootsEnumeratorImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/OrderRootsEnumeratorImpl.java index ea5742cce176..fb9a75176255 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/OrderRootsEnumeratorImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/OrderRootsEnumeratorImpl.java @@ -240,6 +240,7 @@ public class OrderRootsEnumeratorImpl implements OrderRootsEnumerator { } } } + myOrderEnumerator.addCustomRootsForModule(type, rootModel, result, includeProduction, includeTests); } private void collectModuleRootsUrls(OrderRootType type, diff --git a/plugins/gradle/gradle.iml b/plugins/gradle/gradle.iml index 878ec399b87c..e7873ca13ead 100644 --- a/plugins/gradle/gradle.iml +++ b/plugins/gradle/gradle.iml @@ -14,6 +14,7 @@ + @@ -105,6 +106,8 @@ + + diff --git a/plugins/gradle/jps-plugin/gradle-jps-plugin.iml b/plugins/gradle/jps-plugin/gradle-jps-plugin.iml new file mode 100644 index 000000000000..0d1d5300e84b --- /dev/null +++ b/plugins/gradle/jps-plugin/gradle-jps-plugin.iml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.gradle.model.JpsGradleExtensionService b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.gradle.model.JpsGradleExtensionService new file mode 100644 index 000000000000..526afcc9d0a9 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.gradle.model.JpsGradleExtensionService @@ -0,0 +1,16 @@ +# +# 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. +# +org.jetbrains.jps.gradle.model.impl.JpsGradleExtensionServiceImpl \ No newline at end of file diff --git a/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService new file mode 100644 index 000000000000..90e686daeaca --- /dev/null +++ b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService @@ -0,0 +1,16 @@ +# +# 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. +# +org.jetbrains.jps.gradle.compiler.GradleBuilderService \ No newline at end of file diff --git a/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.java.impl.JpsJavaDependenciesEnumerationHandler$Factory b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.java.impl.JpsJavaDependenciesEnumerationHandler$Factory new file mode 100644 index 000000000000..f1518a33d329 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.java.impl.JpsJavaDependenciesEnumerationHandler$Factory @@ -0,0 +1,16 @@ +# +# 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. +# +org.jetbrains.jps.gradle.model.impl.JpsGradleDependenciesEnumerationHandler$GradleFactory \ No newline at end of file diff --git a/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.serialization.JpsModelSerializerExtension b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.serialization.JpsModelSerializerExtension new file mode 100644 index 000000000000..a86ddcf7d451 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.serialization.JpsModelSerializerExtension @@ -0,0 +1,16 @@ +# +# 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. +# +org.jetbrains.jps.gradle.model.impl.JpsGradleModelSerializationExtension \ No newline at end of file diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/ChainingFilterTransformer.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/ChainingFilterTransformer.java new file mode 100644 index 000000000000..c717fe16c792 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/ChainingFilterTransformer.java @@ -0,0 +1,111 @@ +/* + * 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.jps.gradle.compiler; + +import com.intellij.openapi.util.Ref; +import org.gradle.api.Transformer; +import org.gradle.util.ConfigureUtil; +import org.jetbrains.jps.gradle.model.impl.ResourceRootFilter; +import org.jetbrains.jps.incremental.CompileContext; +import org.jetbrains.jps.incremental.messages.BuildMessage; +import org.jetbrains.jps.incremental.messages.CompilerMessage; + +import java.io.File; +import java.io.FilterReader; +import java.io.Reader; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.regex.Matcher; + +/** + * @author Vladislav.Soroka + * @since 7/24/2014 + */ +public class ChainingFilterTransformer implements Transformer { + private final Collection myFilters = new ArrayList(); + private final CompileContext myContext; + private final Ref myOutputFileRef; + + + public ChainingFilterTransformer(CompileContext context, Collection filters, Ref outputFileRef) { + myContext = context; + myOutputFileRef = outputFileRef; + myFilters.addAll(filters); + } + + public ChainingFilterTransformer(CompileContext context, Collection filters) { + this(context, filters, null); + } + + public void addAll(Collection filters) { + myFilters.addAll(filters); + } + + public void add(ResourceRootFilter... filters) { + Collections.addAll(myFilters, filters); + } + + @Override + public Reader transform(Reader original) { + Reader value = original; + for (ResourceRootFilter filter : myFilters) { + value = doTransform(filter, value); + } + return value; + } + + private Reader doTransform(ResourceRootFilter filter, Reader original) { + if ("RenamingCopyFilter" .equals(filter.filterType)) { + final Matcher matcher = (Matcher)filter.getProperties().get("matcher"); + final String replacement = (String)filter.getProperties().get("replacement"); + if (matcher == null || replacement == null) return original; + + matcher.reset(myOutputFileRef.get().getName()); + if (matcher.find()) { + final String newFileName = matcher.replaceFirst(replacement); + myOutputFileRef.set(new File(myOutputFileRef.get().getParentFile(), newFileName)); + } + return original; + } + try { + Class clazz = Class.forName(filter.filterType); + if (!FilterReader.class.isAssignableFrom(clazz)) { + myContext.processMessage( + new CompilerMessage( + GradleResourcesBuilder.BUILDER_NAME, BuildMessage.Kind.WARNING, + String.format("Error - Invalid filter specification for %s. It should extend java.io.FilterReader.", filter.filterType), null) + ); + } + Constructor constructor = clazz.getConstructor(Reader.class); + FilterReader result = (FilterReader)constructor.newInstance(original); + final Map properties = filter.getProperties(); + if (!properties.isEmpty()) { + ConfigureUtil.configureByMap(properties, result); + } + return result; + } + catch (Throwable th) { + myContext.processMessage(new CompilerMessage( + GradleResourcesBuilder.BUILDER_NAME, BuildMessage.Kind.WARNING, + String.format("Error - Failed to apply filter(%s): %s", filter.filterType, th.getMessage()), null) + ); + } + return original; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleBuilderService.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleBuilderService.java new file mode 100644 index 000000000000..5219a2ccad7b --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleBuilderService.java @@ -0,0 +1,44 @@ +/* + * 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.jps.gradle.compiler; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.BuildTargetType; +import org.jetbrains.jps.gradle.model.impl.GradleResourcesTargetType; +import org.jetbrains.jps.incremental.BuilderService; +import org.jetbrains.jps.incremental.TargetBuilder; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleBuilderService extends BuilderService { + @NotNull + @Override + public List> getTargetTypes() { + return Arrays.asList(GradleResourcesTargetType.PRODUCTION, GradleResourcesTargetType.TEST); + } + + @NotNull + @Override + public List> createBuilders() { + return Collections.singletonList(new GradleResourcesBuilder()); + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourceFileProcessor.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourceFileProcessor.java new file mode 100644 index 000000000000..dadfa21906a0 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourceFileProcessor.java @@ -0,0 +1,94 @@ +/* + * 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.jps.gradle.compiler; + +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.StreamUtil; +import org.apache.tools.ant.util.ReaderInputStream; +import org.jetbrains.jps.gradle.model.impl.GradleModuleResourceConfiguration; +import org.jetbrains.jps.gradle.model.impl.GradleProjectConfiguration; +import org.jetbrains.jps.gradle.model.impl.ResourceRootConfiguration; +import org.jetbrains.jps.gradle.model.impl.ResourceRootFilter; +import org.jetbrains.jps.incremental.CompileContext; +import org.jetbrains.jps.incremental.messages.BuildMessage; +import org.jetbrains.jps.incremental.messages.CompilerMessage; +import org.jetbrains.jps.model.JpsEncodingConfigurationService; +import org.jetbrains.jps.model.JpsEncodingProjectConfiguration; +import org.jetbrains.jps.model.JpsProject; + +import java.io.*; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourceFileProcessor { + private static final int FILTERING_SIZE_LIMIT = 10 * 1024 * 1024 /*10 mb*/; + protected final JpsEncodingProjectConfiguration myEncodingConfig; + protected final GradleProjectConfiguration myProjectConfig; + protected final GradleModuleResourceConfiguration myModuleConfiguration; + + public GradleResourceFileProcessor(GradleProjectConfiguration projectConfiguration, JpsProject project, + GradleModuleResourceConfiguration moduleConfiguration) { + myProjectConfig = projectConfiguration; + myEncodingConfig = JpsEncodingConfigurationService.getInstance().getEncodingConfiguration(project); + myModuleConfiguration = moduleConfiguration; + } + + public void copyFile(File file, Ref targetFileRef, ResourceRootConfiguration rootConfiguration, CompileContext context, + FileFilter filteringFilter) throws IOException { + boolean shouldFilter = rootConfiguration.isFiltered && !rootConfiguration.filters.isEmpty() && filteringFilter.accept(file); + if (shouldFilter && file.length() > FILTERING_SIZE_LIMIT) { + context.processMessage(new CompilerMessage( + GradleResourcesBuilder.BUILDER_NAME, BuildMessage.Kind.WARNING, + "File is too big to be filtered. Most likely it is a binary file and should be excluded from filtering", file.getPath()) + ); + shouldFilter = false; + } + if (shouldFilter) { + copyWithFiltering(file, targetFileRef, rootConfiguration.filters, context); + } + else { + FileUtil.copyContent(file, targetFileRef.get()); + } + } + + private static void copyWithFiltering(File file, Ref outputFileRef, List filters, CompileContext context) + throws IOException { + final FileInputStream originalInputStream = new FileInputStream(file); + try { + final InputStream inputStream = transform(filters, originalInputStream, outputFileRef, context); + FileUtil.createIfDoesntExist(outputFileRef.get()); + FileOutputStream outputStream = new FileOutputStream(outputFileRef.get()); + try { + FileUtil.copy(inputStream, outputStream); + } + finally { + StreamUtil.closeStream(inputStream); + StreamUtil.closeStream(outputStream); + } + } + finally { + StreamUtil.closeStream(originalInputStream); + } + } + + private static InputStream transform(List filters, FileInputStream original, Ref outputFileRef, CompileContext context) { + return new ReaderInputStream(new ChainingFilterTransformer(context, filters, outputFileRef).transform(new InputStreamReader(original))); + } +} \ No newline at end of file diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourcesBuilder.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourcesBuilder.java new file mode 100644 index 000000000000..295c8bab8133 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourcesBuilder.java @@ -0,0 +1,128 @@ +/* + * 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.jps.gradle.compiler; + +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.FileUtilRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.BuildOutputConsumer; +import org.jetbrains.jps.builders.DirtyFilesHolder; +import org.jetbrains.jps.builders.FileProcessor; +import org.jetbrains.jps.builders.storage.BuildDataPaths; +import org.jetbrains.jps.gradle.model.JpsGradleExtensionService; +import org.jetbrains.jps.gradle.model.impl.*; +import org.jetbrains.jps.incremental.CompileContext; +import org.jetbrains.jps.incremental.ProjectBuildException; +import org.jetbrains.jps.incremental.TargetBuilder; +import org.jetbrains.jps.incremental.messages.ProgressMessage; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourcesBuilder extends TargetBuilder { + public static final String BUILDER_NAME = "Gradle Resources Compiler"; + + public GradleResourcesBuilder() { + super(Arrays.asList(GradleResourcesTargetType.PRODUCTION, GradleResourcesTargetType.TEST)); + } + + @Override + public void build(@NotNull final GradleResourcesTarget target, + @NotNull final DirtyFilesHolder holder, + @NotNull final BuildOutputConsumer outputConsumer, + @NotNull final CompileContext context) throws ProjectBuildException, IOException { + final BuildDataPaths dataPaths = context.getProjectDescriptor().dataManager.getDataPaths(); + final GradleProjectConfiguration projectConfig = JpsGradleExtensionService.getInstance().getGradleProjectConfiguration(dataPaths); + final GradleModuleResourceConfiguration config = target.getModuleResourcesConfiguration(dataPaths); + if (config == null) return; + + final Map> files = new HashMap>(); + + holder.processDirtyFiles(new FileProcessor() { + + @Override + public boolean apply(GradleResourcesTarget t, File file, GradleResourceRootDescriptor rd) throws IOException { + assert target == t; + + List fileList = files.get(rd); + if (fileList == null) { + fileList = new ArrayList(); + files.put(rd, fileList); + } + + fileList.add(file); + return true; + } + }); + + GradleResourceRootDescriptor[] roots = files.keySet().toArray(new GradleResourceRootDescriptor[files.keySet().size()]); + Arrays.sort(roots, new Comparator() { + @Override + public int compare(GradleResourceRootDescriptor r1, GradleResourceRootDescriptor r2) { + int res = r1.getIndexInPom() - r2.getIndexInPom(); + if (r1.isOverwrite()) { + assert r2.isOverwrite(); + return res; + } + + if (r1.getConfiguration().isFiltered && !r2.getConfiguration().isFiltered) return 1; + if (!r1.getConfiguration().isFiltered && r2.getConfiguration().isFiltered) return -1; + + if (!r1.getConfiguration().isFiltered) { + res = -res; + } + + return res; + } + }); + + GradleResourceFileProcessor fileProcessor = new GradleResourceFileProcessor(projectConfig, target.getModule().getProject(), config); + + for (GradleResourceRootDescriptor rd : roots) { + for (File file : files.get(rd)) { + + String relPath = FileUtil.getRelativePath(rd.getRootFile(), file); + if (relPath == null) continue; + + final File outputDir = + GradleResourcesTarget.getOutputDir(target.getModuleOutputDir(), rd.getConfiguration(), config.outputDirectory); + if (outputDir == null) continue; + + context.processMessage(new ProgressMessage("Copying resources... [" + target.getModule().getName() + "]")); + + final Ref fileRef = Ref.create(new File(outputDir, relPath)); + fileProcessor.copyFile(file, fileRef, rd.getConfiguration(), context, FileUtilRt.ALL_FILES); + outputConsumer.registerOutputFile(fileRef.get(), Collections.singleton(file.getPath())); + + if (context.getCancelStatus().isCanceled()) return; + } + } + + context.checkCanceled(); + context.processMessage(new ProgressMessage("")); + } + + @NotNull + public String getPresentableName() { + return BUILDER_NAME; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleExtensionService.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleExtensionService.java new file mode 100644 index 000000000000..126cf5758ac1 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleExtensionService.java @@ -0,0 +1,49 @@ +/* + * 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.jps.gradle.model; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.builders.storage.BuildDataPaths; +import org.jetbrains.jps.gradle.model.impl.GradleProjectConfiguration; +import org.jetbrains.jps.model.module.JpsDependencyElement; +import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.service.JpsServiceManager; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public abstract class JpsGradleExtensionService { + public static JpsGradleExtensionService getInstance() { + return JpsServiceManager.getInstance().getService(JpsGradleExtensionService.class); + } + + @Nullable + public abstract JpsGradleModuleExtension getExtension(@NotNull JpsModule module); + + @NotNull + public abstract JpsGradleModuleExtension getOrCreateExtension(@NotNull JpsModule module); + + public abstract void setProductionOnTestDependency(@NotNull JpsDependencyElement dependency, boolean value); + + public abstract boolean isProductionOnTestDependency(@NotNull JpsDependencyElement dependency); + + public abstract boolean hasGradleProjectConfiguration(@NotNull BuildDataPaths paths); + + @NotNull + public abstract GradleProjectConfiguration getGradleProjectConfiguration(BuildDataPaths paths); +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleModuleExtension.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleModuleExtension.java new file mode 100644 index 000000000000..c673e4c0d27c --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleModuleExtension.java @@ -0,0 +1,25 @@ +/* + * 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.jps.gradle.model; + +import org.jetbrains.jps.model.JpsElement; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public interface JpsGradleModuleExtension extends JpsElement { +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/FilePattern.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/FilePattern.java new file mode 100644 index 000000000000..98938f596d05 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/FilePattern.java @@ -0,0 +1,38 @@ +/* + * 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.jps.gradle.model.impl; + +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Tag; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class FilePattern { + + @Tag("includes") + @AbstractCollection(surroundWithTag = false, elementTag = "pattern") + public Set includes = new HashSet(); + + @Tag("excludes") + @AbstractCollection(surroundWithTag = false, elementTag = "pattern") + public Set excludes = new HashSet(); + +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleModuleResourceConfiguration.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleModuleResourceConfiguration.java new file mode 100644 index 000000000000..9b6732a6d5d5 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleModuleResourceConfiguration.java @@ -0,0 +1,81 @@ +/* + * 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.jps.gradle.model.impl; + +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.OptionTag; +import com.intellij.util.xmlb.annotations.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleModuleResourceConfiguration { + @NotNull + @Tag("id") + public ModuleVersion id; + + @Nullable + @Tag("parentId") + public ModuleVersion parentId; + + @NotNull + @Tag("directory") + public String directory; + + @OptionTag + public boolean overwrite; + + @OptionTag + public String outputDirectory = null; + + @Tag("resources") + @AbstractCollection(surroundWithTag = false, elementTag = "resource") + public List resources = new ArrayList(); + + @Tag("test-resources") + @AbstractCollection(surroundWithTag = false, elementTag = "resource") + public List testResources = new ArrayList(); + + public int computeConfigurationHash(boolean forTestResources) { + int result = computeModuleConfigurationHash(); + + final List _resources = forTestResources ? testResources : resources; + result = 31 * result; + for (ResourceRootConfiguration resource : _resources) { + result += resource.computeConfigurationHash(); + } + return result; + } + + public int computeModuleConfigurationHash() { + int result = id.hashCode(); + result = 31 * result + (parentId != null ? parentId.hashCode() : 0); + result = 31 * result + directory.hashCode(); + result = 31 * result + (outputDirectory != null ? outputDirectory.hashCode() : 0); + result = 31 * result + (overwrite ? 1 : 0); + return result; + } +} + + + diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleProjectConfiguration.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleProjectConfiguration.java new file mode 100644 index 000000000000..083bba570d8a --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleProjectConfiguration.java @@ -0,0 +1,35 @@ +/* + * 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.jps.gradle.model.impl; + +import com.intellij.util.xmlb.annotations.MapAnnotation; +import com.intellij.util.xmlb.annotations.Tag; +import gnu.trove.THashMap; + +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleProjectConfiguration { + public static final String CONFIGURATION_FILE_RELATIVE_PATH = "gradle/configuration.xml"; + + @Tag("resource-processing") + @MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false, entryTagName = "gradle-module", + keyAttributeName = "name") + public Map moduleConfigurations = new THashMap(); +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceFileFilter.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceFileFilter.java new file mode 100644 index 000000000000..60e7fd295daa --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceFileFilter.java @@ -0,0 +1,81 @@ +/* + * 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.jps.gradle.model.impl; + +import com.intellij.openapi.util.io.FileUtil; +import org.gradle.api.file.RelativePath; +import org.gradle.api.internal.file.pattern.PatternMatcherFactory; +import org.gradle.api.specs.Spec; +import org.gradle.api.specs.Specs; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.regex.Pattern; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourceFileFilter implements FileFilter { + private FilePattern myFilePattern; + private File myRoot; + private final Spec myFileFilterSpec; + + public GradleResourceFileFilter(@NotNull File rootFile, @NotNull FilePattern filePattern) { + myFilePattern = filePattern; + myRoot = rootFile; + myFileFilterSpec = getAsSpec(); + } + + @Override + public boolean accept(@NotNull File file) { + final String relPath = FileUtil.getRelativePath(myRoot, file); + return relPath != null && isIncluded(relPath); + } + + private boolean isIncluded(@NotNull String relativePath) { + RelativePath path = new RelativePath(true, relativePath.split(Pattern.quote(File.separator))); + return myFileFilterSpec.isSatisfiedBy(path); + } + + private Spec getAsSpec() { + return Specs.and(getAsIncludeSpec(true), Specs.not(getAsExcludeSpec(true))); + } + + private Spec getAsExcludeSpec(boolean caseSensitive) { + Collection allExcludes = new LinkedHashSet(myFilePattern.excludes); + List> matchers = new ArrayList>(); + for (String exclude : allExcludes) { + Spec patternMatcher = PatternMatcherFactory.getPatternMatcher(false, caseSensitive, exclude); + matchers.add(patternMatcher); + } + return Specs.or(false, matchers); + } + + private Spec getAsIncludeSpec(boolean caseSensitive) { + List> matchers = new ArrayList>(); + for (String include : myFilePattern.includes) { + Spec patternMatcher = PatternMatcherFactory.getPatternMatcher(true, caseSensitive, include); + matchers.add(patternMatcher); + } + return Specs.or(true, matchers); + } +} \ No newline at end of file diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceRootDescriptor.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceRootDescriptor.java new file mode 100644 index 000000000000..e8ae0d701200 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceRootDescriptor.java @@ -0,0 +1,88 @@ +/* + * 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.jps.gradle.model.impl; + +import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.BuildRootDescriptor; + +import java.io.File; +import java.io.FileFilter; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourceRootDescriptor extends BuildRootDescriptor { + private final GradleResourcesTarget myTarget; + private final ResourceRootConfiguration myConfig; + private final File myFile; + private final String myId; + private final boolean myOverwrite; + + private final int myIndexInPom; + + public GradleResourceRootDescriptor(@NotNull GradleResourcesTarget target, + ResourceRootConfiguration config, + int indexInPom, + boolean overwrite) { + myTarget = target; + myConfig = config; + final String path = FileUtil.toCanonicalPath(config.directory); + myFile = new File(path); + myId = path; + myIndexInPom = indexInPom; + myOverwrite = overwrite; + } + + public ResourceRootConfiguration getConfiguration() { + return myConfig; + } + + @Override + public String getRootId() { + return myId; + } + + @Override + public File getRootFile() { + return myFile; + } + + @Override + public GradleResourcesTarget getTarget() { + return myTarget; + } + + @NotNull + @Override + public FileFilter createFileFilter() { + return new GradleResourceFileFilter(myFile, myConfig); + } + + @Override + public boolean canUseFileCache() { + return true; + } + + public int getIndexInPom() { + return myIndexInPom; + } + + public boolean isOverwrite() { + return myOverwrite; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTarget.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTarget.java new file mode 100644 index 000000000000..344c83080186 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTarget.java @@ -0,0 +1,161 @@ +/* + * 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.jps.gradle.model.impl; + +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.builders.*; +import org.jetbrains.jps.builders.storage.BuildDataPaths; +import org.jetbrains.jps.cmdline.ProjectDescriptor; +import org.jetbrains.jps.gradle.model.JpsGradleExtensionService; +import org.jetbrains.jps.incremental.CompileContext; +import org.jetbrains.jps.indices.IgnoredFileIndex; +import org.jetbrains.jps.indices.ModuleExcludeIndex; +import org.jetbrains.jps.model.JpsModel; +import org.jetbrains.jps.model.java.JpsJavaExtensionService; +import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.util.JpsPathUtil; + +import java.io.File; +import java.io.PrintWriter; +import java.util.*; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourcesTarget extends ModuleBasedTarget { + + GradleResourcesTarget(final GradleResourcesTargetType type, @NotNull JpsModule module) { + super(type, module); + } + + @Override + public String getId() { + return myModule.getName(); + } + + @Override + public Collection> computeDependencies(BuildTargetRegistry targetRegistry, TargetOutputIndex outputIndex) { + return Collections.emptyList(); + } + + @Override + public boolean isCompiledBeforeModuleLevelBuilders() { + return true; + } + + @NotNull + @Override + public List computeRootDescriptors(JpsModel model, ModuleExcludeIndex index, IgnoredFileIndex ignoredFileIndex, BuildDataPaths dataPaths) { + final List result = new ArrayList(); + + GradleProjectConfiguration projectConfig = JpsGradleExtensionService.getInstance().getGradleProjectConfiguration(dataPaths); + GradleModuleResourceConfiguration moduleConfig = projectConfig.moduleConfigurations.get(myModule.getName()); + if (moduleConfig == null) return Collections.emptyList(); + + int i = 0; + + for (ResourceRootConfiguration resource : getRootConfigurations(moduleConfig)) { + result.add(new GradleResourceRootDescriptor(this, resource, i++, moduleConfig.overwrite)); + } + return result; + } + + private Collection getRootConfigurations(@Nullable GradleModuleResourceConfiguration moduleConfig) { + if (moduleConfig != null) { + return isTests() ? moduleConfig.testResources : moduleConfig.resources; + } + return Collections.emptyList(); + } + + public GradleModuleResourceConfiguration getModuleResourcesConfiguration(BuildDataPaths dataPaths) { + final GradleProjectConfiguration projectConfig = JpsGradleExtensionService.getInstance().getGradleProjectConfiguration(dataPaths); + return projectConfig.moduleConfigurations.get(myModule.getName()); + } + + public boolean isTests() { + return ((GradleResourcesTargetType)getTargetType()).isTests(); + } + + @Nullable + @Override + public GradleResourceRootDescriptor findRootDescriptor(String rootId, BuildRootIndex rootIndex) { + for (GradleResourceRootDescriptor descriptor : rootIndex.getTargetRoots(this, null)) { + if (descriptor.getRootId().equals(rootId)) { + return descriptor; + } + } + return null; + } + + @NotNull + @Override + public String getPresentableName() { + return getTargetType().getTypeId() + ":" + myModule.getName(); + } + + @NotNull + @Override + public Collection getOutputRoots(CompileContext context) { + GradleModuleResourceConfiguration configuration = + getModuleResourcesConfiguration(context.getProjectDescriptor().dataManager.getDataPaths()); + final Set result = new THashSet(FileUtil.FILE_HASHING_STRATEGY); + final File moduleOutput = getModuleOutputDir(); + for (ResourceRootConfiguration resConfig : getRootConfigurations(configuration)) { + final File output = getOutputDir(moduleOutput, resConfig, configuration.outputDirectory); + if (output != null) { + result.add(output); + } + } + return result; + } + + @Nullable + public File getModuleOutputDir() { + return JpsJavaExtensionService.getInstance().getOutputDirectory(myModule, isTests()); + } + + @Nullable + public static File getOutputDir(@Nullable File moduleOutput, ResourceRootConfiguration config, @Nullable String outputDirectory) { + if(outputDirectory != null) { + moduleOutput = JpsPathUtil.urlToFile(outputDirectory); + } + + if (moduleOutput == null) { + return null; + } + String targetPath = config.targetPath; + if (StringUtil.isEmptyOrSpaces(targetPath)) { + return moduleOutput; + } + final File targetPathFile = new File(targetPath); + final File outputFile = targetPathFile.isAbsolute() ? targetPathFile : new File(moduleOutput, targetPath); + return new File(FileUtil.toCanonicalPath(outputFile.getPath())); + } + + @Override + public void writeConfiguration(ProjectDescriptor pd, PrintWriter out) { + final BuildDataPaths dataPaths = pd.getTargetsState().getDataPaths(); + final GradleModuleResourceConfiguration configuration = getModuleResourcesConfiguration(dataPaths); + if (configuration != null) { + out.write(Integer.toHexString(configuration.computeConfigurationHash(isTests()))); + } + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTargetType.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTargetType.java new file mode 100644 index 000000000000..bd399a164d31 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTargetType.java @@ -0,0 +1,78 @@ +/* + * 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.jps.gradle.model.impl; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.builders.BuildTargetLoader; +import org.jetbrains.jps.builders.ModuleBasedBuildTargetType; +import org.jetbrains.jps.gradle.model.JpsGradleExtensionService; +import org.jetbrains.jps.model.JpsModel; +import org.jetbrains.jps.model.module.JpsModule; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourcesTargetType extends ModuleBasedBuildTargetType { + public static final GradleResourcesTargetType PRODUCTION = new GradleResourcesTargetType("gradle-resources-production", false); + public static final GradleResourcesTargetType TEST = new GradleResourcesTargetType("gradle-resources-test", true); + + private final boolean myIsTests; + + private GradleResourcesTargetType(final String typeId, boolean isTests) { + super(typeId); + myIsTests = isTests; + } + + public boolean isTests() { + return myIsTests; + } + + @NotNull + @Override + public List computeAllTargets(@NotNull JpsModel model) { + final List targets = new ArrayList(); + for (JpsModule module : model.getProject().getModules()) { + if (JpsGradleExtensionService.getInstance().getExtension(module) != null) { + targets.add(new GradleResourcesTarget(this, module)); + } + } + return targets; + } + + @NotNull + @Override + public BuildTargetLoader createLoader(@NotNull JpsModel model) { + final Map modules = new HashMap(); + for (JpsModule module : model.getProject().getModules()) { + modules.put(module.getName(), module); + } + return new BuildTargetLoader() { + @Nullable + @Override + public GradleResourcesTarget createTarget(@NotNull String targetId) { + final JpsModule module = modules.get(targetId); + return module != null ? new GradleResourcesTarget(GradleResourcesTargetType.this, module) : null; + } + }; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleDependenciesEnumerationHandler.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleDependenciesEnumerationHandler.java new file mode 100644 index 000000000000..af0fd08fb6cf --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleDependenciesEnumerationHandler.java @@ -0,0 +1,57 @@ +/* + * 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.jps.gradle.model.impl; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.gradle.model.JpsGradleExtensionService; +import org.jetbrains.jps.model.java.impl.JpsJavaDependenciesEnumerationHandler; +import org.jetbrains.jps.model.module.JpsDependencyElement; +import org.jetbrains.jps.model.module.JpsModule; + +import java.util.Collection; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class JpsGradleDependenciesEnumerationHandler extends JpsJavaDependenciesEnumerationHandler { + private static final JpsGradleDependenciesEnumerationHandler INSTANCE = new JpsGradleDependenciesEnumerationHandler(); + + @Override + public boolean shouldAddRuntimeDependenciesToTestCompilationClasspath() { + return true; + } + + @Override + public boolean isProductionOnTestsDependency(JpsDependencyElement element) { + return JpsGradleExtensionService.getInstance().isProductionOnTestDependency(element); + } + + public static class GradleFactory extends Factory { + @Nullable + @Override + public JpsJavaDependenciesEnumerationHandler createHandler(@NotNull Collection modules) { + JpsGradleExtensionService service = JpsGradleExtensionService.getInstance(); + for (JpsModule module : modules) { + if (service.getExtension(module) != null) { + return INSTANCE; + } + } + return null; + } + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleExtensionServiceImpl.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleExtensionServiceImpl.java new file mode 100644 index 000000000000..81ed9076f13e --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleExtensionServiceImpl.java @@ -0,0 +1,136 @@ +/* + * 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.jps.gradle.model.impl; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.JDOMUtil; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.containers.ConcurrentFactoryMap; +import com.intellij.util.containers.FactoryMap; +import com.intellij.util.xmlb.XmlSerializer; +import gnu.trove.THashMap; +import org.jdom.Document; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.builders.storage.BuildDataPaths; +import org.jetbrains.jps.gradle.model.JpsGradleExtensionService; +import org.jetbrains.jps.gradle.model.JpsGradleModuleExtension; +import org.jetbrains.jps.incremental.resources.ResourcesBuilder; +import org.jetbrains.jps.incremental.resources.StandardResourceBuilderEnabler; +import org.jetbrains.jps.model.JpsElementChildRole; +import org.jetbrains.jps.model.JpsElementFactory; +import org.jetbrains.jps.model.JpsSimpleElement; +import org.jetbrains.jps.model.ex.JpsElementChildRoleBase; +import org.jetbrains.jps.model.module.JpsDependencyElement; +import org.jetbrains.jps.model.module.JpsModule; + +import java.io.File; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class JpsGradleExtensionServiceImpl extends JpsGradleExtensionService { + private static final Logger LOG = Logger.getInstance(JpsGradleExtensionServiceImpl.class); + private static final JpsElementChildRole> PRODUCTION_ON_TEST_ROLE = JpsElementChildRoleBase.create("production on test"); + private final Map myLoadedConfigs = + new THashMap(FileUtil.FILE_HASHING_STRATEGY); + private final FactoryMap myConfigFileExists = new ConcurrentFactoryMap() { + @Nullable + @Override + protected Boolean create(File key) { + return key.exists(); + } + }; + + public JpsGradleExtensionServiceImpl() { + ResourcesBuilder.registerEnabler(new StandardResourceBuilderEnabler() { + @Override + public boolean isResourceProcessingEnabled(JpsModule module) { + // enable standard resource processing only if this is not a gradle module + // for gradle modules use gradle-aware resource builder + return getExtension(module) == null; + } + }); + } + + @Nullable + @Override + public JpsGradleModuleExtension getExtension(@NotNull JpsModule module) { + return module.getContainer().getChild(JpsGradleModuleExtensionImpl.ROLE); + } + + @NotNull + @Override + public JpsGradleModuleExtension getOrCreateExtension(@NotNull JpsModule module) { + JpsGradleModuleExtension extension = module.getContainer().getChild(JpsGradleModuleExtensionImpl.ROLE); + if (extension == null) { + extension = new JpsGradleModuleExtensionImpl(); + module.getContainer().setChild(JpsGradleModuleExtensionImpl.ROLE, extension); + } + return extension; + } + + @Override + public void setProductionOnTestDependency(@NotNull JpsDependencyElement dependency, boolean value) { + if (value) { + dependency.getContainer().setChild(PRODUCTION_ON_TEST_ROLE, JpsElementFactory.getInstance().createSimpleElement(true)); + } + else { + dependency.getContainer().removeChild(PRODUCTION_ON_TEST_ROLE); + } + } + + @Override + public boolean isProductionOnTestDependency(@NotNull JpsDependencyElement dependency) { + JpsSimpleElement child = dependency.getContainer().getChild(PRODUCTION_ON_TEST_ROLE); + return child != null && child.getData(); + } + + @Override + public boolean hasGradleProjectConfiguration(@NotNull BuildDataPaths paths) { + return myConfigFileExists.get(new File(paths.getDataStorageRoot(), GradleProjectConfiguration.CONFIGURATION_FILE_RELATIVE_PATH)); + } + + @NotNull + @Override + public GradleProjectConfiguration getGradleProjectConfiguration(BuildDataPaths paths) { + final File dataStorageRoot = paths.getDataStorageRoot(); + return getGradleProjectConfiguration(dataStorageRoot); + } + + @NotNull + public GradleProjectConfiguration getGradleProjectConfiguration(@NotNull File dataStorageRoot) { + final File configFile = new File(dataStorageRoot, GradleProjectConfiguration.CONFIGURATION_FILE_RELATIVE_PATH); + GradleProjectConfiguration config; + synchronized (myLoadedConfigs) { + config = myLoadedConfigs.get(configFile); + if (config == null) { + config = new GradleProjectConfiguration(); + try { + final Document document = JDOMUtil.loadDocument(configFile); + XmlSerializer.deserializeInto(config, document.getRootElement()); + } + catch (Exception e) { + LOG.info(e); + } + myLoadedConfigs.put(configFile, config); + } + } + return config; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModelSerializationExtension.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModelSerializationExtension.java new file mode 100644 index 000000000000..cebd00878b19 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModelSerializationExtension.java @@ -0,0 +1,59 @@ +/* + * 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.jps.gradle.model.impl; + +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.gradle.model.JpsGradleExtensionService; +import org.jetbrains.jps.model.module.JpsDependencyElement; +import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class JpsGradleModelSerializationExtension extends JpsModelSerializerExtension { + private static final String PRODUCTION_ON_TEST_ATTRIBUTE = "production-on-test"; + + @Override + public void loadModuleOptions(@NotNull JpsModule module, @NotNull Element rootElement) { + if ("GRADLE".equals(rootElement.getAttributeValue("external.system.id"))) { + JpsGradleExtensionService.getInstance().getOrCreateExtension(module); + } + } + + @Override + public void saveModuleOptions(@NotNull JpsModule module, @NotNull Element rootElement) { + if (JpsGradleExtensionService.getInstance().getExtension(module) != null) { + rootElement.setAttribute("external.system.id", "GRADLE"); + } + } + + @Override + public void loadModuleDependencyProperties(JpsDependencyElement dependency, Element orderEntry) { + if (orderEntry.getAttributeValue(PRODUCTION_ON_TEST_ATTRIBUTE) != null) { + JpsGradleExtensionService.getInstance().setProductionOnTestDependency(dependency, true); + } + } + + @Override + public void saveModuleDependencyProperties(JpsDependencyElement dependency, Element orderEntry) { + if (JpsGradleExtensionService.getInstance().isProductionOnTestDependency(dependency)) { + orderEntry.setAttribute(PRODUCTION_ON_TEST_ATTRIBUTE, ""); + } + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModuleExtensionImpl.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModuleExtensionImpl.java new file mode 100644 index 000000000000..ecdd04fce10e --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModuleExtensionImpl.java @@ -0,0 +1,43 @@ +/* + * 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.jps.gradle.model.impl; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.gradle.model.JpsGradleModuleExtension; +import org.jetbrains.jps.model.JpsElementChildRole; +import org.jetbrains.jps.model.ex.JpsElementBase; +import org.jetbrains.jps.model.ex.JpsElementChildRoleBase; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class JpsGradleModuleExtensionImpl extends JpsElementBase implements JpsGradleModuleExtension { + public static final JpsElementChildRole ROLE = JpsElementChildRoleBase.create("gradle"); + + public JpsGradleModuleExtensionImpl() { + } + + @NotNull + @Override + public JpsGradleModuleExtensionImpl createCopy() { + return new JpsGradleModuleExtensionImpl(); + } + + @Override + public void applyChanges(@NotNull JpsGradleModuleExtensionImpl modified) { + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ModuleVersion.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ModuleVersion.java new file mode 100644 index 000000000000..dbb696d8c33c --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ModuleVersion.java @@ -0,0 +1,64 @@ +/* + * 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.jps.gradle.model.impl; + +import com.intellij.util.xmlb.annotations.Tag; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class ModuleVersion { + @Tag("groupId") + public String groupId; + + @Tag("artifactId") + public String artifactId; + + @Tag("version") + public String version; + + public ModuleVersion() { + } + + public ModuleVersion(String groupId, String artifactId, String version) { + this.groupId = groupId; + this.artifactId = artifactId; + this.version = version; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ModuleVersion bean = (ModuleVersion)o; + + if (artifactId != null ? !artifactId.equals(bean.artifactId) : bean.artifactId != null) return false; + if (groupId != null ? !groupId.equals(bean.groupId) : bean.groupId != null) return false; + if (version != null ? !version.equals(bean.version) : bean.version != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = groupId != null ? groupId.hashCode() : 0; + result = 31 * result + (artifactId != null ? artifactId.hashCode() : 0); + result = 31 * result + (version != null ? version.hashCode() : 0); + return result; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootConfiguration.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootConfiguration.java new file mode 100644 index 000000000000..efd419175dc3 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootConfiguration.java @@ -0,0 +1,59 @@ +/* + * 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.jps.gradle.model.impl; + +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +@Tag("resource") +public class ResourceRootConfiguration extends FilePattern { + @Tag("directory") + @NotNull + public String directory; + + @Tag("targetPath") + @Nullable + public String targetPath; + + @Attribute("filtered") + public boolean isFiltered; + + @Tag("filters") + @AbstractCollection(surroundWithTag = false, elementTag = "filter") + public List filters = new ArrayList(); + + public int computeConfigurationHash() { + int result = directory.hashCode(); + result = 31 * result + (targetPath != null ? targetPath.hashCode() : 0); + result = 31 * result + (isFiltered ? 1 : 0); + result = 31 * result + includes.hashCode(); + result = 31 * result + excludes.hashCode(); + for (ResourceRootFilter filter : filters) { + result = 31 * result + filter.computeConfigurationHash(); + } + return result; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootFilter.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootFilter.java new file mode 100644 index 000000000000..e8c39e32417e --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootFilter.java @@ -0,0 +1,75 @@ +/* + * 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.jps.gradle.model.impl; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; +import com.intellij.util.xmlb.annotations.Tag; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Vladislav.Soroka + * @since 7/22/2014 + */ +@Tag("filter") +public class ResourceRootFilter { + @Tag("filterType") + @NotNull + public String filterType; + @Tag("properties") + @NotNull + public String properties; + + private transient Map propertiesMap; + + public int computeConfigurationHash() { + int result = filterType.hashCode(); + result = 31 * result + properties.hashCode(); + return result; + } + + @NotNull + public Map getProperties() { + if (propertiesMap == null) { + try { + Gson gson = new GsonBuilder().create(); + propertiesMap = gson.fromJson( + properties, + new TypeToken>() { + }.getType()); + + if("RenamingCopyFilter".equals(filterType)) { + final Object pattern = propertiesMap.get("pattern"); + final Matcher matcher = Pattern.compile(pattern instanceof String ? (String)pattern : "").matcher(""); + propertiesMap.put("matcher", matcher); + } + } + catch (JsonSyntaxException e) { + throw new RuntimeException("Unsupported filter: " + properties , e); + } catch (JsonParseException e) { + throw new RuntimeException("Unsupported filter: " + properties , e); + } + } + return propertiesMap; + } +} diff --git a/plugins/gradle/src/META-INF/gradle-maven-integration.xml b/plugins/gradle/src/META-INF/gradle-maven-integration.xml index 72f46b785ea7..b8fad2f5c3be 100644 --- a/plugins/gradle/src/META-INF/gradle-maven-integration.xml +++ b/plugins/gradle/src/META-INF/gradle-maven-integration.xml @@ -21,7 +21,6 @@ - diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index de6937c18c6c..f15f424a10b8 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -67,6 +67,11 @@ + + + + + @@ -95,6 +100,7 @@ + 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..1b0386e47be7 --- /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 if it has at least one gradle module. + * + * @author Vladislav.Soroka + * @since 7/22/2014 + */ +public class GradleBuildProcessParametersProvider extends BuildProcessParametersProvider { + @NotNull private final Project myProject; + + private List myClasspath; + + public GradleBuildProcessParametersProvider(@NotNull Project project) { + myProject = project; + } + + @Override + @NotNull + public List getClassPath() { + if (myClasspath == null) { + final ModuleManager moduleManager = ModuleManager.getInstance(myProject); + for (Module module : moduleManager.getModules()) { + if (ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) { + myClasspath = ContainerUtil.newArrayList(); + addGradleClassPath(myClasspath); + addOtherClassPath(myClasspath); + break; + } + } + } + return myClasspath; + } + + private static void addGradleClassPath(@NotNull final List 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 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 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() { + @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 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..0dc670dbefa8 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java @@ -0,0 +1,114 @@ +/* + * 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 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) { + addSourceRoots(externalProject.getSourceSets().get("main"), ExternalSystemSourceType.RESOURCE, result); + } + + if (includeTests) { + addSourceRoots(externalProject.getSourceSets().get("test"), ExternalSystemSourceType.TEST_RESOURCE, result); + } + + return true; + } + + private static void addSourceRoots(@Nullable ExternalSourceSet externalSourceSet, + @NotNull ExternalSystemSourceType sourceType, + @NotNull Collection result) { + if (externalSourceSet == null) return; + final ExternalSourceDirectorySet directorySet = externalSourceSet.getSources().get(sourceType); + if (directorySet == null) return; + + for (File file : directorySet.getSrcDirs()) { + result.add(VfsUtilCore.pathToUrl(file.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 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..877432457336 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 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(); - } - if (testCompileOutputPath == null) { - testCompileOutputPath = output.getTestClassesDir(); + 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); } } + 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 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 ideModule, @@ -319,17 +372,19 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver @Override public Set getExtraProjectModelClasses() { return ContainerUtil.set( - GradleBuild.class, ModuleExtendedModel.class, BuildScriptClasspathModel.class); + GradleBuild.class, ExternalProject.class, ModuleExtendedModel.class, BuildScriptClasspathModel.class); } @NotNull @Override public Set getToolingExtensionsClasses() { return ContainerUtil.set( + ExternalProject.class, // gradle-tooling-extension-api jar ProjectImportAction.class, // gradle-tooling-extension-impl jar - ModelBuildScriptClasspathBuilderImpl.class + ModelBuildScriptClasspathBuilderImpl.class, + GsonBuilder.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 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 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 getExtraProject(@NotNull IdeaModule module, Class modelClazz) { + public T getExtraProject(Class modelClazz) { + return myModels.getExtraProject(null, modelClazz); + } + + @Nullable + public T getExtraProject(@Nullable IdeaModule module, Class 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 { + private static final Logger LOG = Logger.getInstance(ExternalProjectDataService.class); + + @NotNull public static final Key KEY = Key.create(ExternalProject.class, ProjectKeys.TASK.getProcessingWeight() + 1); + + @NotNull private final Map, ExternalProject> myExternalRootProjects; + + @NotNull private ProjectDataManager myProjectDataManager; + + public ExternalProjectDataService(@NotNull ProjectDataManager projectDataManager) { + myProjectDataManager = projectDataManager; + myExternalRootProjects = new ConcurrentFactoryMap, ExternalProject>() { + @Nullable + @Override + protected ExternalProject create(Pair key) { + return new ExternalProjectSerializer().load(key.first, key.second); + } + + @Override + public ExternalProject put(Pair key, ExternalProject value) { + new ExternalProjectSerializer().save(value); + return super.put(key, value); + } + }; + } + + @NotNull + @Override + public Key getTargetDataKey() { + return KEY; + } + + public void importData(@NotNull final Collection> 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 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() { + @Override + public Boolean compute() { + final Ref result = new Ref(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() { + @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 projectDataDataNode = task.getExternalProject(); + if (projectDataDataNode == null) return; + + final Collection> 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/testSources/org/jetbrains/plugins/gradle/compiler/GradleCompilingTestCase.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleCompilingTestCase.java new file mode 100644 index 000000000000..3b508c8cf289 --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleCompilingTestCase.java @@ -0,0 +1,89 @@ +/* + * 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.intellij.compiler.artifacts.ArtifactsTestUtil; +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.util.io.FileUtil; +import com.intellij.packaging.impl.artifacts.ArtifactUtil; +import com.intellij.util.io.TestFileSystemItem; +import org.jetbrains.plugins.gradle.config.GradleResourceCompilerConfigurationGenerator; +import org.jetbrains.plugins.gradle.importing.GradleImportingTestCase; + +import java.io.File; + +/** + * @author Vladislav.Soroka + * @since 7/21/2014 + */ +public abstract class GradleCompilingTestCase extends GradleImportingTestCase { + @Override + protected void setUpInWriteAction() throws Exception { + super.setUpInWriteAction(); + CompilerManager.getInstance(myProject).addBeforeTask(new CompileTask() { + @Override + public boolean execute(CompileContext context) { + AccessToken token = ReadAction.start(); + try { + new GradleResourceCompilerConfigurationGenerator(myProject, context).generateBuildConfiguration(); + } + finally { + token.finish(); + } + return true; + } + }); + } + + protected void assertCopied(String path) { + assertTrue(new File(myProjectConfig.getParent().getPath(), path).exists()); + } + + protected void assertCopied(String path, String content) { + assertCopied(path); + assertSameLinesWithFile(new File(myProjectConfig.getParent().getPath(), path).getPath(), content); + } + + protected void assertNotCopied(String path) { + assertFalse(new File(myProjectConfig.getParent().getPath(), path).exists()); + } + + @Override + protected void assertArtifactOutputPath(String artifactName, String expected) { + final String defaultArtifactOutputPath = ArtifactUtil.getDefaultArtifactOutputPath(artifactName, myProject); + assert defaultArtifactOutputPath != null; + final String basePath = FileUtil.toSystemIndependentName(new File(defaultArtifactOutputPath).getParent()); + super.assertArtifactOutputPath(artifactName, basePath + expected); + } + + protected void assertArtifactOutputFile(String artifactName, String path, String content) { + final String defaultArtifactOutputPath = ArtifactUtil.getDefaultArtifactOutputPath(artifactName, myProject); + assert defaultArtifactOutputPath != null; + final String basePath = FileUtil.toSystemIndependentName(new File(defaultArtifactOutputPath).getParent()); + assertSameLinesWithFile(basePath + path, content); + } + + protected void assertArtifactOutputFile(String artifactName, String path) { + final String defaultArtifactOutputPath = ArtifactUtil.getDefaultArtifactOutputPath(artifactName, myProject); + assert defaultArtifactOutputPath != null; + final String basePath = FileUtil.toSystemIndependentName(new File(defaultArtifactOutputPath).getParent()); + assertExists(new File(basePath + path)); + } +} diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceFilteringTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceFilteringTest.java new file mode 100644 index 000000000000..df9c6a879ac7 --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceFilteringTest.java @@ -0,0 +1,132 @@ +/* + * 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 org.junit.Test; + +/** + * @author Vladislav.Soroka + * @since 7/21/2014 + */ +@SuppressWarnings("JUnit4AnnotatedMethodInJUnit3TestCase") +public class GradleResourceFilteringTest extends GradleCompilingTestCase { + + @Test + public void testHeadFilter() throws Exception { + createProjectSubFile( + "src/main/resources/dir/file.txt", "1 Header\n" + + "2\n" + + "3 another text\n" + + "4\n" + + "5 another text \n" + + "6 another text @token@ another text\n" + + "7\n" + + "8 Footer"); + importProject( + "apply plugin: 'java'\n" + + "\n" + + "import org.apache.tools.ant.filters.*\n" + + "processResources {\n" + + " filter(HeadFilter, lines:3, skip:2)\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopied("build/resources/main/dir/file.txt", "3 another text\n" + + "4\n" + + "5 another text \n"); + } + + @Test + public void testReplaceTokensFilter() throws Exception { + createProjectSubFile( + "src/main/resources/dir/file.txt", "1 Header\n" + + "2\n" + + "3 #token1#another text\n" + + "4\n" + + "5 another text \n" + + "6 another text #token2# another text\n" + + "7\n" + + "8 Footer"); + importProject( + "apply plugin: 'java'\n" + + "\n" + + "import org.apache.tools.ant.filters.*\n" + + "processResources {\n" + + " filter(ReplaceTokens, tokens:[token1:'<11111>', token2:'<2222>'], beginToken: '#', endToken: '#')\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopied("build/resources/main/dir/file.txt", "1 Header\n" + + "2\n" + + "3 <11111>another text\n" + + "4\n" + + "5 another text \n" + + "6 another text <2222> another text\n" + + "7\n" + + "8 Footer"); + } + + @Test + public void testRenameFilter() throws Exception { + createProjectSubFile("src/main/resources/dir/file.txt"); + importProject( + "apply plugin: 'java'\n" + + "\n" + + "import org.apache.tools.ant.filters.*\n" + + "processResources {\n" + + " rename 'file.txt', 'file001.txt'\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopied("build/resources/main/dir/file001.txt"); + } + + @Test + public void testFiltersChain() throws Exception { + createProjectSubFile( + "src/main/resources/dir/file.txt", "1 Header\n" + + "2\n" + + "3 another text@token1@\n" + + "4\n" + + "5 another text \n" + + "6 another text @token2@ another text\n" + + "7\n" + + "8 Footer"); + importProject( + "apply plugin: 'java'\n" + + "\n" + + "import org.apache.tools.ant.filters.*\n" + + "processResources {\n" + + " filter(HeadFilter, lines:4, skip:2)\n" + + " filter(ReplaceTokens, tokens:[token1:'<11111>', token2:'<2222>'])\n" + + " rename 'file.txt', 'file001.txt'\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopied("build/resources/main/dir/file001.txt", "3 another text<11111>\n" + + "4\n" + + "5 another text \n" + + "6 another text <2222> another text"); + } +} \ No newline at end of file diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceProcessingTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceProcessingTest.java new file mode 100644 index 000000000000..873234425e30 --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceProcessingTest.java @@ -0,0 +1,176 @@ +/* + * 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 org.junit.Test; + +import java.io.IOException; + +/** + * @author Vladislav.Soroka + * @since 7/21/2014 + */ +@SuppressWarnings("JUnit4AnnotatedMethodInJUnit3TestCase") +public class GradleResourceProcessingTest extends GradleCompilingTestCase { + + @Test + public void testBasicResourceCopying() throws Exception { + createProjectSubFile("src/main/resources/dir/file.properties"); + createProjectSubFile("src/test/resources/dir/file-test.properties"); + importProject( + "apply plugin: 'java'" + ); + assertModules("project"); + compileModules("project"); + + assertCopied("build/resources/main/dir/file.properties"); + assertCopied("build/resources/test/dir/file-test.properties"); + } + + @Test + public void testResourceProcessingWithIdeaGradlePluginCustomization() throws Exception { + createProjectSubFile("src/main/resources/dir/file.properties"); + createProjectSubFile("src/test/resources/dir/file-test.properties"); + importProject( + "apply plugin: 'java'\n" + + "apply plugin: 'idea'\n" + + "idea {\n" + + " module {\n" + + " inheritOutputDirs = false\n" + + " outputDir = file('muchBetterOutputDir')\n" + + " testOutputDir = file('muchBetterTestOutputDir')\n" + + " }\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopied("muchBetterOutputDir/dir/file.properties"); + assertCopied("muchBetterTestOutputDir/dir/file-test.properties"); + } + + @Test + public void testIncludesAndExcludesInSourceSets() throws Exception { + createFilesForIncludesAndExcludesTest(); + + importProject( + "apply plugin: 'java'\n" + + "\n" + + "sourceSets {\n" + + " main {\n" + + " resources {\n" + + " include '**/*.yyy'\n" + + " include '**/*.xxx'\n" + + " exclude 'dir/*.yyy'\n" + + " exclude '*.xxx'\n" + + " }\n" + + " }\n" + + " test {\n" + + " resources {\n" + + " include '**/*.yyy'\n" + + " include '**/*.xxx'\n" + + " exclude 'dir/*.yyy'\n" + + " exclude '*.xxx'\n" + + " }\n" + + " }\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopiedResources(); + } + + @Test + public void testIncludesAndExcludesInAllSourceSets() throws Exception { + createFilesForIncludesAndExcludesTest(); + + importProject( + "apply plugin: 'java'\n" + + "\n" + + "sourceSets.all {\n" + + " resources {\n" + + " include '**/*.yyy'\n" + + " include '**/*.xxx'\n" + + " exclude 'dir/*.yyy'\n" + + " exclude '*.xxx'\n" + + " }\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopiedResources(); + } + + + @Test + public void testIncludesAndExcludesInResourcesTask() throws Exception { + createFilesForIncludesAndExcludesTest(); + + importProject( + "apply plugin: 'java'\n" + + "\n" + + "processResources {\n" + + " include '**/*.yyy'\n" + + " include '**/*.xxx'\n" + + " exclude 'dir/*.yyy'\n" + + " exclude '*.xxx'\n" + + "}\n" + + "\n" + + "processTestResources {\n" + + " include '**/*.yyy'\n" + + " include '**/*.xxx'\n" + + " exclude 'dir/*.yyy'\n" + + " exclude '*.xxx'\n" + + "}\n" + ); + assertModules("project"); + compileModules("project"); + + assertCopiedResources(); + } + + private void createFilesForIncludesAndExcludesTest() throws IOException { + createProjectSubFile("src/main/resources/dir/file.xxx"); + createProjectSubFile("src/main/resources/dir/file.yyy"); + createProjectSubFile("src/main/resources/file.xxx"); + createProjectSubFile("src/main/resources/file.yyy"); + createProjectSubFile("src/main/resources/file.zzz"); + + createProjectSubFile("src/test/resources/dir/file.xxx"); + createProjectSubFile("src/test/resources/dir/file.yyy"); + createProjectSubFile("src/test/resources/file.xxx"); + createProjectSubFile("src/test/resources/file.yyy"); + createProjectSubFile("src/test/resources/file.zzz"); + } + + private void assertCopiedResources() { + // assert production resources + assertCopied("build/resources/main/dir/file.xxx"); + assertCopied("build/resources/main/file.yyy"); + assertNotCopied("build/resources/main/dir/file.yyy"); + assertNotCopied("build/resources/main/file.xxx"); + assertNotCopied("build/resources/main/file.zzz"); + + // assert test resources + assertCopied("build/resources/test/dir/file.xxx"); + assertCopied("build/resources/test/file.yyy"); + assertNotCopied("build/resources/test/dir/file.yyy"); + assertNotCopied("build/resources/test/file.xxx"); + assertNotCopied("build/resources/test/file.zzz"); + } +} diff --git a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ModuleExtendedModel.java b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ModuleExtendedModel.java index 97dfd2547b73..91889d85fa9f 100644 --- a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ModuleExtendedModel.java +++ b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ModuleExtendedModel.java @@ -22,9 +22,12 @@ import java.io.Serializable; import java.util.List; /** + * @deprecated Use {@link com.intellij.openapi.externalSystem.model.ExternalProject} model instead. + * * @author Vladislav.Soroka * @since 11/5/13 */ +@Deprecated() public interface ModuleExtendedModel extends Serializable { /** * The group of the module. diff --git a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ProjectImportAction.java b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ProjectImportAction.java index af6f4fed60f4..c27a9a216c36 100644 --- a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ProjectImportAction.java +++ b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ProjectImportAction.java @@ -18,6 +18,7 @@ package org.jetbrains.plugins.gradle.model; import com.intellij.openapi.externalSystem.model.ExternalSystemException; import org.gradle.tooling.BuildAction; import org.gradle.tooling.BuildController; +import org.gradle.tooling.model.Model; import org.gradle.tooling.model.build.BuildEnvironment; import org.gradle.tooling.model.idea.BasicIdeaProject; import org.gradle.tooling.model.idea.IdeaModule; @@ -48,8 +49,7 @@ public class ProjectImportAction implements BuildAction aClass1 = myIsPreviewMode ? BasicIdeaProject.class : IdeaProject.class; - final IdeaProject ideaProject = controller.getModel(aClass1); + final IdeaProject ideaProject = controller.getModel(myIsPreviewMode ? BasicIdeaProject.class : IdeaProject.class); if (ideaProject == null || ideaProject.getModules().isEmpty()) { return null; } @@ -59,25 +59,30 @@ public class ProjectImportAction implements BuildAction projectsByPath = new HashMap(); @NotNull private final IdeaProject myIdeaProject; @@ -101,9 +106,13 @@ public class ProjectImportAction implements BuildAction T getExtraProject(Class modelClazz) { + return getExtraProject(null, modelClazz); + } @Nullable - public T getExtraProject(@NotNull IdeaModule module, Class modelClazz) { + public T getExtraProject(@Nullable IdeaModule module, Class modelClazz) { Object extraProject = projectsByPath.get(extractMapKey(modelClazz, module)); if (modelClazz.isInstance(extraProject)) { //noinspection unchecked @@ -129,13 +138,17 @@ public class ProjectImportAction implements BuildAction" + "" + myProject + ((myDescription != null) ? ": " + myDescription : "") + "" + - "\nDetails: " + getErrorMessage(myException) + + (myException != null ? "\nDetails: " + getErrorMessage(myException) : "") + "" ).replaceAll("\r\n|\n\r|\n|\r", EOL_TAG) ); diff --git a/plugins/gradle/tooling-extension-impl/gradle-tooling-extension-impl.iml b/plugins/gradle/tooling-extension-impl/gradle-tooling-extension-impl.iml index 1bcde5e35b79..ea579287b3e8 100644 --- a/plugins/gradle/tooling-extension-impl/gradle-tooling-extension-impl.iml +++ b/plugins/gradle/tooling-extension-impl/gradle-tooling-extension-impl.iml @@ -67,6 +67,7 @@ + diff --git a/plugins/gradle/tooling-extension-impl/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService b/plugins/gradle/tooling-extension-impl/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService index 244e58d2128e..816ef05c1e4d 100644 --- a/plugins/gradle/tooling-extension-impl/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService +++ b/plugins/gradle/tooling-extension-impl/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService @@ -17,3 +17,4 @@ org.jetbrains.plugins.gradle.tooling.builder.WarModelBuilderImpl org.jetbrains.plugins.gradle.tooling.builder.ModuleExtendedModelBuilderImpl org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl org.jetbrains.plugins.gradle.tooling.builder.ScalaModelBuilderImpl +org.jetbrains.plugins.gradle.tooling.builder.ExternalProjectBuilderImpl diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy new file mode 100644 index 000000000000..3bb6b471b755 --- /dev/null +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy @@ -0,0 +1,231 @@ +/* + * 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.tooling.builder + +import com.google.gson.GsonBuilder +import com.intellij.openapi.externalSystem.model.* +import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceType +import org.gradle.api.Action +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.file.ContentFilterable +import org.gradle.api.file.FileCopyDetails +import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.SourceSetContainer +import org.gradle.api.tasks.util.PatternFilterable +import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable +import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder +import org.jetbrains.plugins.gradle.tooling.ModelBuilderService + +import java.util.concurrent.ConcurrentHashMap + +/** + * @author Vladislav.Soroka + * @since 12/20/13 + */ +class ExternalProjectBuilderImpl implements ModelBuilderService { + + private final cache = new ConcurrentHashMap() + + @Override + public boolean canBuild(String modelName) { + return ExternalProject.name.equals(modelName) + } + + @Nullable + @Override + public Object buildAll(final String modelName, final Project project) { + ExternalProject externalProject = cache[project.path] + if (externalProject != null) return externalProject + + DefaultExternalProject defaultExternalProject = new DefaultExternalProject() + defaultExternalProject.externalSystemId = "GRADLE" + defaultExternalProject.name = project.name + defaultExternalProject.QName = ":".equals(project.path) ? project.name : project.path + defaultExternalProject.version = wrap(project.version) + defaultExternalProject.description = project.description + defaultExternalProject.buildDir = project.buildDir + defaultExternalProject.buildFile = project.buildFile + defaultExternalProject.group = wrap(project.group) + defaultExternalProject.projectDir = project.projectDir + defaultExternalProject.sourceSets = getSourceSets(project) + defaultExternalProject.tasks = getTasks(project) + + defaultExternalProject.plugins = getPlugins(project) + //defaultExternalProject.setProperties(project.getProperties()) + + + final Map childProjects = new HashMap(project.getChildProjects().size()) + for (Map.Entry projectEntry : project.getChildProjects().entrySet()) { + final Object externalProjectChild = buildAll(modelName, projectEntry.getValue()) + if (externalProjectChild instanceof ExternalProject) { + childProjects.put(projectEntry.getKey(), (ExternalProject)externalProjectChild) + } + } + defaultExternalProject.setChildProjects(childProjects) + cache.put(project.getPath(), defaultExternalProject) + + defaultExternalProject + } + + static Map getPlugins(Project project) { + def result = [:] as Map + project.convention.plugins.each { key, value -> + ExternalPlugin externalPlugin = new DefaultExternalPlugin() + externalPlugin.id = key + result.put(key, externalPlugin) + } + + result + } + + static Map getTasks(Project project) { + def result = [:] as Map + + project.tasks.all { Task task -> + ExternalTask externalTask = new DefaultExternalTask() + externalTask.name = task.name + externalTask.description = task.description + externalTask.group = task.group + externalTask.QName = task.path + result.put(externalTask.QName, externalTask) + } + + result + } + + static Map getSourceSets(Project project) { + def result = [:] as Map + if (!project.hasProperty("sourceSets") || !(project.sourceSets instanceof SourceSetContainer)) { + return result + } + def sourceSets = project.sourceSets as SourceSetContainer + + def (resourcesIncludes, resourcesExcludes, filterReaders) = getFilters(project, 'processResources') + def (testResourcesIncludes, testResourcesExcludes, testFilterReaders) = getFilters(project, 'processTestResources') + //def (javaIncludes,javaExcludes) = getFilters(project,'compileJava') + + sourceSets.all { SourceSet sourceSet -> + ExternalSourceSet externalSourceSet = new DefaultExternalSourceSet() + externalSourceSet.name = sourceSet.name + + def sources = [:] as Map + ExternalSourceDirectorySet resourcesDirectorySet = new DefaultExternalSourceDirectorySet() + resourcesDirectorySet.name = sourceSet.resources.name + resourcesDirectorySet.srcDirs = sourceSet.resources.srcDirs + resourcesDirectorySet.outputDir = sourceSet.output.resourcesDir + + ExternalSourceDirectorySet javaDirectorySet = new DefaultExternalSourceDirectorySet() + javaDirectorySet.name = sourceSet.allJava.name + javaDirectorySet.srcDirs = sourceSet.allJava.srcDirs + javaDirectorySet.outputDir = sourceSet.output.classesDir +// javaDirectorySet.excludes = javaExcludes + sourceSet.java.excludes; +// javaDirectorySet.includes = javaIncludes + sourceSet.java.includes; + + if (SourceSet.TEST_SOURCE_SET_NAME.equals(sourceSet.name)) { + resourcesDirectorySet.excludes = testResourcesExcludes + sourceSet.resources.excludes; + resourcesDirectorySet.includes = testResourcesIncludes + sourceSet.resources.includes; + resourcesDirectorySet.filters = testFilterReaders + sources.put(ExternalSystemSourceType.TEST, javaDirectorySet) + sources.put(ExternalSystemSourceType.TEST_RESOURCE, resourcesDirectorySet) + } + else { + resourcesDirectorySet.excludes = resourcesExcludes + sourceSet.resources.excludes; + resourcesDirectorySet.includes = resourcesIncludes + sourceSet.resources.includes; + resourcesDirectorySet.filters = filterReaders + sources.put(ExternalSystemSourceType.SOURCE, javaDirectorySet) + sources.put(ExternalSystemSourceType.RESOURCE, resourcesDirectorySet) + } + + externalSourceSet.sources = sources + result[sourceSet.name] = externalSourceSet + } + result + } + + static getFilters(Project project, String taskName) { + def includes = [] + def excludes = [] + def filterReaders = [] as List + def filterableTask = project.tasks.findByName(taskName) + if (filterableTask instanceof PatternFilterable) { + includes += filterableTask.includes + excludes += filterableTask.excludes + } + + if(System.getProperty('idea.disable.gradle.resource.filtering', 'false').toBoolean()) { + return [includes, excludes, filterReaders] + } + + try { + if (filterableTask instanceof ContentFilterable && filterableTask.metaClass.respondsTo(filterableTask, "getMainSpec")) { + def properties = filterableTask.getMainSpec().properties + def copyActions = properties?.allCopyActions ?: properties?.copyActions + + if(copyActions) { + copyActions.each { Action action -> + if (action.hasProperty('val$filterType') && action.hasProperty('val$properties')) { + def filterType = (action?.val$filterType as Class).name + def filter = [filterType: filterType] as DefaultExternalFilter + def props = action?.val$properties + if (props) { + filter.propertiesAsJsonMap = new GsonBuilder().create().toJson(props); + } + filterReaders << filter + } + else if (action.class.simpleName.equals('RenamingCopyAction') && action.hasProperty('transformer')) { + if (action.transformer.hasProperty('matcher') && action?.transformer.hasProperty('replacement')) { + String pattern = action?.transformer?.matcher.pattern().pattern + String replacement = action?.transformer?.replacement + def filter = [filterType: 'RenamingCopyFilter'] as DefaultExternalFilter + if(pattern && replacement){ + filter.propertiesAsJsonMap = new GsonBuilder().create().toJson([pattern: pattern, replacement: replacement]); + filterReaders << filter + } + } + } +// else { +// project.logger.error( +// ErrorMessageBuilder.create(project, "Resource configuration errors") +// .withDescription("Unsupported copy action found: " + action.class.name).build()) +// } + } + } + } + } + catch (Exception ignore) { +// project.logger.error( +// ErrorMessageBuilder.create(project, e, "Resource configuration errors") +// .withDescription("Unable to resolve resources filtering configuration").build()) + } + + return [includes, excludes, filterReaders] + } + + + private static String wrap(Object o) { + return o instanceof CharSequence ? o.toString() : "" + } + + @NotNull + @Override + public ErrorMessageBuilder getErrorMessageBuilder(@NotNull Project project, @NotNull Exception e) { + return ErrorMessageBuilder.create( + project, e, "Project resolve errors" + ).withDescription("Unable to resolve additional project configuration.") + } +}