使用Gradle进行GAE/J开发

Gradle 应用引擎插件

如果你要用 Java 开发 Google App Engine (GAE),可以很容易地通过 Eclipse 的插件来开始,但考虑到团队开发和与 CI 的协作,我们还是想使用像 Gradle 这样的构建工具。

根据Google文档的说法,它似乎更推荐使用Maven,但Google官方GitHub也发布了适用于Gradle的插件。

Gradle App Engine plugin
https://github.com/GoogleCloudPlatform/gradle-appengine-plugin

Gradle App Engine 插件是将应用程序的构建、本地服务器运行、测试、部署等一系列操作定义为 Gradle 任务的 Google App Engine SDK(以下简称SDK)插件。

しかし使う人が少ないのかネット上にあまり情報は見つからない。
そもそも GAE/Java 開発自体が Go などにおされてトレンドから外れているのか、古い資料ばかりで参考にならないものが多い。

とはいえ、 依然 GAE は進化を続けており、GAE/Java SDK も頻繁に更新されている。
2014年は Managed VM サービスの登場があり、Java Runtime の自由度が高まった。
Android Studio も正式版がリリースされ、そのプロジェクトは Gradle ベースになっており、統合されたバックエンド開発にはこの GAE プラグインが組み込まれている。
GAE の Java 開発はネタ的にも盛返しの機運があるということで、技術情報や書籍なども今年あたりからまた出てくるだろう。

それまでのつなぎとして、現状を調べた情報のメモをまとめておく。
いまいち整理しきれていないが、取っ掛かりを拾う参考にはなるだろう。
間違いやタイプミスがあれば教えてほしい。

创建.gradle文件

经过试验和错误,最终找到了以下的 build.gradle。

buildscript {
    ext { 
        // Gradle App Engine plugin version
        gaePlunginVersion = '1.9.19' 
    }
    repositories { jcenter() }
    dependencies {
        classpath "com.google.appengine:gradle-appengine-plugin:${ gaePlunginVersion }"
    }
}

// プラグイン
apply plugin: 'war'
apply plugin: 'appengine'  // Gradle App Engine plugin


// プロジェクト設定
sourceCompatibility = '1.7'
targetCompatibility = '1.7'

//group = 'com.hoge.aaa'
//version = '1.0'

// GAE プラグイン設定
ext {
    // Google App Engine SDK Version
    sdkVersion = '1.9.19'  // = gaePlunginVersion
}
appengine { 
    downloadSdk = true
    appcfg {
        // oauth2 = true  // OAuth2 で認証する
    }
}

// 依存管理
repositories { jcenter() }
dependencies {
    compile     'org.slf4j:slf4j-api:1.7.7'
    testCompile 'junit:junit:4.11'

    providedCompile 'javax.servlet:servlet-api:2.5'

    // Google App Engine SDK for Java
    // appengine.downloadSdk = true のときに、必要
    appengineSdk "com.google.appengine:appengine-java-sdk:${ sdkVersion }"

    //  Google App Engine API
    compile      "com.google.appengine:appengine-api-1.0-sdk:${ sdkVersion }"
    compile      "com.google.appengine:appengine-api-labs:${ sdkVersion }"
    testCompile  "com.google.appengine:appengine-api-stubs:${ sdkVersion }"
    testCompile  "com.google.appengine:appengine-testing:${ sdkVersion }"

    // Memcache サポート
    compile      'net.sf.jsr107cache:jsr107cache:1.1'
    compile      "com.google.appengine:appengine-jsr107cache:${ sdkVersion }"

}

/* JPA/JDO を使う場合はこのコメントを外す
// Persistence サポート
appengine {
    enhancer {
        version     = 'v2'       // DataNucleusのバージョン
        api         = 'jpa'      // Persistence API 'jpa', 'jdo'
        enhanceOnBuild = true    // build 時にエンハンス処理を行う
    }
}
dependencies {
    compile 'org.ow2.asm:asm:4.0'
    compile 'org.datanucleus:datanucleus-api-jpa:3.1.3'
    compile 'org.datanucleus:datanucleus-api-jdo:3.1.3'
    compile 'com.google.appengine.orm:datanucleus-appengine:2.1.2'
    compile 'org.datanucleus:datanucleus-core:3.1.3'
    compile 'org.apache.geronimo.specs:geronimo-jpa_2.0_spec:1.0'
    compile 'javax.jdo:jdo-api:3.0.1'
    compile 'javax.transaction:jta:1.1'
}
*/

