diff options
author | Appu Goundan <appu@google.com> | 2014-06-12 15:52:06 -0400 |
---|---|---|
committer | Appu Goundan <appu@google.com> | 2014-06-12 17:34:55 -0400 |
commit | c621a13b217326dc0811e9fd436e35ddbbd2eabf (patch) | |
tree | 1407ba1da7a7e58e9ac7f293f1a1cb305cb00e41 | |
parent | 0c428ebe257f644d52d732d4d7ff5abc9efa75f4 (diff) | |
download | cloud-c621a13b217326dc0811e9fd436e35ddbbd2eabf.tar.gz |
Builder Model for Appengine Gradle Projects
resubmitting after fixing build script for dependency inclusion
Change-Id: I41dc9db957e3978fc8cfd5edff8e6be3c9542bfa
9 files changed, 283 insertions, 5 deletions
diff --git a/google-cloud-tools.iml b/google-cloud-tools.iml index 706f6e1..2613b4a 100644 --- a/google-cloud-tools.iml +++ b/google-cloud-tools.iml @@ -45,6 +45,15 @@ <SOURCES /> </library> </orderEntry> + <orderEntry type="module-library"> + <library> + <CLASSES> + <root url="jar://$MODULE_DIR$/lib/gradle-appengine-builder-model-0.1.0.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> + </orderEntry> </component> </module> diff --git a/lib/gradle-appengine-builder-model-0.1.0.jar b/lib/gradle-appengine-builder-model-0.1.0.jar Binary files differnew file mode 100644 index 0000000..3f5077a --- /dev/null +++ b/lib/gradle-appengine-builder-model-0.1.0.jar diff --git a/src/META-INF/plugin.xml b/src/META-INF/plugin.xml index 436df77..e05db4d 100644 --- a/src/META-INF/plugin.xml +++ b/src/META-INF/plugin.xml @@ -23,11 +23,17 @@ <project-components> </project-components> + <depends>org.jetbrains.plugins.gradle</depends> + <extensions defaultExtensionNs="org.jetbrains.plugins.gradle"> + <projectResolve implementation="com.google.gct.idea.appengine.gradle.project.AppEngineGradleProjectResolver"/> + </extensions> + <extensions defaultExtensionNs="com.intellij"> - <!-- facet disabled for now <facetType implementation="com.google.gct.idea.appengine.gradle.facet.AppEngineGradleFacetType"/> + <!-- facet detector disabled for now, use the gradle project importer to add the facet <framework.detector implementation="com.google.gct.idea.appengine.gradle.facet.AppEngineFrameworkDetector"/> - --> + --> + <externalProjectDataService implementation="com.google.gct.idea.appengine.gradle.service.AppEngineGradleProjectDataService" /> <!-- Temporarily disable <applicationConfigurable instance="com.google.gct.idea.appengine.synchronization.SampleSyncConfigurable"></applicationConfigurable> diff --git a/src/com/google/gct/idea/appengine/gradle/facet/AppEngineGradleFacet.java b/src/com/google/gct/idea/appengine/gradle/facet/AppEngineGradleFacet.java index 952c9eb..08ef0cd 100644 --- a/src/com/google/gct/idea/appengine/gradle/facet/AppEngineGradleFacet.java +++ b/src/com/google/gct/idea/appengine/gradle/facet/AppEngineGradleFacet.java @@ -15,6 +15,7 @@ */ package com.google.gct.idea.appengine.gradle.facet; +import com.google.gct.idea.appengine.gradle.project.IdeaAppEngineProject; import com.intellij.facet.Facet; import com.intellij.facet.FacetManager; import com.intellij.facet.FacetType; @@ -37,8 +38,7 @@ public class AppEngineGradleFacet extends Facet<AppEngineGradleFacetConfiguratio public static final FacetTypeId<AppEngineGradleFacet> TYPE_ID = new FacetTypeId<AppEngineGradleFacet>(ID); - // Need to modify this to reference the Model for an AppEngine Gradle project - // private IdeaGradleProject myGradleProject; + private IdeaAppEngineProject myIdeaAppEngineProject; @Nullable public static AppEngineGradleFacet getInstance(@NotNull Module module) { @@ -62,4 +62,13 @@ public class AppEngineGradleFacet extends Facet<AppEngineGradleFacetConfiguratio if (module == null) return null; return FacetManager.getInstance(module).getFacetByType(TYPE_ID); } + + public IdeaAppEngineProject getIdeaAppEngineProject() { + return myIdeaAppEngineProject; + } + + public void setIdeaAppEngineProject(IdeaAppEngineProject ideaAppEngineProject) { + myIdeaAppEngineProject = ideaAppEngineProject; + } + } diff --git a/src/com/google/gct/idea/appengine/gradle/project/AppEngineGradleProjectResolver.java b/src/com/google/gct/idea/appengine/gradle/project/AppEngineGradleProjectResolver.java new file mode 100644 index 0000000..e226410 --- /dev/null +++ b/src/com/google/gct/idea/appengine/gradle/project/AppEngineGradleProjectResolver.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * 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.google.gct.idea.appengine.gradle.project; + +import com.google.appengine.gradle.model.AppEngineModel; +import com.google.common.collect.Sets; +import com.google.gct.idea.appengine.gradle.service.AppEngineGradleProjectDataService; + +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; +import com.intellij.openapi.externalSystem.util.Order; +import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension; + +import org.gradle.tooling.model.idea.IdeaModule; + +import java.io.File; +import java.util.Set; + +/** + * Project Resolved called during gradle import, it adds an appengine module key so the + * {@link com.google.gct.idea.appengine.gradle.service.AppEngineGradleProjectDataService} can identify the module and add metadata + */ +@Order(ExternalSystemConstants.UNORDERED) +public class AppEngineGradleProjectResolver extends AbstractProjectResolverExtension { + + public AppEngineGradleProjectResolver() {} + + /** Identify modules that can populate the AppEngineModule gradle builder model */ + @Override + public void populateModuleExtraModels(@NotNull IdeaModule gradleModule, @NotNull DataNode<ModuleData> ideModule) { + + File moduleFilePath = new File(FileUtil.toSystemDependentName(ideModule.getData().getModuleFilePath())); + File moduleRootDirPath = moduleFilePath.getParentFile(); + + AppEngineModel appEngineModel = resolverCtx.getExtraProject(gradleModule, AppEngineModel.class); + if (appEngineModel != null) { + IdeaAppEngineProject ideaAppEngineProject = + new IdeaAppEngineProject(gradleModule.getName(), moduleRootDirPath, appEngineModel); + ideModule.createChild(AppEngineGradleProjectDataService.IDE_APP_ENGINE_PROJECT, ideaAppEngineProject); + } + + nextResolver.populateModuleExtraModels(gradleModule, ideModule); + } + + /** AppEngineModel is the only class we really care about in our resolver */ + @Override + @NotNull + public Set<Class> getExtraProjectModelClasses() { + return Sets.<Class>newHashSet(AppEngineModel.class); + } +} diff --git a/src/com/google/gct/idea/appengine/gradle/project/IdeaAppEngineProject.java b/src/com/google/gct/idea/appengine/gradle/project/IdeaAppEngineProject.java new file mode 100644 index 0000000..97a0270 --- /dev/null +++ b/src/com/google/gct/idea/appengine/gradle/project/IdeaAppEngineProject.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * 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.google.gct.idea.appengine.gradle.project; + +import com.google.appengine.gradle.model.AppEngineModel; + +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * Project wrapper for App Engine Gradle Projects + */ +public class IdeaAppEngineProject { + @NotNull private final String myModuleName; + @NotNull private final VirtualFile myRootDir; + @NotNull private final AppEngineModel myDelegate; + + public IdeaAppEngineProject(@NotNull String moduleName, @NotNull File rootDir, @NotNull AppEngineModel delegate) { + myModuleName = moduleName; + VirtualFile found = VfsUtil.findFileByIoFile(rootDir, true); + // the module's root directory can never be null. + assert found != null; + myRootDir = found; + myDelegate = delegate; + } + + @NotNull + public String getModuleName() { + return myModuleName; + } + + @NotNull + public VirtualFile getRootDir() { + return myRootDir; + } + + @NotNull + public AppEngineModel getDelegate() { + return myDelegate; + } +} diff --git a/src/com/google/gct/idea/appengine/gradle/service/AppEngineGradleProjectDataService.java b/src/com/google/gct/idea/appengine/gradle/service/AppEngineGradleProjectDataService.java new file mode 100644 index 0000000..36b25de --- /dev/null +++ b/src/com/google/gct/idea/appengine/gradle/service/AppEngineGradleProjectDataService.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * 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.google.gct.idea.appengine.gradle.service; + +import com.android.tools.idea.gradle.AndroidProjectKeys; +import com.android.tools.idea.gradle.GradleSyncState; +import com.google.common.collect.Maps; +import com.google.gct.idea.appengine.gradle.facet.AppEngineGradleFacet; +import com.google.gct.idea.appengine.gradle.project.IdeaAppEngineProject; + +import com.intellij.facet.FacetManager; +import com.intellij.facet.ModifiableFacetModel; +import com.intellij.openapi.application.RunResult; +import com.intellij.openapi.command.WriteCommandAction; +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.service.project.manage.ProjectDataService; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Map; + +/** + * Add necessary configuration information to an appengine modules identified by + * {@link com.google.gct.idea.appengine.gradle.project.AppEngineGradleProjectResolver} + */ +public class AppEngineGradleProjectDataService implements ProjectDataService<IdeaAppEngineProject, Void> { + + private static final Logger LOG = Logger.getInstance(AppEngineGradleProjectDataService.class); + // TODO: move this somewhere else, maybe a keys file + @NotNull public static final Key<IdeaAppEngineProject> IDE_APP_ENGINE_PROJECT = + Key.create(IdeaAppEngineProject.class, AndroidProjectKeys.IDE_ANDROID_PROJECT.getProcessingWeight() + 10); + + @NotNull + @Override + public Key<IdeaAppEngineProject> getTargetDataKey() { + return IDE_APP_ENGINE_PROJECT; + } + + /** Add facet to App Engine module on imported modules */ + @Override + public void importData(@NotNull final Collection<DataNode<IdeaAppEngineProject>> toImport, + @NotNull final Project project, boolean synchronous) { + if (toImport.isEmpty()) { + return; + } + + RunResult result = new WriteCommandAction.Simple(project) { + @Override + protected void run() throws Throwable { + Map<String, IdeaAppEngineProject> importModulesMap = indexByModuleName(toImport); + for (Module module : ModuleManager.getInstance(project).getModules()) { + if (importModulesMap.containsKey(module.getName())) { + addAppEngineGradleFacet(importModulesMap.get(module.getName()), module); + } + } + } + }.execute(); + Throwable error = result.getThrowable(); + if (error != null) { + LOG.error(String.format("Failed to set up App Engine Gradle Modules")); + GradleSyncState.getInstance(project).syncFailed(error.getMessage()); + } + } + + @Override + public void removeData(@NotNull Collection<? extends Void> toRemove, @NotNull Project project, boolean synchronous) { + + } + + private static void addAppEngineGradleFacet(IdeaAppEngineProject ideaAppEngineProject, Module appEngineModule) { + //Module does not have AppEngine-Gradle facet. Create one and add it. + FacetManager facetManager = FacetManager.getInstance(appEngineModule); + ModifiableFacetModel model = facetManager.createModifiableModel(); + AppEngineGradleFacet facet = AppEngineGradleFacet.getInstance(appEngineModule); + if (facet == null) { + try { + facet = facetManager.createFacet(AppEngineGradleFacet.getFacetType(), AppEngineGradleFacet.NAME, null); + model.addFacet(facet); + } + finally { + model.commit(); + } + } + facet.setIdeaAppEngineProject(ideaAppEngineProject); + } + + @NotNull + private static Map<String, IdeaAppEngineProject> indexByModuleName(@NotNull Collection<DataNode<IdeaAppEngineProject>> dataNodes) { + Map<String, IdeaAppEngineProject> index = Maps.newHashMap(); + for (DataNode<IdeaAppEngineProject> d : dataNodes) { + IdeaAppEngineProject appEngineProject = d.getData(); + index.put(appEngineProject.getModuleName(), appEngineProject); + } + return index; + } +} diff --git a/src/com/google/gct/idea/appengine/run/AppEngineRunConfigurationSettingsEditor.form b/src/com/google/gct/idea/appengine/run/AppEngineRunConfigurationSettingsEditor.form index 2134d3a..aef286c 100644 --- a/src/com/google/gct/idea/appengine/run/AppEngineRunConfigurationSettingsEditor.form +++ b/src/com/google/gct/idea/appengine/run/AppEngineRunConfigurationSettingsEditor.form @@ -3,7 +3,7 @@ <grid id="27dc6" binding="mainPanel" layout-manager="GridLayoutManager" row-count="6" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <xy x="17" y="25" width="500" height="152"/> + <xy x="17" y="25" width="500" height="169"/> </constraints> <properties/> <border type="none"/> diff --git a/src/com/google/gct/idea/appengine/run/AppEngineRunConfigurationSettingsEditor.java b/src/com/google/gct/idea/appengine/run/AppEngineRunConfigurationSettingsEditor.java index f9c7621..b77872b 100644 --- a/src/com/google/gct/idea/appengine/run/AppEngineRunConfigurationSettingsEditor.java +++ b/src/com/google/gct/idea/appengine/run/AppEngineRunConfigurationSettingsEditor.java @@ -15,6 +15,8 @@ */ package com.google.gct.idea.appengine.run; +import com.google.appengine.gradle.model.AppEngineModel; +import com.google.gct.idea.appengine.gradle.facet.AppEngineGradleFacet; import com.intellij.execution.ui.ConfigurationModuleSelector; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.options.ConfigurationException; @@ -23,6 +25,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import org.jetbrains.annotations.NotNull; +import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JPanel; @@ -49,6 +52,19 @@ public class AppEngineRunConfigurationSettingsEditor extends SettingsEditor<AppE FileChooserDescriptorFactory.createSingleFolderDescriptor()); } + // TODO: unused currently, but useful once gradle facet for App Engine is completely set up. + protected void syncWithBuildFile() { + AppEngineGradleFacet facet = AppEngineGradleFacet.getInstance(moduleSelector.getModule()); + if(facet != null) { + // proof of concept of usefulness of Gradle model + AppEngineModel model = facet.getIdeaAppEngineProject().getDelegate(); + myServerPortField.setText(model.getHttpPort().toString()); + myServerAddressField.setText(model.getHttpAddress()); + myAppEngineSdkField.setText(model.getAppEngineSdkRoot()); + myWarPathField.setText(model.getWarDir().getAbsolutePath()); + } + } + @Override protected void resetEditorFrom(AppEngineRunConfiguration configuration) { if (configuration.getSdkPath() != null) { |