sbt-plugin入門 Global pluginsメモ
少し前に@tototoshiさんがsbt-pluginについてブログを書いてたのを参考に
グローバルなsbtプラグインを試してみた。
(いつもお世話になってます・・(m´・ω・`)mペコ )
参考:sbtでコマンドを定義する
はじめての sbt-plugin
でも、試すというほどのものではなく、
https://github.com/harrah/xsbt/wiki/Plugins の最後の方「Global plugins example」に
書いてあることそのままですね。(というか、自分がやり方知らなかっただけかも・・・)
とりあえず、試します。
まずechoプラグインとつくります。
build.sbt
sbtPlugin := true name := "echo-plugin" organization := "com.sassunt"
import sbt._ import Keys._ object EchoPlugin extends Plugin { override lazy val settings = Seq( commands ++= Seq( echo ) ) lazy val echo = Command.args("echo", "<args>") { (state, args) => println(args.mkString(" ")) state } }
を作ってsbtでpublish-localコマンドを実行します。
ここまでは参考にした@tototoshiさんのブログにありましたね。
でも、ここまで作成したものは、sbtのプロジェクト毎にaddPluginをしないと使えないです。
(毎回書くのは面倒ですね。)
そこで、Globalなプラグインです。
ホームの.sbtフォルダの下にpluginsフォルダ作ってbuild.sbtに書けばOKです。
~/.sbt/plugins/build.sbt
(存在しない場合は、フォルダ・ファイルともに作ってください。)
addSbtPlugin("com.sassunt" % "echo-plugin" % "0.1")
(・・・バージョンって何も定義しない場合は、0.1になるのか?)
(https://github.com/harrah/xsbt/wiki/Pluginsには、
libraryDependencies += "org.example" %% "example-plugin" % "0.1"って書いてあるけど・・・
サンプル通りだとうまく行かない気がする?・・・保留)
以上で終了です。好きなsbtプロジェクトからechoコマンドが使えるようになりました。
おまけ
~/.sbt/plugins/の下に直接
echo.scalaとか作ってもつかえるようになりますよー
unfilteredのスライドショーPicture-Show にアップロード機能を追加してみた
picture-show使いたいけど・・・いろいろインストールするのが面倒・・・(自分のPCじゃないやつに
でも、picture-showつかいたいお (´・ω・`)
あわよくば、他の人にも気軽に使ってもらえたらいいな・・・
で、とりあえずやりたかったことは、
- conf.jsとか含めたZipファイルを(ようするにpshowコマンドするときに必要なもの一式)アップロード
- それを解凍してスライドショー
最初はHerokuとかでやろうと思ったけど、アップロードが無理みたいなので、
(アップロードとかする場合は、S3使えとかどこかのブログに書いてあってけど・・そんな金ない)
でもまぁ会社とかで使えればいいやと思った・・・
使い方 (README書けよってことですね)
https://github.com/sassunt/picture-show
機能としてはsoftprops / picture-showに追加してるだけです。
git clone
> git clone git@github.com:sassunt/picture-show.git
起動する前にアップロードするディレクトリを指定する必要があります
> export PSHOW_ARCHIVE=/hoge/foo > export PICTURE_SHOW=/hoge/bar
PSHOW_ARCHIVEがZipファイルが置かれる場所
PICTURE_SHOWがZipファイルが展開される場所
実行
> cd picture-show > sbt run
確認
http://lcoalhost:8080/
もしくは
> sbt assembly
picture-show/target/PictureShow-assembly-0.1.0-SNAPSHOT.jar
ができるので
java -jar PictureShow-assembly-0.1.0-SNAPSHOT.jar com.sassunt.Main
で実行
念のため、https://github.com/sassunt/picture-show/downloads にJarをおいておきました。
TODO(むしろ問題点):
- 画像表示だけは対応してないので、可能なら対応する・・・(リンクがうまくいかない)
- エラーハンドリング
- 毎回同じものもZipを解凍するので、修正する
- チュートリアル
- etc(その他いっぱい・・・・
まだ、未完成です・・・
もう運用回避で・・・・
補足:
ZipファイルはZipを解凍した状態がかきのようにならないとだめです・・・
example.zipを解凍
example-
-con.js
-css
-sample
-js
Scalaでzipファイルの解凍?2
前回zip解凍を作ったわけだけど・・・微妙でした。
で@xuwei_kさんからIteratorやローンパターン使ったほうがいいってつぶやきがあって
とりあえず、手を加えてみた
import java.io.{File => JFile, FileInputStream, FileOutputStream} import java.util.zip.{ZipEntry, ZipFile, ZipInputStream} import scala.util.control.Exception._ case class Zip(val path: JFile) { private val Extension = """(^.+)\.((?i)zip)$""".r val name = path.getName match { case Extension(name, _) => name case _ => throw new java.lang.IllegalArgumentException("Not Zip file") } def unzip(targetPath: JFile = path.getParentFile): Throwable Either JFile = { def using[A <: java.io.Closeable] (s: A)(f: A => Unit): Unit = { try { f(s) } finally { s.close() } } val baseDirName = name val baseDirPath = new JFile(targetPath, baseDirName) baseDirPath.mkdir() allCatch either { val zis = new ZipInputStream(new FileInputStream(path)) using(zis){zs => Iterator.continually(zs.getNextEntry).takeWhile( _ != null ).filterNot( _.isDirectory ).foreach(e => { val file = new JFile(baseDirPath, e.getName) file.getParentFile.mkdir() val fos = new FileOutputStream(file) using(fos){fs => Iterator.continually(zs.read()).takeWhile(_ != -1).foreach(fs write _) zs.closeEntry() } }) } baseDirPath } } }
修正:Zipの正規表現を大文字小文字の区別をなくしました
Scalaでzipファイルの解凍?
Zipの解凍をScalaで書いてみたけど、う〜ん、どうなんだろう。
import java.util.zip._ import java.io._ val zipFile = "./hoge.zip" val is = new ZipInputStream(new FileInputStream(zipFile)) val curDir = zipFile.substring(0, zipFile.lastIndexOf(".")) new File(curDir).mkdir() val list = Stream.continually(is.getNextEntry).takeWhile(_ != null).filter(f => !f.isDirectory()) list.foreach(e => { val file = new File(curDir, e.getName) file.getParentFile.mkdirs() val fos = new FileOutputStream(file) Stream.continually(is.read()).takeWhile(_ != -1).foreach(i => { fos.write(i) }) is.closeEntry() fos.close() }) is.close()
11/4:ちょい修正
※エラーハンドリングとかはやってないので注意・・・
もっといい感じのあったら
教えてください!!!
unfilteredでファイルアップロード2 書き込み編
前回はInputStreamを使用してたけど
今回は、書き込みを行います。ようするにサーバーにファイルをぽいっと保存します。
とりあえず↓に必要なところだけ抜き出しました。
def intent = { case req @ Path("/") => req match { case GET(_) => case POST(MultiPart(hreq)) => MultiPartParams.Disk(hreq).files("file") match { case Seq(file, _*) if !file.name.isEmpty => { file.write(new java.io.File("./hoge/%s" format file.name)) } case _ => } } }
前回からの変更点は、
MultiPartParams.Streamed
が
MultiPartParams.Disk
になって、
file.write(new java.io.File("./hoge/%s" format file.name))
で書き込みが行われるってことです。そのまんまです。
以上。
unfilteredでファイルアップロード
サポートしてくれてるのですごく簡単です。
build.sbtに以下を追加すれば使えるようになります。
"net.databinder" %% "unfiltered-uploads" % "0.5.1"
実際の例は↓な感じ。 アップロードしたファイルの中身を表示するだけですが・・・。
import scala.io.Source import unfiltered.request._ import unfiltered.response._ import util.Properties class Uploader extends unfiltered.filter.Plan { def intent = { case GET(_) => Ok ~> view(None, Nil) case POST(Path(_) & MultiPart(req)) => MultiPartParams.Streamed(req).files("file") match { case Seq(file, _*) if !file.name.isEmpty => view(Some(file.name), file.stream(t => Source.fromInputStream(t).getLines.toList)) case f => view(None, Nil) } } def view(temp: Option[String], text: List[String]) = Html{ <html> <body> <form method="POST" enctype="multipart/form-data"> <input type="file" value="" name="file" /> <input type="submit" /> </form> { temp.map(t => <div> <h1>File Name: {t}</h1> <pre> {text.zipWithIndex.map{case (line,index) => <div>{"%4d: %s".format(index + 1, line)}</div>}} </pre> </div> ).toSeq } </body> </html> } }
必要ないと思うけど、一応githubにあげてみた。
https://github.com/sassunt/unfiltered-upload-sample
上のコードの
file.stream(t => Source.fromInputStream(t).getLines.toList)
java.io.InputStreamを返してくれるけど、Source使う以外ないのかな
補足メモ:
自分が作ったときは、コンパイル時にMultiPartやらServletのクラスが不足してるよ
みたいなエラーが出て困ったけど・・・(エラーの詳細忘れた)
build.sbtに
"javax.servlet" % "servlet-api" % "2.5"
入れたらOKだった。
Herokuに静的ファイルサイトを作る
タイトルと違うけど、ただpicture-showのスライドをHerokuでみたかっただけです。
1.[unfiltered] picture-showをインストール
https://github.com/softprops/picture-show
2.giter8でpicture-showのテンプレートをダウンロード
> g8 softprops/picture-show
3.編集
好きなように編集する、
上のURL見れば方法が書いてます。
どんな感じかみたいだけなら飛ばしてもダイジョブです。
4.offline出力
3で作ったディレクトリに移動して、以下のコマンドを実行
> pshow --offline
すると、outディレクトリができます。
5.Herokuにアップするディレクトリ構成の準備
Herokuにアップしたいディレクトリを作成(HerokuSite)し、その中にoutディレクトリを移動させます。
そこでoutをpublicという名称に変更してください。
次にconfig.ruという名称のファイルを作成します。
config.ru
use Rack::Static, :urls => ["/assets", "/css", "/hello","/js"], :root => "public" run lambda { |env| [ 200, { 'Content-Type' => 'text/html', 'Cache-Control' => 'public, max-age=86400' }, File.open('public/index.html', File::RDONLY) ] }
最終的にはこんな感じになるはずです。
- HerokuSite/ |- config.ru |- public/ |- assets/ |- css/ |- hello/ |- index.html |- js/
6.いざ、Herokuへ
> git init > git add . > git commit -m init > heroku create > git push heroku master
終了!!!
かっこいいスライドが見えるよ!!!