パッケージシステムについて考える/後編

これまでのおはなし

前編では、Windows で使えるパッケージマネージャーについて、現状をさらっと見てきました。
後編では、願望と妄想を大いに交えつつ、将来の形について考えてみたいと思います。

で、何があったっけ?

キーワードだけ再掲。

多すぎます

記事で話題にする都合上、パッケージ マネージャーとは呼べないようなものも含んでいますが、それを差し引いても、若干乱立している感じは否めません。
というわけで、これらが集約、統合されていくとしたらどうなるのかということを考えてみます。

WebPI は要らない

WebPI は、これらの中でも最も古いシステムです。
GUI でも利用されますが、WebPiCmd という、CUI で利用可能なコマンドも用意されています。
そのため、これまで、サーバーの自動セットアップ等をする際には、この WebPiCmd を使うことが一般的でした。

しかし、WMF 4.0 から、PowerShell DSC という仕組みが搭載され、続けて 5.0 で OneGet が出てきました。
WebPI と OneGet は競合するツールです。
今後、サーバーの自動プロビジョニング技術としては、Microsoft は DSC + OneGet という方向に舵を切っていくのは明白でしょう。
そのため、遠からず、WebPI は無くなるものと思われます。

なお、DSC について詳しいことはぎたぱそせんせーとかむたぐちせんせーが教えてくれます。たぶん。

Chocolatey はどーでもいい

酷い言いぐさですが仕方がありません。
何故なら、これだけ、Microsoft の影響力が及ばないツールだからです。
本稿では上に挙げたような、Microsoft 製(NuGet も含んでしまえ)ツールについて考えているので、これ以降、Chocolatey の出番はありません。

もちろん、OneGet をリリースするにあたり、MS は Chocolatey の開発者とコミュニケーションを取り合っています。
その意味では、影響力はゼロではありません。ここでは、MS は Chocolatey に関して、未来を決定する権利はないということだと思ってください。
NuGet も MS 製ではありませんが、MS の影響力は Chocolatey 以上に大きいと思っています。

OneGet は、現時点では Chocolatey リポジトリしか扱えません。
これは、OneGet をデモンストレーションするのに手ごろなのが Chocolatey だったということでしょう。
おそらく、WMF 5.0 が正式リリースされた暁には、Microsoft が管理する公式 OneGet リポジトリが登場するのではないかと思われます(少なくとも、現在 WebPI で配布しているものを管理する場所が必要です)。
しかし、OneGet 自体は、他にも様々なリポジトリに対応できる柔軟性を持っています。
OneGet に対応したリポジトリは今後増えることが予想され、また、MS もそれを応援していくと思います。
方向性としては Chocolatey と OneGet は競合する関係にありますが、Microsoft が乗っ取りでもしない限りは、すぐに無くなりはしないでしょう。

Windows ストアは別腹

Windows ストアは Metro アプリの配布専用で、ここは独壇場です。
その他のツールはストア環境では動作しませんので、はっきりと境界が引かれています。
Windows ストアが他の仕組みと統合されることはあり得ません。

アプリケーションとモジュールとアドイン(とサンプル コード)

大きく分けて、上に挙げたパッケージ マネージャーが配布するのは、この 4 つだと思います。

アプリケーションを配布するのは OneGet と Windows ストアです。
K Package Manager も使えるようですが、上手く動かすことができませんでした。

モジュールとは、アプリケーションの構築に利用される、再利用可能なパーツのことだとします。
この配布・管理に利用されるのは、NuGet と K Package Manager です。
PowerShellGet をここに含めていない意図は、これから説明します。

アドインとは、他のアプリケーションに機能を追加したり、使い勝手を向上させるための補助ソフトウェアです。
Visual Studio 用のアドインは、Visual Studio Gallery で配布されています。
PowerShell ISE Script Browser は PowerShell ISE 用のアドインです。

サンプル コードは…サンプル コードです。
MSDN Code Recipe と TechNet Script Center で配布されています。

サイド バイ サイド

# 誰かこのへん、わかりやすい画像作ってください…

