@@ -0,0 +1,192 @@
1+{
2+ description = "Jibb, a UI language for Urbit: its desks, and the repo's checks";
3+
4+ inputs = {
5+ # A channel tarball rather than github:NixOS/nixpkgs, so the flake
6+ # also fetches where GitHub's archive downloads are blocked, as in a
7+ # Claude cloud container. flake.lock pins the exact release.
8+ # nixos-unstable has vere 4.6, which the tools were written against.
9+ nixpkgs.url = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz";
10+ # click, which tools/ship formats its requests to the ship with.
11+ urbit-tools = {
12+ url = "git+https://github.com/urbit/tools";
13+ flake = false;
14+ };
15+ };
16+
17+ outputs = { self, nixpkgs, urbit-tools }:
18+ let
19+ # The platforms nixpkgs builds vere for.
20+ systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ];
21+ forSystems = f: nixpkgs.lib.genAttrs systems
22+ (system: f nixpkgs.legacyPackages.${system});
23+ inherit (nixpkgs) lib;
24+ fs = lib.fileset;
25+
26+ # What the desks are assembled from, and the tools that assemble
27+ # them and compile their libraries.
28+ deskFiles = fs.unions [
29+ ./jibb
30+ ./jibb-dev
31+ ./my-app
32+ ./vendor
33+ ./tests
34+ ./tools/ship
35+ ./tools/golden_case.py
36+ ./tools/hoon
37+ ./tools/urbit_eval.py
38+ ./tools/noun.py
39+ ];
40+ # What the checks read: the desks' files, the tools and the doc's
41+ # tabs, but not the other docs, so editing those reruns nothing.
42+ checkFiles = fs.unions [ deskFiles ./tools ./docs/spec ];
43+ source = fileset: fs.toSource { root = ./.; inherit fileset; };
44+
45+ perSystem = pkgs:
46+ let
47+ inherit (pkgs) python3 urbit;
48+ isLinux = pkgs.stdenv.hostPlatform.isLinux;
49+
50+ click = pkgs.stdenvNoCC.mkDerivation {
51+ pname = "click";
52+ version = "0-unstable-${builtins.substring 0 8 urbit-tools.lastModifiedDate}";
53+ src = urbit-tools;
54+ nativeBuildInputs = [ pkgs.makeWrapper ];
55+ buildInputs = [ pkgs.bash ];
56+ installPhase = ''
57+ runHook preInstall
58+ # click runs click-format from its own folder.
59+ install -Dm755 -t $out/libexec/click \
60+ pkg/click/click pkg/click/click-format
61+ makeWrapper $out/libexec/click/click $out/bin/click \
62+ --prefix PATH : ${lib.makeBinPath [ pkgs.coreutils pkgs.gnused ]} \
63+ --prefix PATH : ${pkgs.netcat}/bin
64+ runHook postInstall
65+ '';
66+ meta = {
67+ description = "Thin client for a running Urbit ship's conn.sock";
68+ homepage = "https://github.com/urbit/tools";
69+ license = lib.licenses.mit;
70+ mainProgram = "click";
71+ };
72+ };
73+
74+ # The brass pill from the urbit/urbit commit vendor/ is copied
75+ # from (vendor/SOURCES.txt). GitHub serves it from Git LFS.
76+ pill = pkgs.fetchurl {
77+ name = "brass.pill";
78+ url = "https://media.githubusercontent.com/media/urbit/urbit/50c7f5239610fc72263df7aa99b4d171cfe9d408/bin/brass.pill";
79+ hash = "sha256-tLq9FOnxrL20IbPDHCFe5jetZpG344K5nG/YmR5iNwg=";
80+ };
81+
82+ # A freshly booted fake ~zod: the pier itself. Booting takes
83+ # about half a minute; the ship checks start a copy of it.
84+ fakezod = pkgs.runCommand "fakezod" {
85+ nativeBuildInputs = [ urbit ];
86+ } ''
87+ urbit -F zod -B ${pill} -t -x -c zod
88+ test -d zod/.urb/log
89+ mv zod $out
90+ '';
91+
92+ # The desks, as tools/ship assembles them for the ship:
93+ # $out/my-app, $out/jibb and $out/jibb-dev, the test desk. The
94+ # check phase compiles the two libraries under urbit eval.
95+ desks = pkgs.stdenvNoCC.mkDerivation {
96+ # No version in the name, so a commit that changes no desk
97+ # file reuses the last build.
98+ name = "jibb-desks";
99+ src = source deskFiles;
100+ nativeBuildInputs = [ python3 ];
101+ nativeCheckInputs = [ urbit ];
102+ dontConfigure = true;
103+ buildPhase = ''
104+ runHook preBuild
105+ patchShebangs tools > /dev/null
106+ tools/ship assemble --out desks
107+ runHook postBuild
108+ '';
109+ doCheck = true;
110+ checkPhase = ''
111+ runHook preCheck
112+ for lib in jibb jibb-import; do
113+ echo "compiling $lib.hoon"
114+ tools/hoon --lib desks/jibb-dev/lib/$lib.hoon '~'
115+ done
116+ runHook postCheck
117+ '';
118+ installPhase = ''
119+ runHook preInstall
120+ mv desks $out
121+ runHook postInstall
122+ '';
123+ # The files are the desks' as they are: nothing to patch.
124+ dontFixup = true;
125+ meta = {
126+ description = "The Jibb desks: my-app, jibb and jibb-dev";
127+ platforms = systems;
128+ };
129+ };
130+
131+ # A check: tools/check run on the repo with the given arguments.
132+ check = name: args: extra: pkgs.stdenvNoCC.mkDerivation ({
133+ name = "jibb-check-${name}";
134+ src = source checkFiles;
135+ nativeBuildInputs = [ python3 urbit ];
136+ dontConfigure = true;
137+ dontInstall = true;
138+ dontFixup = true;
139+ buildPhase = ''
140+ runHook preBuild
141+ patchShebangs tools > /dev/null
142+ mkdir $out
143+ tools/check ${args} --logs $out
144+ runHook postBuild
145+ '';
146+ } // extra);
147+
148+ # Every check that needs only urbit and Python, at once.
149+ evalChecks = check "eval" "--group eval -j $NIX_BUILD_CORES" { };
150+
151+ # The checks that need a ship, on a writable copy of fakezod.
152+ shipChecks = check "ship" "--group ship" {
153+ preBuild = ''
154+ cp -r ${fakezod} $TMPDIR/zod
155+ chmod -R u+w $TMPDIR/zod
156+ export JIBB_PIER=$TMPDIR/zod
157+ export JIBB_CLICK=${lib.getExe click}
158+ '';
159+ # A failed run shows the end of the ship's log too.
160+ failureHook = ''
161+ echo "the end of the ship's log, $TMPDIR/zod.log:"
162+ tail -n 100 $TMPDIR/zod.log || true
163+ '';
164+ };
165+ in
166+ {
167+ packages = {
168+ inherit desks click;
169+ default = desks;
170+ } // lib.optionalAttrs isLinux { inherit fakezod; };
171+
172+ checks = {
173+ inherit desks;
174+ eval = evalChecks;
175+ } // lib.optionalAttrs isLinux { ship = shipChecks; };
176+
177+ devShells.default = pkgs.mkShell {
178+ packages = [ python3 urbit click ];
179+ # tools/ship looks for click here; the pier stays
180+ # /root/urbit/zod unless $JIBB_PIER says otherwise.
181+ JIBB_CLICK = lib.getExe click;
182+ };
183+ };
184+
185+ all = forSystems perSystem;
186+ in
187+ {
188+ packages = lib.mapAttrs (_: s: s.packages) all;
189+ checks = lib.mapAttrs (_: s: s.checks) all;
190+ devShells = lib.mapAttrs (_: s: s.devShells) all;
191+ };
192+}