ARGENTO CUORE

 May the code be with you.

--.--.--[--] スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

2010.05.08[土] jarファイル作成&コードの羅列

Scalaでもjarファイルにまとめて実行できる。

$jar -cfm Hoge.jar Manifest.fm *

で作れる。

Manifestには、

Class-Path: scala-library.jar scala-swing.jar

などのように書いておく。↑二つのjarファイルを解凍してjarファイルに同梱してもそんなに大きくならなかった5MBくらいかも。Main-Classは、

Main-Class: PackageName.mainメソッドが含まれているobject名

と書く。


テスト&コンパイルのツールを書いてみた。scalatest-1.01.jarを決め打ちしてるので、そこだけ変えなきゃー。

・指定したディレクトリとメインメソッドを含むオブジェクト名を引数に取り、そのディレクトリを以下の.scalaファイルを監視し続ける。

・ファイルが更新されたらそいつをコンパイルする。

・コンパイルが通ったら、そのディレクトリのtest/以下にあるTest接頭辞が付いた同名のテストファイルの有無を確認→あったらテスト実行(テストファイルを更新した場合には、逆のことをする)

・テストが実行されたら、引数で指定されていたメインメソッドを含むオブジェクトを実行。

みたいなことをしている。pluginとか、Eclipseとか、色々入れないとダメだったり、設定しないといけなかったりとかいうのは面倒そうなので、起動→監視→なんとなくうまく動く 的なものを目指そう。


import java.io._
import java.util.regex._
import scala.collection.immutable._

import javax.swing._
import javax.swing.event._
import java.awt._
import java.awt.event._
import com.sun.awt._

