2009年12月1日火曜日

Google App Engine SDK の dev_appserver.py が自動的に index.yaml を更新してくれない時の対処法

ときどきGoogle App Engine SDKのdev_appserver.pyが自動的にindex.yamlを更新してくれない時があるので、原因を調べてみました。


■いきなりネタバレ
犯人は改行文字


■前提条件
index.yamlは、以下の様な作りになっています。
indexes:

- kind: django_admin_log #手動で定義したインデックス
properties:
- name: content_type
- name: object_id
- name: action_time

# AUTOGENERATED

# This index.yaml is automatically updated whenever the dev_appserver
# detects that a new type of query is run. If you want to manage the
# index.yaml file manually, remove the above marker line (the line
# saying "# AUTOGENERATED"). If you want to manage some indexes
# manually, move them above the marker line. The index.yaml file is
# automatically uploaded to the admin console when you next deploy
# your application using appcfg.py.

- kind: hon_herostatistics #ここから下は、自動的にdev_appserver.pyが追加してくれるindex
properties:
- name: fetchCompleted
- name: hid
- name: datetimeCreate
direction: desc
このように、# AUTOGENERATEDコメントが存在すれば、その下に自動的に必要なindexを生成してくれるようになっているのですが、時々この自動生成がうまくいかない場合があります。


■症状
具体的には、以下のように余計な物をすべて消した状態のindex.yamlを用意しても、dev_appserver.pyが「indexが手動定義されているので、自動生成しないよ」とエラーを吐きます。
indexes:

# AUTOGENERATED
困りました。


■原因と対処
そこでよくよく調べてみるためにvimではないエディタでこのindex.yamlを開いてみたのですが、すると末尾の改行文字がCRLF(dos形式)になっていました。そこで私のMacの環境に合わせて改行文字をLF(unix形式)にしてみたところ、無事にdev_appserver.pyのindex自動生成が動作するようになりました。vimで操作するなら、
:set fileformat=unix
とすればよいです。

2009年11月23日月曜日

maven2を使ってScalaのHello Worldを書いてみた

先日@yuroyoro氏により開催されましたScala Hackathon #1に行ってきました。Scalaは初めてだったので、ハッカソン資料に従ってまずはHello Worldから作ってみました。資料によると、
  • インタラクティブコンソールを使う
  • Eclipseのプラグインを使う非推奨
  • NetBeansのプラグインを使う
  • IntelliJ IDEAのプラグインを使う
  • テキストエディタとMavenとmaven-scala-toolsを使う
  • テキストエディタとsbt(Simple build Tool)を使う
これだけの開発手法を選択することが出来るそうです。そこであえて私はMaven2を使ってScalaのHello Worldを書いてみることにしました。

参考にした資料はこちら。
http://dl.dropbox.com/u/261418/scala-hackathon/setup.html#maven2
参考にしたページはこちら。
http://scala-tools.org/mvnsites/maven-scala-plugin/plugin-info.html
http://scala-tools.org/mvnsites/maven-scala-plugin/usage_run.html


■まずはmvnプロジェクトを作る
基本的には資料に記載されている内容と全く同じです。次の殺人的に長いmvnコマンドを入力するだけでプロジェクトを作ってくれます。
mvn org.apache.maven.plugins:maven-archetype-plugin:1.0-alpha-7:create \
-DarchetypeGroupId=org.scala-tools.archetypes \
-DarchetypeArtifactId=scala-archetype-simple \
-DarchetypeVersion=1.2 \
-DremoteRepositories=http://scala-tools.org/repo-releases \
-DgroupId=scalahackathon.helloworld -DartifactId=scalahackathon.helloworld
ただし、このコマンドによって生成されたデフォルトのScalaプロジェクトではそのままビルド結果を実行することができません。多少不備があります。後ほど詳しく説明します。とりあえずビルドとテストはできるので後回しにします。


■Appクラスを書かなくちゃ始まらない
生成されたデフォルトのScalaプロジェクトにあるAppクラスを書きます。このAppクラスと言う奴が、いわゆるJavaでいうmain関数を持ったメインクラスの扱いになってるみたいです。
akisute scalahackathon.helloworld$ cd src/main/scala/scalahackathon/helloworld 
akisute helloworld$ vim App.scala
package scalahackathon.helloworld

/**
* Hello world!
*
*/
object App extends Application {
println("Hello World!");
val l = List(1, 2, 3, 4, 5, 6);
l.foreach(println(_));
}
Applicationを拡張したAppクラスの中身が、そのままmain関数相当になるみたいです。このあたりよく分かってませんが、Appクラスの中で再度main関数を定義すると思いっきり怒られるのできっとそうなんだと思います。