/* Google Cloud Endpoints を使う場合はこのコメントを外す
// Endpoints サポート
{    
    endpoints {
        getDiscoveryDocsOnBuild = true
        getClientLibsOnBuild    = true
    }
}
dependencies {
    "compile com.google.appengine:appengine-endpoints:${ sdkVersion }"
    "compile com.google.appengine:appengine-endpoints-deps:${ sdkVersion }"
}
*/

プロジェクトの作成

由于Gradle的项目生成和模板功能较弱,所以需要进行一些额外的工作。

まずはプロジェクトディレクトリで gradle init する。
生成された build.gradle ファイルの中身を上記スクリプトで置き換える。
./gradlew コマンドも組み込まれるので以降こちらを使う。

Gradle Java プロジェクトのディレクトリ規約はいわゆる Maven レイアウトに従うが、Gradle はあまり面倒をみてくれない。
init タスクに Java 用のオブションがあるにはあるが中途半端だ。

以下のタスクを build.gradel に一時的にコピペして layout タスクを走らせればソースディレクトリを作成できる。
後で git に空ディレクトリを捨てられたりするので、とっておいてもいい。

task layout << {
    sourceSets*.allSource.srcDirs*.each { it.mkdirs() }   // *. は Spread Operator という groovy の演算子
    new File(sourceSets.main.resources.srcDirs[0], 'META-INF').mkdirs()
    new File(webAppDir, 'WEB-INF').mkdirs()
}

動作検証用にサンプルソースが欲しいところだ。
Maven 用なら guestbook-artifact というひな形があるのだが、Gradle にこれを単純に流用することはできないようだ。
SDK の demos ディレクトリ配下にもサンプルプロジェクトがいくつか(guestbookも)あるので、ここから適当に拾うのもいいだろう。
だだし Eclipse 用のプロジェクト構成になっているで、ソースファイルや設定を適切なでディレクトリに手作業で移動する必要がある。

如果是demos/guestbook的情况,将其安排如下。

$ tree
.
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    ├── endpointsSrc
    │   └── resources
    ├── functionalTest
    │   ├── java
    │   └── resources
    ├── main
    │   ├── java
    │   │   └── guestbook
    │   │       ├── GuestbookServlet.java
    │   │       └── SignGuestbookServlet.java
    │   ├── resources
    │   │   └── META-INF
    │   └── webapp
    │       ├── WEB-INF
    │       │   ├── appengine-web.xml
    │       │   ├── logging.properties
    │       │   └── web.xml
    │       ├── guestbook.jsp
    │       └── stylesheets
    │           └── main.css
    └── test
        ├── java
        └── resources

./gradlew build してエラーがでなければ OK。
初回の実行では、Gradle、SDK、依存関係の jar などがダウンロードされるので時間と通信量がかかる。
おそらく 300MB 以上の通信量になるので、スタバでテザリングをしている人は月末の実行を避けたほうがいいだろう。
ホームディレクトリをみると 500MB ほど膨らむようだ。

本地操作验证

使用 appengineRun 任务启动本地开发服务器。

$ ./gradlew appengineRun

デフォルトではサーバがフォアグラウンドで起動され、http://localhost:8080/ で Web アプリにアクセスできるようになる。

最初は一通りの動作確認をなるべくしっかりやっておいてほしい(後述)。

管理画面 http://localhost:8080/_ah/admin も確認しておこう。
Datastore の内容などが確認できる。

ローカル開発サーバを停止するには appengineStop タスクを使う。
(自分は別ターミナルを開くのが面倒なので Ctrl+C することが多い)

初めてのデプロイ

