最低限おさえておきたいEGitの使い方について

最近ソース管理にGitを使うプロジェクトがかなり増えてきました。ソース管理はSVNで十分と思っているユーザもプロジェクトの方針としてGitになった場合、最低限の操作を覚えないと作業に支障をきたしてしまいます。その際にコマンドラインで操作しても良いのですが、今までSVNSubversiveとかSubclipseなどを使ってきたEclipseユーザは、EclipseからGitを操作したいところです。

そこでEGitを使おうと思ってもEGit自体はそこそこ歴史がある割に意外と情報が少なくて困ってしまった人もいるのではないでしょうか?。

今回はプロジェクトで使うに当たって、最低限知っておけばどうにかなりそうな操作をまとめてみることにしました。構成としては利用者側としてGitを利用することを想定してみました。実際、作業して順番とは違うのでファイルに一部矛盾するところがありますが気にしないでください。

私自身まだまだ知らないことも多いので、間違っている点やもっと効率よく出来る点などがございましたらご指摘ください。

環境としては以下で試しています。
OS:Mac
Eclipse:3.6
EGit:1.0

リポジトリにはGitHubを利用しています。

Gitのリモートリポジトリからプロジェクトを取得

誰かがGitに上げたプロジェクトをEclipseに取り込みます。Gitではcloneすると言います。
Package Explorerを右クリック>importを選択します。

Git>Projects from Gitを選択します。

取得するリポジトリを指定します。GitHubの場合、Webでコピー出来るurlをURL欄にコピーします。Protocol欄にSSHを選択します。するとURL欄がSSHにあわせて変更されますが、そのままでかまいません。nextをクリックします。

cloneするリポジトリを選択してnextをクリックします。

ローカルリポジトリを作成する必要があるのでパスを指定します。指定したらfinishをクリックします。

importするプロジェクトの選択が表示されます。そのままnextをクリックします。

今回はEclipseプロジェクトをGitからcloneするので、Import Existing Projectsにチェックしてnextを押します。

importしたいプロジェクトを選択してfinishをクリックします。

これでEclipseにプロジェクトをcloneすることが出来ました。

ローカルリポジトリへのcommit

Gitの場合、ファイルを修正したらまずはローカルリポジトリにcommitします。

では現在のプロジェクトをローカルリポジトリにcommitしてみます。右クリック>Team>Commitを選択します。

初回はユーザ情報を求められるので入力します。

コミットダイアログが表示されるのでコメントの入力とコミットするファイルを選択して、commitボタンを押します。

これでローカルリポジトリにコミットが出来ました。マーク「?」が消えているのが確認出来ると思います。

Gitの場合、commitしただけではソースを反映することが出来ません。その後にリモートリポジトリに対してpushする必要があります。続いてリモートリポジトリにpushする方法についてです。

リモートリポジトリにpushする

ローカルリポジトリにcommitしたらリモートリポジトリに反映させるためにpushする必要があります。
プロジェクトを選択して、右クリック>Team>Remote>Pushをクリックします。

pushするリポジトリを設定してnextをクリックします。

pushしたいブランチを選択します。

選択したらAdd Specボタンをクリックします。するとSpecifications for pushに設定が反映されます。nextをクリックします。

確認画面が表示されるのでfinishをクリックします。

このとき初回の場合、セキュリティの警告が出る場合があるようです。

完了画面が表示されOKをクリックして完了です。

自分や他の人が変更した内容の確認

変更を確認します。
プロジェクトを選択して右クリック>Team>Synchronize>FETCH_HEADを選択します。

Synchronizing perspectiveを表示するかとダイアログで訪ねられます。YesでもNoでもかまいません。ここではYesを選択します。

リポジトリとの差分が表示されます。ここでは、HelloWorld.scalaが他の人から編集されて、HelloWorld2.scalaが自分が新規に作成したことを表しています。

ファイルをダブルクリックすると差分を確認することが出来ます。

