SVNKit(2)
前回の続き。
前回はとりあえずISVNRepository
とISVNEditor
とISVNDiffWindow
を使ってリポジトリの内容にアクセスできそう、というところまでやった。
一応注記しておくと、前回取得できた情報を何とかすればSVNクライアントとして動けるのかもしれないが、前回の内容ではいわゆる .svn
フォルダ配下の情報を作ることについては何も気にしていないので、まっとうなSVNクライアントとして動作させるにはいろいろと足りないかもしれない。
ここの記事では今後もまっとうなSVNクライアントとして動かすことは考えていないことはここでお断りしておく。たぶん、SVNクライアントを実装したいのなら、high-level APIを使うべきだろう。
で、今回は定期または不定期的にリポジトリから最新の情報を取得することを考える。その場合、前回取得した内容から現時点での最新までの差分のみを取得したい。前回はcheckout
を呼んでみたので、差分となるとそこからのupdate
ということになるだろう。diff
というメソッドもあるようなのでリビジョンを指定してDiffを取るのでもいいのかもしれないが、とりあえず今回はupdate
を調べてみる。
ISVNRepository#update
セットアップと接続までは前回と同じ。update
メソッドには(にも)いくつかオーバライドがあるが、以下のように呼びだしてみる。
repository.update(-1, "trunk", true, new ExpReporter(), new ExpEditor());
前回は端折ったが、引数について順に。
-1
- アップデートする先のリビジョン。APIドキュメントによるとデフォルトはHEADだ、と書いてあるが、型が
long
なのでデフォルトって何のことだと思ったが、どうも-1
(というかたぶん0より小さい値だろう)っぽい。
- アップデートする先のリビジョン。APIドキュメントによるとデフォルトはHEADだ、と書いてあるが、型が
"trunk"
- APIドキュメントではこれはリポジトリのインスタンスを生成する際に指定するURLの次の1レベルのパス、見たいな説明がされている。今回、trunkの上までを指定してリポジトリのインスタンスを生成しているので、こんな感じになる。optionalと書かれているので、リポジトリオブジェクトを生成する際に trunk を含めている場合、なくてもいいのかもしれない。
- ブランチを指定したい場合にどうなるのかよくわからないが
branches/branch-name
的な書き方でいいんだろうか
true
- 再帰的に処理するかどうかフラグ。SVNクライアントの画面なんかでもチェックボックスを見ることがある
new ExpReporter()
ISVNReporterBaton
をimplementsした適当実装。後述。
new ExpEditor()
- 前回若干説明したやつ
- 今回も呼ばれたメソッド名と引数を適当に結合して出力する適当実装
ISVNReporterBaton
前回のISVNEditor
に加えてISVNReporterBatonというinterfaceの実装を要求されている。
APIドキュメントに加えて若干の説明がここにあるが、要はワーキングコピーに存在するディレクトリやファイルについて個別にどんな状態か(チェックアウトされたものか、どのリビジョンか、削除するつもりかどうかなど)個別のパス情報としてリポジトリに伝えてやる必要があるらしい。
- 上記のインタフェースを実装すると引数に
ISVNReporter
インスタンスを引数に受け取れるので、それに対してsetPath
というメソッドを呼ぶことで個別のディレクトリ、ファイルについての状態を伝えていけということのようだ。 - ユーザの操作によってチェックアウト時とurlが変わってしまう場合(ファイルの移動などだろうか)は代わりに
linkPath
を呼べ、とか同様にしてファイルをリポジトリから削除するつもりなら、deletePath
を呼べとも書かれている。 - そして一通りの報告処理が終わったら
finishReport
を呼ぶ必要があるようだ。なんでそんな必要があるのかよくわからないが、個別にパスを調べる処理はそれなりに時間がかかることが想像されるのでマルチスレッド化されて処理されることを見越してのことかな?
ということで、ワーキングコピーに何もないことにして以下のような報告をするコードを書いてみる。
public class ExpReporter implements ISVNReporterBaton { @Override public void report(final ISVNReporter reporter) throws SVNException { reporter.setPath("", null, 0, SVNDepth.INFINITY, false); reporter.finishReport(); return; } }
reporter.setPath
の引数について
- ワーキングコピーには
""
しか存在してない - 特にロックは使用していないので ロックトークンは
null
""
のリビジョンは0
(最初)- 対象にするサブエントリ(配下のファイルとかフォルダ)の階層は無限(
SVNDepth.INFINITY
) - このパス(この場合
""
)がディレクトリでかつ前回のupdate
がエラーで失敗した場合はtrue
である必要があるが、そうでないのでfalse
setPathの第一引数は"/"
ではないかと思ったのだが、それだとよくわからないエラーが返ってきた。というかapacheのSVNモジュールがassertで死んでた。ドキュメントでは絶対パスで書かれているように見えるが…。
で以下のような出力を得た
#targetRevision start > [rev.3] #openRoot start > [rev.0] #addDir start > trunk #changeDirProperty start > svn:wc:ra_dav:version-url /svn/test/!svn/ver/3/trunk #changeDirProperty start > svn:entry:committed-rev 3 #changeDirProperty start > svn:entry:committed-date 2016-03-03T18:15:19.061137Z #changeDirProperty start > svn:entry:last-author test #changeDirProperty start > svn:entry:uuid 5025b694-87bc-4570-9e45-8a2bcb52a122 #addFile start > trunk/file2.txt #changeFileProperty start > trunk/file2.txt svnkit:entry:sha1-checksum 54563f95fefa691baa82a522156322c21f7d6df3 #changeFileProperty start > trunk/file2.txt svn:wc:ra_dav:version-url /svn/test/!svn/ver/3/trunk/file2.txt #changeFileProperty start > trunk/file2.txt svn:entry:committed-rev 3 #changeFileProperty start > trunk/file2.txt svn:entry:committed-date 2016-03-03T18:15:19.061137Z #changeFileProperty start > trunk/file2.txt svn:entry:last-author test #changeFileProperty start > trunk/file2.txt svn:entry:uuid 5025b694-87bc-4570-9e45-8a2bcb52a122 #changeFileProperty start > trunk/file2.txt svn:mime-type text/plain #applyTextDelta start > trunk/file2.txt #textDeltaChunk start > trunk/file2.txt 0:0:7:1:7:8:0 #textDeltaEnd start > trunk/file2.txt #closeFile start > trunk/file2.txt #addFile start > trunk/.project #changeFileProperty start > trunk/.project svnkit:entry:sha1-checksum 4d0a7da34b1a6f2e1416d746bf268c1137453e14 #changeFileProperty start > trunk/.project svn:wc:ra_dav:version-url /svn/test/!svn/ver/2/trunk/.project #changeFileProperty start > trunk/.project svn:entry:committed-rev 2 #changeFileProperty start > trunk/.project svn:entry:committed-date 2016-03-03T18:14:34.687289Z #changeFileProperty start > trunk/.project svn:entry:last-author test #changeFileProperty start > trunk/.project svn:entry:uuid 5025b694-87bc-4570-9e45-8a2bcb52a122 #changeFileProperty start > trunk/.project svn:mime-type text/plain #applyTextDelta start > trunk/.project #textDeltaChunk start > trunk/.project 0:0:208:3:208:211:0 #textDeltaEnd start > trunk/.project #closeFile start > trunk/.project #addFile start > trunk/file1.txt #changeFileProperty start > trunk/file1.txt svnkit:entry:sha1-checksum 994c650e0954fd76b6859dae6d87caf2fad19e35 #changeFileProperty start > trunk/file1.txt svn:wc:ra_dav:version-url /svn/test/!svn/ver/3/trunk/file1.txt #changeFileProperty start > trunk/file1.txt svn:entry:committed-rev 3 #changeFileProperty start > trunk/file1.txt svn:entry:committed-date 2016-03-03T18:15:19.061137Z #changeFileProperty start > trunk/file1.txt svn:entry:last-author test #changeFileProperty start > trunk/file1.txt svn:entry:uuid 5025b694-87bc-4570-9e45-8a2bcb52a122 #changeFileProperty start > trunk/file1.txt svn:mime-type text/plain #applyTextDelta start > trunk/file1.txt #textDeltaChunk start > trunk/file1.txt 0:0:16:1:16:17:0 #textDeltaEnd start > trunk/file1.txt #closeFile start > trunk/file1.txt #closeDir start > #closeDir start > #closeEdit start >
ファイルを順に追加しているのがわかる。
リポジトリの詳細な内容は前回 svn log --diff
した結果を貼っているが、ざっくりおさらいすると
- rev.0 : このリポジトリの最初
- rev.1 : プロジェクト構造(trunkとかbranchesとか)つくった
- rev.2 : /.projectと /file1.txtを追加
- rev.3 : /file1.txtを更新、/file2.txtを追加
といった履歴になっている。
この状態でワーキングコピー""
のリビジョンが2とだけ報告したらどうなるのだろうか。
つまり本来ワーキングコピー全体がリビジョン2であるならば/.projectと /file1.txtが存在するはずなのでそれらについても報告する必要があるが、意図的にそれをしない。
public class ExpReporter implements ISVNReporterBaton { @Override public void report(final ISVNReporter reporter) throws SVNException { reporter.setPath("", null, 2, SVNDepth.INFINITY, false); reporter.finishReport(); return; } }
得られた出力は以下
#targetRevision start > [rev.3] #openRoot start > [rev.2] #openDir start > trunk[rev.2] #changeDirProperty start > svn:wc:ra_dav:version-url /svn/test/!svn/ver/3/trunk #changeDirProperty start > svn:entry:committed-rev 3 #changeDirProperty start > svn:entry:committed-date 2016-03-03T18:15:19.061137Z #changeDirProperty start > svn:entry:last-author test #changeDirProperty start > svn:entry:uuid 5025b694-87bc-4570-9e45-8a2bcb52a122 #addFile start > trunk/file2.txt #changeFileProperty start > trunk/file2.txt svnkit:entry:sha1-checksum 54563f95fefa691baa82a522156322c21f7d6df3 #changeFileProperty start > trunk/file2.txt svn:wc:ra_dav:version-url /svn/test/!svn/ver/3/trunk/file2.txt #changeFileProperty start > trunk/file2.txt svn:entry:committed-rev 3 #changeFileProperty start > trunk/file2.txt svn:entry:committed-date 2016-03-03T18:15:19.061137Z #changeFileProperty start > trunk/file2.txt svn:entry:last-author test #changeFileProperty start > trunk/file2.txt svn:entry:uuid 5025b694-87bc-4570-9e45-8a2bcb52a122 #changeFileProperty start > trunk/file2.txt svn:mime-type text/plain #applyTextDelta start > trunk/file2.txt #textDeltaChunk start > trunk/file2.txt 0:0:7:1:7:8:0 #textDeltaEnd start > trunk/file2.txt #closeFile start > trunk/file2.txt #openFile start > trunk/file1.txt[rev.2] #changeFileProperty start > trunk/file1.txt svn:wc:ra_dav:version-url /svn/test/!svn/ver/3/trunk/file1.txt #changeFileProperty start > trunk/file1.txt svn:entry:committed-rev 3 #changeFileProperty start > trunk/file1.txt svn:entry:committed-date 2016-03-03T18:15:19.061137Z #changeFileProperty start > trunk/file1.txt svn:entry:last-author test #changeFileProperty start > trunk/file1.txt svn:entry:uuid 5025b694-87bc-4570-9e45-8a2bcb52a122 #applyTextDelta start > trunk/file1.txt #textDeltaChunk start > trunk/file1.txt 0:7:16:3:9:12:0 #textDeltaEnd start > trunk/file1.txt #closeFile start > trunk/file1.txt #closeDir start > #closeDir start > #closeEdit start >
/file2.txt がaddFile
で /file1.txt はopenFile
から始まっている。単純に差分になるようだ。
別途ISVNEditor#textDeltaChunk
で受け取れるSVNDiffWindow
オブジェクトのインスタンスから、ファイルの内容としてどういったものが取得できるのか見てみると、rev2->HEADでファイルの追加になる /file2.txt はファイルの内容すべて、内容の変更のみだった /file1.txt は変更差分のみ取得できた。
となると、ワーキングコピーとこれらの内容からどうにかして本来(というか、最新の全体)の内容を得るためには、ワーキングコピーに対してpatchしなければならない?
続きはまた次回。