アプリの動作に問題なければ GAE のクラウドサーバへデプロイしてみよう。

在那之前,需要做一些准备。

・设置应用程序ID

言うまでもなく Google Developers Console で GAE プロジェクトを作成しておく必要がある。

作成したプロジェクトの「プロジェクト ID」が SDK では「アプリケーション ID」と呼ばれる(ややこしい)。

アプリケーション ID の設定項目はなぜか build.gradle には存在しない。
appengine-web.xml のほうを編集する必要がある。

<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <application>my-application-id</application>
    <version>v1</version>
    <!-- TODO review code for thread-safety. -->
    <threadsafe>false</threadsafe>

    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
    </system-properties>
</appengine-web-app>

application 要素にアプリケーション ID を記述する。
version 要素は英数字の任意の文字列でよい。

・ Datastore インデックスの確認

Datastore を使う場合(guestbookは使う)、各エンティティ用に追加するインデックスを定義する必要がある。
それを怠ると、ローカルサーバ環境では問題なくても、AGE 本番サーバでは 500 ステータス(DatastoreNeedIndexException)のエラーが返されてしまう。

インデックス定義は自分で設定ファイルに記述しなくても、以下のファイルとして自動生成されるので当面はとりあえずそのままで OK だ。

build/exploded-app/WEB-INF/appengine-generated/datastore-indexes-auto.xml

しかしこのファイルは build するだけでは作成されない。

appengineRun でローカル開発サーバを起動後、Datastore API にアクセスするロジックを通った時に初めて生成される。
ローカル開発サーバ稼働中に Datastore スタブがエンティティに対するクエリを見ているようで、それから適切なインデックス定義を生成し、上記XMLファイルに追加される。

アクセスしなかった Entity のインデックス定義は追加されないので、最初のローカル動作確認ではすべての エンティティ に通るよう念入りにやっておきたい。
Function Test での自動化も TODO に入れておこう。

また、新規に追加されたインデックスは、デプロイ後クラウドサーバ上で有効になるまで数分かかることがあるので、すぐにアクセスしてエラーになっても慌てないように。

・ 認証方法を決める

GAE サーバへの認証はデフォルトでパスワード認証となっている。
プロジェクト管理者の Google アカウントの Gmail アドレスとパスワードで認証できるはずなのだが、現在はまずもって成功しない。

それは GAE 側の問題ではなく、Google の認証基盤のセキュリティポリシーが厳しくなった影響だ。
普通にパスワード認証を試みると、ブロックしましたという通知メールがくる。

作为解决方案,可以考虑以下三种选项。

A. 2段階認証を有効にして、アプリ パスワードを発行する
B. 「安全性の低いアプリを許可」し、アカウントのセキュリティレベルを下げる
C. パスワードではなく OAuth で認証する

上のA. B.2つの案は Google アカウント設定の変更になり、今後の Google 生活に与える影響を判断しなければならない。
その判断は今やりたいことではない。
ここでは、C. 案の OAuth を使うようにする。

build.gradle で appengine.appcfg.oatuh2=true を追加する(コメントアウトを外す)と OAuth2 認証が有効になる。


appengine {
    downloadSdk = true
    appcfg {
        oauth2 = true
    }
}

デフォルトでは認証情報がキャッシュされ、以降のアクセスでは認証入力が省略できる。
それを避けたい理由があるのなら、appengine.appcfg.noCookies=true を追加しておく。

追記 SDK 1.9.19 から、OAuth2 でないと、warning が出るようになったらしい。
1.9.20 からは OAuth2 がデフォルトの認証になる。
https://code.google.com/p/googleappengine/wiki/SdkReleaseNotes

デプロイタスク実行

デプロイのタスク名は deploy ではなく、upload でもなく、ましてや push でもない update だ。

$ ./gradlew appengineUpdate

在执行Gradle脚本的过程中,会弹出Web浏览器,并要求进行OAuth认证。

0auth2.png

認証後に表示される認証トークンをコピーし、入力待ちしている Gradle ターミナルにぺーストする。
するとタスクスクリプトが続行し、GAE クラウドサーバへのデプロイが完了する。