アプリケーションは、モジュールを利用します。
アプリケーション A がモジュール X と Y を利用し、アプリケーション B がモジュール Y と Z を利用するというような状況を考えます。
モジュール Y は両アプリケーションから利用されています。
しかし、実はアプリケーション A はモジュール Y のバージョン 1 を使っていて、アプリケーション B はモジュール Y のバージョン 2 を使っていたなんてことも、よくあります。
アプリケーション B をインストールしたらモジュール Y がバージョン 2 に更新されて、アプリケーション A が動かなくなってしまっては困ります。
昔はそういうことがありました。俗に DLL Hell と呼ばれる現象です。
複数のアプリケーションから使われるモジュールは、C:\Windows\System32 にインストールしてくださいなんていう、今から見れば恐ろしいドキュメントがゴロゴロありました。

.NET Framework は、DLL Hell の解消を目的として、アセンブリという技術を導入しました。
GAC (Global Assembly Cache) という場所にインストールされたモジュール(アセンブリ)は、同じモジュール Y であっても、バージョン 1 とバージョン 2 が同じマシン上に共存でき、それぞれのアプリケーションから参照されます。
このように、あるアプリケーションのインストールが、他のアプリケーションに影響を与えないことを、「サイド バイ サイド」と言います。

サイド バイ サイドは、NuGet の登場によって、一層推し進められます。
NuGet で配布されるライブラリは、基本的に GAC ではなくアプリケーションと同じディレクトリに配置され、他のアプリケーションからは参照されないからです。

K Version Manager で、この方向性はさらに強化されます。
KRE (K Runtime Engine) を利用するアプリケーションでは、GAC を一切使わず、.NET Framework のすべてをアプリケーション ディレクトリに抱え込むこともできます(従来通り GAC を利用することも、また、GAC とは別の共有アセンブリ ディレクトリを参照することもできます)。
事前に .NET Framework をインストールしておく必要も、場合によっては IIS さえも必要なく、アプリケーション ディレクトリを他のマシンに持っていくだけで Web サーバーを立ち上げることができます(ファイアーウォールなんかの設定は必要だと思いますが)。

もっとも、これは特殊なシナリオです。
K システムは ASP.NET のためにデザインされた仕組みです。
そして、1 つの Web サーバーには通常、そんなに多数の Web アプリケーションは配置されません。
そのため、1 つの Web アプリケーションが、少々多めにディスクスペースを占有しても構いません。それより優先すべきことがあるからです。
一般のアプリケーションではそうはいきません。
.NET Framework で動くすべてのアプリケーションが、それぞれ個別に .NET Framework のコピーを抱え込んだら、あっという間にディスクが枯渇してしまうでしょう。

ともかく、モジュールにはサイド バイ サイド性が求められる傾向にあるということは確かです。

また、依存性はモジュール同士の間にある場合もあります。
先の例と同じように、今度は、モジュール M が別のモジュール Y のバージョン 1 に、また、モジュール N が Y のバージョン 2 に依存していたらどうなるでしょうか?
GAC では、同様に、モジュール Y のバージョン 1 と 2 が共存できるので問題はありません。
GAC を使わない NuGet でも、少なくとも DLL Hell は起こりません。
あるアプリケーション プロジェクト A に、モジュール M と Y のバージョン 1 がインストールされているとしましょう。
この状態で、NuGet を使って A にモジュール N をインストールしようとすると、「モジュール Y の互換性が無いためインストールできない」というエラーになります。
両立はできませんが、うっかり壊れてしまうということは避けられるわけです。

で、PowerShell

PowerShell モジュールには、元々、モジュール間に依存性を持たせる仕組みがあります。
また、PowerShellGet では NuPkg 形式を採用したため、その機能を使っても、依存モジュールを定義することができます。
では、あるモジュール X が別のモジュール Y に依存している時、PowerShellGet でモジュール X をインストールしたらどうなるでしょうか?

NuGet であれば、依存関係にあるモジュールが芋蔓式にインストールされます。
一方、PowerShellGet ではされません。
これが、プレビュー版ゆえの制限なのか、敢えての仕様なのかはわかりません。

ただ、敢えての仕様でないとすれば問題があります。
PowerShellGet は、ユーザーまたはマシンの標準モジュール ディレクトリにモジュールをインストールします。
そして、このモジュール ディレクトリは、GAC とは違って、サイド バイ サイド性がありません。
つまり、迂闊に芋蔓式のインストールをすると、DLL Hell ならぬ Module Hell が発生する可能性があります。

現状、PowerShell Resource Gallery がプレビュー段階のため、このような実験に都合のいいモジュールがありません。
モジュールのアップロードができるようになったら、改めて実験してみるつもりです。

