Nixでハッシュ関係の処理をPythonで実装してみる

前回の記事でstore pathを手で計算する方法を見てきたが、output hashの計算については手で計算するのが無理だった。これをPythonスクリプトで実装するとどうなるかをやってみた。 ゴールとしてはoutput hashを計算するコードを実装することであるが、 Nix32表現の計算とtruncateオプションの計算はそれにあたって必要なので実装した おまけでderivation hashとsource hashの計算も実装した なお、今回のコードについて Nix 2.21.1を参考に作っている すべてのパターンは網羅できていない可能性が高い(特にoutput hashの計算方法) Nixのいくつかの処理をPythonで実装してみるのコードを一部使って実装する である。また、コードの実行例にあたって、前回の記事のderivationの準備にしたがってsampleのderivationが準備されているものとする。 Nix32表現の計算 Nix32の計算はlibutil/hash.ccで行われている。 以下の並びのビット列があるとする(見やすさのため8bitごとに縦棒で区切ってある)。 1 b07 b06 b05 b04 b03 b02 b01 b00 | b15 b14 b13 b12 b11 b10 b09 b08 | b23 b22 b21 b20 b19 b18 b17 b16 | ... Nix32表現では、以下のように5bitずつ取り出していく。 1 2 3 4 5 b04 b03 b02 b01 b00 b09 b08 | b07 b06 b05 b14 b13 b12 b11 b10 b19 b18 b17 b16 | b15 ....

2024-04-21 · (updated 2024-04-21) · 3 min · 622 words

Nixのstore path計算方法メモ

Nixでは、パッケージの再現性を担保するために、/nix/store/下にハッシュ値を含んだ名前であらゆるファイルを保管する。そのハッシュ値がどのような情報から計算されるものなのかを知っておくことは、なぜNixが再現性を確保できるのかを考える上で重要である。 そこで、この記事では、Nixのstore path、つまりその中に含まれるハッシュの計算方法について解説し、実際にステップバイステップで計算してみる。 参考記事 How Nix Isntantiation Works (Web Archive) Nix manual(unstable)Store Pathの仕様 Nix PillsのChapter 18 なお、本記事では nix derivation show コマンドの結果からいろいろと情報を取り出すために jq を用いる。 store pathの種類 ほとんどStore Pathの書き起こしみたいになってしまうが書いておく。 まずstore pathは、/nix/store/<digest>-<name>の形式を持っている。 <digest>というのは、fingerprint(後述)をSHA256でハッシュ化し、160bitに圧縮したうえでNix32表現にしたもの。ドキュメントには「SHA256の先頭160bitをBase32表現にしたもの」と記載があるが、 Base32という言葉はRelease Note 2.20でNix32という名前に改められた。理由としては通常の意味のBase32表現とは処理が異なり紛らわしいためのようだ 先頭160bitを単純に切り取ってNix32表現にするのではなく、実装では complressHash という関数で圧縮処理が行われている(該当ソース)。 fingerprintは、<type>:sha256:<inner-digest>:/nix/store:<name>の形式 <type>というのは以下のいずれか text:<input store path>:<input store path>:...:derivation。<input store path>には、(存在すれば)derivationが参照する他のファイルのパスを指定する source:<input store path>:<input store path>:...:外部から持ってきたファイルをNAR形式でアーカイブ化したもの sourceがinput store pathを持つケースってどんなときなの?と感じるが、確かにlibstore/store-api.ccにそれっぽいコードが見つかる。しかし実例がまだ良くわかっていない…。 output:<id>:derivationからビルドされたもの、もしくはビルド予定のものを表す。<id>には通常outが入るが、ビルド出力結果を複数分けているようなパッケージではbinやlib、devなどが指定されうる。 <inner-digest>は、inner-fingerprintをSHA256でハッシュ化し、Base16表現にしたもの inner-fingerprintの計算方法は、上述のtypeによって異なるが、これは後々実際に計算してみつつ解説する いろいろと書いてあるが、結局/nix/store下におかれるパスの種類は実質fingerprintの種類であり、すなわち3種類である。 text:derivationを表す source:ビルドに必要なファイル、ソースコードを表す output:ビルド生成物そのもの、ないしディレクトリを表す (前準備)derivationの準備 今回手で計算するもととなるderivationを簡単に書く。 Nix PillsのChapter 7の内容をもとに。汎用性とかは意識せず、x86_64-linux前提で書く ただNix Pillsをそのまま書き起こしになってしまうのもつまらないので、flakeを使って書いてみる。 まずいくつかのファイルを作成する flake.nix:flakeファイル default.nix で分けないで、ここに直接derivationを書く mubuilder....