公開されたアプリは、https://.appspot.com/ でアクセスできる。
ただし、Datastore にアクセスするリクエストでは、最初の数分は 500 エラー応答で待たされる。
前に触れたように、インデックス登録が完了するまで時間がかかるからだ。
エラー内容は Developers コンソールのログ画面で参照できるので確認してみてほしい。

起始的提交

如果初次部署顺利,我希望在此处进行源代码管理。
当然,要使用Git。


$ ./gradlew clean
$ git init
$ vi .gitignore
.gradle
build
local.properties

$ git add .
$ git status 
$ git commit -m "Kick start !"

ソースを開発メンバーと共有するために GitHub などのリモートレポジトリに上げたい。
Google Cloud にも プロジェクト専用の Git レポジトリ(Cloud レポジトリという)が用意されるので今回それを使ってみる。

在开发者控制台,可以通过“源代码”>“浏览”来查看项目的代码库内容。
在初始阶段,代码库是空的,没有任何分支,会被引导到初始设置的说明页面上。

start.png
select.png

在这里提供了三种步骤。

最初のは、Cloud レポジトリを GitHub や Bitbucket にある既存のプロジェクトと同期させる方法。
2番目はローカルレポジトリを push してリモートレポジトリを作成する方法。
3番目は最初に空のレポジトリをリモートに作成し、ローカルに clone させる方法。

今ローカルレポジトリを作ったばかりなので、ここは2番目の方法でいくことにする。

local.png

すると手順の最初でいきなり Google Cloud SDK のインストールを要請される。
それに含まれる glcoud コマンドは Google Cloud ツール共通の自動認証環境を提供するらしい。
詳細は以下が参考になる。

    ハンズオン : Google Cloud SDK 基本と認証 – Qiita

今回は開発者にできるだけ環境構築をさせてない方針で、 Gradle と Git だけで完結させたいので gcloud コマンドを使わない方法で行く。

代わりにパスワード認証でリモートレポジトリにアクセスする。
アカウント名は Google アカウントのメールアドレスをそのまま使うが、パスワードがこれまた異なる。
GAE と Git サーバは認証基盤が統合されていないらしい。

手順を飛ばして説明画面の文中下部にある「こちらのリンクに沿って 」(赤丸)というリンクを開くと、OAuth の認証トークンの文字列が得られる。

pass.png

将此令牌作为 Git 密码输入。

在画面上,可以省略输入密码,同时也会显示可用于复制粘贴到.netrc文件的文本,尽管如今以明文形式运行密码当然是不可行的。

如果不自信能记住这个字符串,也可以让Git将其缓存。

    git を https 経由で使うときのパスワードを保存する – Qiita

远程存储库的 URL 将如下所示:

https://source.developers.google.com/p/<我的应用程序 ID>

顺便提一下,使用 gcloud 命令会在以下 URL 中添加路径并进行注册,但目前似乎指向了相同的存储库,所以不要太在意。

https://source.developers.google.com/p//r/default

在中国本土化的语境中,以上命令的中文释义如下:
首先,将远程仓库添加到本地仓库,并推送第一次提交。

$ git remote add origin https://source.developers.google.com/p/my-application-id
$ git push origin master

在开发者控制台中再次确认时,应该会显示主分支的源代码树。除了能够查看源代码和差异之外,还可以在浏览器上直接编辑文件并提交,这对于进行一些小的值修改等非常方便。另外,如果想重新开始,还可以将整个仓库删除。

在另一个环境中克隆并尝试运行`./gradlew build`,如果通过了,则没问题。

现在,要做什么呢?

记事本

GAE 插件和 SDK

只需要一个选项,以下是对该句的中文本地化改写:
使用GAE插件只需在buildscript中定义依赖关系并应用appengine即可。
还需要应用war(如果有war文件,则应该不需要java)。

由于 GAE 插件的版本与 SDK 同步,因此它们是共通的。
由于它经常更新,我希望将版本设为全局常量,但是由于 buildscript 代码块的变量作用域不同,这样做可能并不简单。

