Skip to content
This repository has been archived by the owner on Sep 16, 2022. It is now read-only.

Integrate GAE Plugin with Eclipse Plugin #9

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Expand Up @@ -5,3 +5,7 @@ out
*.iws *.iws
.idea .idea
.gradle .gradle
.settings
.classpath
.project
bin
12 changes: 12 additions & 0 deletions README.md
Expand Up @@ -58,10 +58,12 @@ web application directory each time you run this task. This behavior can be chan
* `gaeUpload`: Uploads files for an application given the application's root directory. The application ID and version are taken from the appengine-web.xml file. * `gaeUpload`: Uploads files for an application given the application's root directory. The application ID and version are taken from the appengine-web.xml file.
* `gaeVacuumIndexes`: Deletes unused indexes in App Engine server. * `gaeVacuumIndexes`: Deletes unused indexes in App Engine server.
* `gaeVersion`: Prints detailed version information about the SDK, Java and the operating system. * `gaeVersion`: Prints detailed version information about the SDK, Java and the operating system.
* `gaeEclipseGenerateSettings`: Generates files to integrate with the Eclipse Google Plugin


## Project layout ## Project layout


The GAE plugin uses the same layout as the War plugin. The GAE plugin uses the same layout as the War plugin.
*Note:* If the Gradle Eclipse plugin is configured, the webAppDirName/WEB-INF/lib directory will also need to exist


## Convention properties ## Convention properties


Expand Down Expand Up @@ -108,6 +110,16 @@ requested data, it does not guarantee the file won't contain duplicate error mes
the plugin will overwrite the log output file. the plugin will overwrite the log output file.
* `outputFile`: The file the logs get written to. * `outputFile`: The file the logs get written to.


### Integration with Gradle Eclipse Plugin / Google Plugin

If this plugin is enabled on the same project that the eclipse plugin is, then executing 'gradle eclipse' will set up the project
so that it will integrate nicely with the Google plugin for eclipse. There are a few caveats due to this.

* You will need to have a webAppDirName/WEB-INF/lib directory
* Because the Google plugin expects the JARs to be in WEB-INF/lib, the 'gradle eclipse' task will copy the required files there
* The Eclipse build output will also be in webAppDirName/WEB-INF/classes
* Due to above, you likely should exclude those directory from version control

### Example ### Example


