diff --git a/.gitignore b/.gitignore
new file mode 100755
index 0000000..0fc3716
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+build
+out
+*.iml
+*.ipr
+*.iws
+.idea
+.gradle
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..aad5725
--- /dev/null
+++ b/README.md
@@ -0,0 +1,54 @@
+# Gradle GAE plugin
+
+The plugin provides tasks for uploading, downloading, running and managing Google App Engine projects in any given
+Gradle build. It extends the War plugin.
+
+## Usage
+
+To use the GAE plugin, include in your build script:
+
+ apply plugin: 'gae'
+
+The plugin JAR and the App Engine tools SDK library need to be defined in the classpath of your build script. You can
+either get the plugin from the GitHub download section or upload it to your local repository. The following code snippet
+shows an example:
+
+ buildscript {
+ repositories {
+ add(new org.apache.ivy.plugins.resolver.URLResolver()) {
+ name = "GitHub"
+ addArtifactPattern 'http://cloud.github.com/downloads/bmuschko/gradle-gae-plugin/[module]-[revision].[ext]'
+ }
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.google.appengine:appengine-tools-sdk:1.4.2'
+ classpath ':gradle-gae-plugin:0.1'
+ }
+ }
+
+*Note:* The plugin requires you to set the environment variable _APPENGINE_HOME_ or the system property _google.appengine.sdk_
+pointing to your current Google App Engine SDK installation. In case you have both variables set the system property takes
+precedence over the environment variable.
+
+## Tasks
+
+The GAE plugin defines the following tasks:
+
+* `gaeRun`: Starts a local development server running your project code.
+* `gaeEnhance`: Enhances DataNucleus classes by using byte-code manipulation to make your normal Java classes "persistable".
+* `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.
+* `gaeRollback`: Undoes a partially completed update for the given application.
+* `gaeUpdateIndexes`: Updates datastore indexes in App Engine to include newly added indexes.
+* `gaeVacuumIndexes`: Deletes unused indexes in App Engine server.
+* `gaeUpdateQueues`: Updates the task queue configuration (queue.xml) in App Engine.
+* `gaeUpdateDos`: Updates the DoS protection configuration for the app, based on the dos.xml file.
+* `gaeUpdateCron`: Updates the schedule task (cron) configuration for the app, based on the cron.xml file.
+* `gaeCronInfo`: Verifies and prints the scheduled task (cron) configuration.
+* `gaeLogs`: Retrieves log data for the application running on App Engine.
+* `gaeVersion`: Prints detailed version information about the SDK, Java and the operating system.
+
+## Project layout
+
+The GAE plugin uses the same layout as the War plugin.
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100755
index 0000000..3d1df77
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,50 @@
+apply plugin: 'groovy'
+apply plugin: 'idea'
+
+sourceCompatibility = 1.5
+targetCompatibility = 1.5
+version = '0.1'
+ant.property(environment: 'env')
+
+if(!ant.properties['env.GRADLE_HOME']) {
+ throw new Exception('Please set $GRADLE_HOME')
+}
+
+def gradleHomeDir = System.getenv().get('GRADLE_HOME')
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ groovy 'org.codehaus.groovy:groovy:1.7.+'
+ compile gradleApi()
+ compile group: 'com.google.appengine', name: 'appengine-tools-sdk', version: '1.4.2'
+ testCompile "junit:junit:4.+"
+}
+
+jar {
+ manifest {
+ attributes 'Implementation-Title': 'Gradle GAE plugin',
+ 'Implementation-Version': version,
+ 'Built-By': System.getProperty("user.name"),
+ 'Built-Date': new Date(),
+ 'Built-JDK': System.getProperty("java.version")
+ }
+}
+
+ideaProject {
+ javaVersion = '1.6'
+
+ withXml { provider ->
+ def node = provider.asNode()
+
+ // Use GIT
+ def vcsConfig = node.component.find { it.'@name' == 'VcsDirectoryMappings' }
+ vcsConfig.mapping[0].'@vcs' = 'Git'
+
+ // Set Gradle home
+ def gradleSettings = node.appendNode('component', [name: 'GradleSettings'])
+ gradleSettings.appendNode('option', [name: 'SDK_HOME', value: gradleHomeDir])
+ }
+}
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/GaePlugin.groovy b/src/main/groovy/org/gradle/api/plugins/gae/GaePlugin.groovy
new file mode 100755
index 0000000..e5b6f02
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/GaePlugin.groovy
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.plugins.WarPlugin
+import org.gradle.api.plugins.WarPluginConvention
+import org.gradle.api.plugins.gae.task.GaeEnhanceTask
+import org.gradle.api.plugins.gae.task.GaeRunTask
+import org.gradle.api.plugins.gae.task.GaeWebAppDirTask
+import org.gradle.api.plugins.gae.task.appcfg.*
+
+/**
+ *
A {@link Plugin} that provides tasks for uploading, running and managing of Google App Engine projects.
+ *
+ * @author Benjamin Muschko
+ */
+class GaePlugin implements Plugin {
+ static final String GAE_RUN = "gaeRun"
+ static final String GAE_ENHANCE = "gaeEnhance"
+ static final String GAE_UPLOAD = "gaeUpload"
+ static final String GAE_ROLLBACK = "gaeRollback"
+ static final String GAE_UPDATE_INDEXES = "gaeUpdateIndexes"
+ static final String GAE_VACUUM_INDEXES = "gaeVacuumIndexes"
+ static final String GAE_UPDATE_TASK_QUEUES = "gaeUpdateQueues"
+ static final String GAE_UPDATE_DOS = "gaeUpdateDos"
+ static final String GAE_UPDATE_CRON = "gaeUpdateCron"
+ static final String GAE_CRON_INFO = "gaeCronInfo"
+ static final String GAE_LOGS = "gaeLogs"
+ static final String GAE_VERSION = "gaeVersion"
+
+ @Override
+ public void apply(Project project) {
+ project.plugins.apply(WarPlugin.class)
+ GaePluginConvention gaePluginConvention = new GaePluginConvention()
+ project.convention.plugins.appengine = gaePluginConvention
+
+ configureWebAppDir(project)
+ configureEmail(project, gaePluginConvention)
+ configureGaeRun(project, gaePluginConvention)
+ configureGaeEnhance(project)
+ configureGaeUpload(project)
+ configureGaeRollback(project)
+ configureGaeUpdateIndexes(project)
+ configureGaeVacuumIndexes(project)
+ configureGaeUpdateTaskQueues(project)
+ configureGaeUpdateDoS(project)
+ configureGaeUpdateCron(project)
+ configureGaeCronInfo(project)
+ configureGaeDownloadLogs(project)
+ configureGaeVersion(project)
+ }
+
+ private void configureWebAppDir(final Project project) {
+ project.tasks.withType(GaeWebAppDirTask.class).whenTaskAdded { GaeWebAppDirTask gaeWebAppDirTask ->
+ gaeWebAppDirTask.conventionMapping.map("webAppSourceDirectory") { getWarConvention(project).webAppDir }
+ }
+ }
+
+ private void configureEmail(final Project project, GaePluginConvention gaePluginConvention) {
+ project.tasks.withType(GaeAppConfigTaskTemplate.class).whenTaskAdded { GaeAppConfigTaskTemplate gaeAppConfigTaskTemplate ->
+ gaeAppConfigTaskTemplate.conventionMapping.map("email") { gaePluginConvention.email }
+ gaeAppConfigTaskTemplate.conventionMapping.map("server") { gaePluginConvention.server }
+ gaeAppConfigTaskTemplate.conventionMapping.map("host") { gaePluginConvention.host }
+ gaeAppConfigTaskTemplate.conventionMapping.map("passIn") { gaePluginConvention.passIn }
+ gaeAppConfigTaskTemplate.conventionMapping.map("httpProxy") { gaePluginConvention.httpProxy }
+ gaeAppConfigTaskTemplate.conventionMapping.map("httpsProxy") { gaePluginConvention.httpsProxy }
+ }
+ }
+
+ private void configureGaeRun(final Project project, GaePluginConvention gaePluginConvention) {
+ project.tasks.withType(GaeRunTask.class).whenTaskAdded { GaeRunTask gaeRunTask ->
+ gaeRunTask.conventionMapping.map("httpPort") { gaePluginConvention.httpPort }
+ }
+
+ GaeRunTask gaeRunTask = project.tasks.add(GAE_RUN, GaeRunTask.class)
+ gaeRunTask.description = "Starts up a local App Engine development server."
+ gaeRunTask.group = WarPlugin.WEB_APP_GROUP
+ }
+
+ private void configureGaeEnhance(final Project project) {
+ project.tasks.withType(GaeEnhanceTask.class).whenTaskAdded { GaeEnhanceTask gaeEnhanceTask ->
+ gaeEnhanceTask.conventionMapping.map("sourceDirectories") { project.sourceSets.main.allSource.sourceTrees.srcDirs.flatten() as Set }
+ }
+
+ GaeEnhanceTask gaeEnhanceTask = project.tasks.add(GAE_ENHANCE, GaeEnhanceTask.class)
+ gaeEnhanceTask.description = "Enhances DataNucleus classes."
+ gaeEnhanceTask.group = "Compilation"
+ }
+
+ private void configureGaeUpload(final Project project) {
+ GaeUploadTask gaeUploadTask = project.tasks.add(GAE_UPLOAD, GaeUploadTask.class)
+ gaeUploadTask.description = "Uploads your application to App Engine."
+ gaeUploadTask.group = WarPlugin.WEB_APP_GROUP
+ }
+
+ private void configureGaeRollback(final Project project) {
+ GaeRollbackTask gaeRollbackTask = project.tasks.add(GAE_ROLLBACK, GaeRollbackTask.class)
+ gaeRollbackTask.description = "Undoes a partially completed update for the given application."
+ gaeRollbackTask.group = WarPlugin.WEB_APP_GROUP
+ }
+
+ private void configureGaeUpdateIndexes(final Project project) {
+ GaeUpdateIndexesTask gaeUpdateIndexesTask = project.tasks.add(GAE_UPDATE_INDEXES, GaeUpdateIndexesTask.class)
+ gaeUpdateIndexesTask.description = "Updates indexes on App Engine."
+ gaeUpdateIndexesTask.group = WarPlugin.WEB_APP_GROUP
+ }
+
+ private void configureGaeVacuumIndexes(final Project project) {
+ GaeVacuumIndexesTask gaeVacuumIndexesTask = project.tasks.add(GAE_VACUUM_INDEXES, GaeVacuumIndexesTask.class)
+ gaeVacuumIndexesTask.description = "Deletes unused indexes on App Engine."
+ gaeVacuumIndexesTask.group = WarPlugin.WEB_APP_GROUP
+ }
+
+ private void configureGaeUpdateTaskQueues(final Project project) {
+ GaeUpdateQueuesTask gaeUpdateQueuesTask = project.tasks.add(GAE_UPDATE_TASK_QUEUES, GaeUpdateQueuesTask.class)
+ gaeUpdateQueuesTask.description = "Updates task queues on App Engine."
+ gaeUpdateQueuesTask.group = WarPlugin.WEB_APP_GROUP
+ }
+
+ private void configureGaeUpdateDoS(final Project project) {
+ GaeUpdateDoSTask gaeUpdateDoSTask = project.tasks.add(GAE_UPDATE_DOS, GaeUpdateDoSTask.class)
+ gaeUpdateDoSTask.description = "Updates DoS protection configuration on App Engine."
+ gaeUpdateDoSTask.group = WarPlugin.WEB_APP_GROUP
+ }
+
+ private void configureGaeUpdateCron(final Project project) {
+ GaeUpdateCronTask gaeUpdateCronTask = project.tasks.add(GAE_UPDATE_CRON, GaeUpdateCronTask.class)
+ gaeUpdateCronTask.description = "Updates scheduled tasks definition (known as cron jobs) on App Engine."
+ gaeUpdateCronTask.group = WarPlugin.WEB_APP_GROUP
+ }
+
+ private void configureGaeCronInfo(final Project project) {
+ GaeCronInfoTask gaeCronInfoTask = project.tasks.add(GAE_CRON_INFO, GaeCronInfoTask.class)
+ gaeCronInfoTask.description = "Get cron information from App Engine."
+ gaeCronInfoTask.group = WarPlugin.WEB_APP_GROUP
+ }
+
+ private void configureGaeDownloadLogs(final Project project) {
+ GaeDownloadLogsTask gaeDownloadLogsTask = project.tasks.add(GAE_LOGS, GaeDownloadLogsTask.class)
+ gaeDownloadLogsTask.description = "Download logs from App Engine."
+ gaeDownloadLogsTask.group = WarPlugin.WEB_APP_GROUP
+ }
+
+ private void configureGaeVersion(final Project project) {
+ GaeVersionTask gaeVersionTask = project.tasks.add(GAE_VERSION, GaeVersionTask.class)
+ gaeVersionTask.description = "Prints detailed version information about the SDK, Java and the operating system."
+ gaeVersionTask.group = WarPlugin.WEB_APP_GROUP
+ }
+
+ private WarPluginConvention getWarConvention(Project project) {
+ project.convention.getPlugin(WarPluginConvention.class)
+ }
+}
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/GaePluginConvention.groovy b/src/main/groovy/org/gradle/api/plugins/gae/GaePluginConvention.groovy
new file mode 100755
index 0000000..84caec7
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/GaePluginConvention.groovy
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae
+
+/**
+ * Defines App Engine plugin convention.
+ *
+ * @author Benjamin Muschko
+ */
+class GaePluginConvention {
+ Integer httpPort = 8080
+ String email
+ String server
+ String host
+ boolean passIn
+ String httpProxy
+ String httpsProxy
+
+ def gae(Closure closure) {
+ closure.delegate = this
+ closure()
+ }
+}
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/AbstractGaeTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/AbstractGaeTask.groovy
new file mode 100755
index 0000000..56d19cb
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/AbstractGaeTask.groovy
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task
+
+import org.gradle.api.InvalidUserDataException
+import org.gradle.api.internal.ConventionTask
+import org.gradle.api.tasks.TaskAction
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+abstract class AbstractGaeTask extends ConventionTask {
+ static final Logger LOGGER = LoggerFactory.getLogger(AbstractGaeTask.class)
+ final String APPENGINE_HOME_ENV_PROP_KEY = "APPENGINE_HOME"
+ final String APPENGINE_SDK_ROOT_SYS_PROP_KEY = "appengine.sdk.root"
+ final String JAVA_CLASSPATH_SYS_PROP_KEY = "java.class.path"
+
+ @TaskAction
+ protected void start() {
+ validateConfiguration()
+ executeTask()
+ }
+
+ @Override
+ void validateConfiguration() {
+ validateAppEngineSdkRoot()
+ validateAppEngineToolsApiJar()
+ }
+
+ private void validateAppEngineSdkRoot() {
+ setAppEngineSdkRoot()
+ def appEngineSdkRoot = System.getProperty(APPENGINE_SDK_ROOT_SYS_PROP_KEY)
+
+ if(!appEngineSdkRoot) {
+ throw new InvalidUserDataException("""The App Engine SDK root was not set. Please make sure you set the environment
+ variable '${APPENGINE_HOME_ENV_PROP_KEY}' system property '${APPENGINE_SDK_ROOT_SYS_PROP_KEY}'!""")
+ }
+ else {
+ if(!new File(appEngineSdkRoot).isDirectory()) {
+ throw new InvalidUserDataException("Set App Engine SDK root directory does not exist: '${appEngineSdkRoot}'!")
+ }
+ }
+
+ LOGGER.info "App Engine SDK root = ${appEngineSdkRoot}"
+ }
+
+ private void setAppEngineSdkRoot() {
+ def appEngineSdkRoot = System.getProperty(APPENGINE_SDK_ROOT_SYS_PROP_KEY)
+
+ if(!appEngineSdkRoot) {
+ def appEngineHomeEnvVariable = System.getenv(APPENGINE_HOME_ENV_PROP_KEY)
+
+ if(appEngineHomeEnvVariable) {
+ System.setProperty APPENGINE_SDK_ROOT_SYS_PROP_KEY, appEngineHomeEnvVariable
+ }
+ }
+ }
+
+ private void validateAppEngineToolsApiJar() {
+ def fileSeparator = System.getProperty("file.separator")
+ def pathSeparator = File.pathSeparator
+ def appEngineSdkRoot = System.getProperty(APPENGINE_SDK_ROOT_SYS_PROP_KEY)
+ def javaClasspath = System.getProperty(JAVA_CLASSPATH_SYS_PROP_KEY)
+ def appEngineToolsApiJar = "${appEngineSdkRoot}${fileSeparator}lib${fileSeparator}appengine-tools-api.jar"
+
+ if(!new File(appEngineSdkRoot).exists()) {
+ throw new InvalidUserDataException("Required library 'appengine-tools-api.jar' could not be found in specified path: '${appEngineToolsApiJar}'!")
+ }
+
+ if(!javaClasspath.contains(appEngineToolsApiJar)) {
+ System.setProperty JAVA_CLASSPATH_SYS_PROP_KEY, "${javaClasspath}${pathSeparator}${appEngineToolsApiJar}"
+ }
+
+ LOGGER.info "Java classpath = ${System.getProperty('java.class.path')}"
+ }
+
+ abstract void executeTask()
+}
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/GaeEnhanceTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/GaeEnhanceTask.groovy
new file mode 100644
index 0000000..b1dba18
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/GaeEnhanceTask.groovy
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task
+
+import com.google.appengine.tools.enhancer.EnhancerTask
+import org.apache.tools.ant.Project
+import org.apache.tools.ant.types.FileSet
+import org.gradle.api.GradleException
+import org.gradle.api.tasks.InputFiles
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+/**
+ * Google App Engine task enhancing DataNucleus classes.
+ *
+ * @see Documentation
+ * @author Benjamin Muschko
+ */
+class GaeEnhanceTask extends GaeWebAppDirTask {
+ static final Logger logger = LoggerFactory.getLogger(GaeEnhanceTask.class)
+ private Set sourceDirectories
+
+ @Override
+ void executeTask() {
+ enhanceClasses()
+ }
+
+ private void enhanceClasses() {
+ try {
+ logger.info "Enhancing DataNucleus classes..."
+
+ def enhancerTask = new EnhancerTask()
+ enhancerTask.setEnhancerName "Gradle GAE plugin enhancer"
+ enhancerTask.setProject createProject()
+
+ getSourceDirectories().each { sourceDir ->
+ if(sourceDir.exists()) {
+ logger.info "Adding source dir '$sourceDir' for enhancement process."
+ def fileSet = new FileSet()
+ fileSet.setDir(sourceDir)
+ enhancerTask.addFileSet(fileSet)
+ }
+ else {
+ logger.debug "Available source directory '$sourceDir' does not exist. It will not be used for the enhancement process."
+ }
+ }
+
+ enhancerTask.execute()
+ }
+ catch(Exception e) {
+ throw new GradleException("An error occurred enhancing DataNucleus classes.", e)
+ }
+ finally {
+ logger.info "Finished enhancing DataNucleus classes."
+ }
+ }
+
+ private Project createProject() {
+ def project = new Project()
+
+ project.with {
+ setName "GAE project"
+ init()
+ }
+
+ project
+ }
+
+ @InputFiles
+ public Set getSourceDirectories() {
+ sourceDirectories
+ }
+
+ public void setSourceDirectories(Set sourceDirectories) {
+ this.sourceDirectories = sourceDirectories
+ }
+}
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/GaeRunTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/GaeRunTask.groovy
new file mode 100755
index 0000000..774c7de
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/GaeRunTask.groovy
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task
+
+import com.google.appengine.tools.KickStart
+import org.gradle.api.GradleException
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+/**
+ * Google App Engine task starting up a local development server.
+ *
+ * @see Documentation
+ * @author Benjamin Muschko
+ */
+class GaeRunTask extends GaeWebAppDirTask {
+ static final Logger logger = LoggerFactory.getLogger(GaeRunTask.class)
+ private Integer httpPort
+
+ @Override
+ void executeTask() {
+ startLocalDevelopmentServer()
+ }
+
+ void startLocalDevelopmentServer() {
+ try {
+ logger.info "Starting local development server..."
+
+ String[] params = ["com.google.appengine.tools.development.DevAppServerMain", "--port=" + getHttpPort(), getWebAppSourceDirectory().getCanonicalPath()] as String[]
+ KickStart.main(params)
+ }
+ catch(Exception e) {
+ throw new GradleException("An error occurred starting the local development server.", e)
+ }
+ finally {
+ logger.info "Local development server exiting."
+ }
+ }
+
+ public Integer getHttpPort() {
+ httpPort
+ }
+
+ public void setHttpPort(Integer httpPort) {
+ this.httpPort = httpPort
+ }
+}
+
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/GaeWebAppDirTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/GaeWebAppDirTask.groovy
new file mode 100755
index 0000000..05c156d
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/GaeWebAppDirTask.groovy
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task
+
+import org.gradle.api.InvalidUserDataException
+import org.gradle.api.tasks.InputDirectory
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+/**
+ * Abstract Google App Engine task that requires setting the web application dir.
+ *
+ * @author Benjamin Muschko
+ */
+abstract class GaeWebAppDirTask extends AbstractGaeTask {
+ static final Logger logger = LoggerFactory.getLogger(GaeWebAppDirTask.class)
+ private File webAppSourceDirectory
+
+ @Override
+ void validateConfiguration(){
+ super.validateConfiguration()
+
+ try {
+ if(!getWebAppSourceDirectory() || !getWebAppSourceDirectory().exists()) {
+ throw new InvalidUserDataException("Webapp source directory "
+ + (getWebAppSourceDirectory() == null ? "null" : getWebAppSourceDirectory().getCanonicalPath())
+ + " does not exist")
+ }
+ else {
+ logger.info "Webapp source directory = ${getWebAppSourceDirectory().getCanonicalPath()}"
+ }
+ }
+ catch(IOException e) {
+ throw new InvalidUserDataException("Webapp source directory does not exist", e)
+ }
+ }
+
+ @InputDirectory
+ public File getWebAppSourceDirectory() {
+ webAppSourceDirectory
+ }
+
+ public void setWebAppSourceDirectory(File webAppSourceDirectory) {
+ this.webAppSourceDirectory = webAppSourceDirectory
+ }
+}
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeAppConfigTaskTemplate.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeAppConfigTaskTemplate.groovy
new file mode 100755
index 0000000..73330d1
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeAppConfigTaskTemplate.groovy
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task.appcfg
+
+import com.google.appengine.tools.admin.AppCfg
+import org.gradle.api.GradleException
+import org.gradle.api.plugins.gae.task.GaeWebAppDirTask
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+/**
+ * Abstract Google App Engine task used for application configuration.
+ *
+ * @author Benjamin Muschko
+ */
+abstract class GaeAppConfigTaskTemplate extends GaeWebAppDirTask {
+ static final Logger LOGGER = LoggerFactory.getLogger(GaeAppConfigTaskTemplate.class)
+ private String email
+ private String server
+ private String host
+ private boolean passIn
+ private String httpProxy
+ private String httpsProxy
+
+ @Override
+ void executeTask() {
+ try {
+ LOGGER.info startLogMessage()
+
+ def params = []
+ addCommonParams(params)
+ params.addAll getParams()
+ LOGGER.info "Using params = $params"
+
+ AppCfg.main(params as String[])
+ }
+ catch(Exception e) {
+ throw new GradleException(errorLogMessage(), e)
+ }
+ finally {
+ LOGGER.info finishLogMessage()
+ }
+ }
+
+ private void addCommonParams(params) {
+ LOGGER.info "PASS IN : ${getPassIn()}"
+ if(getEmail()) {
+ params << "--email=${getEmail()}"
+ }
+
+ if(getServer()) {
+ params << "--server=${getServer()}"
+ }
+
+ if(getHost()) {
+ params << "--host=${getHost()}"
+ }
+
+ if(getPassIn()) {
+ params << "--passin"
+ }
+
+ if(getHttpProxy()) {
+ params << "--proxy=${getHttpProxy()}"
+ }
+
+ if(getHttpsProxy()) {
+ params << "--proxy_https=${getHttpsProxy()}"
+ }
+ }
+
+ public String getEmail() {
+ email
+ }
+
+ public void setEmail(String email) {
+ this.email = email
+ }
+
+ public String getServer() {
+ server
+ }
+
+ public void setServer(String server) {
+ this.server = server
+ }
+
+ public String getHost() {
+ host
+ }
+
+ public void setHost(String host) {
+ this.host = host
+ }
+
+ public boolean getPassIn() {
+ passIn
+ }
+
+ public void setPassIn(boolean passIn) {
+ this.passIn = passIn
+ }
+
+ public String getHttpProxy() {
+ httpProxy
+ }
+
+ public void setHttpProxy(String httpProxy) {
+ this.httpProxy = httpProxy
+ }
+
+ public String getHttpsProxy() {
+ httpsProxy
+ }
+
+ public void setHttpsProxy(String httpsProxy) {
+ this.httpsProxy = httpsProxy
+ }
+
+ abstract String startLogMessage()
+ abstract String errorLogMessage()
+ abstract String finishLogMessage()
+ abstract List getParams()
+}
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeCronInfoTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeCronInfoTask.groovy
new file mode 100755
index 0000000..5fd0721
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeCronInfoTask.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task.appcfg
+
+/**
+ * Google App Engine task pulling cron information from the server.
+ *
+ * @see Documentation
+ * @author Benjamin Muschko
+ */
+class GaeCronInfoTask extends GaeAppConfigTaskTemplate {
+ final String COMMAND = "cron_info"
+
+ @Override
+ String startLogMessage() {
+ "Starting getting cron information..."
+ }
+
+ @Override
+ String errorLogMessage() {
+ "An error occurred getting cron information."
+ }
+
+ @Override
+ String finishLogMessage() {
+ "Finished getting cron information."
+ }
+
+ @Override
+ List getParams() {
+ [COMMAND, getWebAppSourceDirectory().getCanonicalPath()]
+ }
+}
\ No newline at end of file
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeDownloadLogsTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeDownloadLogsTask.groovy
new file mode 100755
index 0000000..a86452b
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeDownloadLogsTask.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task.appcfg
+
+/**
+ * Google App Engine task downloading application logs from the server.
+ *
+ * @see Documentation
+ * @author Benjamin Muschko
+ */
+class GaeDownloadLogsTask extends GaeAppConfigTaskTemplate {
+ final String COMMAND = "request_logs"
+
+ @Override
+ String startLogMessage() {
+ "Starting downloading logs process..."
+ }
+
+ @Override
+ String errorLogMessage() {
+ "An error occurred downloading logs from App Engine."
+ }
+
+ @Override
+ String finishLogMessage() {
+ "Finished downloading logs process."
+ }
+
+ @Override
+ List getParams() {
+ [COMMAND, getWebAppSourceDirectory().getCanonicalPath(), "somefile.txt"]
+ }
+}
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeRollbackTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeRollbackTask.groovy
new file mode 100644
index 0000000..1c97e29
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeRollbackTask.groovy
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task.appcfg
+
+/**
+ * Google App Engine task undoing a partially completed update for the given application.
+ *
+ * @author Benjamin Muschko
+ */
+class GaeRollbackTask extends GaeAppConfigTaskTemplate {
+ final String COMMAND = "rollback"
+
+ @Override
+ String startLogMessage() {
+ "Starting to rollback update..."
+ }
+
+ @Override
+ String errorLogMessage() {
+ "An error occurred rolling back update."
+ }
+
+ @Override
+ String finishLogMessage() {
+ "Finished rolling back update."
+ }
+
+ @Override
+ List getParams() {
+ [COMMAND, getWebAppSourceDirectory().getCanonicalPath()]
+ }
+}
\ No newline at end of file
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUpdateCronTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUpdateCronTask.groovy
new file mode 100755
index 0000000..d9f2203
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUpdateCronTask.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task.appcfg
+
+/**
+ * Google App Engine task updating cron definition on the server.
+ *
+ * @see Documentation
+ * @author Benjamin Muschko
+ */
+class GaeUpdateCronTask extends GaeAppConfigTaskTemplate {
+ final String COMMAND = "update_cron"
+
+ @Override
+ String startLogMessage() {
+ "Starting updating scheduled tasks..."
+ }
+
+ @Override
+ String errorLogMessage() {
+ "An error occurred updating scheduled tasks."
+ }
+
+ @Override
+ String finishLogMessage() {
+ "Finished updating scheduled tasks."
+ }
+
+ @Override
+ List getParams() {
+ [COMMAND, getWebAppSourceDirectory().getCanonicalPath()]
+ }
+}
\ No newline at end of file
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUpdateDoSTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUpdateDoSTask.groovy
new file mode 100755
index 0000000..56d1be9
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUpdateDoSTask.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task.appcfg
+
+/**
+ * Google App Engine task updating DoS protection configuration on the server.
+ *
+ * @see Documentation
+ * @author Benjamin Muschko
+ */
+class GaeUpdateDoSTask extends GaeAppConfigTaskTemplate {
+ final String COMMAND = "update_cron"
+
+ @Override
+ String startLogMessage() {
+ "Starting updating DoS protection configuration..."
+ }
+
+ @Override
+ String errorLogMessage() {
+ "An error occurred updating DoS protection configuration."
+ }
+
+ @Override
+ String finishLogMessage() {
+ "Finished updating DoS protection configuration."
+ }
+
+ @Override
+ List getParams() {
+ [COMMAND, getWebAppSourceDirectory().getCanonicalPath()]
+ }
+}
\ No newline at end of file
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUpdateIndexesTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUpdateIndexesTask.groovy
new file mode 100755
index 0000000..7b20c26
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUpdateIndexesTask.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task.appcfg
+
+/**
+ * Google App Engine task updating indexes on the server.
+ *
+ * @see Documentation
+ * @author Benjamin Muschko
+ */
+class GaeUpdateIndexesTask extends GaeAppConfigTaskTemplate {
+ final String COMMAND = "update_indexes"
+
+ @Override
+ String startLogMessage() {
+ "Starting updating indexes..."
+ }
+
+ @Override
+ String errorLogMessage() {
+ "An error occurred updating indexes."
+ }
+
+ @Override
+ String finishLogMessage() {
+ "Finished updating indexes."
+ }
+
+ @Override
+ List getParams() {
+ [COMMAND, getWebAppSourceDirectory().getCanonicalPath()]
+ }
+}
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUpdateQueuesTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUpdateQueuesTask.groovy
new file mode 100755
index 0000000..597b730
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUpdateQueuesTask.groovy
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task.appcfg
+
+/**
+ * Google App Engine task updating task queue configuration on the server.
+ *
+ * @see Documentation
+ * @author Benjamin Muschko
+ */
+class GaeUpdateQueuesTask extends GaeAppConfigTaskTemplate {
+ final String COMMAND = "update_queues"
+
+ @Override
+ String startLogMessage() {
+ "Starting updating task queues..."
+ }
+
+ @Override
+ String errorLogMessage() {
+ "An error occurred updating task queues."
+ }
+
+ @Override
+ String finishLogMessage() {
+ "Finished updating task queues."
+ }
+
+ @Override
+ List getParams() {
+ [COMMAND, getWebAppSourceDirectory().getCanonicalPath()]
+ }
+}
+
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUploadTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUploadTask.groovy
new file mode 100755
index 0000000..4850ef6
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeUploadTask.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task.appcfg
+
+/**
+ * Google App Engine task uploading your application to the server.
+ *
+ * @see Documentation
+ * @author Benjamin Muschko
+ */
+class GaeUploadTask extends GaeAppConfigTaskTemplate {
+ final String COMMAND = "update"
+
+ @Override
+ String startLogMessage() {
+ "Starting upload process..."
+ }
+
+ @Override
+ String errorLogMessage() {
+ "An error occurred uploading the application to App Engine."
+ }
+
+ @Override
+ String finishLogMessage() {
+ "Finished uploading process."
+ }
+
+ @Override
+ List getParams() {
+ [COMMAND, getWebAppSourceDirectory().getCanonicalPath()]
+ }
+}
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeVacuumIndexesTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeVacuumIndexesTask.groovy
new file mode 100755
index 0000000..93c377b
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeVacuumIndexesTask.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task.appcfg
+
+/**
+ * Google App Engine task deleting unused indexes on the server.
+ *
+ * @see Documentation
+ * @author Benjamin Muschko
+ */
+class GaeVacuumIndexesTask extends GaeAppConfigTaskTemplate {
+ final String COMMAND = "vacuum_indexes"
+
+ @Override
+ String startLogMessage() {
+ "Starting deleting unused indexes..."
+ }
+
+ @Override
+ String errorLogMessage() {
+ "An error occurred deleting unused indexes."
+ }
+
+ @Override
+ String finishLogMessage() {
+ "Finished deleting unused indexes."
+ }
+
+ @Override
+ List getParams() {
+ [COMMAND, getWebAppSourceDirectory().getCanonicalPath()]
+ }
+}
diff --git a/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeVersionTask.groovy b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeVersionTask.groovy
new file mode 100644
index 0000000..78daf0c
--- /dev/null
+++ b/src/main/groovy/org/gradle/api/plugins/gae/task/appcfg/GaeVersionTask.groovy
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.gradle.api.plugins.gae.task.appcfg
+
+/**
+ * Google App Engine task printing detailed version information about the SDK, Java and the operating system.
+ *
+ * @author Benjamin Muschko
+ */
+class GaeVersionTask extends GaeAppConfigTaskTemplate {
+ final String COMMAND = "version"
+
+ @Override
+ String startLogMessage() {
+ "Starting to get version information..."
+ }
+
+ @Override
+ String errorLogMessage() {
+ "An error occurred getting version information."
+ }
+
+ @Override
+ String finishLogMessage() {
+ "Finished to get version information."
+ }
+
+ @Override
+ List getParams() {
+ [COMMAND]
+ }
+}
diff --git a/src/main/resources/META-INF/gradle-plugins/gae.properties b/src/main/resources/META-INF/gradle-plugins/gae.properties
new file mode 100755
index 0000000..bed522e
--- /dev/null
+++ b/src/main/resources/META-INF/gradle-plugins/gae.properties
@@ -0,0 +1,16 @@
+#
+# Copyright 2011 the original author or authors.
+#
+# 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.
+#
+implementation-class=org.gradle.api.plugins.gae.GaePlugin