GAE 插件可以说是将 SDK (Google App Engine SDK for Java) 的命令行操作转化为任务,但 SDK 本身并未包含在其中。

在依赖项.appengineSdk的构成中,您可以将SDK包含在Gradle的依赖管理中,并且将appengine.downloadSdk设置为true时,SDK将通过appengineDownloadSdk任务进行下载和部署。

但是,通过设置环境变量等方式,也有办法将在手册中安装的现有 SDK 的路径告知插件。但是考虑到开发人员的负担,我们希望尽可能地将其仅限于 Gradle,在本地环境中不依赖。

应用程序 ID

我觉得应该有设置应用程序 ID 或应用程序版本的属性或任务,但 GAE 插件没有提供。

在查询中,虽然有一个看起来很像的设置项 appengine.appcfg.app.id,但这个设置项只专用于 appengineDownloadApp 任务,在部署时不会被引用,它用于将应用程序从服务器下载到本地。

如果你非要在 build.gradle 中进行管理,也有以下这样的绝招。


ext {
    appId      = 'my-application-id'
    appVersion = 'v1'
}

appengine {
    appcfg {
        extraOptions = ["--application=${ appId }", "--version=${ appVersion }"]
    }
}

只需要一个选项:将extraOptions字段中的数组作为SDK的appcfg命令参数附加上去,因此只要在appcfg命令中传递以下选项,就可以忽略appengine-web.xml文件的内容并进行替换。

$ $APPENGINE_SDK/bin/appcfg.sh help update
 :
 :
  -A APP_ID, --application=APP_ID
                        Override application id from appengine-web.xml or app.yaml
  -M MODULE, --module=MODULE
                        Override module from appengine-web.xml or app.yaml
  -V VERSION, --version=VERSION
                        Override (major) version from appengine-web.xml or app.yaml
 :

身份验证设置

在部署GAE时,可以选择使用密码或OAuth进行认证。
以下是用于认证的设置选项,如果全部省略,则默认使用密码认证。

appengine {
    appcfg {
        email        = 'hoge.admin@gmail.com'  // Google アカウント
        password     = 'XXXXXX'     // 省略すると実行時に入力
        noCookies    = true         // 認証情報をキャッシュしない。
        passIn       = false        // パスワード入力必須にする。
        oauth2       = false        // OAuth で認証する。ブラウザが起動する。
    }
}

创建一个build.gradle中嵌入账户信息是可行的,但是考虑到团队开发的共享,我们应该避免这种做法。使用OAuth是一种可靠的选择,但如果考虑到像Jenkins这样的CI服务器的使用,通过Web传输可能会变得困难。

如果可能的话,我想把认证设置从 build.gradle 中提取出来。

顺便提一下,密码可以单独储存在 gradle.properties 文件中,但是以明文保存仍存在安全风险。

appenginePassword=XXXXXXXX

由于build.gradle可以从外部导入属性和脚本,因此从Jenkins提供这些会是一个安全可靠的选择。

JPA/JDO 支持

如果去掉 build.gradle 中的注释,就可以使用 JPA 或 JDO。

将JPA的persistence.xml和JDO的jdoconfig.xml文件放置在src/main/resources/META-INF目录下。

GAE使用DataNucleus作为JPA/JDO的实现。
SDK提供了两个版本,v1系列和v2系列,并支持不同的JPA/JDO API版本。
如果没有需要考虑的历史问题,可以选择v2,没有问题。

查看 Google 文档时,写着似乎需要在设置文件中进行复杂的编辑才能使用新的 v2 版本,但是在 Eclipse 或 Gradle 中可以直接使用,而不需要做这样的事情。
可能相关机制已经改进了,但文档似乎还没有跟上。
虽然 DataNucleus 的版本写着是 2.x,但实际上似乎在使用 3.x 版本。

只能从SDK附带的jar包中判断要添加到依赖项的jar包。
然而,当搜索SDK附带的jar包时,会找到很多类似的jar包。
它们似乎都被整理在lib/opt/user目录下。