package rolecake{
object ExTextArea extends JTextArea{}

object Dir {
val test_dirname = "test"
val testout_dirname = "output"
private var _current_dir = new File(".").getAbsoluteFile().getParent()
var list_dir = Set[String]()

def current_dir:String = _current_dir
def current_dir_=(s:String) = _current_dir = s

private var _main_class = ""
def main_class:String = _main_class
def main_class_=(s:String) = _main_class = s


def getDirectories(cd:String):Set[String]={
val dir = new File(cd)
val list = dir.list()
var ret = Set[String]()
for(n <- list){
if(isDirectory(cd + File.separator + n)){
ret += cd + File.separator + n.asInstanceOf[String]
val r = getDirectories(cd + File.separator + n)
r.foreach(d => {
ret += d.asInstanceOf[String]
})
}
}
return ret
}

def isDirectory(d:String):Boolean = {
val dir = new File(d)
if (dir.isDirectory()){
return true
}else{

return false
}
}

/**
* カレントディレクトリの名前を返します
*/
def current_dir_name():String={
val dirs = _current_dir.split(File.separator)
val last = dirs(dirs.length - 1)

return last
}
}

/**
* ディレクトリの実体
* ディレクトリ名を与えてインスタンス化
*/
class Directory(var _current_dir:String) {
def current_dir:String = _current_dir
def current_dir_=(s:String) = _current_dir = s

val scala_pattern = ".*.scala$"

//現時点でのファイル集合
var file_set = Set[String]()
var file_map = HashMap[String, Long]()


def getFiles():String = {
var result = ""
file_set.foreach(f => {
result += f + "\n"
})
return result
}
/*
* 新規ファイルをチェック
*/
def checkNew():String={
//ディレクトリ内のファイルを全て取得
val dir = new File(_current_dir)
if(dir.exists()){
val list = dir.list()
for(n <- list){
if(!Dir.isDirectory(_current_dir + File.separator + n)){
val p = Pattern.compile(scala_pattern)
val m = p.matcher(n)
if(m.find){
val fullpath_filename = _current_dir + File.separator + n
if(!file_set.contains(fullpath_filename)){
file_set += fullpath_filename
return fullpath_filename+"を新規に追加します"
}
}
}
}
}
return null
}

/**
* 更新ファイルをチェック
*/
def checkModified():String={
file_set.foreach(file => {
val filename = getFileName(file)
val f = new File(_current_dir, filename)
//更新時間を取得
val modified_time_new = f.lastModified()
file_map.get(file) match {
//更新時間が記録されているファイル
case Some(time) => {
//以前の更新時間を取得
val modified_time_old = time
//現在の更新時間を取得
if(modified_time_old < modified_time_new){
//ファイルの更新時間を更新
file_map += (file -> modified_time_new)
val fo = new FileOperation(file,_current_dir)
fo.start()

return file+"を更新しました"
}
}
//更新時間が記録されていないファイル
case None => {
file_map += (file -> modified_time_new)
}
}
})
return null
}

/**
* 削除ファイルをチェック
*/
def checkRemoved():String={
file_set.foreach(file => {
val filename = getFileName(file)
val f = new File(_current_dir, filename)
if(!f.exists()){
file_set -= file
file_map -= file

return file+"を削除します"
}
})
return null
}

private def getFileName(fullpath_filename:String):String={
if(fullpath_filename != null){
val dirs = fullpath_filename.split(File.separator)
if(dirs.length > 0){
return dirs(dirs.length-1)
}else{
return null
}
}else{
return null
}
}
}


/**
* ファイルが更新されたときに行う操作
*/
class FileOperation(val fullpath_filename:String, val _current_dir:String) extends Thread{

val testfile_prefix = "Test"

override def run():Unit={
build()
}
def build():Unit={
val compile_result = compile()
if (compile_result == null){ //コンパイル成功
val test_result = tryTest() ;
for(k <- test_result.keySet){ //テスト結果を取得
ExTextArea.append(test_result(k)+"\n")
ExTextArea.setCaretPosition(ExTextArea.getText().length())
if(k == 0){
execute()
}
}
}else{
ExTextArea.append(compile_result+"\n")
ExTextArea.setCaretPosition(ExTextArea.getText().length())

}
}

/**
* FileOperationの操作対象となるファイルをコンパイルします。
* @return コンパイル結果の文字列を返す。コンパイルエラーがないばあいにはnullが入る。
*/
def compile():String={
var result = ""
val r = Runtime.getRuntime()
val command = "fsc " + fullpath_filename + " -d " + _current_dir
//val command = "fsc " + fullpath_filename
ExTextArea.append("command:" + command + "\n")
ExTextArea.setCaretPosition(ExTextArea.getText().length())
val p = r.exec(command)

var in = p.getInputStream()
result = getStreamResult(in)
in.close()

in = p.getErrorStream()
result += getStreamResult(in)
in.close()

if(p.waitFor() == 0){
//エラーなしの場合はnull
return null
}else{
//エラーの場合はエラーメッセージを返す
return result
}
}

/**
* テストを試みる。
*/
def tryTest():Map[Int,String]={
var result = ""
val dirs = fullpath_filename.split(File.separator)
var filename = dirs(dirs.length - 1)
val point = filename.lastIndexOf(".")
var isTest = 0

//テストファイル名を作成
var test_filename = ""
if (point != -1){
test_filename = filename.substring(0, point)
isTest = test_filename.indexOf("Test")
if(isTest!=0){ //Testファイルでない場合
test_filename = testfile_prefix + test_filename
}
ExTextArea.append("test_filename:" + test_filename + "\n")
ExTextArea.setCaretPosition(ExTextArea.getText().length())

}

//テストファイルのディレクトリを作成
var test_dir:File = null
if(isTest != 0){
//対象がテストファイルでない場合はテストディレクトリを設定
test_dir = new File(_current_dir + File.separator + Dir.test_dirname)
ExTextArea.append("test_dir" + test_dir + "\n")
ExTextArea.setCaretPosition(ExTextArea.getText().length())

if(!test_dir.exists()){
test_dir.mkdirs()
}
}else{
//対象がテストファイルの場合には、カレントをそのまま設定
test_dir = new File(_current_dir)
}

if(isTest != 0){
val testfile_path = test_dir + File.separator + test_filename
val testfile = new File(testfile_path+".scala")
if(!testfile.exists()){
var ret = Map[Int,String]()
ret += (-1 -> "テストファイルが存在しないため処理を中止します")
return ret.asInstanceOf[Map[Int,String]]
}
}

//テスト結果のXMLファイル出力ディレクトリ
val testout_dir = new File(test_dir + File.separator + Dir.testout_dirname)
if(!testout_dir.exists()){
testout_dir.mkdirs()
}

val r = Runtime.getRuntime()
val command = "scala -cp .:scalatest-1.01.jar org.scalatest.tools.Runner -p "+test_dir+" -o -s "+test_filename+" -u "+testout_dir
ExTextArea.append("command:" + command + "\n")
ExTextArea.setCaretPosition(ExTextArea.getText().length())

//コマンドを実行
val p = r.exec(command)
val in = p.getInputStream()
result += getStreamResult(in)

//ESCが混じるのでSPACEに置換
result = result.replace('\u001b','\u0020')
in.close()

//結果取得
val result_number = p.waitFor()
if(result_number==0){
result += "Message:テストは成功しました\n"
}else{
result += "Message:テストは失敗しました\n"
}
var ret = Map[Int,String]()
ret += (result_number -> result)
return ret.asInstanceOf[Map[Int,String]]
}

def execute():Unit={
//target_classをメインクラスとみなし、実行
val r = Runtime.getRuntime()
val command = "scala "+ Dir.main_class
ExTextArea.append("command:" + command + "\n")
ExTextArea.setCaretPosition(ExTextArea.getText().length())
val p = r.exec(command)
val in = p.getInputStream();
ExTextArea.append(getStreamResult(in)+ "\n")
ExTextArea.setCaretPosition(ExTextArea.getText().length())
in.close()
}

/**
* InputStreamから内容を読み込みStringで返す
*/
private def getStreamResult(in:InputStream):String={
var result = ""
try{
val out = new StringBuffer()
val br = new BufferedReader(new InputStreamReader(in))
var line=""
while({line = br.readLine(); line != null}){
out.append(line + System.getProperty("line.separator"))
}
result = out.toString()
}catch{
case e:IOException => e.printStackTrace()
}
return result
}


}

object RoleCake extends scala.swing.Frame{
var status = true

var filelist_area:JTextArea = null
var message_area:JTextArea = null

var current:Directory = null
var test:Directory = null
var dir_set = Set[Directory]()

def main(args:Array[String]):Unit={
Dir.current_dir = args(0)
Dir.main_class = args(1)

dir_set += new Directory(Dir.current_dir)
val dirs = Dir.getDirectories(Dir.current_dir)
dirs.foreach(d => {
dir_set += new Directory(d)
})

val panel = new JPanel()
panel.setLayout(new BorderLayout())
filelist_area = new JTextArea()
filelist_area.setLineWrap(true)
val sp1 = new JScrollPane(filelist_area)
sp1.setPreferredSize(new Dimension(500,200))
panel.add(sp1, BorderLayout.CENTER)


ExTextArea.setLineWrap(true)
val sp2 = new JScrollPane(ExTextArea)
sp2.setPreferredSize(new Dimension(400,200))
panel.add(sp2, BorderLayout.EAST)

message_area = new JTextArea()
val sp3 = new JScrollPane(message_area)
sp3.setPreferredSize(new Dimension(800,100))
panel.add(sp3, BorderLayout.SOUTH)

peer.getContentPane().add(panel)
pack()
peer.setTitle("RoleCake")
peer.setVisible(true)

val th = new Thread(new Seeker())
// th.setDaemon(true)
th.start()
}

def getRootNode():DefaultListModel={
val point = Dir.current_dir.lastIndexOf(File.separator)
val base_dir = Dir.current_dir.substring(point, Dir.current_dir.length)
val model = new DefaultListModel()
dir_set.foreach(d => {
val dir = d.current_dir.substring(point, d.current_dir.length)
model.addElement(dir)
})

return model
}

def setFileNameToViewer(str:String):Unit={
filelist_area.setText(str)
}

def check():Unit={
if(status){
var file_result = ""
dir_set.foreach(d => {
val res1 = d.checkNew()
if(res1 != null) message_area.append(res1 + "\n")

val res2 = d.checkModified()
if(res2 != null) message_area.append(res2 + "\n")

val res3 = d.checkRemoved()
if(res3 != null) message_area.append(res3 + "\n")

file_result += d.getFiles()
})
message_area.setCaretPosition(message_area.getText().length())

setFileNameToViewer(file_result)
}
}

def stop():Unit={
status = false
}

class Seeker extends Runnable {
def run():Unit={
while(true){
check()
try{
Thread.sleep(1000)
}catch{
case e:InterruptedException => e.printStackTrace()
}
}
}
}

reactions += {
case scala.swing.event.WindowClosing(_) =>
System.exit(1)
}
}
}


スポンサーサイト

Comment






(編集・削除用)


管理者にだけ表示を許可

Trackback

http://ronor.blog81.fc2.com/tb.php/76-74099fc5

この記事にトラックバック(FC2Blog User)

Scala Feed

scala feed

FC2カウンター

プロフィール

RoNor

Author:RoNor
得意呪文はScalaですって言えるようになるのが夢です。
デスマーチ中、パーティメンバーの防御力を向上させたりさせなかったり。

検索フォーム

QRコード

QRコード

Copyright © 2009-2010 ARGENTO CUORE and RoNor All rights reserved.

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。