HelloWorld.scalaを選択して右クリック>Mergeで取り込むことが出来ます。

自分の更新は通常と同じようにcommit→pushで対応します。

ローカルリポジトリの登録

一応、プロジェクトの登録についても説明します。ここではGitTestというプロジェクトを登録してみることにします。
まずは、プロジェクトを選択して、右クリック>Team>Share Projectを選択します。

Gitを選択してNextをクリックします。

ローカルリポジトリのパスを指定してリポジトリを作成します。createボタンを押して選択ダイアログを表示されます。

ローカルのGitリポジトリのパスを選択します。好きな場所を選択しましょう。ここでは、/local_gitを指定しました。名前にGitTestを指定しました。

チェックボックス「Use or create Repository in parent folder of project」にチェックをつけると現在のプロジェクトにリポジトリを作ることも出来ます。

注意点としては、その後リモートリポジトリに登録した際にリポジトリを指定する方の方法だとGitTestリポジトリの下にEclipseのGitTestプロジェクトが配置されるような構成になるようです。チェックボックスをチェックする方法だとGitTestリポジトリの下にGitTestフォルダは作られません。GitHub有料オプションを使用していて利用出来るリポジトリに制限がある場合などは上のパターンを利用した方がよいでしょう。

自分でリポジトリの場所を選んだ場合

チェックボックス「Use or create Repository in parent folder of project」にチェックをつけた場合

リポジトリを選択したらFinishボタンを押して終了です。

リポジトリの設定が出来ました。以下のような感じになっていると思います。

終わりに

今回はEGitについてまとめました。画像をふんだんに使用したため何気にものすごく手間がかかりました。EGitは安定していないかな?と感じることもありますが十分に実用で使用出来るレベルに達してきていると思います。私自身も知らない機能がたくさんあるのでご存知の方は色々と教えていただけるとありがたいです。

EGitについてさらに詳しく知りたい場合は、以下にUser Guideがあるので参照してみてください。
http://wiki.eclipse.org/EGit/User_Guide

忘れやすい人のためにscpコマンドメモ

いつも忘れてしまうのでメモ。いまいちネットを検索しても直感的に分かる情報がなくて困る。

リモートからローカルにコピー

scp ユーザ名@リモートのホスト名:コピーしたいリモートのファイル .

以下の場合、今いるカレントディレクトリにリモートremoteHostのユーザuserでtext.txtをコピーする。

scp user@remoteHost:/home/user/test.txt .

ローカルからリモートにコピー

scp コピーしたいローカルのファイルパス ユーザ名@リモートのホスト名:保存したいパス

ローカルのtext.txtをremoteHostのユーザuserで/home/user/tmp/にコピーする。

scp test.txt user@remoteHost:/home/user/tmp/

Ubuntuにkyoto tycoonをインストールしてみた。

色々とKVSを調べているのですが、kyoto tycoonがRDBMSレプリケーションできたりするみたいで興味深かったので試しにインストールしてみました。

wget http://fallabs.com/kyotocabinet/pkg/kyotocabinet-1.2.52.tar.gz
apt-get install g++
apt-get install zlib-devel
tar -zxvf kyotocabinet-1.2.52.tar.gz

cd kyotocabinet-1.2.52
./configure
→zlib.hがないと怒られる

zlib.hを探して入れる
apt-get install apt-file
apt-file update
apt-file search zlib.h
apt-get install zlib1g-dev

./configure
make
make install

wget http://fallabs.com/kyototycoon/pkg/kyototycoon-0.9.40.tar.gz
tar -zxvf kyototycoon-0.9.40.tar.gz
cd kyototycoon-0.9.40
./configure
make
make install

/user/local/bin/ktserver
エラーが出た
ktserver: error while loading shared libraries: libkyototycoon.so.2: cannot open shared object file: No such file or directory