アプリケーションについても考えてみましょう。
PowerShell を、.NET Framework に対応したプログラミング言語のひとつと考えるならば、PowerShell で書いたアプリケーションというものが考えられてもよいでしょう。
今後発展してほしい分野です。
では、そういうものが出来たとして、それは PowerShellGet で配布するべきか? という問題があります。
PowerShellGet は、モジュールを配布するために用意されています。
モジュールは再利用されるための仕組みですが、アプリケーションはそうではありません。
そのため、PowerShell アプリケーションが、標準モジュール ディレクトリにインストールされるというのは、あまり嬉しい状況ではありません。

なお、PowerShellGet では出来ないようですが、PowerShell 自体の仕組みとしては、標準モジュール ディレクトリ以外にモジュールを配置することも可能です。
Import-Module コマンドは、モジュール名だけでなく、パスを指定して読み込むこともできるからです。
だとすれば、アプリケーションが依存するモジュールは、アプリケーション ディレクトリ下に配置して、アプリケーションと一緒にパッケージ化してしまうという手もあります。
これならサイド バイ サイド性が成立します。NuGet と同じです。
そうして作ったアプリケーションは、PowerShellGet ではなく OneGet で配布すればよいと思います。
PowerShellGet は PowerShell のためのパッケージシステムだから、PowerShell アプリケーションもこれで配布しようというのは、やめた方がいいでしょうね。

Chocolatey のダメなところ

出番がないかと思っていたらまさかの呼び出し、そしてダメ出し。Chocolatey、不憫な子…!
Chocolatey は、そのデザイン上仕方がないことではあるのですが、割とダメダメです。

そもそも、Chocolatey は、アプリケーションをパッケージ化して配布するための仕組みではないと言ってしまってもよいと思います。
あれは、アプリケーションを簡単にインストールするための仕組みであって、それ以上でもそれ以下でもありません。

例えば、Chocolatey のリポジトリには、Adobe Reader のパッケージがあります。
NuPkg をダウンロードして展開してみればわかりますが、この中には、Adobe Readerインストーラーは入っていません。
Adobe のサイトからインストーラーをダウンロードして実行するためのスクリプトがあるだけです。
統計を取ったわけではありませんが、おそらく、Chocolatey パッケージの大半がこういう形態ではないかと思われます。

パッケージ情報を見ると、Authors: Adobe となっていますが、こんなのは何とでも書くことができます。誰もチェックしていません。
パッケージ作者の ferventcoder という人は、十中八九、Adobe の人ではありません。
そんな人が、Adobe のサイトからダウンロードしたインストーラーをパッケージに含めて配布したら、著作権的に問題になってしまいますよね。
まぁ、再配布契約を結んでいればいいんですけど…。

Chocolatey というのは基本的に、(パッケージ内にあるか、都度ダウンロードするかはともかくとして)インストーラーを取得して実行するための手段です。
実際にインストールを行うのは各ソフトウェアのインストーラーであって、Chocolatey ではありません。

ということは、です。
インストール作業がどのように行われるかはインストーラー次第であって、Chocolatey はそれを制御することができないということです。
一応、インストーラーにパラメーターを渡すことはできるようになっています。
が、インストーラーがどのようなパラメーターを受け入れるのかを、事前に知る方法はなさそうです。
例えば、インストール先のディレクトリを指定しようと思っても、どのようなパラメーターを与えればよいのか、それ以前に、そもそも指定することが可能なのかどうかも不明です。
指定可能なパラメーター情報をメタデータとして NuPkg に含めておいて、Get-Help 的なコマンドで表示するとか、やりようはあったと思います。

パラメーターがインストーラー固有になるのは仕方のないことです。
が、それでも、インストール先のように多くのインストーラーで指定可能であると思われるパラメーターくらいは、Chocolatey の機能として持っていて欲しかったと思います。

しかし、実のところ、インストール先が指定可能かどうかということは、さほど重要なことではありません。
例えば Windows ストアアプリは、インストール先を指定できませんよね(パッケージマネージャーの一覧に Windows ストアを入れていたのは、これが言いたかったからです)。
ユーザーは、アプリケーションのインストール先など知らなくてもよいのです。
ただ、それがスタート画面なり何なりに表示されて、適切に起動することさえできればいい。

だとしても、Chocolatey はダメです。
あまりに自由奔放すぎるために、あるパッケージは C:\tools とかいうフォルダにインストールしたり、別のパッケージは Program Files にインストールしたりと、バラバラです。
そこからアプリを起動するための方法も、統一的には示されません。
要するに、何もガバナンスを効かせていないし、ユーザーがコントロールすることもできないというのがダメなところだと思います。