2024-04-20 · (updated 2024-04-21) · 7 min · 1462 words

Nixのいくつかの処理をPythonで実装してみる

Nixのパッケージ・derivationの探り方まとめにて色々なコマンドを紹介したが、それらがNix内部でどう処理されているのかを知りたくなり、その過程でPython実装を書いた。 目的は、以下の2つの処理をPythonで実装することである。 build dependenciesを(間接的なものも含め)出力する runtime dependenciesを(間接的なものも含め)出力する なお、公式ではどちらもnix-store --query --requisitesないしnix-store --query --treeで出力可能である。 (parse) drvファイルを読み込み、パースする この先の処理を実装するにあたって、drvから情報を取り出す必要があるので、ここでパーサーを実装する。 まずdrvのファイル形式は以下のようなものであった。見やすいように改行を挟んでいるが、実際には無い。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 bombrary@nixos:~$ nix derivation show `which ls` | jq -r 'to_entries[]....

2024-04-05 · (updated 2024-04-16) · 12 min · 2475 words

Nixのパッケージ・derivationの探り方まとめ

Nixで、あるパッケージがどのパッケージに依存しているのかを調べたくなったのを発端に、パッケージやその依存関係の調べ方についていろいろ調べた。 要約 アプリ・ツールがどのパッケージに収録されているのかを知る NixOS Search や nix search コマンドを使う which や realpath コマンドから /nix/store 下のディレクトリがわかるのでそこからパッケージ名を知る nix-index、 nix-index-databaseを使う derivationの詳細を知る: nix derivation show [drv or output] output ⇔ derivation outputがどのderivationでビルドされたのかを知る: niq-store --query --deriver [output] derivationのoutputを知る: nix-store --query --outputs [drv] derivationについて build dependenciesを知る: nix-store --query --references [drv] 間接的なbuild dependenciesもすべて知る: nix-store --query --requisites [drv] outputについて runtime dependenciesを知る: nix-store --query --references [output] 間接的なruntime dependenciesもすべて知る: nix-store --query --requisites [output] 前置き 用語解説 いろいろとNix固有(?)の言葉が出てくるため、ここでまとめて解説しておく。 GlossaryとNix Pills Chapter9を参考にする。 パッケージ:ファイルやデータの集まり。 derivation:何らかのビルドタスクを行うための記述書。端的にはパッケージを作るための仕様書である。次の節で詳しく述べる output:derivationから生成されたもの store object:Nixによって管理されているあらゆるオブジェクトをさす。通常は/nix/store/に保管されているはず store path:store objectが置かれている場所。通常は/nix/store/にあるはず build depencencies:ビルドの時点で必要になる依存関係。ビルドに必要なソースコードや、derivationの中で参照されている別のderivationを指す。これはderivationに記載されている runtime dependencies:実行時に必要になる依存関係。動的ライブラリや、ほかのパッケージの実行ファイルなどを指す これを検出する方法は素朴で、生成したパッケージをNAR形式で固め、そこに埋め込まれているoutputのパスがruntime dependenciesと判定するだけである NAR (Nix Archive):tarのように複数ファイルを1つのファイルに固めた形式。ただし、同じアーカイブ対象であればまったく同じNARファイルができるように、tarに比べてシンプルなつくりになっている。例えば、tarだとアーカイブする度にタイムスタンプ(mtimeフィールド)が埋め込まれるが、NARにはそれがない(参考) NARが作られた背景について、edolstra氏のPh....

2024-04-04 · (updated 2024-09-17) · 6 min · 1098 words