ensimeをdockerで動かしてローカルのemacsからつなぎたい

みなさんさようなら. 最近わけあってscalaを触ってます.

いつもの通りemacsで開発環境をつくろうとして,ちょっと悩んだ挙句,解決しなかったのでメモ.

emacsscalaの開発をしようとすると,scala-modeはまず使うでしょう. ただ,それだけだとちょっと不満で,メソッドをサジェストしてほしかったり,デバッグするために,ensimeというものがよく紹介されていますね.

そして,開発環境自体はDockerで作っていたりします.

そう,このensimeとDockerを上手いこと組み合わせて開発したかった.

先に結論を書きます. 今のところできなかった

ensime

scalaのコードをemacsで書きたくなると,ensimeを使いたくなります(vimsublimeからも使えます). これを使えば型チェックもできるし,デバッグもやりやすいはず!

型チェックなんてことができるってことは,裏側でコンパイルが走っているということです. これをやってくれているのが,ensime-serverです.

ensimeは,emacsプラグインとして提供されていますが,ensime-server自体は独立していて,ensime-sbtというプラグインをsbt側でインストールしておく必要があります.

導入方法等は割愛しますが,emacsはこのensime-serverを動かすことで,scalaコンパイルを実現しています.

だとするなら,ensime-serverをdocker内で動かし,そこにローカルのemacsから接続できれば, 環境を全てdockerにした上で(ローカルにscalaの実行環境を構築しなくても),ensimeを動かせるんじゃないだろうか,と思いました.

ensimeの起動

activatorから起動

help ensimeしてみました.

それっぽいコマンドが見当たりません.

ensimeRunDebugあたりはそれっぽい……5005でlistenできるし,emacsからつなげそうな気配はあります.

しかし,docker内でensimeRunDebugを立ち上げて,手元のemacsからensime-connectすると,エラーとなりました.

Cache dir in ensime configuration file appears to be unset

と言われました. .ensimeにはcache-dir項目があるのにもかかわらずできない.

これはどういうことなんだろう……(ちなみにここの謎は未だに溶けていない

起動コマンドを調べる

activatorから起動できなかったので,実際にensimeを起動するときはどうやって起動しているんだろう?と思いました. というわけで,とりあえずローカルでensimeの環境を整えてensimeを起動してみます.

非常に長ったらしいjavaっぽいコマンドが出てきました. そうですね,ensime-serverはjavaですからね.

しかしjavaっぽいコマンドはensime-emacsの中には出てきません.設定ファイルである.ensimeをひたすら読み込んでいる.

で,よくよくコマンドを眺めてみると…….

これは,.ensime に記述されている!

そう,ensime-emacs.ensime に記述されているコマンドを呼び出すだけでした. つまりensime-serverの起動コマンドは.ensime にかかれています.

しかし……長い! これをパースして起動するような何かを作る?いやそれensime-emacselispそのままだろ…….

emacsで起動

というわけでコマンド起動は諦めて, docker内で emacs --daemon && emacsclient -e "(ensime)" でensimeを起動してみました. これをやればもちろんdocker内でensime-serverが起動します.

が,そもそもこいつはtcpなのか? どのポートで生きているのか?

起動ポートは .ensime_cache/port に書きだされています.

しかしこれは起動毎に変わってしまう…….

そこで,先に .ensime_cache/port を作っておきます.

$ echo "65005 > .ensime_cache/port

この状態で起動したら,ちゃんと65005で起動しているようなログが見て取れました.

が,65005ポートを開けておいても,接続できません. lsofで見るとわかるのですが,おそらくportで指定されたポート直接ではなく少しずらしたポートを使っているんじゃないでしょうか. それを調べる前に,せっかくなのでdocker内のensime-serverにdocker内からconnectしてみます.

ところが!

Cache dir in ensime configuration file appears to be unset

またですよ.

これってローカルからでもconnectできないのであればもう解決策がないのでは…….

これではポートを調べても意味がありません.

ここで今回は諦め.

あまり期待できない

そもそもデバッグemacsから投げるためには,実際にscalaのプログラムが動いているプロセスに繋がないと駄目はなずです. となると,Dockerで,別のJVMで動いているプロセスに,ローカルからつなぐというのはやっぱり原理的に難しいのでは……と思ってきました.

さらに,ensime-emacsのソースを読んでいて思うのですが,.ensime をいろんなところで使っています.

これ,クライアント側とサーバ側で同じconfigを読むということは,実は同じ環境でしか実行できなんじゃないでしょうか.

仮にensime-connectのときも .ensime を読んでいて,サーバ起動の時ももちろん.ensime を読むとなると,実行環境が別の場合,どちらかがエラーになるのは当然な気がします. この設計をしている限り,ensime-serverをdockerに閉じ込めて外からつなぐというのは非現実的なのかもしれません.

まぁそれでもensime-connectがエラーになるのは,そもそもローカルでも発生しているので原因がわかりませんが…….

参考

一応外からつなごうとしている人がパラパラと見受けられますが,順序立てた手順等は不明です.

github.com

stackoverflow.com