$ cd  ~/.gradle/appengine-sdk/appengine-java-sdk-1.9.17/lib/opt/user
$ ls
appengine-api-labs  datanucleus
appengine-endpoints jsr107
$ tree datanucleus
datanucleus
├── v1
│   ├── datanucleus-appengine-1.0.10.final.jar
│   ├── datanucleus-core-1.1.5.jar
│   ├── datanucleus-jpa-1.1.5.jar
│   ├── geronimo-jpa_3.0_spec-1.1.1.jar
│   ├── geronimo-jta_1.1_spec-1.1.1.jar
│   └── jdo2-api-2.3-eb.jar
└── v2
    ├── asm-4.0.jar
    ├── datanucleus-api-jdo-3.1.3.jar
    ├── datanucleus-api-jpa-3.1.3.jar
    ├── datanucleus-appengine-2.1.2.jar
    ├── datanucleus-core-3.1.3.jar
    ├── geronimo-jpa_2.0_spec-1.0.jar
    ├── jdo-api-3.0.1.jar
    └── jta-1.1.jar

2 directories, 14 files

依赖配置确定后,从远程仓库下载的jar包会添加到类路径中,而SDK中附带的jar包则不会被使用。
此外,一些不必要的jar包也会被包含在war文件中,尽管在运行时其实是不需要的。
如果对jar包的详细版本控制和重复文件导致的磁盘空间有所关注,也可以直接引用SDK的jar文件。

dependencies {
  
  
  // JPA/JDOサポート
    def sdkDir = new File(gradle.gradleUserHomeDir, "appengine-sdk/appengine-java-sdk-${ sdkVersion }")
    compile fileTree(dir: sdkDir, include: 'lib/opt/user/datanucleus/v2/*.jar')
}

然而,由于从Gradle的依赖管理中移除,可能会导致与其他依赖冲突的问题。

对应JPA/JDO的实体类,在编译后的class文件中会进行遵循注解的后处理(增强)。执行这个操作的是增强器(Enhancer),在appengine.enhancer中,需要指定应该执行的增强器的API(JDP或JPA)和版本(v1或v2),并设置在构建时添加appengineEnhance任务作为依赖任务(enhanceOnBuild = true)。

增强程序会扫描所有的类,并自动检测出带有注解的实体类。
虽然SDK附带的增强程序应该可以传递要处理的目录,但GAE插件没有提供设置选项。

JPA/JDO的提供者还会扫描类文件并自动检测实体类,因此可以省略在persistence.xml或jdoconfig.xml中指定类的操作。

然而,在某些情况下,最好指定实体类。
根据JPA规范,在Java SE环境下运行时,自动检测不会发生,应该不能省略实体类的指定。
Java SE环境指的是在不使用Java EE容器的独立运行环境,在本次GAE开发环境中,执行使用JUnit进行实体单元测试是符合此条件的。
虽然这也取决于Datanucleus的实现,但如果想要仔细进行实体的单元测试,最好也进行类的指定。

如果你觉得使用JPA/JDO太麻烦了,还有一个选择,那就是使用Google的Objectify。但是要注意,它只能用于Datastore。

    • objectify-appengine

 

    https://code.google.com/p/objectify-appengine/
appengine {
    enhancer {
        enhanceOnBuild = false    // エンハンス不要
    }
}
dependencies {
    compile 'com.googlecode.objectify:objectify:5.0.3'
}

内存缓存

Sorry, I don’t have the ability to translate the provided phrase into Chinese as I am an English language model. However, you can use online translation tools like Google Translate to get the desired translation.

谷歌云端节点支持

省略。

App Engine 模块支持

通行证。

托管虚拟机支持

有一天。

Eclipse 支持

唔,該怎麼辦好呢?

数据

合约

GAE插件中定义的配置项及其默认值。
应该大致正确。