gae { gae {
Expand Down
1 change: 1 addition & 0 deletions build.gradle
@@ -1,5 +1,6 @@
apply plugin: 'groovy' apply plugin: 'groovy'
apply plugin: 'idea' apply plugin: 'idea'
apply plugin: 'eclipse'


def compatibilityVersion = 1.5 def compatibilityVersion = 1.5
sourceCompatibility = compatibilityVersion sourceCompatibility = compatibilityVersion
Expand Down
59 changes: 59 additions & 0 deletions src/main/groovy/org/gradle/api/plugins/gae/GaePlugin.groovy
Expand Up @@ -23,6 +23,10 @@ import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.gradle.api.plugins.gae.task.* import org.gradle.api.plugins.gae.task.*
import org.gradle.api.plugins.gae.task.appcfg.* import org.gradle.api.plugins.gae.task.appcfg.*
import org.gradle.api.tasks.Copy;
import org.gradle.plugins.ide.eclipse.EclipsePlugin;
import org.gradle.plugins.ide.eclipse.GenerateEclipseClasspath;
import org.gradle.plugins.ide.eclipse.GenerateEclipseProject;


/** /**
* <p>A {@link Plugin} that provides tasks for uploading, running and managing of Google App Engine projects.</p> * <p>A {@link Plugin} that provides tasks for uploading, running and managing of Google App Engine projects.</p>
Expand All @@ -48,6 +52,7 @@ class GaePlugin implements Plugin<Project> {
static final String GAE_LOGS = 'gaeLogs' static final String GAE_LOGS = 'gaeLogs'
static final String GAE_VERSION = 'gaeVersion' static final String GAE_VERSION = 'gaeVersion'
static final String GAE_EXPLODE_WAR = 'gaeExplodeWar' static final String GAE_EXPLODE_WAR = 'gaeExplodeWar'
static final String GAE_ECLIPSE_GEN_SETTINGS = 'gaeEclipseGenerateSettings'
static final String GRADLE_USER_PROP_PASSWORD = 'gaePassword' static final String GRADLE_USER_PROP_PASSWORD = 'gaePassword'
static final String STOP_PORT_CONVENTION_PARAM = 'stopPort' static final String STOP_PORT_CONVENTION_PARAM = 'stopPort'
static final String STOP_KEY_CONVENTION_PARAM = 'stopKey' static final String STOP_KEY_CONVENTION_PARAM = 'stopKey'
Expand Down Expand Up @@ -84,6 +89,7 @@ class GaePlugin implements Plugin<Project> {
configureGaeDownloadLogs(project, gaePluginConvention) configureGaeDownloadLogs(project, gaePluginConvention)
configureGaeVersion(project) configureGaeVersion(project)
configureGaeSdk(project, gaePluginConvention) configureGaeSdk(project, gaePluginConvention)
configureEclipseIntegration(project)
} }


private File getExplodedSdkDirectory(Project project) { private File getExplodedSdkDirectory(Project project) {
Expand Down Expand Up @@ -291,4 +297,57 @@ class GaePlugin implements Plugin<Project> {
private WarPluginConvention getWarConvention(Project project) { private WarPluginConvention getWarConvention(Project project) {
project.convention.getPlugin(WarPluginConvention.class) project.convention.getPlugin(WarPluginConvention.class)
} }

private void configureEclipseIntegration(Project project) {
project.tasks.withType(GenerateEclipseProject.class).whenTaskAdded { GenerateEclipseProject eclipsePlugin ->
eclipsePlugin.projectModel.natures << 'com.google.appengine.eclipse.core.gaeNature'
eclipsePlugin.projectModel.natures << 'com.google.gdt.eclipse.core.webAppNature'
eclipsePlugin.projectModel.buildCommands << [name: 'com.google.appengine.eclipse.core.enhancerbuilder']
eclipsePlugin.projectModel.buildCommands << [name: 'com.google.appengine.eclipse.core.projectValidator']
}

GaeEclipseSettingsTask gaeEclipseSettingsTask = project.tasks.add(GAE_ECLIPSE_GEN_SETTINGS, GaeEclipseSettingsTask.class)
gaeEclipseSettingsTask.description = 'Generates GAE files for eclipse in the .settings directory'
gaeEclipseSettingsTask.group = GAE_GROUP
gaeEclipseSettingsTask.conventionMapping.map('explodedSdkDirectory') { getExplodedSdkDirectory(project) }

project.afterEvaluate {
project.tasks.findAll { task -> task.name.equals('eclipseClasspath') }.each { eclipseClasspathTask ->
eclipseClasspathTask.classpath.file.withXml { xml ->
xml.asNode().appendNode('classpathentry', [kind: 'con', path: 'com.google.appengine.eclipse.core.GAE_CONTAINER'])
.appendNode('attributes')
.appendNode('attribute', [name: 'org.eclipse.jst.component.nondependency', value: "/${project.webAppDirName}/WEB-INF/lib"])
}

eclipseClasspathTask.classpath.file.whenMerged { classpath ->
classpath.entries.removeAll { entry ->
entry.path.contains('com.google.appengine') && !entry.path.contains('appengine-testing')
}

classpath.entries.find { entry ->
entry.kind == 'output'
}.path = "${project.webAppDirName}/WEB-INF/classes"

// Copy all to WEB-INF/lib (for eclipse runtime)
classpath.entries.each { entry ->
if (entry.path.endsWith(".jar")) {
new AntBuilder().copy(todir: "${project.webAppDirName}/WEB-INF/lib") {
fileset(file: entry.path)
}
}
}
}
}

project.tasks.findAll { task -> task.name.equals('eclipse') }.each { eclipseTask ->
eclipseTask.dependsOn gaeEclipseSettingsTask

// Modify the WAR plugin - to ensure we don't get double in WEB-INF/lib & WEB-INF/classes (From Eclipse)
project.tasks.findAll { task -> task.name.equals('war') }.each { warTask ->
warTask.excludes << "WEB-INF/lib/*.jar"
warTask.excludes << "WEB-INF/classes/*"
}
}
}
}
} }
@@ -0,0 +1,48 @@
package org.gradle.api.plugins.gae.task

import java.io.File;

import org.gradle.api.tasks.InputDirectory;

class GaeEclipseSettingsTask extends AbstractGaeTask {
@InputDirectory File explodedSdkDirectory
def prefixesForAppEnginePrefs = ['appengine-api-1.0-sdk', 'jsr107cache', 'datanucleus-core', 'geronimo-jpa_3.0_spec', 'datanucleus-appengine', 'geronimo-jta_1.1_spec', 'jdo2-api', 'datanucleus-jpa', 'appengine-api-labs']

@Override
void executeTask() {
generateGdtPreferences()
generateAppenginePrefrences()
}

private void generateGdtPreferences() {
def gdtPrefsFile = new File(".settings/com.google.gdt.eclipse.core.prefs")
if (gdtPrefsFile.exists()) gdtPrefsFile.delete()
gdtPrefsFile << 'eclipse.preferences.version=1' + System.getProperty("line.separator")
gdtPrefsFile << 'jarsExcludedFromWebInfLib=' + System.getProperty("line.separator")
gdtPrefsFile << "warSrcDir=${project.webAppDirName}" + System.getProperty("line.separator")
gdtPrefsFile << 'warSrcDirIsOutput=true' + System.getProperty("line.separator")
}

private void generateAppenginePrefrences() {
// AppEngine Prefs File
def appEnginePrefsFile = new File(".settings/com.google.appengine.eclipse.core.prefs")
if (appEnginePrefsFile.exists()) appEnginePrefsFile.delete()
appEnginePrefsFile << 'eclipse.preferences.version=1' + System.getProperty("line.separator")
appEnginePrefsFile << 'filesCopiedToWebInfLib='
prefixesForAppEnginePrefs.each {
appEnginePrefsFile << getJarFileName(it)
appEnginePrefsFile << "|"
}
}

protected String getJarFileName(String beginning) {
def answer;

getExplodedSdkDirectory().eachFileRecurse {
if (it.name.startsWith(beginning))
answer = it.name
}

return answer
}
}