Nix, the purely functional package manager - NixOS/nix
/etc
├── bashrc -> /nix/store/1if176wh1r4x9s7y1az71jfl5kbmh98j-etc-bashrc
├── dbus-1 -> /nix/store/4flwcifazgfgf161sy6814b0rbn7v34s-dbus-1
├── default
│ └── useradd -> /nix/store/vdlvg48amgd4ypjmbcbc0bphr38zylp7-useradd
├── dhcpcd.exit-hook -> /nix/store/68q2mgnzkrpg4lz1hvi438jvbsdhvm5v-dhcpcd.exit-hook
├── dnsmasq.hosts -> /nix/store/5bc88knzm6vzps0v8ji04dkr4m3bjlaz-etc-dnsmasq.hosts
├── fonts -> /nix/store/i8xwbp6l79m5zqv2li1fqbb7pblzck5s-fontconfig-etc/etc/fonts/
├── fstab -> /nix/store/49wyysybgjykgiahl81cgdvv27z7hcl1-etc-fstab
├── hostname -> /nix/store/gkpkfghwjlpgz5j9hsw5q38j3yqb5izb-etc-hostname
├── hosts -> /nix/store/kx490d701mxgszqmvm321akh3d1d327d-hosts
├── issue -> /nix/store/fc32c1jyxdfz4d4s3ly2q6dn4fk8vpaw-issue
├── locale.conf -> /nix/store/yjw073w6rjs8ixrj7ny1w4g69yrxsj0q-locale.conf
├── localtime -> /etc/zoneinfo/Asia/Japan
…
/nix/store
を不変にすることでリンクの貼り直しによるロールバックが可能にFiles | Lines | Code | Comments | Blanks |
---|---|---|---|---|
118 | 11981 | 10506 | 167 | 1308 |
haum
コマンドが実装の本体
Derivation = {
name: String, ───── パッケージ名
sources: {Path}, ───┬─ 依存パス
dependencies: {Path}, ───┘
builder: String, ───── ビルドコマンド
args: [String], ───── ビルドコマンドの引数
envs: {(String, String)}, ── ビルド時の環境変数
}
packageID(drv) = hash(
drv.name,
sort(drv.sources),
sort(drv.dependencies),
drv.builder,
drv.args,
sort(drv.envs),
)
/haumea/derivation/{sha256} - パッケージ定義, input-addressed
├──────/package/{sha256} - ビルド結果, ↑のハッシュに対応
└──────/content/{sha256} - content-addressed なデータ
~/.haumea-env → /package/{sha256}
PATH=~/.haumea-env/bin:$PATH
などとすれば利用できるlet
stdenv = import ./pkgs/stdenv.haumea;
in
stdenv.mkDerivation {
pname = "hello";
version = "2.10";
src = builtins.fetchUrl {
url = "https://ftp.jaist.ac.jp/pub/GNU/hello/hello-2.10.tar.gz";
sha256 = "34c89df862082bca464bc8073315b06b325655c04ec9eb478360f121666e992d";
executable = false;
};
}
主に下記の 2 つを実現し、Nix と同様のシステムを追実装することができた
スライド
https://coord-e.github.io/slide-specialseminar21-reimpl-functional-package-manager/
let
sources = filter (i: typeOf i == "path") buildInputs;
dependencies = filter (i: typeOf i == "derivation") buildInputs;
in derivation {
inherit sources dependencies;
envs = mapValues toString envs
++ mapMembers (n: "STDENV_OVERRIDE_#{n}") override
++ {
STDENV_PHASES = phases
|> filter (x: not (elem x disablePhases))
|> join ":";
};
}
#[derive(Debug, FromValue)]
pub struct Arg {
object: Object,
member: String,
}
pub async fn call(arg: Arg) -> BuiltinResult<Value, Infallible> {
let mut object = arg.object;
object.remove_member(arg.member);
Ok(Value::Object(object))
}