svnno****@sourc*****
svnno****@sourc*****
2009年 12月 17日 (木) 12:48:47 JST
Revision: 66 http://sourceforge.jp/projects/ngms/svn/view?view=rev&revision=66 Author: osiire Date: 2009-12-17 12:48:47 +0900 (Thu, 17 Dec 2009) Log Message: ----------- [NMTree] add localCommit with unit test. Modified Paths: -------------- trunk/source/NMTree/src/info/ngms/nmtree/AbstractDescriptionElement.scala trunk/source/NMTree/src/info/ngms/nmtree/NMFileSystemTree.scala trunk/source/NMTree/src/info/ngms/nmtree/NMPath.scala trunk/source/NMTree/src/info/ngms/nmtree/NMTree.scala trunk/source/NMTree/test/NMFileSystemTreeTest.scala trunk/source/NMTree/test/NMTreeBehavior.scala trunk/source/NMTree/test/NMTreeWithFileSystemTest.scala Modified: trunk/source/NMTree/src/info/ngms/nmtree/AbstractDescriptionElement.scala =================================================================== --- trunk/source/NMTree/src/info/ngms/nmtree/AbstractDescriptionElement.scala 2009-12-17 02:41:39 UTC (rev 65) +++ trunk/source/NMTree/src/info/ngms/nmtree/AbstractDescriptionElement.scala 2009-12-17 03:48:47 UTC (rev 66) @@ -6,15 +6,37 @@ import scala.collection.mutable.LinkedHashMap +/** + * NMDescriptionのデータとするハッシュを保持するheaderと任意の文字列のリストを保持するbodyを持つ構造。 + * @version $Id$ + * @auther ogasa****@itpl***** + */ trait AbstractDescriptionElement { + /** + * タグ(String)をキーとしてNMDescriptionsを保持する構造。 + */ val header : LinkedHashMap[String, NMDescription] + + /** + * ヘッダ以下の任意のデータ行 + */ val body : List[String] + /** + * NMDescriptionのヘッダーをリスト型として返す関数。 + * @return ヘッダとして登録されているNMDescriptionのリスト。順番が保持されている。 + */ def descriptions : List[NMDescription] = { header.values.toList } + /** + * 指定されたタグ文字列をキーとするNMDescriptionを検索する関数。 + * @param tag 発見したいNMDescriptionに対応するタグ + * @return もし指定されたタグに対応するNMDescriptionが存在すれば、そのインスタンスをSomeコンストラクタで包んだ値が返される。 + * 存在しなければNoneが返される。 + */ def find(tag : String) : Option[NMDescription] = { val nmlz_tag = DescriptionElement.normalizeTag(tag) try { @@ -25,6 +47,12 @@ } } + /** + * 指定されたタグ文字列をキーとするNMDescriptionを検索する関数。 + * @param tag 発見したいNMDescriptionに対応するタグ + * @return もし指定されたタグに対応するNMDescriptionが存在すれば、そのインスタンスのvalueをSomeコンストラクタで包んだ値が返される。 + * 存在しなければNoneが返される。 + */ def findVal(tag : String) : Option[String] = { val nmlz_tag = DescriptionElement.normalizeTag(tag) try { @@ -35,6 +63,14 @@ } } + /** + * 指定されたタグ文字列をキーとするNMDescriptionを使って指定された関数fを呼び出す関数。 + * @param tag 発見したいNMDescriptionに対応するタグ + * @param default 指定したタグが存在しなかった場合、戻り値となる値 + * @param f 指定したタグが存在した場合、そのタグに対応するNMDescriptionを引数として呼び出される関数。タグが存在しない場合は呼び出されない。 + * @return もし指定されたタグに対応するNMDescriptionが存在すれば、関数fにNMDescriptionを適用した結果が返される。 + * タグが存在しない場合は、defaultの値が返される。 + */ def findWith[A](tag : String) (default : A) (f : NMDescription => A) : A = { find(tag) match { case Some(desc) => Modified: trunk/source/NMTree/src/info/ngms/nmtree/NMFileSystemTree.scala =================================================================== --- trunk/source/NMTree/src/info/ngms/nmtree/NMFileSystemTree.scala 2009-12-17 02:41:39 UTC (rev 65) +++ trunk/source/NMTree/src/info/ngms/nmtree/NMFileSystemTree.scala 2009-12-17 03:48:47 UTC (rev 66) @@ -30,28 +30,43 @@ def createStream( path : NMPath ) : NMTree.TStreamElement = { val file = new File( path ) + file.createNewFile() new { val input : InputStream = new FileInputStream( file ) val output : OutputStream = new FileOutputStream( file ) + def close : Unit = + input.close + output.close } } + def createDir( path : NMPath ) : Unit = { + val file = new File( path ) + if( !file.mkdir() ) { + throw new LowLevelException("cannot create direcoty " + path ) + } + } + def createDescription( path : NMPath ) : NMTree.TDescriptionElement = { + val file = new File( path ) + file.createNewFile() val h = new LinkedHashMap[String, NMDescription]() val b = Nil new AbstractDescriptionElement { val header = h val body = b + def close : Unit = () } } def createTable( path : NMPath ) : NMTree.TTableElement = { // 未実装 new { - val lines : Array[Array[String]] = Array(Array()) - def foldl[T] (init : T) (f : (T, Array[String]) => T) : T = { - init - } + val lines : Array[Array[String]] = Array(Array()) + def foldl[T] (init : T) (f : (T, Array[String]) => T) : T = { + init + } + def close : Unit = () } } @@ -152,7 +167,9 @@ if(recursive) deleteFileRec( new File( path ) ) else - ( new File( path ) ).delete + if( !( new File( path ) ).delete ) { + throw new LowLevelException("cannot delete file " + path) + } } def symLink( src : NMPath, dst : NMPath ) : Unit = { } Modified: trunk/source/NMTree/src/info/ngms/nmtree/NMPath.scala =================================================================== --- trunk/source/NMTree/src/info/ngms/nmtree/NMPath.scala 2009-12-17 02:41:39 UTC (rev 65) +++ trunk/source/NMTree/src/info/ngms/nmtree/NMPath.scala 2009-12-17 03:48:47 UTC (rev 66) @@ -172,7 +172,7 @@ } def concat ( path : String, child : String ) : String = { - path + separator + child + canonical(path) + separator + child } def diff( path : String, base : String) : String = { @@ -236,6 +236,14 @@ } /** + * 自身のパスがディレクトリかどうか判定する。 + * @return 自身のパスがディレクトリであればtrue, そうでなければfalseが返される。 + */ + def isDir : Boolean = { + impl.pathOp.isNode( this ) + } + + /** * 自身のパスが持つ直下の子供のパスのリストを作成する。 * @return 自身のパスが持つ直下の子供のパスのリストが返される。 * 自身のパスに子供がいない場合は空リストが返される。 Modified: trunk/source/NMTree/src/info/ngms/nmtree/NMTree.scala =================================================================== --- trunk/source/NMTree/src/info/ngms/nmtree/NMTree.scala 2009-12-17 02:41:39 UTC (rev 65) +++ trunk/source/NMTree/src/info/ngms/nmtree/NMTree.scala 2009-12-17 03:48:47 UTC (rev 66) @@ -101,17 +101,6 @@ def delete( path : NMPath, recursive : Boolean ) : Unit /* - * シンボリックリンクを定義する関数。 - * @param src リンクされる側のパス。 - * @param dst リンクした結果新しく作成されるパス。 - * @throws AppPermissionException - * @throws DestinationNotFoundException - * @throws DestinationAlreadyExistsException - * @throws LowLevelException - */ - def symLink( src : NMPath, dst : NMPath ) : Unit - - /* * エレメントのアクセス許可を定義する関数。 * @param src アクセス許可を変更したいパス。 * @param dst リンクした結果新しく作成されるパス。 @@ -173,6 +162,11 @@ * ストリームへの書き込みを行うためのハンドラインスタンス。 */ val output : OutputStream + + /* + * エレメントのクローズ処理 + */ + def close : Unit } /** @@ -220,6 +214,11 @@ * @param f 更新をするための関数。引数には現在のDescription情報が渡され、戻り値のDescription情報がエレメントへ反映される。 */ def update( f : List[NMDescription] => List[NMDescription] ) : Unit + + /* + * エレメントのクローズ処理 + */ + def close : Unit } /** @@ -239,6 +238,11 @@ * @return 畳み込まれた値。 */ def foldl[T] (init : T) (f : (T, Array[String]) => T) : T + + /* + * エレメントのクローズ処理 + */ + def close : Unit } /** @@ -246,6 +250,7 @@ */ type NMTreeImplimentation = { def createStream( path : NMPath ) : TStreamElement + def createDir( path : NMPath ) : Unit def createDescription( path : NMPath ) : TDescriptionElement def createTable( path : NMPath ) : TTableElement def pathOp : TPathOperations @@ -294,9 +299,17 @@ true } def find( path : String ) : Option[NMTreeImplimentation] = { - // 未完成 - impls.get( path ) + impls.get( path ) match { + case None => + if( path.equals(NMPath.root) ) { + None + } else { + find( NMPath.parent( path ) ) + } + case impl => impl + } } + def withImpl[T] ( path : String, f : NMTreeImplimentation => T ) : T = { ImplMap.find(path) match { case None => @@ -314,6 +327,10 @@ ImplMap.withImpl( path.canonical, impl => impl.createStream( path ) ) } + def createDir ( path : NMPath ) : Unit = { + ImplMap.withImpl( path.canonical, impl => impl.createDir( path ) ) + } + def createDescription ( path : NMPath ) : TDescriptionElement = { ImplMap.withImpl( path.canonical, impl => impl.createDescription( path ) ) } @@ -337,39 +354,40 @@ def localCommit( ops : Seq[ NMTreeOperations ] ) : Unit = { try { - val id = 0 // <- 未実装 - val treeOp = - env.getProcessContext(id) match { - case Some (c) => ImplMap.findSurely(c.currentDir).treeOp - case None => return - } - for (op <- ops) { - op match { - case Move(src, dst) => treeOp.move(src, dst) - case Copy(src, dst, overwrite, recursive) => - treeOp.copy(src, dst, overwrite, recursive) - case Delete(path, rec) => - treeOp.delete(path, rec) - case SymLink(src, dst) => - treeOp.symLink(src, dst) - case ChangePermission(src, p) => - treeOp.changePermission(src, p) - case Update(src, rec) => - treeOp.update(src, rec) - case Commit(src, rec) => - treeOp.commit(src, rec) - case Revert(src) => - treeOp.revert(src) - case Resolve(src) => - treeOp.resolve(src) - case _ => println("other") - } - } + for (op <- ops) { + op match { + case Move(src, dst) => + val treeOp = ImplMap.findSurely(src.canonical).treeOp + treeOp.move(src, dst) + case Copy(src, dst, overwrite, recursive) => + val treeOp = ImplMap.findSurely(src.canonical).treeOp + treeOp.copy(src, dst, overwrite, recursive) + case Delete(path, rec) => + val treeOp = ImplMap.findSurely(path.canonical).treeOp + treeOp.delete(path, rec) + case ChangePermission(src, p) => + val treeOp = ImplMap.findSurely(src.canonical).treeOp + treeOp.changePermission(src, p) + case Update(src, rec) => + val treeOp = ImplMap.findSurely(src.canonical).treeOp + treeOp.update(src, rec) + case Commit(src, rec) => + val treeOp = ImplMap.findSurely(src.canonical).treeOp + treeOp.commit(src, rec) + case Revert(src) => + val treeOp = ImplMap.findSurely(src.canonical).treeOp + treeOp.revert(src) + case Resolve(src) => + val treeOp = ImplMap.findSurely(src.canonical).treeOp + treeOp.resolve(src) + case _ => + () + //println("dose not support operation") + } + } + } catch { + case _ => println("err"); } - catch { - case _ => println("err"); - } - } def globalCommit( root : NMPath ) : Unit = { Modified: trunk/source/NMTree/test/NMFileSystemTreeTest.scala =================================================================== --- trunk/source/NMTree/test/NMFileSystemTreeTest.scala 2009-12-17 02:41:39 UTC (rev 65) +++ trunk/source/NMTree/test/NMFileSystemTreeTest.scala 2009-12-17 03:48:47 UTC (rev 66) @@ -24,28 +24,28 @@ } def mkdir(path : String){ - val file = new File(path) - file.mkdirs() + val file = new File(path) + file.mkdirs() } def touch(path : String, content : String){ val output = new OutputStreamWriter(new FileOutputStream( path )) - output.write(content) - output.close() + output.write(content) + output.close() } override def beforeEach() { - mkdir( test_dir ) - touch( test_dir + "foo.txt" , "123\n") - mkdir( test_dir + "bar" ) - touch( test_dir + "bar/bar.txt", "" ) + mkdir( test_dir ) + touch( test_dir + "foo.txt" , "123\n") + mkdir( test_dir + "bar" ) + touch( test_dir + "bar/bar.txt", "" ) - (new File( test_dir + "foo.txt")).setLastModified( today.getTime() ) + (new File( test_dir + "foo.txt")).setLastModified( today.getTime() ) } override def afterEach() { - rm_rf( test_dir ) + rm_rf( test_dir ) } val fs = new NMFileSystemTree( "./test/NMFileSystemTreeTest", "/" ) @@ -54,87 +54,89 @@ // PathOperationsのテスト test( "パスが実際に存在するかの確認" ) { - assert (pathOp.exists("/foo.txt") === true ) - assert (pathOp.exists("/bar") === true ) - assert (pathOp.exists("/non-exists") === false) + assert (pathOp.exists("/foo.txt") === true ) + assert (pathOp.exists("/bar") === true ) + assert (pathOp.exists("/non-exists") === false) } test ( "パスがディレクトリかの確認" ) { - assert (pathOp.isNode("/foo.txt") == false) - assert (pathOp.isNode("/bar") == true) - assert (pathOp.isNode("/non-exists") == false) + assert (pathOp.isNode("/foo.txt") == false) + assert (pathOp.isNode("/bar") == true) + assert (pathOp.isNode("/non-exists") == false) } test ( "サブファイルの取得" ) { - assert (pathOp.children("/") === List[NMPath]("/bar","/foo.txt")) - assert (pathOp.children("/bar") === List[NMPath]("/bar/bar.txt")) + assert (pathOp.children("/") === List[NMPath]("/bar","/foo.txt")) + assert (pathOp.children("/bar") === List[NMPath]("/bar/bar.txt")) } test ( "ファイルの属性" ) { - val attr = pathOp.attribute( "/foo.txt" ) - assert(attr.size === 4) - assert(attr.lastUpdateDate.toString() === today.toString()) - assert(attr.versionStatus === Neutral) + val attr = pathOp.attribute( "/foo.txt" ) + assert(attr.size === 4) + assert(attr.lastUpdateDate.toString() === today.toString()) + assert(attr.versionStatus === Neutral) } test ( "権限" ) ( pending ) test ( "バージョン" ) { - assert( pathOp.versionStatus( "/foo.txt" ) === Neutral ) + assert( pathOp.versionStatus( "/foo.txt" ) === Neutral ) } // tree operation test( "move" ) { - assert( pathOp.exists( "/foo.txt" ) === true ) - assert( pathOp.exists( "/foo2.txt" ) === false ) + assert( pathOp.exists( "/foo.txt" ) === true ) + assert( pathOp.exists( "/foo2.txt" ) === false ) - treeOp.move("/foo.txt","/foo2.txt") + treeOp.move("/foo.txt","/foo2.txt") - assert( pathOp.exists( "/foo.txt" ) === false ) - assert( pathOp.exists( "/foo2.txt" ) === true ) + assert( pathOp.exists( "/foo.txt" ) === false ) + assert( pathOp.exists( "/foo2.txt" ) === true ) } test( "copy-1" ) { - assert( pathOp.exists( "/foo.txt" ) === true ) - assert( pathOp.exists( "/foo2.txt" ) === false ) + assert( pathOp.exists( "/foo.txt" ) === true ) + assert( pathOp.exists( "/foo2.txt" ) === false ) - treeOp.copy("/foo.txt","/foo2.txt",false,false) + treeOp.copy("/foo.txt","/foo2.txt",false,false) - assert( pathOp.exists( "/foo.txt" ) === true ) - assert( pathOp.exists( "/foo2.txt" ) === true ) + assert( pathOp.exists( "/foo.txt" ) === true ) + assert( pathOp.exists( "/foo2.txt" ) === true ) } test( "copy-2" ) { - treeOp.copy("/foo.txt","/bar/bar.txt", false ,false) - assert( pathOp.attribute( "/bar/bar.txt" ).size === 0) + treeOp.copy("/foo.txt","/bar/bar.txt", false ,false) + assert( pathOp.attribute( "/bar/bar.txt" ).size === 0) } test ("copy-overwrite" ){ - treeOp.copy("/foo.txt","/bar/bar.txt", true ,false) - assert( pathOp.attribute( "/bar/bar.txt" ).size === 4) + treeOp.copy("/foo.txt","/bar/bar.txt", true ,false) + assert( pathOp.attribute( "/bar/bar.txt" ).size === 4) } test( "copy-3" ) { - treeOp.copy("/bar","/baz",false,false) - assert( pathOp.exists( "/baz/bar.txt" ) === false ) + treeOp.copy("/bar","/baz",false,false) + assert( pathOp.exists( "/baz/bar.txt" ) === false ) } test( "copy-4") { - treeOp.copy("/bar","/baz",false,true) - assert( pathOp.exists( "/baz/bar.txt" ) === true ) + treeOp.copy("/bar","/baz",false,true) + assert( pathOp.exists( "/baz/bar.txt" ) === true ) } test( "delete-1" ) { - assert( pathOp.exists( "/foo.txt" ) === true ) - treeOp.delete( "/foo.txt",false ) - assert( pathOp.exists( "/foo.txt" ) === false ) + assert( pathOp.exists( "/foo.txt" ) === true ) + treeOp.delete( "/foo.txt", false ) + assert( pathOp.exists( "/foo.txt" ) === false ) } test( "delete-2" ) { - treeOp.delete( "/bar",false ) - assert( pathOp.exists( "/bar" ) === true ) + intercept[LowLevelException] { + treeOp.delete( "/bar",false ) + } + assert( pathOp.exists( "/bar" ) === true ) - treeOp.delete( "/bar",true ) - assert( pathOp.exists( "/bar" ) === false ) + treeOp.delete( "/bar",true ) + assert( pathOp.exists( "/bar" ) === false ) } } Modified: trunk/source/NMTree/test/NMTreeBehavior.scala =================================================================== --- trunk/source/NMTree/test/NMTreeBehavior.scala 2009-12-17 02:41:39 UTC (rev 65) +++ trunk/source/NMTree/test/NMTreeBehavior.scala 2009-12-17 03:48:47 UTC (rev 66) @@ -2,19 +2,49 @@ import org.scalatest.FunSuite import org.scalatest.BeforeAndAfterEach +import info.ngms.nmtree.NMTreeOperations trait NMTreeBehavior extends FunSuite { test("マウント") (pending) test("アンマウント") (pending) - test("ディレクトリの作成") (pending) + test("ディレクトリの作成") { + val path = new NMPath("/dir") + NMTree.createDir( path ) + assert( path.exists === true ) + assert( path.isDir === true ) + } test("ディレクトリの削除") (pending) test("ディレクトリの移動") (pending) test("Tree実装をまたがるディレクトリの移動") (pending) - test("ファイルの作成") (pending) - test("ファイルの削除") (pending) - test("ファイルの移動") (pending) + test("ファイルの作成及び削除") { + val path = new NMPath("/willdelete") + val stream = NMTree.createStream(path) + assert ( path.exists === true ) + stream.close // closeしないと削除に失敗する + NMTree.localCommit( List(Delete( path, false)) ) + assert ( path.exists === false ) + } + test("ファイルの移動") { + val src = new NMPath("/from") + val dst = new NMPath("/to") + val stream = NMTree.createStream(src) + stream.close + assert ( src.exists === true ) + NMTree.localCommit( List(Move( src, dst)) ) + assert ( src.exists === false ) + assert ( dst.exists === true ) + } test("Tree実装をまたがるファイルの移動") (pending) - test("ファイルのコピー") (pending) + test("ファイルのコピー") { + val src = new NMPath("/from2") + val dst = new NMPath("/to2") + val stream = NMTree.createStream(src) + stream.close + assert ( src.exists === true ) + NMTree.localCommit( List(Copy( src, dst, false, false )) ) + assert ( src.exists === true ) + assert ( dst.exists === true ) + } test("ファイルへの書き込み") (pending) test("ファイルからの読み込み") (pending) test("Descriptionファイルへの書き込み") (pending) Modified: trunk/source/NMTree/test/NMTreeWithFileSystemTest.scala =================================================================== --- trunk/source/NMTree/test/NMTreeWithFileSystemTest.scala 2009-12-17 02:41:39 UTC (rev 65) +++ trunk/source/NMTree/test/NMTreeWithFileSystemTest.scala 2009-12-17 03:48:47 UTC (rev 66) @@ -2,6 +2,7 @@ import org.scalatest.FunSuite import org.scalatest.BeforeAndAfterEach +import java.io._ class NMTreeWithFileSystemTest extends FunSuite with BeforeAndAfterEach with NMTreeBehavior { @@ -9,12 +10,31 @@ new NMPath(path) } + def rm_rf(path : String) { + val file = new File(path) + if(file.isDirectory()){ + file.listFiles.foreach(f => rm_rf(f.toString)) + file.delete() + }else { + file.delete() + } + } + + def mkdir(path : String){ + val file = new File(path) + file.mkdirs() + } + + val testdir = "./test/NMTreeTest/" + override def beforeEach() { - val fs = new NMFileSystemTree( "c:/work", "/" ) + mkdir( testdir ) + val fs = new NMFileSystemTree( testdir, "/" ) NMTree.mount( "/", fs ) } override def afterEach() { NMTree.unmount( "/" ) + rm_rf(testdir) } }