ldd ktserver
        linux-gate.so.1 =>  (0xb7837000)
        libkyototycoon.so.2 => not found
        libkyotocabinet.so.9 => not found
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7739000)
        libm.so.6 => /lib/libm.so.6 (0xb7712000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb76f4000)
        libc.so.6 => /lib/libc.so.6 (0xb75af000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xb7596000)
        /lib/ld-linux.so.2 (0xb7838000)

vim /etc/ld.so.conf
/usr/local/lib←追加

ldconfig
/user/local/bin/ktserver

動作確認

set
ktremotemgr set japan tokyo
ktremotemgr set korea seoul
ktremotemgr set china beijing

確認
ktremotemgr inform

get
ktremotemgr get japan

keyのリスト取得
ktremotemgr list

Liftの入門(lift-mapperのquery編)

今回はlift-mapperのQuery関係をまとめます。MappedFieldが先なのではと思わないでもないですがQueryです。lift-mapperは、toFormやtoHtmlであったりモデルのくせにビューにくっついていたり色々知っておかなくてはいけないことがあるのですが、まずはQuery関係に絞って説明します。リファレンス的に使えればと思います。

本題に入る前にちょっとTips

発行したSQLのログを出したい

Boot.scalaに以下を記述

class Boot extends LazyLoggable {
    ・・・
    DB.addLogFunc {
      case (query, time) => {
        logger.info("All queries took " + time + "ms: ")
        query.allEntries.foreach({ case DBLogEntry(stmt, duration) => logger.info(stmt + " took " + duration + "ms")})
        logger.info("End queries")
      }
    }

テーブルを自動で作成したい

Boot.scalaに記述します。

Schemifier.schemify(true, Schemifier.infoF _, modelのobject名)

テーブル名やカラム名を_(アンダーバー)区切りにする

デフォルトだとemployeeNameのようなカラムでテーブルが作成されたり、sqlが発行されたりするので、それをemployee_nameに変える方法です。これもBoot.scalaに記述します。

    LiftRules.stripComments.default.set(() => false)

    import net.liftweb.util.Helpers
    MapperRules.columnName = (_,name) => Helpers.snakify(name)
    MapperRules.tableName = (_,name) => Helpers.snakify(name)

scalaのコンソールでBoot.scalaを動かしたい。

コンソールを起動して以下を入力。

scala>(new bootstrap.liftweb.Boot).boot 


では本題に入ります。なお、完全に網羅するものではないのであしからず。

データをinsertする。

戻り値がbooleanの場合。保存に成功すればtrue。

val result = Employee.create.name("test").jobType(JobType.ANALYST).salary(300).save

戻り値がmodel。

val emp = Employee.create.name("test").jobType(JobType.ANALYST).salary(300).saveMe

keyで1件取得する。

val emp: Box[Employee] = Employee.find(1)

全件取得する。

val empList : List[Employee] = Employee.findAll

条件を指定する。

SQLとしては、「where id > 5」となる。

val empList : List[Employee] = Employee.findAll(By_>(Employee.id, 5))

逆もあります。「where id < 5」

val empList : List[Employee] = Employee.findAll(By_<(Employee.id, 5))

イコールもいけます。「where id = 5」

val empList : List[Employee] = Employee.findAll(By(Employee.id, 5))

検索結果を削除する。

modelのobjectから消すにはdelete_!を使います。

val emp: Employee = Employee.find(1).open_!
val result: Boolean = Employee.delete_!(emp)

※open_!はBox型から値を取得

条件指定で削除する。

条件を指定するにはbulkDelete_!!を使います。ここではLikeを使っています。findAllとかでもLike使えます。

val result: Boolean = Employee.bulkDelete_!!(Like(Employee.name, "山田%"))

件数を取得する。

件数を取得するにはcountを利用します。

val count: Long = Employee.count

条件指定も出来ます。

val count: Long = Employee.count(By(Employee.name, "山田 太郎"))

order byを指定する。

descの場合

Employee.findAll(OrderBy(Employee.name,Descending))

ascの場合(複数も指定出来ます)

Employee.findAll(OrderBy(Employee.name,Ascending),OrderBy(Employee.jobType, Ascending))

取得する件数と何件目から取得するか指定する。

以下だと10件目から5件取得する。

val empList: List[Employee] = Employee.findAll(StartAt(10),MaxRows(5))

SQLを直接発行する。

一つ目のリストにヘッダ名、二つ目のリストに値のリストが取れます。

