Gradle: allow to import IDE configuration from external systems IDEA-174087

This commit is contained in:
Vladislav.Soroka
2017-08-11 20:28:51 +03:00
parent 81a87880a1
commit ea7502be30
18 changed files with 745 additions and 7 deletions
@@ -244,13 +244,13 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura
if (!myDisabledSettings.contains(Setting.RESOURCE_PATTERNS)) {
configuration.removeResourceFilePatterns();
String extensionString = myResourcePatternsField.getText().trim();
applyResourcePatterns(extensionString, (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject));
applyResourcePatterns(extensionString, configuration);
}
BuildManager.getInstance().clearState(myProject);
}
private static void applyResourcePatterns(String extensionString, final CompilerConfigurationImpl configuration)
public static void applyResourcePatterns(String extensionString, final CompilerConfigurationImpl configuration)
throws ConfigurationException {
StringTokenizer tokenizer = new StringTokenizer(extensionString, ";", false);
List<String[]> errors = new ArrayList<>();
@@ -21,9 +21,6 @@ import org.jetbrains.annotations.NotNull;
/**
* Holds common project entity {@link Key keys}.
*
* @author Denis Zhdanov
* @since 4/12/13 11:52 AM
*/
public class ProjectKeys {
@@ -34,7 +31,9 @@ public class ProjectKeys {
@NotNull public static final Key<ModuleDependencyData> MODULE_DEPENDENCY = Key.create(ModuleDependencyData.class, 130);
@NotNull public static final Key<LibraryDependencyData> LIBRARY_DEPENDENCY = Key.create(LibraryDependencyData.class, 150);
@NotNull public static final Key<TaskData> TASK = Key.create(TaskData.class, 250);
@NotNull public static final Key<TaskData> TASK = Key.create(TaskData.class, 250);
@NotNull public static final Key<ConfigurationData> CONFIGURATION = Key.create(ConfigurationData.class, 350);
private ProjectKeys() {
}
@@ -0,0 +1,28 @@
/*
* Copyright 2000-2017 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 org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* @author Vladislav.Soroka
*/
@ApiStatus.Experimental
public interface ConfigurationData extends ExternalEntityData {
Object find(@NotNull String query);
}
@@ -0,0 +1,41 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.externalSystem.service.project.manage;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.externalSystem.model.project.ConfigurationData;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* @author Vladislav.Soroka
*/
@ApiStatus.Experimental
public interface ConfigurationHandler {
ExtensionPointName<ConfigurationHandler> EP_NAME = ExtensionPointName.create("com.intellij.externalSystemConfigurationHandler");
default void apply(@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
@NotNull ConfigurationData configuration) {}
default void apply(@NotNull Module module,
@NotNull IdeModifiableModelsProvider modelsProvider,
@NotNull ConfigurationData configuration) {}
}
@@ -0,0 +1,76 @@
/*
* Copyright 2000-2017 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.AbstractExternalEntityData;
import com.intellij.openapi.externalSystem.model.project.ConfigurationData;
import com.intellij.openapi.util.text.StringUtil;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.io.JsonReaderEx;
import org.jetbrains.io.JsonUtil;
import java.util.Map;
/**
* @author Vladislav.Soroka
*/
@ApiStatus.Experimental
public class ConfigurationDataImpl extends AbstractExternalEntityData implements ConfigurationData {
private static final long serialVersionUID = 1L;
@Language("JSON") @NotNull private final String myData;
@Nullable transient private volatile Object myJsonObject;
public ConfigurationDataImpl(@NotNull ProjectSystemId owner, @Language("JSON") @NotNull String data) {
super(owner);
myData = data;
}
@Language("JSON")
@NotNull
public String getJsonString() {
return myData;
}
@Override
public Object find(@NotNull String query) {
if (StringUtil.isEmpty(query)) return null;
Object jsonObject = getJsonObject();
for (String part : StringUtil.split(query, ".")) {
if (jsonObject instanceof Map) {
jsonObject = ((Map)jsonObject).get(part);
}
else {
return null;
}
}
return jsonObject;
}
public Object getJsonObject() {
if (myJsonObject == null) {
JsonReaderEx reader = new JsonReaderEx(myData);
reader.setLenient(true);
myJsonObject = JsonUtil.nextAny(reader);
}
return myJsonObject;
}
}
@@ -0,0 +1,138 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.externalSystem.service.project.manage;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerConfigurationImpl;
import com.intellij.compiler.CompilerWorkspaceConfiguration;
import com.intellij.compiler.options.CompilerUIConfigurable;
import com.intellij.compiler.server.BuildManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.project.ConfigurationData;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Map;
/**
* @author Vladislav.Soroka
*/
public class CompilerConfigurationHandler implements ConfigurationHandler {
private static final Logger LOG = Logger.getInstance(CompilerConfigurationHandler.class);
@Override
public void apply(@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
@NotNull ConfigurationData configuration) {
Object obj = configuration.find("compiler");
if (!(obj instanceof Map)) return;
Map configurationMap = ((Map)obj);
ApplicationManager.getApplication().invokeLater(() -> {
final CompilerConfigurationImpl compilerConfiguration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(project);
final CompilerWorkspaceConfiguration workspaceConfiguration = CompilerWorkspaceConfiguration.getInstance(project);
boolean changed = false;
String resourcePatterns = getString(configurationMap, "resourcePatterns");
if (resourcePatterns != null) {
try {
String[] resourceFilePatterns = compilerConfiguration.getResourceFilePatterns();
compilerConfiguration.removeResourceFilePatterns();
CompilerUIConfigurable.applyResourcePatterns(resourcePatterns, compilerConfiguration);
if (!Arrays.equals(resourceFilePatterns, compilerConfiguration.getResourceFilePatterns())) {
changed = true;
}
}
catch (ConfigurationException e) {
LOG.warn("Unable to apply compiler resource patterns", e);
}
}
Number processHeapSize = getNumber(configurationMap, "processHeapSize");
if (processHeapSize != null && processHeapSize.intValue() != compilerConfiguration.getBuildProcessHeapSize(0)) {
compilerConfiguration.setBuildProcessHeapSize(processHeapSize.intValue());
changed = true;
}
Boolean autoShowFirstErrorInEditor = getBoolean(configurationMap, "autoShowFirstErrorInEditor");
if (autoShowFirstErrorInEditor != null && workspaceConfiguration.AUTO_SHOW_ERRORS_IN_EDITOR != autoShowFirstErrorInEditor) {
workspaceConfiguration.AUTO_SHOW_ERRORS_IN_EDITOR = autoShowFirstErrorInEditor;
changed = true;
}
Boolean displayNotificationPopup = getBoolean(configurationMap, "displayNotificationPopup");
if (displayNotificationPopup != null && workspaceConfiguration.DISPLAY_NOTIFICATION_POPUP != displayNotificationPopup) {
workspaceConfiguration.DISPLAY_NOTIFICATION_POPUP = displayNotificationPopup;
changed = true;
}
Boolean clearOutputDirectory = getBoolean(configurationMap, "clearOutputDirectory");
if (clearOutputDirectory != null && workspaceConfiguration.CLEAR_OUTPUT_DIRECTORY != clearOutputDirectory) {
workspaceConfiguration.CLEAR_OUTPUT_DIRECTORY = clearOutputDirectory;
changed = true;
}
Boolean addNotNullAssertions = getBoolean(configurationMap, "addNotNullAssertions");
if (addNotNullAssertions != null && compilerConfiguration.isAddNotNullAssertions() != addNotNullAssertions) {
compilerConfiguration.setAddNotNullAssertions(addNotNullAssertions);
changed = true;
}
Boolean enableAutomake = getBoolean(configurationMap, "enableAutomake");
if (enableAutomake != null && workspaceConfiguration.MAKE_PROJECT_ON_SAVE != enableAutomake) {
workspaceConfiguration.MAKE_PROJECT_ON_SAVE = enableAutomake;
changed = true;
}
Boolean parallelCompilation = getBoolean(configurationMap, "parallelCompilation");
if (parallelCompilation != null && workspaceConfiguration.PARALLEL_COMPILATION != parallelCompilation) {
workspaceConfiguration.PARALLEL_COMPILATION = parallelCompilation;
changed = true;
}
Boolean rebuildOnDependencyChange = getBoolean(configurationMap, "rebuildModuleOnDependencyChange");
if (rebuildOnDependencyChange != null && workspaceConfiguration.REBUILD_ON_DEPENDENCY_CHANGE != rebuildOnDependencyChange) {
workspaceConfiguration.REBUILD_ON_DEPENDENCY_CHANGE = rebuildOnDependencyChange;
changed = true;
}
String additionalVmOptions = getString(configurationMap, "additionalVmOptions");
if (additionalVmOptions != null && workspaceConfiguration.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS != additionalVmOptions) {
workspaceConfiguration.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS = additionalVmOptions;
changed = true;
}
if (changed) {
BuildManager.getInstance().clearState(project);
}
});
}
@Nullable
private static Boolean getBoolean(Map map, String key) {
Object o = map.get(key);
return o instanceof Boolean ? (Boolean)o : null;
}
private static Number getNumber(Map map, String key) {
Object o = map.get(key);
return o instanceof Number ? (Number)o : null;
}
@Nullable
private static String getString(Map map, String key) {
Object o = map.get(key);
return o instanceof String ? (String)o : null;
}
}
@@ -0,0 +1,99 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.externalSystem.service.project.manage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.Key;
import com.intellij.openapi.externalSystem.model.ProjectKeys;
import com.intellij.openapi.externalSystem.model.project.ConfigurationData;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
import com.intellij.openapi.externalSystem.util.Order;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import static com.intellij.openapi.externalSystem.service.project.manage.AbstractModuleDataService.MODULE_KEY;
/**
* @author Vladislav.Soroka
*/
@ApiStatus.Experimental
@Order(ExternalSystemConstants.BUILTIN_SERVICE_ORDER)
public class ConfigurationDataService extends AbstractProjectDataService<ConfigurationData, Void> {
private static final Logger LOG = Logger.getInstance(ConfigurationDataService.class);
@NotNull
@Override
public Key<ConfigurationData> getTargetDataKey() {
return ProjectKeys.CONFIGURATION;
}
@Override
public void importData(@NotNull Collection<DataNode<ConfigurationData>> toImport,
@Nullable ProjectData projectData,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider) {
if (toImport.isEmpty()) {
return;
}
final DataNode<ConfigurationData> javaProjectDataNode = toImport.iterator().next();
final DataNode<ProjectData> projectDataNode = ExternalSystemApiUtil.findParent(javaProjectDataNode, ProjectKeys.PROJECT);
assert projectDataNode != null;
DataNode<ConfigurationData> projectConfigurationNode = ExternalSystemApiUtil.find(projectDataNode, ProjectKeys.CONFIGURATION);
if (projectConfigurationNode != null) {
if (ExternalSystemApiUtil.isOneToOneMapping(project, projectDataNode.getData())) {
LOG.warn("This external project are not the only project in the current IDE workspace, " +
"found project level configuration can override the configuration came from other external projects.");
}
for (ConfigurationHandler handler : ConfigurationHandler.EP_NAME.getExtensions()) {
handler.apply(project, modelsProvider, projectConfigurationNode.getData());
}
}
for (DataNode<ConfigurationData> node : toImport) {
if (node == projectConfigurationNode) continue;
DataNode<ModuleData> moduleDataNode = ExternalSystemApiUtil.findParent(node, ProjectKeys.MODULE);
if (moduleDataNode != null) {
Module module = moduleDataNode.getUserData(MODULE_KEY);
module = module != null ? module : modelsProvider.findIdeModule(moduleDataNode.getData());
if (module == null) {
LOG.warn(String.format(
"Can't import module level configuration. Reason: target module (%s) is not found at the ide", moduleDataNode));
continue;
}
for (ConfigurationHandler handler : ConfigurationHandler.EP_NAME.getExtensions()) {
handler.apply(module, modelsProvider, node.getData());
}
}
}
}
}
@@ -5,6 +5,8 @@
interface="com.intellij.openapi.externalSystem.service.project.ExternalProjectsWorkspaceImpl$Contributor"/>
<extensionPoint name="externalProjectDataService"
interface="com.intellij.openapi.externalSystem.service.project.manage.ProjectDataService"/>
<extensionPoint name="externalSystemConfigurationHandler"
interface="com.intellij.openapi.externalSystem.service.project.manage.ConfigurationHandler"/>
<extensionPoint name="externalSystemConfigLocator"
interface="com.intellij.openapi.externalSystem.service.settings.ExternalSystemConfigLocator"/>
<extensionPoint name="externalSystemNotificationExtension"
@@ -33,6 +33,9 @@
<externalProjectDataService implementation="com.intellij.openapi.externalSystem.service.project.manage.ContentRootDataService"/>
<externalProjectDataService implementation="com.intellij.openapi.externalSystem.service.project.manage.LibraryDependencyDataService"/>
<externalProjectDataService implementation="com.intellij.openapi.externalSystem.service.project.manage.ModuleDependencyDataService"/>
<externalProjectDataService implementation="com.intellij.openapi.externalSystem.service.project.manage.ConfigurationDataService"/>
<externalSystemConfigurationHandler implementation="com.intellij.openapi.externalSystem.service.project.manage.CompilerConfigurationHandler"/>
<configuration.ModuleStructureExtension implementation="com.intellij.openapi.externalSystem.service.project.manage.ExternalModuleStructureExtension"/>
@@ -22,6 +22,7 @@ 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.ConfigurationDataImpl;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalSystemException;
import com.intellij.openapi.externalSystem.model.ProjectKeys;
@@ -162,6 +163,12 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver
ideProject.createChild(ExternalProjectDataService.KEY, externalProject);
ideProject.getData().setDescription(externalProject.getDescription());
}
final IntelliJSettings intellijSettings = resolverCtx.getExtraProject(IntelliJProjectSettings.class);
if (intellijSettings != null) {
ideProject.createChild(ProjectKeys.CONFIGURATION,
new ConfigurationDataImpl(GradleConstants.SYSTEM_ID, intellijSettings.getSettings()));
}
}
@NotNull
@@ -299,6 +306,12 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver
}
ideModule.createChild(GradleExtensionsDataService.KEY, extensions);
}
final IntelliJSettings intellijSettings = resolverCtx.getExtraProject(gradleModule, IntelliJSettings.class);
if (intellijSettings != null) {
ideModule.createChild(ProjectKeys.CONFIGURATION,
new ConfigurationDataImpl(GradleConstants.SYSTEM_ID, intellijSettings.getSettings()));
}
}
@Override
@@ -629,6 +642,8 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver
result.add(BuildScriptClasspathModel.class);
result.add(GradleExtensions.class);
result.add(ExternalProject.class);
result.add(IntelliJProjectSettings.class);
result.add(IntelliJSettings.class);
return result;
}
@@ -0,0 +1,22 @@
/*
* Copyright 2000-2017 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.model;
/**
* @author Vladislav.Soroka
*/
public interface IntelliJProjectSettings extends IntelliJSettings {
}
@@ -0,0 +1,25 @@
/*
* Copyright 2000-2017 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.model;
import java.io.Serializable;
/**
* @author Vladislav.Soroka
*/
public interface IntelliJSettings extends Serializable {
String getSettings();
}
@@ -20,3 +20,5 @@ org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImp
org.jetbrains.plugins.gradle.tooling.builder.ScalaModelBuilderImpl
org.jetbrains.plugins.gradle.tooling.builder.ExternalProjectBuilderImpl
org.jetbrains.plugins.gradle.tooling.builder.ProjectExtensionsDataBuilderImpl
org.jetbrains.plugins.gradle.tooling.builder.IntelliJSettingsBuilder
org.jetbrains.plugins.gradle.tooling.builder.IntelliJProjectSettingsBuilder
@@ -0,0 +1,34 @@
/*
* Copyright 2000-2017 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.model;
/**
* @author Vladislav.Soroka
*/
public class DefaultIntelliJSettings implements IntelliJSettings {
private static final long serialVersionUID = 1L;
private final String mySettings;
public DefaultIntelliJSettings(String settings) {
mySettings = settings;
}
@Override
public String getSettings() {
return mySettings;
}
}
@@ -0,0 +1,58 @@
/*
* Copyright 2000-2017 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 org.gradle.api.Project
import org.gradle.api.plugins.ExtensionAware
import org.gradle.plugins.ide.idea.IdeaPlugin
import org.jetbrains.annotations.NotNull
import org.jetbrains.plugins.gradle.model.DefaultIntelliJSettings
import org.jetbrains.plugins.gradle.model.IntelliJProjectSettings
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
import org.jetbrains.plugins.gradle.tooling.ModelBuilderService
import org.jetbrains.plugins.gradle.tooling.internal.DynamicSettings
/**
* @author Vladislav.Soroka
*/
class IntelliJProjectSettingsBuilder implements ModelBuilderService {
@Override
boolean canBuild(String modelName) {
modelName == IntelliJProjectSettings.name
}
@Override
Object buildAll(String modelName, Project project) {
if (project.parent == null) {
ExtensionAware extensionAware = project.plugins.findPlugin(IdeaPlugin.class)?.model?.project as ExtensionAware
if (extensionAware) {
def object = extensionAware.extensions.findByName("settings")
if (object instanceof DynamicSettings) {
return new DefaultIntelliJSettings(object.toString())
}
}
}
return null
}
@Override
ErrorMessageBuilder getErrorMessageBuilder(@NotNull Project project, @NotNull Exception e) {
return ErrorMessageBuilder
.create(project, e, "IntelliJ settings import errors")
.withDescription("Unable to build IntelliJ project settings")
}
}
@@ -0,0 +1,58 @@
/*
* Copyright 2000-2017 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 groovy.transform.CompileStatic
import org.gradle.api.Project
import org.gradle.api.plugins.ExtensionAware
import org.gradle.plugins.ide.idea.IdeaPlugin
import org.jetbrains.annotations.NotNull
import org.jetbrains.plugins.gradle.model.DefaultIntelliJSettings
import org.jetbrains.plugins.gradle.model.IntelliJSettings
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
import org.jetbrains.plugins.gradle.tooling.ModelBuilderService
import org.jetbrains.plugins.gradle.tooling.internal.DynamicSettings
/**
* @author Vladislav.Soroka
*/
@CompileStatic
class IntelliJSettingsBuilder implements ModelBuilderService {
@Override
boolean canBuild(String modelName) {
modelName == IntelliJSettings.name
}
@Override
Object buildAll(String modelName, Project project) {
ExtensionAware extensionAware = project.plugins.findPlugin(IdeaPlugin.class)?.model?.module as ExtensionAware
if (extensionAware) {
def object = extensionAware.extensions.findByName("settings")
if (object instanceof DynamicSettings) {
return new DefaultIntelliJSettings(object.toString())
}
}
return null
}
@Override
ErrorMessageBuilder getErrorMessageBuilder(@NotNull Project project, @NotNull Exception e) {
return ErrorMessageBuilder
.create(project, e, "IntelliJ settings import errors")
.withDescription("Unable to build IntelliJ project settings")
}
}
@@ -0,0 +1,130 @@
/*
* Copyright 2000-2017 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.internal
import groovy.json.JsonOutput
/**
* @author Vladislav.Soroka
*/
class DynamicSettings extends GroovyObjectSupport {
def objects = [:]
DynamicSettings() {
}
def methodMissing(String name, def args) {
if (args.length == 1 && args[0] instanceof Closure) {
def value = JDelegate.cloneDelegateAndGetContent((Closure)args[0])
objects.put(name, value)
return objects
}
}
def propertyMissing(String name) {
def content = super.getContent()
if (content instanceof Map) return content.get(name)
}
@Override
String toString() {
return JsonOutput.toJson(this.objects)
// return JsonOutput.prettyPrint(JsonOutput.toJson(this.objects))
}
}
class JDelegate extends GroovyObjectSupport {
private Object content
JDelegate() {
}
Object invokeMethod(String name, Object args) {
Object val = null
if (args != null && Object[].class.isAssignableFrom(args.getClass())) {
Object[] arr = (Object[])((Object[])args)
if (arr.length == 1) {
val = arr[0]
}
else if (isIterableOrArrayAndClosure(arr)) {
Closure<?> closure = (Closure)arr[1]
Iterator<?> iterator = arr[0] instanceof Iterable ? ((Iterable)arr[0]).iterator() :
Arrays.asList((Object[])((Object[])arr[0])).iterator()
ArrayList list = new ArrayList()
while (iterator.hasNext()) {
list.add(curryDelegateAndGetContent(closure, iterator.next()))
}
val = list
}
else {
val = Arrays.asList(arr)
}
}
if (!content) {
content = new LinkedHashMap()
}
if (content instanceof Map) {
if (content.containsKey(name)) {
def list = new ArrayList()
content.each { k, v -> list.add([k, v]) }
content = list
}
else {
this.content.put(name, val)
}
}
if (content instanceof List) {
content.add([name, val])
}
return val
}
static boolean isIterableOrArrayAndClosure(Object[] args) {
if (args.length == 2 && args[1] instanceof Closure) {
return args[0] instanceof Iterable || args[0] != null && args[0].getClass().isArray()
}
else {
return false
}
}
static Object cloneDelegateAndGetContent(Closure<?> c) {
JDelegate delegate = new JDelegate()
Closure<?> cloned = (Closure)c.clone()
cloned.setDelegate(delegate)
cloned.setResolveStrategy(1)
cloned.call()
return delegate.getContent()
}
static Object curryDelegateAndGetContent(Closure<?> c, Object o) {
JDelegate delegate = new JDelegate()
Closure<?> curried = c.curry(o)
curried.setDelegate(delegate)
curried.setResolveStrategy(1)
curried.call()
return delegate.getContent()
}
Object getContent() {
return this.content
}
}
@@ -1,6 +1,6 @@
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.plugins.gradle.tooling.internal.DynamicSettings
import org.jetbrains.plugins.gradle.tooling.internal.ExtraModelBuilder
System.setProperty("idea.active", "true")
@@ -57,3 +57,11 @@ class JetGradlePlugin implements Plugin<Gradle> {
}
}
}
allprojects {
apply plugin: 'idea'
if (parent == null) {
idea.project.extensions.create('settings', DynamicSettings)
}
idea.module.extensions.create('settings', DynamicSettings)
}