■さて実行、その前に
さてここで
mvn scala:run
を実行すればプロジェクトをビルドして実行してくれるのですが、実は先ほど申し上げましたようにこのままではビルドには成功しますが実行に失敗します。原因はメインクラスがpom.xmlで定義されていないためです。
実行するためには、以下のように直接メインクラスを指定するか、
mvn scala:run -DmainClass=scalahackathon.helloworld.App
または以下のようにpom.xmlを修正してから実行する必要があります。毎回毎回直接メインクラスを指定するのは骨が折れるので、pom.xmlを直してみましょう。
<!-- reportingの中を直す、build要素はそのままでよい -->
<reporting>
<plugins>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<configuration>
<scalaVersion>${scala.version}</scalaVersion>
<!-- このlaunchers要素を新規に作る。idとmainClassは必須。 -->
<launchers>
<launcher>
<id>app</id>
<mainClass>scalahackathon.helloworld.App</mainClass>
<!-- 以下、任意要素。 args と jvmArgs を指定できます。 -->
<!--
<args>
<arg>arg1</arg>
</args>
<jvmArgs>
<jvmArg>-Xmx128m</jvmArg>
<jvmArg>-Djava.library.path=...</jvmArg>
</jvmArgs>
-->
</launcher>
</launchers>
</configuration>
</plugin>
</plugins>
</reporting>
修正してからmvn scala:runを実行すると、長い長いjarダウンロードの末、以下のような結果が得られます。
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'scala'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Unnamed - scalahackathon.helloworld:scalahackathon.helloworld:jar:1.0-SNAPSHOT
[INFO] task-segment: [scala:run]
[INFO] ------------------------------------------------------------------------
[INFO] Preparing scala:run
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [scala:compile {execution: default}]
[INFO] Checking for multiple versions of scala
[INFO] Nothing to compile - all classes are up to date
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [scala:testCompile {execution: default}]
[INFO] Checking for multiple versions of scala
[INFO] Nothing to compile - all classes are up to date
[INFO] [scala:run]
[INFO] Checking for multiple versions of scala
[INFO] launcher 'app' selected => scalahackathon.helloworld.App
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
Hello World!
1
2
3
4
5
6
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3 seconds
[INFO] Finished at: Mon Nov 23 20:59:51 JST 2009
[INFO] Final Memory: 18M/79M
[INFO] ------------------------------------------------------------------------
うまくいったみたいですね。

Mac OS Xには最初から/usr/share以下にmaven2やantが付いてくる

先日のScala Hackathon #1にて初めて気づいた驚愕の事実。なんとMac OS Xには最初からJavaの開発ツールが付いてきていたのでした。
akisute ~$ mvn --version
Maven version: 2.0.9
Java version: 1.6.0_15
OS name: "mac os x" version: "10.6.2" arch: "x86_64" Family: "mac"
akisute ~$ ant -version
Apache Ant version 1.7.0 compiled on July 20 2009
akisute ~$ which mvn
/usr/bin/mvn
akisute ~$ which ant
/usr/bin/ant
ちょっとmaven2のバージョンが古いですが、普通に使う分にはたぶん問題なさそうです。ちなみにこれらのツールは/usr/share以下に用意されています。
akisute ~$ cd /usr/share
akisute share$ ls
NotificationServer/ distcc_compilers info/ sandbox/
Ssh.bin doc/ java/ screen/
TargetConfigs/ emacs/ junit/ sdef/
aclocal/ enscript/ langid/ servermgrd/
aclocal-1.10/ examples/ libiodbc/ skel/
ant/ file/ libtool/ snmp/
apr-1/ ftpd/ locale/ statsCollector/
autoconf/ gdb/ man/ swig/
automake-1.10/ germantok/ maven@ tabset/
bakefile/ gprof.callg mecab/ tcsh/
bison/ gprof.flat misc/ terminfo/
caldavd/ groff/ mk/ texi2html/
calendar/ gtk-doc/ openmpi/ texinfo/
cracklib/ gutenprint/ openmpi-default-hostfile uucp/
cups/ heapdiff/ openmpi-mca-params.conf vim/
cvs/ hiutil/ openmpi-totalview.tcl xcode-select/
derby/ httpd/ podcastproducer/ zoneinfo/
dict/ icu/ ri@ zsh/
おお、他にもderbyとかありますね。TomcatやJettyのようなサーブレットコンテナがないので、そのまますぐにWebアプリ開発とはいきませんが、なかなか面白そうです。

・・・む、ひょっとしてこれ常識ですか? ><