PortableApps.com の方がずっと良くできています。
USB メモリに入れて持ち運べるというのがウリですが、パッケージ マネージャー兼ランチャーとして使うのでも、十分に便利です。

とはいえ、利点と欠点は紙一重です。
そのようなゆるい仕組みであったからこそ、これほどまでにリポジトリの規模が拡大したとも言えます。

再び PowerShell について

わざわざ Chocolatey を槍玉に挙げて何を言いたかったかといえば、ソフトウェアがインストールされる場所は重要ではなく、それを適切に実行する仕組みさえあれば良い(ただしガバナンスは効かせるべき)ということに尽きます。それだけです。

あ、もう本当に、Chocolatey の出番はありません。

で。
つまりは、PowerShell のモジュール ディレクトリも、そういう形になってもいいんじゃないか? ということです。
これまで、原則として、PowerShell モジュールをインストールするには、ユーザーが手動でモジュール ディレクトリにコピーする必要がありました。
そのため、モジュール ディレクトリの位置はユーザーにとって既知である必要がありました。

しかし、PowerShellGet で事情は変わります。
適切な場所にインストールされ、powershell がそれを適切に読み込んでくれさえするのなら、モジュールがどこにあろうと構わないのです。
そういう風になれば、サイド バイ サイド性を獲得することもできるでしょう。

KVM/KPM

これは正直、あまりいじれていないので、未知数なものがあります。

KVM は、NuGet リポジトリの仕組みを使って、K Runtime Engine(.NET Framework 的なもの)を取得、管理するためのツールのようです。
インストールされている複数の KRE の中から、使用するバージョンを切り替えるようなことも可能なようです。
KRE 自体を取得、管理するのは OneGet で良さそうな気がします。

KPM は、NuGet のように、リポジトリからクラス ライブラリを取得して、アプリケーション プロジェクトにインストールすることと、アプリケーション全体を配布用にパッケージングする(KRE を丸ごと含めることも可能)ことの 2 つの機能を持つようです。
前者はまさに NuGet がやっていることそのままですし、後者は OneGet でカバー出来そうな気もします。

どうせアプリケーションの開発には Visual Studio を使うわけですから、NuGet も使うでしょう。
そこで、いや NuGet ではなく KPM を使えというのはナンセンスで、生産性を下げるだけです。
裏側には NuGet リポジトリがいるわけですし。

ということになると、積極的に統合を進めた場合、残るのは KVM のうちのバージョン切り替えの機能だけということになりそうです。

正直、なぜ今の段階で ASP.NET チームがこんなツールをリリースしてきたのか、意図を掴みかねているところです…。

アドイン

アドインというのは、特定のアプリケーションの機能を拡張するモジュールのことです。
Visual Studio 向けのアドインは Visual Studio Gallery で配布されています。

また、PowerShell ISE にもアドインがあります。
PowerShell ISE のアドインは PowerShell モジュールの形態を取りますから、今後は PowerShellGet で配布されることが予想されます。
そもそも、PowerShell のモジュール自体、powershell.exe の機能を拡張するものだと考えれば、アドインのようでもあります。

つまり、現状では、

  • PowerShell アプリケーションという概念があまりメジャーでないこと
  • PowerShell モジュールはアプリケーションを作る時のパーツというより、powershell.exe の機能を拡張するように作用すること
  • 標準のモジュール ディレクトリにサイド バイ サイド性がないこと

といった理由により、PowerShell モジュールは、一般的な意味でのモジュールというよりは、アドインに近い性質のものであると言えるでしょう。

PowerShellVisual Studio

PowerShell でちょっと長いスクリプトや複雑なモジュールを書いてデバッグする場合、PowerShell ISE を使うと思います。
そうそう。ISE Steroids は強力なアドインです。ISE を使うなら是非入れておきたいものです。

しかし、こう思ったことはないでしょうか。
Visual Studio で出来たらいいのに…」と。
ISE Steroids をインストールしていなければ、変数ウォッチ機能すら ISE には無いのです。VS ならあるのに!

PowerShell Tools for Visual Studio は VS で PowerShell を書く人には必携のアドインです。無料ですし。
ただ、まだまだ発展途上の感が否めません。
機能的には ISE + ISE Steroids の方が優れていると思います。