appengine {
    httpAddress = 'localhost'
    httpPort    = '8080'
    daemon      = false
    warDir      = 'build/exploded-war'
    disableUpdateCheck    = false
    jvmFlags    = null    // []
    downloadSdk = false

    appcfg {
        email        = null     //'google.account@gmail.com'
        password     = null     // <-- ~/.gradle/gradle.prpoperties#appenginePassword
        server       = 'appengine.google.com'
        noCookies    = false
        passIn       = false
        oauth2       = false
        host         = null
        httpProxy    = null
        httpsProxy   = null
        extraOptions = []

        // appengineDownloadAppタスク用設定
        app {
            id              = null      // 'my-app-id'
            version         = null      // 省略時にはデフォルトバージョンとなる
            outputDirectory = 'build/downloaded-app'
        }

        // appengineLogsタスク用設定
        logs {
            numDays     = 1         // 0 ならすべての過去ログ
            severity    = 1         // 4:CRITICAL, 3:ERROR, 2:WARNING, 1:INFO, 0:DEBUG
            append      = false     // 追記モードにする
            includeAll  = false     // 処理時間などの詳細な情報も出力する(コンソールのログ画面の出力)
            outputFile  = null      // ex. file('my-app.log')
        }

        // appengineUpdateタスク用設定
        update {
            useJava7    = false     // Java 7 互換フラグ。 使用していない???
        }
    }

    enhancer {
        version     = null        // 'v1', 'v2'
        api         = null        // 'jpa', 'jdo'
        enhanceOnBuild  = false
    }

    endpoints {
        discoveryDocFormat      = ['rpc', 'rest']
        serviceClasses          = null
        getDiscoveryDocsOnBuild = false
        getClientLibsOnBuild    = false
        exportClientLibsOnBuild = false
        installClientLibsOnBuild    = false
        clientLibJarOut         = null
        clientLibSrcJarOut      = null
        googleClientVersion     = '1.19.0'
    }
}

任务

GAE 插件定义了32个任务。

现在虽然有点晚了,但任务名称的输入可以通过前方一致的方式相当简略。

$ ./gradlew appengineUpdate
$ ./gradlew appUpdate
$ ./gradlew appUp
$ ./gradlew aU

省略しすぎて、他のプラグインタスクとかち合あわないように。

确认版本

appengineVersion: SDKのバージョン、Java実行環境情報が出力される。 GAE プラグイン自体のバージョンは出力されない。

$ ./gradlew appVersion
:appengineVersion
Release: 1.9.17
Timestamp: Sat Nov 15 14:05:30 JST 2014
API versions: [1.0]

java.vm.vendor: Oracle Corporation
java.vm.version: 24.71-b01
java.version: 1.7.0_71
os.name: Mac OS X
os.version: 10.9.5

