CaskをWindowsで動作させる
2014/03/18現在、CaskはWindowsでの動作は保証していないようです。
実際、私の環境では動作しませんでした。
しかし、WindowsでもCaskをどうしても使いたかったので、試行錯誤の末、解決策を見つけました。
先に結論
こちらの拙作の拡張を使うことで可能になります。
とはいえ、拡張とか要らないんだよねって人もいると思いますので、 それに至った経緯を備忘録を兼ねてまとめてみようと思います。
まず、私の環境は以下です。
- WindowsXP Professional SP3 32bit
- GNU Emacs 24.2.1 (i386-mingw-nt5.1.2600) of 2012-12-08 on GNUPACK
- ActivePython 2.7.3
- Cygwin 1.7.17
とりあえず、README通りにインストールを試みる
ちなみに、事前にUbuntuではインストールして動作させるのに成功していました。
その時のログは以下のような感じ。
/tmp$ curl -fsSkL https://raw.github.com/cask/cask/master/go | python Cloning into '/home/hiroaki/.cask'... remote: Reusing existing pack: 2919, done. remote: Counting objects: 46, done. ・・・ Contacting host: melpa.milkbox.net:80 Saving file /home/hiroaki/.emacs.d/.cask/24.3.1/bootstrap/archives/melpa/archive-contents... Loading vc-svn... Wrote /home/hiroaki/.emacs.d/.cask/24.3.1/bootstrap/archives/melpa/archive-contents ・・・ Generating autoloads for s-pkg.el... Generating autoloads for s-pkg.el...done Generating autoloads for s.el... Generating autoloads for s.el...done Saving file /home/hiroaki/.emacs.d/.cask/24.3.1/bootstrap/s-20131223.944/s-autoloads.el... Wrote /home/hiroaki/.emacs.d/.cask/24.3.1/bootstrap/s-20131223.944/s-autoloads.el Checking /home/hiroaki/.emacs.d/.cask/24.3.1/bootstrap/s-20131223.944... Compiling /home/hiroaki/.emacs.d/.cask/24.3.1/bootstrap/s-20131223.944/s-autoloads.el... Compiling /home/hiroaki/.emacs.d/.cask/24.3.1/bootstrap/s-20131223.944/s-pkg.el... Wrote /home/hiroaki/.emacs.d/.cask/24.3.1/bootstrap/s-20131223.944/s-pkg.elc Compiling /home/hiroaki/.emacs.d/.cask/24.3.1/bootstrap/s-20131223.944/s.el... Wrote /home/hiroaki/.emacs.d/.cask/24.3.1/bootstrap/s-20131223.944/s.elc Done (Total of 2 files compiled, 1 skipped) ・・・ Contacting host: elpa.gnu.org:80 Saving file /home/hiroaki/.emacs.d/.cask/24.3.1/bootstrap/archives/gnu/archive-contents... Wrote /home/hiroaki/.emacs.d/.cask/24.3.1/bootstrap/archives/gnu/archive-contents Successfully installed Cask! Now, add the cask binary to your $PATH: export PATH="/home/hiroaki/.cask/bin:$PATH" /tmp$
というわけで、Windowsでも同じようにしてみると、以下のエラーが。
~ # curl -fsSkL https://raw.github.com/cask/cask/master/go | python Cloning into 'C:\home\.cask'... Traceback (most recent call last): File "<stdin>", line 100, in <module> File "<stdin>", line 90, in main File "<stdin>", line 62, in bootstrap_cask File "C:\Dev\python\2.7\lib\subprocess.py", line 506, in check_call retcode = call(*popenargs, **kwargs) File "C:\Dev\python\2.7\lib\subprocess.py", line 493, in call return Popen(*popenargs, **kwargs).wait() File "C:\Dev\python\2.7\lib\subprocess.py", line 679, in __init__ errread, errwrite) File "C:\Dev\python\2.7\lib\subprocess.py", line 896, in _execute_child startupinfo) WindowsError: [Error 193] %1 は有効な Win32 アプリケーションではありません。 ~ #
Caskのリポジトリを検索してみると、既にissueが登録されていて、
さらに、この問題を解消できると思われるプルリクも出されていました。
修正されたgoファイルを使ってみる
上記のインストールの処理は、
「CaskのリポジトリにあるgoというPythonのファイルをダウンロードして実行する」ということなので、
このプルリクで修正されているgoファイルをダウンロードして実行してみました。
~ # python go Cloning into 'C:\home\.cask'... remote: Reusing existing pack: 2965, done. remote: Total 2965 (delta 0), reused 0 (delta 0) Receiving objects: 100% (2965/2965), 815.17 KiB | 255 KiB/s, done. Resolving deltas: 100% (1659/1659), done. Traceback (most recent call last): File "C:\home\.cask\bin\cask", line 301, in <module> main() File "C:\home\.cask\bin\cask", line 291, in main exec_cask(sys.argv[1:]) File "C:\home\.cask\bin\cask", line 253, in exec_cask emacs = get_cask_emacs() File "C:\home\.cask\bin\cask", line 220, in get_cask_emacs ensure_supported_emacs(emacs) File "C:\home\.cask\bin\cask", line 177, in ensure_supported_emacs if not is_supported_emacs(emacs): File "C:\home\.cask\bin\cask", line 162, in is_supported_emacs return get_emacs_version(emacs) >= MIN_EMACS_VERSION File "C:\home\.cask\bin\cask", line 146, in get_emacs_version raise ValueError('Could not determine the version of {0}'.format(emacs)) ValueError: Could not determine the version of emacs Cask could not be bootstrapped. Try again later, or report an issue at https://github.com/cask/cask/issues ~ #
どうも、Emacsのバージョンについて怒られているように見えます。
goファイルのソースを見てみると、Caskのリポジトリをgit cloneして、
その中のbin/caskをupgradeという引数で実行しているだけのようでした。
で、このcaskというファイルもPythonのソースファイルになっており、試行錯誤の末、
Emacsのバージョンを判別するための正規表現が、NTEmacsの出力するバージョン情報に
CRが入っているためマッチしていないということがわかりました。
VERSION_RE = re.compile(r'^GNU Emacs (?P<version>\d+(?:\.\d+)*)$', re.MULTILINE) # ↑\rが必要
caskファイルを修正して実行してみる
上記の正規表現を修正して、再度goファイルを実行したのですが、 既にgit cloneしたディレクトリがあるとcaskを実行する前に終了してしまいます。
~ # python go Directory C:\home\.cask exists. Is Cask already installed? ~ #
上述の通り、goファイルはgit cloneしてcask upgradeしているだけなので、 修正したcaskファイルを直接実行することにしました。
~ # c:/home/.cask/bin/cask upgrade ~ # Contacting host: melpa.milkbox.net:80 ~ #
すると、すぐ実行が終了してしまい、サーバにアクセスした後の処理が実行されていないように見えます。
emacsのプロセスがもう一つ生成されており、何か処理をし続けているようでした。
これも試行錯誤の末、以下のエントリにまとめた問題があることを発見しました。
NTEmacsのbatch/scriptモードでは、set-process-filterなどの非同期通信処理ができないみたい
package.elのダウンロード処理にcurlを使う
cask upgradeによりpackage.elの機能が呼び出され、その中でmelpaなどのリポジトリからデータやファイルを
ダウンロードするためにプロセス通信が行われるため、上記の問題と同じ現象で処理が進まなくなってしまっているようです。
それを回避するために、ダウンロードを実行するurl-retrieve-synchronouslyという関数の挙動を、
curlコマンドを使うように変更しました。
cask upgradeの処理は、単に以下を実行しているだけで、
~ # emacs -Q --script $HOME/.cask/cask-cli.el -- upgrade
cask-cli.elの実行により、上記の問題が起きます。
なので、url-retrieve-synchronouslyの挙動変更を行って、cask-cli.elをロードするラッパーを用意して、
caskファイルはそのラッパーを実行するように変更しました。
caskファイルの変更内容は以下の感じ。
~ # diff .cask/bin/cask.bk .cask/bin/cask 50c50 < VERSION_RE = re.compile(r'^GNU Emacs (?P<version>\d+(?:\.\d+)*)$', re.MULTILINE) --- > VERSION_RE = re.compile(r'^GNU Emacs (?P<version>\d+(?:\.\d+)*)\r?$', re.MULTILINE) 254c254 < cli = os.path.join(CASK_DIRECTORY, 'cask-cli.el') --- > cli = os.path.join(CASK_DIRECTORY, 'cask-cli-patch.el') ~ #
cask-cli-patch.elの定義は以下を参照。
https://github.com/aki2o/caskxy/blob/master/contrib/cask-cli.el
改めてcask upgrade
~ # c:/home/.cask/bin/cask upgrade ~ # Contacting by cURL : http://melpa.milkbox.net/packages/archive-contents Saving file c:/home/.emacs.d/.cask/24.2.1/bootstrap/archives/melpa/archive-contents... Loading vc-svn... Wrote c:/home/.emacs.d/.cask/24.2.1/bootstrap/archives/melpa/archive-contents Contacting by cURL : http://elpa.gnu.org/packages/archive-contents Saving file c:/home/.emacs.d/.cask/24.2.1/bootstrap/archives/gnu/archive-contents... Wrote c:/home/.emacs.d/.cask/24.2.1/bootstrap/archives/gnu/archive-contents Cannot update Cask because of dirty tree ~ #
git cloneしたディレクトリのファイルに変更があると、upgradeでエラーになるようにされてました。
なので、別にディレクトリを作って、修正したファイルはそちらに配置し、~/.caskディレクトリは元の状態に戻しました。
~ # mkdir -p .cask.patch/bin ~ # cp .cask/bin/cask .cask.patch/bin/ ~ # mv .cask/cask-cli-patch.el .cask.patch/ ~ #
修正した方のcaskファイルでcask upgrade
~ # c:/home/.cask.patch/bin/cask upgrade ~ # Contacting by cURL : http://melpa.milkbox.net/packages/archive-contents Saving file c:/home/.emacs.d/.cask/24.2.1/bootstrap/archives/melpa/archive-contents... Loading vc-svn... Wrote c:/home/.emacs.d/.cask/24.2.1/bootstrap/archives/melpa/archive-contents ・・・ Generating autoloads for s-pkg.el... Generating autoloads for s-pkg.el...done Generating autoloads for s.el... Generating autoloads for s.el...done Saving file c:/home/.emacs.d/.cask/24.2.1/bootstrap/s-20131223.944/s-autoloads.el... Wrote c:/home/.emacs.d/.cask/24.2.1/bootstrap/s-20131223.944/s-autoloads.el Checking c:/home/.emacs.d/.cask/24.2.1/bootstrap/s-20131223.944... Compiling c:/home/.emacs.d/.cask/24.2.1/bootstrap/s-20131223.944/s-autoloads.el... Compiling c:/home/.emacs.d/.cask/24.2.1/bootstrap/s-20131223.944/s-pkg.el... Wrote c:/home/.emacs.d/.cask/24.2.1/bootstrap/s-20131223.944/s-pkg.elc Compiling c:/home/.emacs.d/.cask/24.2.1/bootstrap/s-20131223.944/s.el... Wrote c:/home/.emacs.d/.cask/24.2.1/bootstrap/s-20131223.944/s.elc Done (Total of 2 files compiled, 1 skipped) ・・・ Contacting by cURL : http://melpa.milkbox.net/packages/archive-contents Saving file c:/home/.emacs.d/.cask/24.2.1/bootstrap/archives/melpa/archive-contents... Wrote c:/home/.emacs.d/.cask/24.2.1/bootstrap/archives/melpa/archive-contents Contacting by cURL : http://elpa.gnu.org/packages/archive-contents Saving file c:/home/.emacs.d/.cask/24.2.1/bootstrap/archives/gnu/archive-contents... Wrote c:/home/.emacs.d/.cask/24.2.1/bootstrap/archives/gnu/archive-contents ~ #
やったよ。インストールできた。長かった・・・。
と喜びも束の間・・・
試しに、テストを実行してみたところ、
/cygdrive/c/MyWork/caskxy # c:/home/.cask.patch/bin/cask exec emacs -Q --batch -L . -l test/run-test.el -f batch-expectations Traceback (most recent call last): File "c:/home/.cask.patch/bin/cask", line 301, in <module> main() File "c:/home/.cask.patch/bin/cask", line 293, in main exit_error(error) File "c:/home/.cask.patch/bin/cask", line 271, in exit_error print('{0}{1}: error: {2}'.format(executable, command, error), UnicodeDecodeError: 'ascii' codec can't decode byte 0x82 in position 15: invalid start byte /cygdrive/c/MyWork/caskxy #
調べると以下のリンクが見つかりましたが、私の環境ではasciiがutf8になっただけでエラーは解消されませんでした。
Python スクリプト実行時に UnicodeDecodeError が出る場合の対処方法 - Over&Out その後
パス形式の問題も存在
ちなみに、caskにパスを通して実行すると、以下のようにパスが見つからないと言われます。
/cygdrive/y/MyWork/caskxy # cask exec emacs -Q --batch -L . -l test/run-test.el -f batch-expectations C:\Dev\python\2.7\python.exe: can't open file '/cygdrive/c/home/.cask.patch/bin/cask': [Errno 2] No such file or directory /cygdrive/y/MyWork/caskxy #
PythonがActivePythonなので、Cygwinのパス形式が認識できないのだと思われます。
Cygwinに入っているpythonを使えばcaskは見つかりますが、
それだと、NTEmacsがCygwinのパス形式を認識できないため、-lとかで指定するパスが見つからないと言われます。
goファイルを修正しているプルリクには、batファイルが用意されているので、
それを使えば、コマンドプロンプトからなら、いけるのかも知れませんが、
他の作業はCygwinのシェルを使っているので、Caskだけコマンドプロンプトというのは・・・でした。
という感じで、のたうちまわった末にひらめいた
Pythonを使ってるから、こんな面倒くさい事になってんじゃん!
Pythonの部分って、ラッパーとしての役割ぐらいしかないんだし、Elispで代替すりゃ良いんじゃね!?
となって、拡張を作りましたとさ。