VS には、PowerShell を書く上で使いたい機能が山のようにあります。プロジェクトによるモジュールのソースコード管理、単体テスト、エラー一覧、TFS によるバージョン管理や自動処理、WMI エクスプローラー、スタック トレース…枚挙に暇がありません。
ブレーク ポイントや検索/置換といった、ISE でもサポートされている機能であっても、操作性が同じであるということはメリットになります。

しかし、残念ながら、Microsoft には、どうもやる気が無いように感じられます。
PowerShell Tools だけが残された希望です。頑張って欲しいと切に思います。

まぁ、この記事はもともと妄想の産物です。
Microsoft によって、Visual Studio での PowerShell 編集がサポートされ、PowerShell を書くなら Visual Studio!となった世界のことを想像してみましょう。

ISE はお役御免です。
ISE のアドインは、PowerShell のモジュールとしてではなく、Visual Studio のアドインに姿を変えるでしょう。
ISE アドインの開発というのは正直マイナーな分野ですが、VS に統合されれば、PowerShell を書きやすくするようなアドインも、もっと増えることが期待されます。

Visual Studio との統合は、複雑なモジュールの開発だけでなく、PowerShell アプリケーションの普及に、間違いなく一役買います。
そうなった時、モジュールはどうなるでしょうか?
アプリケーションから利用される、本来の意味でのモジュールです。
これは、NuGet で配布され、アプリケーション ディレクトリに配置されるようになるでしょうね。
そして、アプリケーション丸ごとパッケージングされて、OneGet で配布されるようになります。

PowerShell のモジュールはアドイン的であると言いました。
では、ISE アドインでない従来のモジュールも、Visual Studio のアドインと同じように、Visual Studio Gallery で配布されるようになるでしょうか?
いいえ、それはありえません。
複雑なスクリプトを書くのは Visual Studio の役目になっても、powershell.exe が無くなることはないからです。
Visual Studio は、PowerShell の標準コーディング環境になることはできても、標準実行環境になることはできません。
スクリプトを実行するためだけに、サーバーマシンに Visual Studio を入れるなんてことはできませんからね。
つい開発者目線になってしまいますが、PowerShell は元来、サーバーを管理するためのツールです。
Server Core のような環境もサポートしなければならないことを考えると、すべての PowerShell モジュールが Visual Studio アドインになることはないでしょう。
ということは、PowerShellGet も存続するということです。
標準のモジュール ディレクトリという概念も残り続けます(ユーザーからは意識されない場所になるでしょうが)。
ただし、PowerShell アプリケーションを構成するモジュールや、ISE のアドインは、PowerShellGet で配布されなくなるでしょう。
まぁ、Visual Studio 拡張マネージャーを UI として、PowerShellGet に接続して、モジュールを探したりインストールしたり…といった管理はできてもいいでしょうね。

サンプルコードはどうでしょうか。
Visual Studio は既に、MSDN Code Recipe にあるサンプルコードを読み込む機能を備えています。ISE Script Browser のようなものです。
この仕組みの上に乗るのが自然でしょう。
その時、サンプルコードが TechNet Script Center から MSDN に移動になるのか、それとも、Visual StudioTechNet に接続されるようになるのか、それはわかりません。どちらでもよいことです。
ただ、例えばマネージコードで PowerShell モジュールを開発するような場合のサンプルは、開発者向けということで MSDN の領分になるでしょうか。
PowerShell の関連リソースが分断されてしまうのは、あまり望ましいとは思いません。
MSDNTechNet のどちらか一方に集約するか、もしくは、そのどちらとも独立したサンプル リポジトリを立てるか…いずれにせよ、一ヵ所にまとまっていて欲しいと思います。

そういえば、Visual Studio は未だに、NuPkg を作る機能も標準では持ち合わせていません(アドインはいくつかあります)。
まったく、あり得ない怠慢さです。
VS はとっとと NuPkg と OneGet Package を作る機能を標準でサポートすべきです!

で、どうなりました?

こうなりました(妄想)。

Web Platform Installer OneGet に統合
NuGet 存続
Visual Studio Gallery 存続
Chocolatey どうにでもなれ
OneGet 存続
PowerShellGet 存続、ただし一部役割を NuGet と Visual Studio Gallery に移譲
KVM/KPM 基本的に NuGet と OneGet に分割統合
Windows ストア 存続
MSDN Code Recipe 存続
TechNet Script Center MSDN Code Recipe に統合
PowerShell ISE Script Browser Visual Studio に統合

…あまり減らなかったね。でも、これで寝れる!よかった!