TeX Liveのスキームに含まれるパッケージを一覧したい話

2018-08-18 (updated: 2025-12-09) #TeX Live #Ruby #golf

某ソフトウェアの保守作業をしていて、各スキームに含まれるパッケージの一覧が必要になりました。TeX Liveのスキームというのは、要するにTeX Liveのサブセットのことで、TeX Liveをインストールしたいユーザがそれぞれの目的に適ったものを選択できるようにすることを意図して定義されたもののようです。具体的には

  • scheme-full: 全部入りTeX Live
  • scheme-basic: LaTeXするのに必要な最低限のもの
  • scheme-small: scheme-basicにXeTeX, MetaPostなどを加えた小さめのサブセット
  • scheme-medium: 中ぐらいのサブセット

などがあります1。ちなみに、スキームの他にもコレクションと呼ばれるグループもあります。スキームがインストール上の便宜のために存在しているのに対して、コレクションは似た目的をもつパッケージを集めたものだと思います。

話が逸れましたが、とにかく各スキームに含まれるパッケージ、すなわち、あるスキームを選択したときにインストールされるパッケージの一覧が欲しいわけです。

まずはもちろん、ググりました。そして、アレWikiに次のように書いてあるのを見つけました:

詳細はtexlive.tlpdbというファイルを見ればわかります

そう言われたのでtexlive.tlpdbを見ました

「……なるほど、わからん」

どういうことかというと、texlive.tlpdbには次のような包含関係2が(独特の形式で)列挙されています:

  • scheme-mediumはcollection-latex, collection-luatex, …… を含む
  • collection-luatexはcollection-basic, lualibs, …… を含む

こんな調子が全部でおよそ2万5千行です。こんなの「見て」わかるわけがない!

とはいえ、TeX Liveチームはtlmgrという素晴らしいツールを用意してくれていて、さすがにtexlive.tlpdbを目grepしたり独自にパースしたりしなくても

$ tlmgr info --list <package|collection|scheme> ...

のようにすると、引数に与えたパッケージ(またはコレクション、スキーム)に関してtexlive.tlpdbに記載されている情報を表示してくれます3

これで一件落着かと思いきや、まだそういうわけにもいきません。試しにscheme-basicの情報を表示してみます。

$ tlmgr info --list scheme-basic
package:     scheme-basic
category:    Scheme
shortdesc:   basic scheme (plain and latex)
longdesc:    This is the basic TeX Live scheme: it is a small set of files sufficient to typeset plain TeX or LaTeX documents in PostScript or PDF, using the Computer Modern fonts.  This scheme corresponds to collection-basic and collection-latex.
installed:   Yes
revision:    25923
sizes:       147293k
relocatable: Yes
depends:
	collection-basic
	collection-latex

ここで表示されるのはscheme-basicがcollection-basic, collection-latexを含むということだけで、さらにcollection-basicやcollection-latexが何を含んでいるかを調べないことには「パッケージの一覧」を得ることはできません。scheme-basicは最小のスキームなので、それぞれのコレクションが何を含むのかtlmgrで調べてもいいかもしれませんが、もっと大きなスキームについてはそんなことをしていては日が暮れてしまいます。

残念ながらtlmgrには再帰的に包含関係を展開して表示する機能はなさそうだったので、自分でスクリプトを書くことにしました。しかし「見ればわかる」と言われている程度の情報を得るわけですから、そんな大掛かりなスクリプトを書くこともなさそうです。きっと短く1行でも短く書けることでしょう……

書けました:
$ echo scheme-basic | ruby -rjson -ne'def f a;(c=(b=JSON.parse(`tlmgr info --json #{[*a]*" "}`).flat_map{|r|r["depends"]}).grep /col.*-.*/)==[]?b:b+=(f c)end;p (f $_).uniq.sort'
うわぁ……

真面目な話をしましょう。

(見ればわかると思いますが)そんなに真剣に書いていないので、すべてのケースできちんと動作するかは保証できませんが、一応echo <name>のところに適当なスキームやコレクションの名前を入れると、包含されるパッケージの一覧が表示されるはずです。

なるべく回数を減らす工夫はしていますが再帰的にtlmgr infoの呼び出しを行うので動作はかなり遅いです4。上のscheme-smallに含まれるパッケージを一覧にする例では、手許のPC (MBA 2017, 1.8 GHz Intel Core i5) で50秒ほどかかります。

かなりアレな解決法だった気もしますが、とりあえず求めていたパッケージの一覧が手に入ったのでよしとしましょう。


W「上記のワンライナーはまだもっと短くなる気がする。求ム、挑戦者」


  1. 詳しくはTeX Wikiアミノフェンさんのホンキの解説をご参照ください。 ↩︎

  2. ここでは文脈上自然なので「包含関係」と言ってしまいますが、TeX Live的に正しい用語は「依存関係」のようです。 ↩︎

  3. --listを付けないと包含関係は省略されてしまいます。また、tlmgrの出力をプログラムで扱いたい場合は--jsonオプションの方が便利でしょう。 ↩︎

  4. tlmgr infoが遅いのは、結局のところ13MB近いサイズのあるtexlive.tlpdbの読み込みに時間がかかるからで、その他の処理はそこまで遅くないはずです。要するに、texlive.tlpdbのパースが1回で済むようなコードを書けばいいのですが、これだけのことをするのには労力に見合わない気がします(tlmgrが対応してくれるといいのだけどなぁ)。 ↩︎