├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build.sbt ├── notes ├── 0.2.markdown ├── 0.3.0.markdown ├── 0.3.1.markdown ├── 0.4.0.markdown ├── 0.4.1.markdown ├── 0.4.2.markdown ├── 0.5.0.markdown ├── 0.6.0.markdown ├── 0.6.1.markdown ├── 0.6.2.markdown ├── 0.7.0.markdown ├── 0.8.0.markdown └── about.markdown ├── project ├── build.properties ├── plugin.sbt └── scripted.sbt ├── scripted.sbt └── src ├── main ├── scala-2.10 │ └── Compat.scala ├── scala-2.12 │ └── Compat.scala └── scala │ ├── AppenginePlugin.scala │ └── SbtCompat.scala └── sbt-test └── sbt-appengine ├── helloxmpp ├── COPYING ├── README ├── build.sbt ├── build.xml ├── project │ └── plugins.sbt ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── google │ │ │ └── appengine │ │ │ └── demos │ │ │ └── helloxmpp │ │ │ └── HelloXmpp.java │ │ └── webapp │ │ └── WEB-INF │ │ ├── appengine-web.xml │ │ ├── classes │ │ └── README │ │ └── web.xml └── test └── simple ├── build.sbt ├── project └── plugins.sbt ├── src └── main │ ├── resources │ └── META-INF │ │ └── jdoconfig.xml │ ├── scala │ ├── counter.scala │ ├── echofilter.scala │ └── pmf.scala │ └── webapp │ ├── WEB-INF │ ├── appengine-web.xml │ └── web.xml │ └── index.html └── test /.gitignore: -------------------------------------------------------------------------------- 1 | lib_managed/ 2 | project/boot/ 3 | project/build/target/ 4 | project/plugins/lib_managed/ 5 | project/plugins/src_managed/ 6 | project/plugins/target/ 7 | target/ 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: scala 3 | dist: trusty 4 | matrix: 5 | include: 6 | - env: SBT_VERSION="0.13.18" 7 | jdk: openjdk7 8 | - env: SBT_VERSION="1.0.4" 9 | jdk: oraclejdk8 10 | cache: 11 | directories: 12 | - $HOME/gae-sdk 13 | before_install: 14 | - pushd $HOME/gae-sdk 15 | - SDK=appengine-java-sdk-1.9.76 16 | - SDK_ZIP=$SDK.zip 17 | - wget -N https://storage.googleapis.com/appengine-sdks/featured/$SDK_ZIP 18 | - unzip $SDK_ZIP 19 | - export APPENGINE_SDK_HOME=$HOME/gae-sdk/$SDK 20 | - popd 21 | before_cache: 22 | - rm -rf $HOME/gae-sdk/$SDK/ 23 | script: 24 | - sbt "^^ ${SBT_VERSION}" compile test scripted 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, 2011 e.e d3si9n 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sbt-appengine is a sbt 0.10+ port of the awesome [Yasushi/sbt-appengine-plugin][1]. 2 | 3 | # https://github.com/sbt/sbt-appengine/issues/59 4 | 5 | requirements 6 | ------------ 7 | 8 | export environment variables (`JREBEL_PATH` is optional). 9 | 10 | export APPENGINE_SDK_HOME=/Applications/appengine-java-sdk-1.6.2.1 11 | export JREBEL_PATH=/Applications/ZeroTurnaround/JRebel/jrebel.jar 12 | 13 | If you have problems setting the APPENGINE_SDK_HOME environment variable (for example if you're using IntelliJ), then you can instead create a `appengine.properties` file with a single line of `sdkHome=/Applications/appengine-java-sdk-1.6.2.1`. 14 | 15 | setup for sbt 0.13 and sbt 1.x 16 | ------------------ 17 | 18 | put the following in the `project/appengine.sbt`: 19 | 20 | ```scala 21 | addSbtPlugin("com.eed3si9n" % "sbt-appengine" % "0.8.0") 22 | ``` 23 | 24 | and the following in `appengine.sbt`: 25 | 26 | ```scala 27 | libraryDependencies += "org.mortbay.jetty" % "jetty" % "6.1.22" % "container" 28 | 29 | enablePlugins(AppenginePlugin) 30 | ``` 31 | 32 | setup for sbt 0.12 33 | ------------------ 34 | 35 | see 36 | 37 | usage 38 | ----- 39 | 40 | ### deploy 41 | 42 | you can deploy your application like this: 43 | 44 | > appengineDeploy 45 | 46 | ### development server 47 | 48 | to (re)start the development server in the background: 49 | 50 | > appengineDevServer 51 | 52 | to redeploy development server continuously: 53 | 54 | > ~ appengineDevServer 55 | 56 | ### hot loading! 57 | 58 | to hot reload development server continuously, set `JREBEL_PATH` and: 59 | 60 | > appengineDevServer 61 | > ~ packageWar 62 | 63 | by default development server runs in debug mode. IDE can connect to it via port 1044. 64 | 65 | ### appengineDevServer lifecyle hooks 66 | 67 | to run a code on start/stop of dev server: 68 | 69 | ```scala 70 | (appengineOnStartHooks in appengineDevServer in Compile) += { () => 71 | println("hello") 72 | } 73 | 74 | (appengineOnStopHooks in appengineDevServer in Compile) += { () => 75 | println("bye") 76 | } 77 | ``` 78 | 79 | ### backend support 80 | 81 | you can deploy your backend application(s) like this: 82 | 83 | > appengineDeployBackends 84 | 85 | to start a backend instance in the cloud: 86 | 87 | > appengineStartBackend 88 | 89 | to stop a backend instance: 90 | 91 | > appengineStopBackend 92 | 93 | ### DataNucleous enhancer support (experimental) 94 | 95 | sbt-appengine provides experimental support for DataNucleous enhancer. to use this, include the following in `build.sbt`: 96 | 97 | ```scala 98 | enablePlugins(AppenginePlugin) 99 | 100 | appengineDataNucleusSettings 101 | 102 | appenginePersistenceApi in appengineEnhance in Compile := "JDO" 103 | ``` 104 | 105 | this will call the enhancer automatically on `packageWar` task. since DataNucleous expects plain Java fields, the entity class looks a bit ugly in Scala: 106 | 107 | ```scala 108 | import javax.jdo.annotations._ 109 | import com.google.appengine.api.datastore.Key 110 | import scala.annotation.meta.field 111 | 112 | @PersistenceCapable 113 | case class Counter( 114 | @(PrimaryKey @field) 115 | @(Persistent @field)(valueStrategy = IdGeneratorStrategy.IDENTITY) 116 | var key: Key, 117 | @(Persistent @field) 118 | var count: Int) 119 | ``` 120 | 121 | sample 122 | ------ 123 | 124 | - [simple sample][3] 125 | 126 | note 127 | ---- 128 | 129 | When trying to launch the dev server with `appengineDevServer`, you might run 130 | into the following exception: `java.lang.RuntimeException: Unable to restore the previous TimeZone`. 131 | [This issue][4] has been resolved in the latest App Engine SDK. 132 | 133 | [1]: https://github.com/Yasushi/sbt-appengine-plugin 134 | [2]: https://github.com/Yasushi 135 | [3]: https://github.com/sbt/sbt-appengine/tree/master/src/sbt-test/sbt-appengine/simple 136 | [4]: http://code.google.com/p/googleappengine/issues/detail?id=6928 137 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | sbtPlugin := true 2 | 3 | crossSbtVersions := Seq("1.0.4", "0.13.18") 4 | 5 | name := "sbt-appengine" 6 | 7 | organization := "com.eed3si9n" 8 | 9 | version := "0.8.2-SNAPSHOT" 10 | 11 | description := "sbt plugin to deploy on appengine" 12 | 13 | licenses := Seq("MIT License" -> url("https://github.com/sbt/sbt-appengine/blob/master/LICENSE")) 14 | 15 | libraryDependencies += Defaults.sbtPluginExtra( 16 | "com.earldouglas" % "xsbt-web-plugin" % "4.2.1", 17 | (sbtBinaryVersion in pluginCrossBuild).value, 18 | (scalaBinaryVersion in pluginCrossBuild).value 19 | ) 20 | 21 | libraryDependencies += Defaults.sbtPluginExtra( 22 | "io.spray" % "sbt-revolver" % "0.9.1", 23 | (sbtBinaryVersion in pluginCrossBuild).value, 24 | (scalaBinaryVersion in pluginCrossBuild).value 25 | ) 26 | 27 | scalacOptions := Seq("-deprecation", "-unchecked") 28 | 29 | credentials += Credentials(Path.userHome / ".ivy2" / ".credentials") 30 | 31 | publishArtifact in (Compile, packageBin) := true 32 | 33 | publishArtifact in (Test, packageBin) := false 34 | 35 | publishArtifact in (Compile, packageDoc) := false 36 | 37 | publishArtifact in (Compile, packageSrc) := false 38 | 39 | resolvers += "spray repo" at "http://repo.spray.cc" 40 | 41 | publishMavenStyle := false 42 | 43 | credentials += Credentials(Path.userHome / ".ivy2" / ".sbtcredentials") 44 | 45 | bintrayRepository := "sbt-plugin-releases" 46 | 47 | bintrayOrganization := Some("sbt") 48 | 49 | bintrayPackage := "sbt-appengine" 50 | -------------------------------------------------------------------------------- /notes/0.2.markdown: -------------------------------------------------------------------------------- 1 | - cross published for sbt 0.10.0 and 0.10.1. 2 | 3 | libraryDependencies <+= (sbtVersion) { sv => "com.eed3si9n" %% "sbt-appengine" % ("sbt" + sv + "_0.2") } -------------------------------------------------------------------------------- /notes/0.3.0.markdown: -------------------------------------------------------------------------------- 1 | ## breaking changes 2 | In an effort to solve namespace conflicts and to increase consistency among the plugins, a number of sbt plugin authors have discussed on the mailing list, and come up with [sbt plugins best practices](https://github.com/harrah/xsbt/wiki/Plugins-Best-Practices). Here are the changes: 3 | 4 | ### keys are under `AppengineKeys` object 5 | Keys provided by sbt-appengine now resides in `AppengineKeys` object. If you do rewire any of the keys in `build.sbt`, place the following at the top of file: 6 | 7 | import sbtappengine.Plugin.{AppengineKeys => gae} 8 | 9 | Instead of the custom `Appengine` config, settings are by default loaded on `Compile`: 10 | 11 | gae.classpath in Compile := ... 12 | 13 | Key names accessible from the shell are now prefixed with `appengine-` (e.g. `appengine-deploy`). To deploy you app to the appengine: 14 | 15 | > appengine-deploy 16 | -------------------------------------------------------------------------------- /notes/0.3.1.markdown: -------------------------------------------------------------------------------- 1 | - xsbt-web-plugin 0.2.10. see [web plugin's wiki][1] for details on setting. 2 | 3 | [1]: https://github.com/siasia/xsbt-web-plugin/wiki 4 | -------------------------------------------------------------------------------- /notes/0.4.0.markdown: -------------------------------------------------------------------------------- 1 | ## sbt-appengine + sbt-revolver = hot reloading dev server 2 | 3 | One glaring omission in [sbt-appengine][1] when it was ported from [@Yasushi][1]'s [sbt-appengine-plugin][3] was the ability to run development server locally from sbt shell. 4 | 5 | sbt-appengine 0.4.0 adds a new task: 6 | 7 | > appengine-dev-server 8 | 9 | This (re)starts development server in the background managed by sbt-revolver. This also allows triggered redeployment: 10 | 11 | > ~ appengine-dev-server 12 | 13 | But wait there's more! By installing [JRebel][4] (there's a free Scala license) and setting the path as: 14 | 15 | export JREBEL_PATH=/Applications/ZeroTurnaround/JRebel/jrebel.jar 16 | 17 | development server launches under JRebel. This allows hot reloading: 18 | 19 | > appengine-dev-server 20 | > ~ package-war 21 | 22 | You change your code, and it reflects to http://localhost:8080/ automatically. This feature was implemented by [@philcali][philcali] and [@eed3si9n][eed3si9n]. 23 | 24 | ## how to install 25 | 26 | The use of sbt-revolver requires an additional resolver in `plugins.sbt`: 27 | 28 | addSbtPlugin("com.eed3si9n" % "sbt-appengine" % "0.4.0") 29 | 30 | resolvers ++= Seq( 31 | "spray repo" at "http://repo.spray.cc", 32 | Resolver.url("sbt-plugin-releases", 33 | url("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases/"))(Resolver.ivyStylePatterns) 34 | ) 35 | 36 | [1]: https://github.com/sbt/sbt-appengine 37 | [2]: https://github.com/Yasushi 38 | [3]: https://github.com/Yasushi/sbt-appengine-plugin 39 | [4]: http://zeroturnaround.com/jrebel/ 40 | [eed3si9n]: https://github.com/eed3si9n 41 | [philcali]: https://github.com/philcali 42 | -------------------------------------------------------------------------------- /notes/0.4.1.markdown: -------------------------------------------------------------------------------- 1 | ## bug fixes and minor enhancements 2 | 3 | - Adds debugging JVM options to the dev server. [#12][12] reported by [@greenrd][@greenrd] 4 | - Uses alternative path for the local datastore backing for the dev server. [#14][14] reported by [@greenrd][@greenrd] 5 | - Adds static files to the watched sources during [triggered execution][t]. [#15][15] reported by [@greenrd][@greenrd] 6 | - Includes appengine sdk jars into the generated war to fix the dev server. [#16][16] reported by [@mmakowski][@mmakowski] 7 | 8 | [12]: https://github.com/sbt/sbt-appengine/issues/12 9 | [14]: https://github.com/sbt/sbt-appengine/issues/14 10 | [15]: https://github.com/sbt/sbt-appengine/issues/15 11 | [16]: https://github.com/sbt/sbt-appengine/issues/16 12 | [@mmakowski]: https://github.com/mmakowski 13 | [@greenrd]: https://github.com/greenrd 14 | [t]: http://www.scala-sbt.org/release/docs/Howto/triggered.html 15 | -------------------------------------------------------------------------------- /notes/0.4.2.markdown: -------------------------------------------------------------------------------- 1 | ## bug fixes and minor enhancements 2 | 3 | - Prevent dev server from showing up on OSX Dock. [#21][21] reported by [@stephanos][@stephanos] 4 | 5 | [21]: https://github.com/sbt/sbt-appengine/issues/21 6 | [@stephanos]: https://github.com/stephanos 7 | -------------------------------------------------------------------------------- /notes/0.5.0.markdown: -------------------------------------------------------------------------------- 1 | ## Backends command support 2 | 3 | [Backends Java API Overview][backends]: 4 | 5 | > App Engine Backends are instances of your application that are exempt from request deadlines and have access to more memory and CPU than normal instances. 6 | 7 | [@stephanos][@stephanos] contributed commands to manage backends [#23][23]. 8 | 9 | To deploy your backend application(s): 10 | 11 | > appengine-deploy-backends 12 | 13 | To start a backend instance in the cloud: 14 | 15 | > appengine-start-backend 16 | 17 | To stop a backend instance: 18 | 19 | > appengine-stop-backend 20 | 21 | [backends]: https://developers.google.com/appengine/docs/java/backends/overview 22 | [@stephanos]: https://github.com/stephanos 23 | [23]: https://github.com/sbt/sbt-appengine/pull/23 24 | -------------------------------------------------------------------------------- /notes/0.6.0.markdown: -------------------------------------------------------------------------------- 1 | [@stephanos]: https://github.com/stephanos 2 | [25]: https://github.com/sbt/sbt-appengine/pull/25 3 | 4 | ## for sbt 0.13 5 | 6 | sbt-appengine is ported to sbt 0.13. Its dependencies are updated to xsbt-web-plugin 0.4.0 and sbt-revolver 0.7.1. 7 | 8 | ## appengineDevServer lifecyle hooks 9 | 10 | sbt-appengine 0.6.0 adds hooks to `appengineDevServer` on start and stop. 11 | 12 | (gae.onStartHooks in gae.devServer in Compile) += { () => 13 | println("hello") 14 | } 15 | 16 | This feature was contributed by [@stephanos][@stephanos] as [#25][25]. 17 | 18 | ## DataNucleus enhancer support 19 | 20 | sbt-appengine 0.6.0 also adds experimental support for DataNucleous enhancer. See [details](https://github.com/sbt/sbt-appengine#datanucleous-enhancer-support-experimental). 21 | -------------------------------------------------------------------------------- /notes/0.6.1.markdown: -------------------------------------------------------------------------------- 1 | [28]: https://github.com/sbt/sbt-appengine/pull/28 2 | [@aij]: https://github.com/aij 3 | 4 | ## bug fix 5 | 6 | - Fixes backends tasks that broke in 0.6.0. [#28][28] contributed by [@aij][@aij] 7 | -------------------------------------------------------------------------------- /notes/0.6.2.markdown: -------------------------------------------------------------------------------- 1 | [32]: https://github.com/sbt/sbt-appengine/pull/32 2 | [@int128]: https://github.com/int128 3 | 4 | ## bug fix 5 | 6 | - Fixes invalid jar file error with SDK 1.9.10. [#32][32] by [@int128][@int128] 7 | -------------------------------------------------------------------------------- /notes/0.7.0.markdown: -------------------------------------------------------------------------------- 1 | - [fix "field" annotation package in README](https://github.com/sbt/sbt-appengine/commit/47a5805c697c2f81171902e4b4fa04fbb04a0802) 2 | - [update dependency in test project](https://github.com/sbt/sbt-appengine/commit/e235ec36d47c9df48a2fb9b0c7c41c6ecf20e2a9) 3 | - [migrate to AutoPlugin](https://github.com/sbt/sbt-appengine/pull/45) 4 | - [fix url in test](https://github.com/sbt/sbt-appengine/commit/c265823712217df5372e026fbe645630558701a4) 5 | - [execute scripted test in travis-ci](https://github.com/sbt/sbt-appengine/commit/f467b979217c46c1329c3b76db6a4ae5accb3918) 6 | - [update sbt-revolver 0.8.0 (#43)](https://github.com/sbt/sbt-appengine/commit/5c8ec26bfa79ef0a61636535a0e45a3457ac70a4) 7 | - [update sbt 0.13.15. fix warnings](https://github.com/sbt/sbt-appengine/commit/b9850f63ccd3ac05a4056c475558996cdf93caf5) 8 | - [remove ls](https://github.com/sbt/sbt-appengine/commit/5866f3e1cc0c09c01ee5e030d6139de1b21095df) 9 | - [drop old sbt support (#40)](https://github.com/sbt/sbt-appengine/commit/ecfd10eb60cc185a6c78ed773a62a3c9e322314b) 10 | - [add .travis.yml](https://github.com/sbt/sbt-appengine/commit/ea1974091164935571b0d0a66bdba3309559245b) 11 | -------------------------------------------------------------------------------- /notes/0.8.0.markdown: -------------------------------------------------------------------------------- 1 | - [fix warning](https://github.com/sbt/sbt-appengine/commit/0cadd24981c31db7a2cf61ef1f12511db0393814) 2 | - [support sbt 1.0](https://github.com/sbt/sbt-appengine/commit/2940a4bd8bd40f7bb400bb61c58ef85f4b0ea6a5) 3 | - [fix deprecation warning](https://github.com/sbt/sbt-appengine/commit/22082783769048e98ec04a88191677a9d9867a70) 4 | - [xsbt-web-plugin 4.0.1](https://github.com/sbt/sbt-appengine/commit/de36ba3812a9e213999b4e1c9128be481fadf292) 5 | - [sbt 0.13.16](https://github.com/sbt/sbt-appengine/commit/343609223a7e61fd713b17de7c21c162d4d957a3) 6 | - [Update README to include appengine.properties](https://github.com/sbt/sbt-appengine/commit/9b1f1a8969dcb6265cc423f73204f5b36f885b1a) 7 | - [Allow for reading the Appengine SDK path from a properties file if not in the environment. (#52)](https://github.com/sbt/sbt-appengine/commit/432091ec84ef771870dead5a9359eac297d99394) 8 | - [sbt-revolver 0.9.0](https://github.com/sbt/sbt-appengine/commit/6bc79730cec7b7861630d517f8c5c72a207d7900) 9 | -------------------------------------------------------------------------------- /notes/about.markdown: -------------------------------------------------------------------------------- 1 | [sbt-appengine](https://github.com/sbt/sbt-appengine) is a plug-in for sbt that automates Google App Engine deployment. 2 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.18 2 | -------------------------------------------------------------------------------- /project/plugin.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.6") 2 | -------------------------------------------------------------------------------- /project/scripted.sbt: -------------------------------------------------------------------------------- 1 | libraryDependencies += "org.scala-sbt" % "scripted-plugin" % sbtVersion.value 2 | -------------------------------------------------------------------------------- /scripted.sbt: -------------------------------------------------------------------------------- 1 | ScriptedPlugin.scriptedSettings 2 | 3 | scriptedLaunchOpts ++= sys.process.javaVmArguments.filter( 4 | a => Seq("-Xmx", "-Xms", "-XX", "-Dsbt.log.noformat").exists(a.startsWith) 5 | ) 6 | 7 | scriptedLaunchOpts += ("-Dplugin.version=" + version.value) 8 | 9 | scriptedBufferLog := false 10 | -------------------------------------------------------------------------------- /src/main/scala-2.10/Compat.scala: -------------------------------------------------------------------------------- 1 | package sbtappengine 2 | 3 | private[sbtappengine] object Compat { 4 | type Process = sbt.Process 5 | val Process = sbt.Process 6 | 7 | implicit class ForkOptionsOps(val self: sbt.ForkOptions) extends AnyVal { 8 | def withRunJVMOptions(runJVMOptions: Seq[String]): sbt.ForkOptions = 9 | self.copy(runJVMOptions = runJVMOptions) 10 | def withOutputStrategy(outputStrategy: sbt.OutputStrategy): sbt.ForkOptions = 11 | self.copy(outputStrategy = Option(outputStrategy)) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/scala-2.12/Compat.scala: -------------------------------------------------------------------------------- 1 | package sbtappengine 2 | 3 | private[sbtappengine] object Compat { 4 | type Process = scala.sys.process.Process 5 | val Process = scala.sys.process.Process 6 | } 7 | -------------------------------------------------------------------------------- /src/main/scala/AppenginePlugin.scala: -------------------------------------------------------------------------------- 1 | package sbtappengine 2 | 3 | import java.util.Properties 4 | 5 | import sbt._ 6 | import spray.revolver.RevolverPlugin 7 | import sbtappengine.Compat.{Process, _} 8 | 9 | @deprecated("will be removed. use enablePlugins(AppenginePlugin)", "0.7.0") 10 | object Plugin { 11 | val AppengineKeys = AppenginePlugin.autoImport.AppengineKeys 12 | val appengineSettings = AppenginePlugin.projectSettings 13 | } 14 | 15 | object AppenginePlugin extends AutoPlugin { 16 | import Keys._ 17 | import Def.Initialize 18 | import com.earldouglas.xwp.ContainerPlugin 19 | import com.earldouglas.xwp.WarPlugin 20 | import com.earldouglas.xwp.WebappPlugin.autoImport.webappPrepare 21 | import spray.revolver 22 | import revolver.Actions._ 23 | import revolver.Utilities._ 24 | 25 | override def requires = sbt.plugins.JvmPlugin && WarPlugin && ContainerPlugin 26 | 27 | object autoImport { 28 | @deprecated("", "") 29 | object AppengineKeys extends revolver.RevolverKeys 30 | 31 | lazy val appengineRequestLogs = InputKey[Unit]("appengine-request-logs", "Write request logs in Apache common log format.") 32 | lazy val appengineRollback = InputKey[Unit]("appengine-rollback", "Rollback an in-progress update.") 33 | lazy val appengineDeploy = InputKey[Unit]("appengine-deploy", "Create or update an app version.") 34 | lazy val appengineDeployBackends = InputKey[Unit]("appengine-deploy-backends", "Update the specified backend or all backends.") 35 | lazy val appengineRollbackBackend = InputKey[Unit]("appengine-rollback-backends", "Roll back a previously in-progress update.") 36 | lazy val appengineConfigBackends = InputKey[Unit]("appengine-config-backends", "Configure the specified backend.") 37 | lazy val appengineStartBackend = InputKey[Unit]("appengine-start-backend", "Start the specified backend.") 38 | lazy val appengineStopBackend = InputKey[Unit]("appengine-stop-backend", "Stop the specified backend.") 39 | lazy val appengineDeleteBackend = InputKey[Unit]("appengine-delete-backend", "Delete the specified backend.") 40 | lazy val appengineDeployIndexes = InputKey[Unit]("appengine-deploy-indexes", "Update application indexes.") 41 | lazy val appengineDeployCron = InputKey[Unit]("appengine-deploy-cron", "Update application cron jobs.") 42 | lazy val appengineDeployQueues = InputKey[Unit]("appengine-deploy-queues", "Update application task queue definitions.") 43 | lazy val appengineDeployDos = InputKey[Unit]("appengine-deploy-dos", "Update application DoS protection configuration.") 44 | lazy val appengineCronInfo = InputKey[Unit]("appengine-cron-info", "Displays times for the next several runs of each cron job.") 45 | lazy val appengineDevServer = InputKey[revolver.AppProcess]("appengine-dev-server", "Run application through development server.") 46 | lazy val appengineStopDevServer = TaskKey[Unit]("appengine-stop-dev-server", "Stop development server.") 47 | lazy val appengineEnhance = TaskKey[Unit]("appengine-enhance", "Execute ORM enhancement.") 48 | lazy val appengineEnhanceCheck = TaskKey[Unit]("appengine-enhance-check", "Just check the classes for enhancement status.") 49 | 50 | lazy val appengineOnStartHooks = SettingKey[Seq[() => Unit]]("appengine-on-start-hooks") 51 | lazy val appengineOnStopHooks = SettingKey[Seq[() => Unit]]("appengine-on-stop-hooks") 52 | lazy val appengineApiToolsJar = SettingKey[String]("appengine-api-tools-jar", "Name of the development startup executable jar.") 53 | lazy val appengineApiToolsPath = SettingKey[File]("appengine-api-tools-path", "Path of the development startup executable jar.") 54 | lazy val appengineSdkVersion = SettingKey[String]("appengine-sdk-version") 55 | lazy val appengineSdkPath = SettingKey[File]("appengine-sdk-path") 56 | lazy val appengineClasspath = SettingKey[Classpath]("appengine-classpath") 57 | lazy val appengineApiJarName = SettingKey[String]("appengine-api-jar-name") 58 | lazy val appengineApiLabsJarName = SettingKey[String]("appengine-api-labs-jar-name") 59 | lazy val appengineJsr107CacheJarName = SettingKey[String]("appengine-jsr107-cache-jar-name") 60 | lazy val appengineBinPath = SettingKey[File]("appengine-bin-path") 61 | lazy val appengineLibPath = SettingKey[File]("appengine-lib-path") 62 | lazy val appengineLibUserPath = SettingKey[File]("appengine-lib-user-path") 63 | lazy val appengineLibImplPath = SettingKey[File]("appengine-lib-impl-path") 64 | lazy val appengineApiJarPath = SettingKey[File]("appengine-api-jar-path") 65 | lazy val appengineAppcfgName = SettingKey[String]("appengine-appcfg-name") 66 | lazy val appengineAppcfgPath = SettingKey[File]("appengine-appcfg-path") 67 | lazy val appengineOverridePath = SettingKey[File]("appengine-override-path") 68 | lazy val appengineOverridesJarPath = SettingKey[File]("appengine-overrides-jar-path") 69 | lazy val appengineAgentJarPath = SettingKey[File]("appengine-agent-jar-path") 70 | lazy val appengineEmptyFile = TaskKey[File]("appengine-empty-file") 71 | lazy val appengineTemporaryWarPath = SettingKey[File]("appengine-temporary-war-path") 72 | lazy val appengineLocalDbPath = SettingKey[File]("appengine-local-db-path") 73 | lazy val appengineDebug = SettingKey[Boolean]("appengine-debug") 74 | lazy val appengineDebugPort = SettingKey[Int]("appengine-debug-port") 75 | lazy val appengineIncludeLibUser = SettingKey[Boolean]("appengine-include-lib-user") 76 | lazy val appenginePersistenceApi = SettingKey[String]("appengine-persistence-api", "Name of the API we are enhancing for: JDO, JPA.") 77 | 78 | @deprecated("will be removed. use enablePlugins(AppenginePlugin)", "0.7.0") 79 | lazy val appengineSettings = AppenginePlugin.projectSettings 80 | 81 | lazy val appengineDataNucleusSettings: Seq[Def.Setting[_]] = 82 | inConfig(Compile)(baseAppengineDataNucleusSettings) 83 | } 84 | import autoImport._ 85 | 86 | object AppEngine { 87 | // see https://github.com/jberkel/android-plugin/blob/master/src/main/scala/AndroidHelpers.scala 88 | def appcfgTask(action: String, 89 | depends: TaskKey[File] = appengineEmptyFile, outputFile: Option[String] = None): Initialize[InputTask[Unit]] = 90 | Def.inputTask { 91 | import complete.DefaultParsers._ 92 | val input: Seq[String] = spaceDelimited("").parsed 93 | val x = depends.value 94 | appcfgTaskCmd(appengineAppcfgPath.value, input, Seq(action, appengineTemporaryWarPath.value.getAbsolutePath) ++ outputFile.toSeq, streams.value) 95 | } 96 | def appcfgBackendTask(action: String, 97 | depends: TaskKey[File] = appengineEmptyFile, reqParam: Boolean = false): Initialize[InputTask[Unit]] = 98 | Def.inputTask { 99 | import complete.DefaultParsers._ 100 | val input: Seq[String] = spaceDelimited("").parsed 101 | val (opts, args) = input.partition(_.startsWith("--")) 102 | if (reqParam && args.isEmpty) { 103 | sys.error("error executing appcfg: required parameter missing") 104 | } 105 | val x = depends.value 106 | appcfgTaskCmd(appengineAppcfgPath.value, opts, Seq("backends", appengineTemporaryWarPath.value.getAbsolutePath, action) ++ args, streams.value) 107 | } 108 | def appcfgTaskCmd(appcfgPath: sbt.File, args: Seq[String], 109 | params: Seq[String], s: TaskStreams) = { 110 | val appcfg: Seq[String] = Seq(appcfgPath.absolutePath.toString) ++ args ++ params 111 | s.log.debug(appcfg.mkString(" ")) 112 | val out = new StringBuffer 113 | val exit = Process(appcfg).!< 114 | 115 | if (exit != 0) { 116 | s.log.error(out.toString) 117 | sys.error("error executing appcfg") 118 | } 119 | else s.log.info(out.toString) 120 | () 121 | } 122 | 123 | def buildAppengineSdkPath(baseDir: File): File = { 124 | var sdk = System.getenv("APPENGINE_SDK_HOME") 125 | if (sdk == null) { 126 | val appengineSettings = baseDir / "appengine.properties" 127 | val prop = new Properties() 128 | IO.load(prop, appengineSettings) 129 | sdk = prop.getProperty("sdkHome") 130 | } 131 | if (sdk == null) sys.error("You need to set the 'APPENGINE_SDK_HOME' environment variable " + 132 | "or the 'sdkHome' property in 'appengine.properties'") 133 | new File(sdk) 134 | } 135 | 136 | def buildSdkVersion(libUserPath: File): String = { 137 | val pat = """appengine-api-1.0-sdk-(\d\.\d+\.\d+(?:\.\d+)*)\.jar""".r 138 | (libUserPath * "appengine-api-1.0-sdk-*.jar").get.toList match { 139 | case jar::_ => jar.name match { 140 | case pat(version) => version 141 | case _ => sys.error("invalid jar file. " + jar) 142 | } 143 | case _ => sys.error("not found appengine api jar.") 144 | } 145 | } 146 | 147 | def isWindows = System.getProperty("os.name").startsWith("Windows") 148 | def osBatchSuffix = if (isWindows) ".cmd" else ".sh" 149 | 150 | // see https://github.com/spray/sbt-revolver/blob/master/src/main/scala/spray/revolver/Actions.scala#L26 151 | def restartDevServer(streams: TaskStreams, logTag: String, project: ProjectRef, options: ForkOptions, mainClass: Option[String], 152 | cp: Classpath, args: Seq[String], startConfig: ExtraCmdLineOptions, war: File, 153 | onStart: Seq[() => Unit], onStop: Seq[() => Unit]): revolver.AppProcess = { 154 | if (revolverState.getProcess(project).exists(_.isRunning)) { 155 | colorLogger(streams.log).info("[YELLOW]Stopping dev server ...") 156 | stopAppWithStreams(streams, project) 157 | onStop foreach { _.apply() } 158 | } 159 | startDevServer(streams, logTag, project, options, mainClass, cp, args, startConfig, onStart) 160 | } 161 | // see https://github.com/spray/sbt-revolver/blob/master/src/main/scala/spray/revolver/Actions.scala#L32 162 | def startDevServer(streams: TaskStreams, logTag: String, project: ProjectRef, options: ForkOptions, mainClass: Option[String], 163 | cp: Classpath, args: Seq[String], startConfig: ExtraCmdLineOptions, onStart: Seq[() => Unit]): revolver.AppProcess = { 164 | assert(!revolverState.getProcess(project).exists(_.isRunning)) 165 | 166 | val color = updateStateAndGet(_.takeColor) 167 | val logger = new revolver.SysoutLogger(logTag, color, streams.log.ansiCodesSupported) 168 | colorLogger(streams.log).info("[YELLOW]Starting dev server in the background ...") 169 | onStart foreach { _.apply() } 170 | val appProcess = revolver.AppProcess(project, color, logger) { 171 | val f = new Fork("java", mainClass) 172 | val config = options 173 | .withRunJVMOptions( 174 | Vector("-cp", cp.map(_.data.absolutePath).mkString(System.getProperty("file.separator"))) ++ 175 | options.runJVMOptions ++ startConfig.jvmArgs 176 | ) 177 | .withOutputStrategy( 178 | StdoutOutput 179 | ) 180 | f.fork(config, startConfig.startArgs ++ args) 181 | } 182 | registerAppProcess(project, appProcess) 183 | appProcess 184 | } 185 | } 186 | 187 | lazy val baseAppengineSettings: Seq[Def.Setting[_]] = Seq( 188 | // this is classpath during compile 189 | unmanagedClasspath ++= appengineClasspath.value, 190 | // this is classpath included into WEB-INF/lib 191 | // https://developers.google.com/appengine/docs/java/tools/ant 192 | // "All of these JARs are in the SDK's lib/user/ directory." 193 | unmanagedClasspath in Runtime ++= unmanagedClasspath.value, 194 | 195 | appengineRequestLogs := AppEngine.appcfgTask("request_logs", outputFile = Some("request.log")).evaluated, 196 | appengineRollback := AppEngine.appcfgTask("rollback").evaluated, 197 | appengineDeploy := AppEngine.appcfgTask("update", `package`).evaluated, 198 | appengineDeployIndexes := AppEngine.appcfgTask("update_indexes", `package`).evaluated, 199 | appengineDeployCron := AppEngine.appcfgTask("update_cron", `package`).evaluated, 200 | appengineDeployQueues := AppEngine.appcfgTask("update_queues", `package`).evaluated, 201 | appengineDeployDos := AppEngine.appcfgTask("update_dos", `package`).evaluated, 202 | appengineCronInfo := AppEngine.appcfgTask("cron_info").evaluated, 203 | 204 | appengineDeployBackends := AppEngine.appcfgBackendTask("update", `package`).evaluated, 205 | appengineConfigBackends := AppEngine.appcfgBackendTask("configure", `package`).evaluated, 206 | appengineRollbackBackend := AppEngine.appcfgBackendTask("rollback", `package`, true).evaluated, 207 | appengineStartBackend := AppEngine.appcfgBackendTask("start", `package`, true).evaluated, 208 | appengineStopBackend := AppEngine.appcfgBackendTask("stop", `package`, true).evaluated, 209 | appengineDeleteBackend := AppEngine.appcfgBackendTask("delete", `package`, true).evaluated, 210 | 211 | appengineDevServer := { 212 | val args = startArgsParser.parsed 213 | val x = (products in Compile).value 214 | AppEngine.restartDevServer(streams.value, (RevolverPlugin.autoImport.reLogTag in appengineDevServer).value, 215 | thisProjectRef.value, (RevolverPlugin.autoImport.reForkOptions in appengineDevServer).value, 216 | (mainClass in appengineDevServer).value, (fullClasspath in appengineDevServer).value, 217 | (RevolverPlugin.autoImport.reStartArgs in appengineDevServer).value, args, 218 | `package`.value, 219 | (appengineOnStartHooks in appengineDevServer).value, (appengineOnStopHooks in appengineDevServer).value) 220 | }, 221 | RevolverPlugin.autoImport.reForkOptions in appengineDevServer := { 222 | ForkOptions( 223 | javaHome = javaHome.value, 224 | outputStrategy = outputStrategy.value, 225 | bootJars = scalaInstance.value.libraryJar +: scalaInstance.value.allJars.toVector, 226 | workingDirectory = Some(appengineTemporaryWarPath.value), 227 | runJVMOptions = (javaOptions in appengineDevServer).value.toVector, 228 | connectInput = false, 229 | envVars = Map.empty[String, String] 230 | ) 231 | }, 232 | RevolverPlugin.autoImport.reLogTag in appengineDevServer := "appengineDevServer", 233 | mainClass in appengineDevServer := Some("com.google.appengine.tools.development.DevAppServerMain"), 234 | fullClasspath in appengineDevServer := Seq(appengineApiToolsPath.value).classpath, 235 | appengineLocalDbPath in appengineDevServer := target.value / "local_db.bin", 236 | RevolverPlugin.autoImport.reStartArgs in appengineDevServer := Seq(appengineTemporaryWarPath.value.absolutePath), 237 | // http://thoughts.inphina.com/2010/06/24/remote-debugging-google-app-engine-application-on-eclipse/ 238 | appengineDebug in appengineDevServer := true, 239 | appengineDebugPort in appengineDevServer := 1044, 240 | appengineOnStartHooks in appengineDevServer := Nil, 241 | appengineOnStopHooks in appengineDevServer := Nil, 242 | SbtCompat.impl.changeJavaOptions { (o, a, jr, ldb, d, dp) => 243 | Seq("-ea" , "-javaagent:" + a.getAbsolutePath, "-Xbootclasspath/p:" + o.getAbsolutePath, 244 | "-Ddatastore.backing_store=" + ldb.getAbsolutePath) ++ 245 | Seq("-Djava.awt.headless=true") ++ 246 | (if (d) Seq("-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=" + dp.toString) else Nil) ++ 247 | createJRebelAgentOption(revolver.SysoutLogger, jr).toSeq }, 248 | appengineStopDevServer := RevolverPlugin.autoImport.reStop.value, 249 | 250 | appengineApiToolsJar := "appengine-tools-api.jar", 251 | appengineSdkVersion := AppEngine.buildSdkVersion(appengineLibUserPath.value), 252 | appengineSdkPath := AppEngine.buildAppengineSdkPath(baseDirectory.value), 253 | 254 | appengineIncludeLibUser := true, 255 | // this controls appengine classpath, which is used in unmanagedClasspath 256 | appengineClasspath := { 257 | if (appengineIncludeLibUser.value) (appengineLibUserPath.value ** "*.jar").classpath 258 | else Nil 259 | }, 260 | 261 | appengineApiJarName := { "appengine-api-1.0-sdk-" + appengineSdkVersion.value + ".jar" }, 262 | appengineApiLabsJarName := { "appengine-api-labs-" + appengineSdkVersion.value + ".jar" }, 263 | appengineJsr107CacheJarName := { "appengine-jsr107cache-" + appengineSdkVersion.value + ".jar" }, 264 | 265 | appengineBinPath := appengineSdkPath.value / "bin", 266 | appengineLibPath := appengineSdkPath.value / "lib", 267 | appengineLibUserPath := appengineLibPath.value / "user", 268 | appengineLibImplPath := appengineLibPath.value / "impl", 269 | appengineApiJarPath := appengineLibUserPath.value / appengineApiJarName.value, 270 | appengineApiToolsPath := appengineLibPath.value / appengineApiToolsJar.value, 271 | appengineAppcfgName := "appcfg" + AppEngine.osBatchSuffix, 272 | appengineAppcfgPath := appengineBinPath.value / appengineAppcfgName.value, 273 | appengineOverridePath := appengineLibPath.value / "override", 274 | appengineOverridesJarPath := appengineOverridePath.value / "appengine-dev-jdk-overrides.jar", 275 | appengineAgentJarPath := appengineLibPath.value / "agent" / "appengine-agent.jar", 276 | appengineEmptyFile := file(""), 277 | appengineTemporaryWarPath := target.value / "webapp" 278 | ) 279 | 280 | lazy val baseAppengineDataNucleusSettings: Seq[Def.Setting[_]] = Seq( 281 | `package` := `package`.dependsOn(appengineEnhance).value, 282 | appengineClasspath := { 283 | val appengineORMJars = (appengineLibPath.value / "orm" * "*.jar").get 284 | appengineClasspath.value ++ appengineORMJars.classpath 285 | }, 286 | appengineEnhance := { 287 | val r: ScalaRun = (runner in Runtime).value 288 | val main: String = (mainClass in appengineEnhance).value.get 289 | val files: Seq[File] = (exportedProducts in Runtime).value flatMap { dir => 290 | (dir.data ** "*.class").get ++ (dir.data ** "*.jdo").get 291 | } 292 | val args: Seq[String] = (scalacOptions in appengineEnhance).value ++ (files map {_.toString}) 293 | r.run(main, (fullClasspath in appengineEnhance).value map {_.data}, args, streams.value.log) 294 | }, 295 | appengineEnhanceCheck := { 296 | val r: ScalaRun = (runner in Runtime).value 297 | val main: String = (mainClass in appengineEnhance).value.get 298 | val files: Seq[File] = (exportedProducts in Runtime).value flatMap { dir => 299 | (dir.data ** "*.class").get ++ (dir.data ** "*.jdo").get 300 | } 301 | val args: Seq[String] = (scalacOptions in appengineEnhance).value ++ Seq("-checkonly") ++ (files map {_.toString}) 302 | r.run(main, (fullClasspath in appengineEnhance).value map {_.data}, args, streams.value.log) 303 | }, 304 | mainClass in appengineEnhance := Some("org.datanucleus.enhancer.DataNucleusEnhancer"), 305 | fullClasspath in appengineEnhance := { 306 | val appengineORMEnhancerJars = (appengineLibPath.value / "tools" / "orm" * "datanucleus-enhancer-*.jar").get ++ 307 | (appengineLibPath.value / "tools" / "orm" * "asm-*.jar").get 308 | (Seq(appengineApiToolsPath.value) ++ appengineORMEnhancerJars).classpath ++ (fullClasspath in Compile).value 309 | }, 310 | // http://www.datanucleus.org/products/accessplatform_2_2/enhancer.html 311 | scalacOptions in appengineEnhance := ((logLevel in appengineEnhance) match { 312 | case Level.Debug => Seq("-v") 313 | case _ => Seq() 314 | } ) ++ Seq("-api", (appenginePersistenceApi in appengineEnhance).value), 315 | logLevel in appengineEnhance := Level.Debug, 316 | appenginePersistenceApi in appengineEnhance := "JDO" 317 | ) 318 | 319 | lazy val webSettings = projectSettings 320 | 321 | override lazy val projectSettings: Seq[Def.Setting[_]] = 322 | inConfig(Compile)(WarPlugin.projectSettings ++ revolver.RevolverPlugin.settings ++ baseAppengineSettings) ++ 323 | inConfig(Test)(Seq( 324 | unmanagedClasspath ++= appengineClasspath.value, 325 | appengineClasspath := { 326 | val impljars = ((appengineLibImplPath in Compile).value * "*.jar").get 327 | val testingjars = ((appengineLibPath in Compile).value / "testing" * "*.jar").get 328 | (appengineClasspath in Compile).value ++ Attributed.blankSeq(impljars ++ testingjars) 329 | } 330 | )) ++ 331 | Seq( 332 | watchSources ++= ((sourceDirectory in webappPrepare in Compile).value ** "*").get) 333 | } 334 | -------------------------------------------------------------------------------- /src/main/scala/SbtCompat.scala: -------------------------------------------------------------------------------- 1 | package sbtappengine 2 | 3 | import sbt._ 4 | import Keys._ 5 | import spray.revolver.RevolverKeys 6 | 7 | /** 8 | * Sbt compatibility code concrete instances are declared in sbt version specific folders 9 | */ 10 | trait SbtCompat { 11 | /** 12 | * Changes javaOptions by using transformator function 13 | * (overridesJarPath, agentJarPath, reJRebelJar, localDbPath in devServer, 14 | * debug in devServer, debugPort in devServer) => newJavaOptions 15 | */ 16 | def changeJavaOptions(f: (File, File, String, File, Boolean, Int) => Seq[String]): Setting[_] 17 | } 18 | 19 | object SbtCompat { 20 | def impl: SbtCompat = SbtCompatImpl 21 | } 22 | 23 | // ---- 24 | 25 | object SbtCompatImpl extends SbtCompat with RevolverKeys { 26 | import AppenginePlugin.autoImport._ 27 | 28 | def changeJavaOptions(f: (File, File, String, File, Boolean, Int) => Seq[String]) = 29 | javaOptions in appengineDevServer := f( 30 | appengineOverridesJarPath.value, 31 | appengineAgentJarPath.value, 32 | spray.revolver.RevolverPlugin.autoImport.reJRebelJar.value, 33 | (appengineLocalDbPath in appengineDevServer).value, 34 | (appengineDebug in appengineDevServer).value, 35 | (appengineDebugPort in appengineDevServer).value 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/helloxmpp/COPYING: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | 1. Definitions. 7 | 8 | "License" shall mean the terms and conditions for use, reproduction, and 9 | distribution as defined by Sections 1 through 9 of this document. 10 | 11 | "Licensor" shall mean the copyright owner or entity authorized by the 12 | copyright owner that is granting the License. 13 | 14 | "Legal Entity" shall mean the union of the acting entity and all other 15 | entities that control, are controlled by, or are under common control with 16 | that entity. For the purposes of this definition, "control" means (i) the 17 | power, direct or indirect, to cause the direction or management of such 18 | entity, whether by contract or otherwise, or (ii) ownership of fifty percent 19 | (50%) or more of the outstanding shares, or (iii) beneficial ownership of 20 | such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, 26 | including but not limited to software source code, documentation source, and 27 | configuration files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation 30 | or translation of a Source form, including but not limited to compiled 31 | object code, generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, 34 | made available under the License, as indicated by a copyright notice that is 35 | included in or attached to the work (an example is provided in the Appendix 36 | below). 37 | 38 | "Derivative Works" shall mean any work, whether in Source or Object form, 39 | that is based on (or derived from) the Work and for which the editorial 40 | revisions, annotations, elaborations, or other modifications represent, as a 41 | whole, an original work of authorship. For the purposes of this License, 42 | Derivative Works shall not include works that remain separable from, or 43 | merely link (or bind by name) to the interfaces of, the Work and Derivative 44 | Works thereof. 45 | 46 | "Contribution" shall mean any work of authorship, including the original 47 | version of the Work and any modifications or additions to that Work or 48 | Derivative Works thereof, that is intentionally submitted to Licensor for 49 | inclusion in the Work by the copyright owner or by an individual or Legal 50 | Entity authorized to submit on behalf of the copyright owner. For the 51 | purposes of this definition, "submitted" means any form of electronic, 52 | verbal, or written communication sent to the Licensor or its 53 | representatives, including but not limited to communication on electronic 54 | mailing lists, source code control systems, and issue tracking systems that 55 | are managed by, or on behalf of, the Licensor for the purpose of discussing 56 | and improving the Work, but excluding communication that is conspicuously 57 | marked or otherwise designated in writing by the copyright owner as "Not a 58 | Contribution." 59 | 60 | "Contributor" shall mean Licensor and any individual or Legal Entity on 61 | behalf of whom a Contribution has been received by Licensor and subsequently 62 | incorporated within the Work. 63 | 64 | 2. Grant of Copyright License. Subject to the terms and conditions of this 65 | License, each Contributor hereby grants to You a perpetual, worldwide, 66 | non-exclusive, no-charge, royalty-free, irrevocable copyright license to 67 | reproduce, prepare Derivative Works of, publicly display, publicly perform, 68 | sublicense, and distribute the Work and such Derivative Works in Source or 69 | Object form. 70 | 71 | 3. Grant of Patent License. Subject to the terms and conditions of this 72 | License, each Contributor hereby grants to You a perpetual, worldwide, 73 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in 74 | this section) patent license to make, have made, use, offer to sell, sell, 75 | import, and otherwise transfer the Work, where such license applies only to 76 | those patent claims licensable by such Contributor that are necessarily 77 | infringed by their Contribution(s) alone or by combination of their 78 | Contribution(s) with the Work to which such Contribution(s) was submitted. 79 | If You institute patent litigation against any entity (including a 80 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 81 | Contribution incorporated within the Work constitutes direct or contributory 82 | patent infringement, then any patent licenses granted to You under this 83 | License for that Work shall terminate as of the date such litigation is 84 | filed. 85 | 86 | 4. Redistribution. You may reproduce and distribute copies of the Work or 87 | Derivative Works thereof in any medium, with or without modifications, and 88 | in Source or Object form, provided that You meet the following conditions: 89 | 90 | a. You must give any other recipients of the Work or Derivative Works a copy 91 | of this License; and 92 | 93 | b. You must cause any modified files to carry prominent notices stating that 94 | You changed the files; and 95 | 96 | c. You must retain, in the Source form of any Derivative Works that You 97 | distribute, all copyright, patent, trademark, and attribution notices from 98 | the Source form of the Work, excluding those notices that do not pertain to 99 | any part of the Derivative Works; and 100 | 101 | d. If the Work includes a "NOTICE" text file as part of its distribution, 102 | then any Derivative Works that You distribute must include a readable copy 103 | of the attribution notices contained within such NOTICE file, excluding 104 | those notices that do not pertain to any part of the Derivative Works, in at 105 | least one of the following places: within a NOTICE text file distributed as 106 | part of the Derivative Works; within the Source form or documentation, if 107 | provided along with the Derivative Works; or, within a display generated by 108 | the Derivative Works, if and wherever such third-party notices normally 109 | appear. The contents of the NOTICE file are for informational purposes only 110 | and do not modify the License. You may add Your own attribution notices 111 | within Derivative Works that You distribute, alongside or as an addendum to 112 | the NOTICE text from the Work, provided that such additional attribution 113 | notices cannot be construed as modifying the License. 114 | 115 | You may add Your own copyright statement to Your modifications and may 116 | provide additional or different license terms and conditions for use, 117 | reproduction, or distribution of Your modifications, or for any such 118 | Derivative Works as a whole, provided Your use, reproduction, and 119 | distribution of the Work otherwise complies with the conditions stated in 120 | this License. 121 | 122 | 5. Submission of Contributions. Unless You explicitly state otherwise, any 123 | Contribution intentionally submitted for inclusion in the Work by You to the 124 | Licensor shall be under the terms and conditions of this License, without 125 | any additional terms or conditions. Notwithstanding the above, nothing 126 | herein shall supersede or modify the terms of any separate license agreement 127 | you may have executed with Licensor regarding such Contributions. 128 | 129 | 6. Trademarks. This License does not grant permission to use the trade 130 | names, trademarks, service marks, or product names of the Licensor, except 131 | as required for reasonable and customary use in describing the origin of the 132 | Work and reproducing the content of the NOTICE file. 133 | 134 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in 135 | writing, Licensor provides the Work (and each Contributor provides its 136 | Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 137 | KIND, either express or implied, including, without limitation, any 138 | warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or 139 | FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining 140 | the appropriateness of using or redistributing the Work and assume any risks 141 | associated with Your exercise of permissions under this License. 142 | 143 | 8. Limitation of Liability. In no event and under no legal theory, whether 144 | in tort (including negligence), contract, or otherwise, unless required by 145 | applicable law (such as deliberate and grossly negligent acts) or agreed to 146 | in writing, shall any Contributor be liable to You for damages, including 147 | any direct, indirect, special, incidental, or consequential damages of any 148 | character arising as a result of this License or out of the use or inability 149 | to use the Work (including but not limited to damages for loss of goodwill, 150 | work stoppage, computer failure or malfunction, or any and all other 151 | commercial damages or losses), even if such Contributor has been advised of 152 | the possibility of such damages. 153 | 154 | 9. Accepting Warranty or Additional Liability. While redistributing the Work 155 | or Derivative Works thereof, You may choose to offer, and charge a fee for, 156 | acceptance of support, warranty, indemnity, or other liability obligations 157 | and/or rights consistent with this License. However, in accepting such 158 | obligations, You may act only on Your own behalf and on Your sole 159 | responsibility, not on behalf of any other Contributor, and only if You 160 | agree to indemnify, defend, and hold each Contributor harmless for any 161 | liability incurred by, or claims asserted against, such Contributor by 162 | reason of your accepting any such warranty or additional liability. 163 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/helloxmpp/README: -------------------------------------------------------------------------------- 1 | Google App Engine Java Runtime SDK - XMPP API Demo 2 | 3 | Illustrates simple application that use the XMPP API. 4 | 5 | To compile and run this sample on the local dev server, run ant in this 6 | directory as follows: 7 | 8 | ant runserver 9 | 10 | Once the server is running, point your web browser at: 11 | 12 | http://127.0.0.1:8080/_ah/admin/xmpp 13 | 14 | And send test messages to see it in action. Look at the logging console to 15 | see outbound echo messages. 16 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/helloxmpp/build.sbt: -------------------------------------------------------------------------------- 1 | name := "taskqueueexamples" 2 | 3 | libraryDependencies ++= Seq( 4 | "javax.servlet" % "servlet-api" % "2.5" % "provided", 5 | "org.eclipse.jetty" % "jetty-webapp" % "7.6.8.v20121106" % "container" 6 | ) 7 | 8 | enablePlugins(AppenginePlugin) 9 | 10 | unmanagedJars in Compile ++= { 11 | val libUserPath = (appengineLibUserPath in Compile).value 12 | val baseDirectories = libUserPath +++ (libUserPath / "orm") 13 | (baseDirectories * "*.jar").classpath 14 | } 15 | 16 | unmanagedJars in Compile ++= { 17 | (((appengineLibPath in Compile).value / "shared") ** "*.jar").classpath 18 | } 19 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/helloxmpp/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 33 | 34 | 35 | 36 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/helloxmpp/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | { 2 | val pluginVersion = System.getProperty("plugin.version") 3 | if(pluginVersion == null) 4 | throw new RuntimeException("""|The system property 'plugin.version' is not defined. 5 | |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) 6 | else addSbtPlugin("com.eed3si9n" % "sbt-appengine" % pluginVersion) 7 | } 8 | 9 | resolvers += "spray repo" at "http://repo.spray.cc" 10 | 11 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/helloxmpp/src/main/java/com/google/appengine/demos/helloxmpp/HelloXmpp.java: -------------------------------------------------------------------------------- 1 | // Copyright 2008 Google Inc. All rights reserved. 2 | 3 | package com.google.appengine.demos.helloxmpp; 4 | 5 | import com.google.appengine.api.xmpp.JID; 6 | import com.google.appengine.api.xmpp.Message; 7 | import com.google.appengine.api.xmpp.MessageBuilder; 8 | import com.google.appengine.api.xmpp.MessageType; 9 | import com.google.appengine.api.xmpp.Presence; 10 | import com.google.appengine.api.xmpp.SendResponse; 11 | import com.google.appengine.api.xmpp.XMPPService; 12 | import com.google.appengine.api.xmpp.XMPPServiceFactory; 13 | 14 | import java.io.IOException; 15 | import java.util.Map; 16 | 17 | import javax.servlet.http.HttpServlet; 18 | import javax.servlet.http.HttpServletRequest; 19 | import javax.servlet.http.HttpServletResponse; 20 | 21 | /** 22 | * HelloXmpp is an echo bot that sends back the message it receives. 23 | */ 24 | public class HelloXmpp extends HttpServlet { 25 | 26 | private XMPPService xmppService; 27 | 28 | @Override 29 | public void init() { 30 | this.xmppService = XMPPServiceFactory.getXMPPService(); 31 | } 32 | 33 | public void doGet(HttpServletRequest req, HttpServletResponse res) 34 | throws IOException { 35 | Message message =new MessageBuilder() 36 | .withMessageType(MessageType.CHAT) 37 | .withFromJid(new JID(req.getParameter("from"))) 38 | .withRecipientJids(new JID(req.getParameter("to"))) 39 | .withBody(req.getParameter("body")) 40 | .build(); 41 | processMessage(message, res); 42 | } 43 | 44 | public void doPost(HttpServletRequest req, HttpServletResponse res) 45 | throws IOException { 46 | processMessage(xmppService.parseMessage(req), res); 47 | } 48 | 49 | public void processMessage(Message message, HttpServletResponse res) throws IOException { 50 | JID fromId = message.getFromJid(); 51 | Presence presence = xmppService.getPresence(fromId); 52 | String presenceString = presence.isAvailable() ? "" : "not "; 53 | SendResponse response = xmppService.sendMessage( 54 | new MessageBuilder(). 55 | withBody(message.getBody() + " (you are " + presenceString + "available)"). 56 | withRecipientJids(fromId). 57 | build()); 58 | 59 | for (Map.Entry entry : 60 | response.getStatusMap().entrySet()) { 61 | res.getWriter().println(entry.getKey() + "," + entry.getValue() + "
"); 62 | } 63 | 64 | res.getWriter().println("processed"); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/helloxmpp/src/main/webapp/WEB-INF/appengine-web.xml: -------------------------------------------------------------------------------- 1 | 2 | sbt-plugin-test 3 | 2 4 | true 5 | 6 | 7 | xmpp_message 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/helloxmpp/src/main/webapp/WEB-INF/classes/README: -------------------------------------------------------------------------------- 1 | Source code is compiled into this directory to be uploaded to the server. 2 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/helloxmpp/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | HelloXmpp Java 8 | 9 | 10 | hello 11 | com.google.appengine.demos.helloxmpp.HelloXmpp 12 | 13 | 14 | 15 | hello 16 | /_ah/xmpp/message/* 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/helloxmpp/test: -------------------------------------------------------------------------------- 1 | > test 2 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/simple/build.sbt: -------------------------------------------------------------------------------- 1 | name := "sample" 2 | 3 | scalaVersion := "2.11.11" 4 | 5 | libraryDependencies ++= Seq( 6 | "ws.unfiltered" %% "unfiltered-filter" % "0.9.1", 7 | "javax.servlet" % "servlet-api" % "2.5" % "provided", 8 | "org.mortbay.jetty" % "jetty" % "6.1.22" % "container" 9 | ) 10 | 11 | enablePlugins(AppenginePlugin) 12 | 13 | (appengineOnStartHooks in appengineDevServer in Compile) += { () => 14 | println("hello") 15 | } 16 | 17 | (appengineOnStopHooks in appengineDevServer in Compile) += { () => 18 | println("bye") 19 | } 20 | 21 | appengineDataNucleusSettings 22 | 23 | appenginePersistenceApi in appengineEnhance in Compile := "JDO" 24 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/simple/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | { 2 | val pluginVersion = System.getProperty("plugin.version") 3 | if(pluginVersion == null) 4 | throw new RuntimeException("""|The system property 'plugin.version' is not defined. 5 | |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) 6 | else addSbtPlugin("com.eed3si9n" % "sbt-appengine" % pluginVersion) 7 | } 8 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/simple/src/main/resources/META-INF/jdoconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/simple/src/main/scala/counter.scala: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import javax.jdo.annotations._ 4 | import javax.jdo._ 5 | import com.google.appengine.api.datastore.Key 6 | import scala.annotation.meta.field 7 | 8 | @PersistenceCapable 9 | case class Counter( 10 | @(PrimaryKey @field) 11 | @(Persistent @field)(valueStrategy = IdGeneratorStrategy.IDENTITY) 12 | var key: Key, 13 | @(Persistent @field) 14 | var count: Int) 15 | 16 | // https://cloud.google.com/appengine/docs/standard/java/datastore/jdo/creatinggettinganddeletingdata 17 | object CounterAdapter { 18 | def get(key: Key): Option[Counter] = { 19 | val pm = PMF.instance.getPersistenceManager 20 | try { 21 | Some(pm.detachCopy(pm.getObjectById(classOf[Counter], key))) 22 | } catch { 23 | case e: JDOObjectNotFoundException => 24 | None 25 | case e: Exception => throw e 26 | } finally { 27 | pm.close 28 | } 29 | } 30 | 31 | def save(value: Counter): Unit = { 32 | val pm = PMF.instance.getPersistenceManager 33 | try { 34 | pm.makePersistent(value) 35 | } finally { 36 | pm.close 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/simple/src/main/scala/echofilter.scala: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import unfiltered.filter.Plan 4 | import unfiltered.request._ 5 | import unfiltered.response._ 6 | import unfiltered.request.{Path => UFPath} 7 | import com.google.appengine.api.datastore.{Key, KeyFactory} 8 | 9 | class EchoFilter extends Plan { 10 | override val intent: Plan.Intent = { 11 | case GET(UFPath(Seg(what :: Nil)) & Params(params0)) => 12 | val key = KeyFactory.createKey(classOf[Counter].getSimpleName, what) 13 | val counter = CounterAdapter.get(key) getOrElse new Counter(key, 0) 14 | val inc = new Counter(key, counter.count + 1) 15 | CounterAdapter.save(inc) 16 | ResponseString(what + inc.count.toString + "!") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/simple/src/main/scala/pmf.scala: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import javax.jdo._ 4 | 5 | object PMF { 6 | lazy val instance: PersistenceManagerFactory = JDOHelper.getPersistenceManagerFactory("transactions-optional") 7 | } 8 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/simple/src/main/webapp/WEB-INF/appengine-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | sbt-plugin-test 4 | 1 5 | true 6 | 7 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/simple/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | echofilter 5 | simple.EchoFilter 6 | 7 | 8 | 9 | echofilter 10 | * 11 | 12 | 13 | 14 | 30 15 | 16 | 17 | 18 | index.html 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/simple/src/main/webapp/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbt/sbt-appengine/26f6b493ea55e10f007755b78f3087cdd0ed3427/src/sbt-test/sbt-appengine/simple/src/main/webapp/index.html -------------------------------------------------------------------------------- /src/sbt-test/sbt-appengine/simple/test: -------------------------------------------------------------------------------- 1 | > test 2 | --------------------------------------------------------------------------------