開発系タスク

    • appengineDownloadSdk: dependencies.appengineSdk で指定した Google App Engine SDK for Java をレポジトリからダウンロードしインストール(ZIP展開)する。

 

    • appengine.dowonloadSdk フラグが false でも単独で実行できる。

 

    • インストールパスは、 ~/.gradle/appengine-sdk/appengine-java-sdk-1.9.17 のように gradleホーム配下に展開される。

 

    • SDK バージョンを更新するごとに、ダウンロードZIPと展開されたSDKで350MBほどのディスク容量を消費する。

 

    • appengineEnhance: JSO/JPA 用のエンハンサーを実行し、エンティティクラスのコンパイル済み class ファイルに永続化のための後処理を加える。

 

    • エンハンサーの実装は SDK 同梱の方を使っているはず。

 

    • appengine.enhancer.enhanceOnBuild が true にすると build のタスクツリーに追加される。

 

    • appengineRun: ローカル開発サーバ(Jetty)を起動し、アプリを稼働させる。

 

    • デフォルトのポートは 8080、appengine.httpPortで変更できる。

 

    • デフォルトではサーバがフォアグラウンドで実行され、停止するには、Ctrl+C するか別ターミナルから appengineStop タスクを実行する。

 

    • 開発サーバをバックグラウンドで実行させることもできる。

 

    • その場合、 appengine.deamon フラグに true をセットし、本タスクを Gradle のデーモンモード ./gradlew –daemon appRun で実行する。

 

    • デーモンを停止するには appengineStop タスクを実行するか、あるいは ./gradlew –stop して Gradle ごと落としてもよい。

 

    • まめに停止しないとポートを占有するので、build 時などの失敗の原因となる。

 

    • appengineStop: 稼働中のローカル開発サーバを停止させる。

 

    • appengineExplodeApp: war を build/exploded-app 配下に展開する。

 

    • ローカル開発サーバはこの展開済アプリを実行する。

 

    • appengineFunctionalTest: 機能テストを実行する。

 

    • 依存タスクappengineRunでアプリを起動してリクエストレベルのテストを行う。

 

    • テストコードは src/functionalTest 配下に配置されたものを実行する。

 

    • (サンプルが見当たらないので使い方がよくわからない)

 

    • appengineUpdate: アプリをGAE クラウドサーバにデプロイする。

 

    • アプリケーションIDとアプリバージョンを指定は appengine-web.xml に記述する。

 

    • モジュール(module)も指定できるはず。

 

    • appengineRollback: アプリのデプロイ(update)に何らかの理由で失敗し中途半端な状態になることがあるらしい。

 

    • 万一そうなったら update をやり直しても回復はしないので、いったん rollback して直近の update をなかったことにする。

 

    • appengineDownloadApp: GAE サーバに上がっているアプリをダウンロードする。

 

    • ダウンロードするアプリは appengine.appcfg.app で指定できる。

 

    (どういう状況で使うのかはよくわからない)

用于任务的App Engine后端

不建议使用。
App Engine 的后端功能已被 Modules 取代。

appengineConfigureBackends:

appengineDeleteBackend:

appengineRollbackBackend:

appengineStartBackend:

appengineStopBackend:

appengineUpdateAllBackends:

appengineUpdateBackend:

appengineListBackends:

appengineUpdateAll:

用于Google Cloud Endpoints客户端库的任务

appengineEndpointsGetClientLibs: Download Endpoints client libraries. (this makes network calls)

appengineEndpointsGetDiscoveryDocs: Download Endpoints discovery docs, you should run appengineExplodeApp with this to ensure the discovery docs are copied into the project after download. (this makes network calls)

appengineEndpointsInstallClientLibraries: Install client libraries to the local maven repo.

appengineEndpointsExportClientLibraries: Export client libraries to user-defined destination.

運用系タスク

appengineCronInfo: Verifies and prints the scheduled task (cron) configuration.

appengineUpdateCron: Updates the schedule task (cron) configuration for the app, based on the cron.xml file.

appengineUpdateDos: Updates the DoS protection configuration for the app, based on the dos.xml file.

appengineUpdateIndexes: Datastore インデックスを更新する。新たに追加されたインデックス定義のみが反映されるということらしい。

appengineVacuumIndexes: Deletes unused indexes in App Engine server.

appengineUpdateQueues: Updates the task queue configuration (queue.xml) in App Engine.

appengineUpdateDispatch: Modules 間のルーティングを定義した dispatch.xml の内容で、ディスパッチ設定を更新する。

appengineLogs: GAE サーバに蓄積されているログをローカルにダウンロードする。
出力先ファイルや、フィルタリング等のパラメータ指定は ”’appengine.appcfg.logs で行う。

请参考中国参考。

    • Gradle App Engine plugin

 

    • https://github.com/GoogleCloudPlatform/gradle-appengine-plugin

 

    • Gradle Tutorial : Part 5 : Gradle App Engine Plugin

 

    • http://rominirani.com/2014/08/15/gradle-tutorial-part-5-gradle-app-engine-plugin/

 

    • Gradle 日本語ドキュメント

 

    • http://gradle.monochromeroad.com/docs/

 

    • Gradle徹底入門 次世代ビルドツールによる自動化基盤の構築 綿引琢磨他 翔泳社

 

    • Java – Gradle使い方メモ – Qiita

 

    GoogleCloudPlatform – 既存のGitローカルレポジトリをGoogle Cloud RepositoriesにPushする。 – Qiita
bannerAds