    val resultList: (List[String], List[List[String]]) =
      DB.runQuery("select * from employee")

    val headerList: List[String] = resultList._1
    val bodyList: List[List[String]] = resultList._2

とりあえず、ざっくりとはこんな感じです。まだまだあるのですが僕自身がリファレンス的に参照しててあった方が便利だと感じたら追加します。

Liftの入門(intellijでの開発環境編)

※2011/4/17追記 jrebelプラグインの設定がもれていたので追記しました。


liftで開発環境を整える際に知らないと手間がかかるのでまとめておきます。ここではintellijを利用します。
IDEintellijの他にはEclipseNetbeans、ensimeなどがあります。ビルドツールには、sbtとmavenがあります。昔はmavenでしたが、最近はsbtの利用が推奨されているようです。

今回構築する環境のバージョンは以下の通りです。
intellij:10
sbt:0.74
lift:2.3
scala:2.8.1.final

注:OSはMacを利用しています。Windows環境とは多少異なる部分がありますがWindowsでも構築したとこがありますが問題ないと思います。

intellijのダウンロード

intellijを以下のサイトからダウンロードします。
http://www.jetbrains.com/idea/download/index.html

intellijプラグインのインストール

intelljでIntellij IDEA>Preferencs>Pluginsを選択します。
PluginsのAvailableタブを開いて、検索窓にscalaと入力して以下のプラグインをインストールします。

jrebelプラグインもインストールします。

※jrebelとはアプリケーションサーバ(jettyとか)を再起動せずにコードに変更があった場合に自動で再読み込みをしてくれるツールです。

jrebelの入手とjrebelプラグインの設定

jrebelはhttp://www.zeroturnaround.com/jrebel/からダウンロードします。

jrebelプラグインの設定をします。メニューのIntelliJ IDEA>Preferencesでjrebelを選択して上記URLから入手したjrebel.jarのパスを指定します。

liftのブランクプロジェクトの入手

liftのサイト(http://liftweb.net/)からブランクプロジェクトをダウンロードします。
アーカイブを解凍するといくつかプロジェクトが入っています。DB接続をしたいならlift_basicかlift_xhtml辺りがいいと思います。lift_blankだとDB接続の設定がされていないです。

ブランクプロジェクトの修正

intellijで取り込めるようにするにはいくつか追加/修正が必要です。

1.sbt-idea-pluginの設定
intellijで利用するために必要なプラグインをダウンロードする設定を行います。
[プロジェクト]/project/plugins/Plugins.scalaを作成します。

Plugins.scala

import sbt._
class Plugins(info: ProjectInfo) extends PluginDefinition(info) {
  val sbtIdeaRepo = "sbt-idea-repo" at "http://mpeltonen.github.com/maven/"
  val sbtIdea = "com.github.mpeltonen" % "sbt-idea-plugin" % "0.4.0"
}

sbt-idea-pluginは現在0.4.0が最新です。0.5が開発中みたいです。

project/build/LiftProject.scalaの修正
intellijに取り込むための設定を追加します。

【修正前】

class LiftProject(info: ProjectInfo) extends DefaultWebProject(info) {

【修正後】

class LiftProject(info: ProjectInfo) extends DefaultWebProject(info) with IdeaProject {

sbtを利用してintellijプロジェクトの作成

ターミナルでプロジェクトの直下に移動します。
sbt.shがあります。windowsの場合でもsbt.batがあるので同様に動きます。

$sbt (sbtが起動)
>update
>idea

ideaと入力した際に「ideaなんて知らないぜ!」と言われる場合は、ブランクプロジェクトの修正がうまくいっておらず、プラグインがダウンロード出来ていない可能性があります。設定を見直してください。それでもダメならとりあえずsbtで「clean」をして、再度「update」をしてみてください。もしかしたらうまくいくかもしれません。

プロジェクトの取り込み

プロジェクトを取り込むには、intellijでFile>OpenProjectから作成したプロジェクトを選択します。
しばらくすると取り込まれます。この際に時々エラーダイアログが出力されることがありますが問題ないようです。いくつかソースを開いてみてエラーが出ていないことを確認してください。

アプリの動作確認

intellijで[プロジェクト]/src/test/RunWebAppを選択して右クリックから「Run with JRebel "RunWeebApp.main"」を選択してください。
下部のコンソール画面にログが出力されます。問題なければ、http://localhost:8080で画面が表示されると思います。

開発時の方法

私の場合は、コンソールでsbtで「~compile」を入力しておいて、ソースの修正があった場合に自動で再コンパイルするにしています。同時にintellijでは、RunWebAppでアプリケーションサーバを起動して自動で反映されるようにしています。この方法ならinttelijのデバッグにも対応することが出来ます。intellijでのデバッグが不要ならsbtの「~jetty-run」だけでも大丈夫です。

※sbtでの「~compile」などはファイルに変更があったらもう一度行うようにする設定です。

おわりに

現時点ではintellijが開発環境では一番良いと思っていますが、現在ベータ版のScala IDE for Eclipse辺りの動向も見守っています。進化が早いのでどのIDEがいいかはまだまだ注意深く見守った方が良いと思います。

The Scala IDE for Eclipse beta 2 available now!
http://www.scala-lang.org/node/9222

以上でintellijでの開発環境編を終わります。

*[scala][lift]Liftの入門(sitemap編)

liftは若干癖があるフレームワークなので勉強を始めると最初に画面遷移あたりで引っかかるかもしれません。
最初はどのファイルが呼ばれているのかすらよくわからないかもしれません。リンクでどんなURLを指定すれば良いのか迷います。

調べているとsitemapってのを書く必要があるみたいだけど、書き方も一見よくわかりにくいため、戸惑うかもしれません。

そこで色々な指定方法があるので、一部ですがまとめていきたいと思います。

今回の本題のsitemapの前に画面が表示される流れだけ簡単に説明しときます。

sbtでプロジェクトを作成した標準的な場合を前提に話します。
まず[プロジェクト]/src/webapp/templates-hidden/default.htmlが呼ばれます。
その中にデフォルトで以下のような記述があります。

default.html

<div id="content" ></div>

上記の部分にその他のhtmlを埋め込んで表示させます。
例えば以下のような指定をします。

index.html

    <div id="main" class="lift:surround?with=default;at=content">
      <div class="lift:helloWorld">
      </div>
    </div>

classで指定してあるlift:surroundがポイントでwith=default;at=contentと記述するとdefault.htmlのid、contentと入れ替わります。なお、lift:surroundの外にある部分は無視され表示されません。

かなりざっくりで読んでいる人がついて来ているか心配ですが、表示される仕組みはこんな感じです。

ではsitemapでの画面遷移についてです。
sitemapを指定するとメニューが表示されます。

sitemapの一番簡単な指定方法

一番シンプルな設定は以下のように行います。
Homeがメニューのリンク名でindexがパスになります。

def sitemap(): SiteMap = SiteMap(
  Menu.i("Home") / "index"
)

複数指定する

複数指定する場合は、「,」区切りで指定します。

def sitemap(): SiteMap = SiteMap(
  Menu.i("Home") / "index",
  Menu.i("Home2") / "index2"
)

呼び出されるhtmlの場所

画面遷移時に呼び出されるHTMLは、[プロジェクト]/src/main/webapp配下に格納します。
ファイル名はパスをindexと指定した場合、index.htmlとなります。

開発モード(liftではrunmodeというのが指定出来ます。)では、毎回画面ロード時に読み込みが行われるため即時反映されます。その他のモードでは、1度だけ読み込まれます。
毎回読み込まれるのは便利ですがコストが高いです。

メニューに表示させない方法について

メニューに表示させないようにするには、「>> Hidden」と記述します。

Menu.i("Home") / "index" >> Hidden

フッタに表示させたい場合

Menu.i("About") / "about" >> LocGroup("bottom")

LogGroup("XX")で指定します。上記例では、bottomを指定しています。グループbottomはdefault.htmlで以下のように指定します。指定した場所にリンクが表示されます。

<span class="lift:Menu.group?group=bottom"></span>

メニューには表示させないでフッタにだけ表示させたい場合は、「>> Hidden」と組み合わせて利用することも出来ます。

Menu.i("About") / "about" >> Hidden >> LocGroup("bottom")

動的なページについて

パスについて全てsitemapに指定しなくてはいけないわけではないです。
以下のようにワイルドカードで指定すると「http://localhost:8080/sample/index」のようなsample/以下の任意のパスを呼び出すことが出来ます。

Menu.i("Sample") / "sample" / **

ファイルは、[プロジェクト]/src/main/webapp/sample/XXX.htmlとして格納します。

デザインについて

liftはデザイナフレンドリなフレームワークですが、事前にsitemapで出力されるhtmlを理解しておく必要があります。
HTMLとしては、以下のようなタグが表示されます。選択されているメニューはspanタグが出力されます。選択されていないメニューはaタグが出力されます。
○lift例

<div id="menu">
<span class="lift:Menu.builder"></span>
</div>

○html例

<div id="menu">
<ul>
  <li><span>Home</span></li>
  <li> <a href="/contents">Contents</a></li>
  <li> <a href="/contents2">Contents2</a></li>
</ul>
</div>

cssを指定するにはliftでは以下のような感じで記述すればよいです。

css

#menu ul li {xxx}
#menu ul li span {xxx}
#menu ul li a {xxx}

メニューの階層化

メニューの階層化を行うことが出来ます。サブメニューは初期表示された段階では非表示になっています。親メニューが選択されると表示されます。

      Menu.i("Info") / "info" submenus(
        Menu.i("About") / "about" >> Hidden >> LocGroup("bottom"),
        Menu.i("Contact") / "contact",
        Menu.i("Feedback") / "feedback" >> LocGroup("bottom")
      )

HTMLは以下のようにulタグ、liタグがネストされる形で表示されます。

<ul>
  <li> <span>info</span>
    <ul>
      <li> <a href="/contact">Contact</a></li>
      <li> <a href="/feedback">Feedback</a></li>
    </ul>
  </li>
</ul>

ざっと駆け足で説明しましたがsitemapについての説明は以上です!

scalaでservlet3.0を動かす

scalaで簡単にWebアプリを作る方法を考えてて、とりあえずservlet3.0で簡単に動かしてみた。
scalaで書くと以下のような感じ。

package code

import java.io.IOException;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(Array("/test"))
class ScalaServlet extends HttpServlet {
	override def doGet(req: HttpServletRequest,
			res: HttpServletResponse) = {
	    res.getWriter().print(new Date());
	}
}

@WebServlet(Array("/test"))のようにArrayを書く必要がある点に注意が必要。
普段は、intellijを使っているけど、最近出たeclipseScala IDE 2.0.0-beta1(http://download.scala-ide.org/)を使ってみた。

うーん。確かに動くけど、servletを生で使うのは微妙かも。
scalaであるメリットが活きてこなそう。ロジック書いてないってのもあるけど、java臭さしかない。
でもjava部分を隠すようなラップをしてあげるだけで、結構いい感じになるかも。
例えば、req.getParameter("aaa")でOption型返すようにするとか。リストの戻り値をscalaのListにするとか。

一番の収穫は、scalaでWebだとliftとかplayを使わなくてはいけないみたいな固定観念があったけど、
意外と既存のjavaでもいけるかもと考えが変わったのが良かった。

次はJPAでも試してみるか。