Perlのバージョン管理ツールであるCartonの内部について、社内勉強会で発表したので、その時の資料をそのまま公開する。けっこう雑に作ってしまったので、正確性については保証できないけど、Cartonのソースコードリーディングの際の参考になればと思う。
アジェンダ
- Cartonとは
- いろいろトラブル
- carton installの挙動を理解する
Cartonとは
- Perlのモジュール管理ツール
- 依存モジュールを特定のバージョンに固定して、インストールしてくれる
Cartonとは(深堀)
- 一番重要なのはcarton install
- 基本的にはcpanmのラッパーとしてcarton installが実現
- Module::CPANfileなど、小さいモジュールを組み合わせている
いろいろトラブルもある
- cpanfile.snapshotが環境によって変わる
- carton install --deploymentでインストール出来ないものがあり失敗
- carton installの挙動を理解すると、大体なんでそういうことが起こるかわかるので紹介
carton installの登場人物
- cpanm
- cpanfile
- 依存モジュールを書くファイル
- cpanfile.snapshot
- cartonのバージョン固定用ファイル
- 02packages.details.txt.gz
- CPANにおけるインデックスファイル
- モジュールをインストールするために、どこからダウンロードすればいいか記述
- install.json MYMETA.json
- あるモジュールのメタ情報が記述
- 現在のversion, 依存モジュール
- cpanmがモジュールインストール後に作る
carton installがやっていること
- バージョン固定のためのファイルを生成(02packages.details.txt.gz)
- cpanmでインストール
- cpanfile.snapshotを生成(install.json, MYMETA.jsonを利用)
バージョン固定のためのファイルを生成
- cpanfile.snapshotからCPANのインデックスファイルを生成
- 02packages.details.txt
- 02packages.details.txtには、モジュール名、version、ダウンロード元が記述
- cpanmがあるモジュールはどのversionをどこからインストールすればいいか分かる
Apache::LogFormat::Compiler 0.32 K/KA/KAZEBURO/Apache-LogFormat-Compiler-0.32.tar.gz Attribute::Params::Validate 1.18 D/DR/DROLSKY/Params-Validate-1.18.tar.gz Class::Inspector 1.28 A/AD/ADAMK/Class-Inspector-1.28.tar.gz Class::Inspector::Functions 1.28 A/AD/ADAMK/Class-Inspector-1.28.tar.gz Class::Singleton 1.5 S/SH/SHAY/Class-Singleton-1.5.tar.gz DateTime 1.18 D/DR/DROLSKY/DateTime-1.18.tar.gz DateTime::Duration 1.18 D/DR/DROLSKY/DateTime-1.18.tar.gz DateTime::Helpers 1.18 D/DR/DROLSKY/DateTime-1.18.tar.gz DateTime::Infinite 1.18 D/DR/DROLSKY/DateTime-1.18.tar.gz DateTime::Infinite::Future 1.18 D/DR/DROLSKY/DateTime-1.18.tar.gz DateTime::Infinite::Past 1.18 D/DR/DROLSKY/DateTime-1.18.tar.gz
cpanmでインストール
- cpanfileを使って依存モジュールを知る
- 02packages.details.txtを使って、どのバージョンをインストールするか知る
発行されるコマンド
- 以下の様なコマンドが発行される
cpanm -L local --mirror http://cpan.metacpan.org/ --mirror http://backpan.perl.org/ --mirror-index local/cache/modules/02packages.details.txt --cascade-search --save-dists local/cache --cpanfile cpanfile --installdeps .
- -L local
- local以下にインストール
- --mirror http://cpan.metacpan.org/ --mirror http://backpan.perl.org/ --mirror-index local/cache/modules/02packages.details.txt --cascade-search
- 02packages.details.txtのindexでインストール、そこに存在しなかったらmetacpanやbackpanにfallback
- --save-dists local/cache
- モジュールのtarはlocal/cacheに保存する
- --cpanfile cpanfile
- cpanfileの指定
cpanm内での挙動
- cpanfileを見ながら、依存モジュールを走査
- あるモジュールをインストールする
- そのモジュールのどのバージョンをインストールするかは02packages.details.txtをみて決める
- cpanfile.snapshot -> 02packages.details.txtなので、cpanfile.snapshotに記述されたバージョンが入る
- 02packages.details.txtに存在しない -> 他のmirrorにfallbackされ、インストールされる
- モジュールの依存がすべて解決されるまで、これを繰り返す
cpanfile.snapshotを生成する
なぜ問題が起こるか
- cpanfile.snapshotが環境によって変わる
- carton install --deploymentでインストール出来ないものがあり失敗
cpanfile.snapshotが環境によって変わる
- local/以下にインストールされているモジュールをすべて見るため
- local/以下に手動でモジュール入れたらおかしくなる
- 一回cpanfileに依存を増やした後、消してもlocalからは消えないので残る
- rm -rf local/ して再インストールしないとおかしくなる...
- MYMETA.jsonを参考にするが、動的に依存を変えるモジュールによって、環境によって違うMYMETA.jsonが作成される
carton install --deploymentでインストール出来ないものがあり失敗
- carton install --deploymentは02packages.details.txtだけを見て、metacpanにfallbackしないモード
- 環境によってミスったcpanfile.snapshotが作られていると死ぬ
- 02packages.details.txtに必要なモジュールが含まれていないため
結論
- モジュールのインストールはcpanmがやっている
- うまく02packages.details.txtを作って、cpanmをだますことで、バージョン固定
- cartonはcpanfile.snapshotからCPANのインデックスを作るのと、cpanfile.snapshotを作るだけ
他のパッケージ管理ツールは?
- bundler
- npm
- etc
bundler
- 基本はglobalに全部モジュール入れる、bundle exec時にPATHの通し方を工夫する
- 同じモジュール入っていたら無視できるのでインストール速い
- Gemfile.lockは毎回Gemfileから依存をたどって作り直す(local/から全部ではない)
- gemに依存を全部取ってくるAPIがあって、そこから環境依存のものも全部取ってきてるっぽい(?)
- cpanfile.snapshot, Gemfile.lockには依存が多く記述されるのは問題ないため
carmel
- bundlerっぽい動き方を目指している
- 5分くらい使ってみたけどなんかうまく動かなかった