···11+# Dhall {#sec-language-dhall}
22+33+The Nixpkgs support for Dhall assumes some familiarity with Dhall's language
44+support for importing Dhall expressions, which is documented here:
55+66+* [`dhall-lang.org` - Installing packages](https://docs.dhall-lang.org/tutorials/Language-Tour.html#installing-packages)
77+88+## Remote imports
99+1010+Nixpkgs bypasses Dhall's support for remote imports using Dhall's
1111+semantic integrity checks. Specifically, any Dhall import can be protected by
1212+an integrity check like:
1313+1414+```dhall
1515+https://prelude.dhall-lang.org/v20.1.0/package.dhall
1616+ sha256:26b0ef498663d269e4dc6a82b0ee289ec565d683ef4c00d0ebdd25333a5a3c98
1717+```
1818+1919+… and if the import is cached then the interpreter will load the import from
2020+cache instead of fetching the URL.
2121+2222+Nixpkgs uses this trick to add all of a Dhall expression's dependencies into the
2323+cache so that the Dhall interpreter never needs to resolve any remote URLs. In
2424+fact, Nixpkgs uses a Dhall interpreter with remote imports disabled when
2525+packaging Dhall expressions to enforce that the interpreter never resolves a
2626+remote import. This means that Nixpkgs only supports building Dhall expressions
2727+if all of their remote imports are protected by semantic integrity checks.
2828+2929+Instead of remote imports, Nixpkgs uses Nix to fetch remote Dhall code. For
3030+example, the Prelude Dhall package uses `pkgs.fetchFromGitHub` to fetch the
3131+`dhall-lang` repository containing the Prelude. Relying exclusively on Nix
3232+to fetch Dhall code ensures that Dhall packages built using Nix remain pure and
3333+also behave well when built within a sandbox.
3434+3535+## Packaging a Dhall expression from scratch
3636+3737+We can illustrate how Nixpkgs integrates Dhall by beginning from the following
3838+trivial Dhall expression with one dependency (the Prelude):
3939+4040+```dhall
4141+-- ./true.dhall
4242+4343+let Prelude = https://prelude.dhall-lang.org/v20.1.0/package.dhall
4444+4545+in Prelude.Bool.not False
4646+```
4747+4848+As written, this expression cannot be built using Nixpkgs because the
4949+expression does not protect the Prelude import with a semantic integrity
5050+check, so the first step is to freeze the expression using `dhall freeze`,
5151+like this:
5252+5353+```bash
5454+$ dhall freeze --inplace ./true.dhall
5555+```
5656+5757+… which gives us:
5858+5959+```dhall
6060+-- ./true.dhall
6161+6262+let Prelude =
6363+ https://prelude.dhall-lang.org/v20.1.0/package.dhall
6464+ sha256:26b0ef498663d269e4dc6a82b0ee289ec565d683ef4c00d0ebdd25333a5a3c98
6565+6666+in Prelude.Bool.not False
6767+```
6868+6969+To package that expression, we create a `./true.nix` file containing the
7070+following specification for the Dhall package:
7171+7272+```nix
7373+# ./true.nix
7474+7575+{ buildDhallPackage, Prelude }:
7676+7777+buildDhallPackage {
7878+ name = "true";
7979+ code = ./true.dhall;
8080+ dependencies = [ Prelude ];
8181+ source = true;
8282+}
8383+```
8484+8585+… and we complete the build by incorporating that Dhall package into the
8686+`pkgs.dhallPackages` hierarchy using an overlay, like this:
8787+8888+```nix
8989+# ./example.nix
9090+9191+let
9292+ nixpkgs = builtins.fetchTarball {
9393+ url = "https://github.com/NixOS/nixpkgs/archive/94b2848559b12a8ed1fe433084686b2a81123c99.tar.gz";
9494+ sha256 = "1pbl4c2dsaz2lximgd31m96jwbps6apn3anx8cvvhk1gl9rkg107";
9595+ };
9696+9797+ dhallOverlay = self: super: {
9898+ true = self.callPackage ./true.nix { };
9999+ };
100100+101101+ overlay = self: super: {
102102+ dhallPackages = super.dhallPackages.override (old: {
103103+ overrides =
104104+ self.lib.composeExtensions (old.overrides or (_: _: {})) dhallOverlay;
105105+ });
106106+ };
107107+108108+ pkgs = import nixpkgs { config = {}; overlays = [ overlay ]; };
109109+110110+in
111111+ pkgs
112112+```
113113+114114+… which we can then build using this command:
115115+116116+```bash
117117+$ nix build --file ./example.nix dhallPackages.true
118118+```
119119+120120+## Contents of a Dhall package
121121+122122+The above package produces the following directory tree:
123123+124124+```bash
125125+$ tree -a ./result
126126+result
127127+├── .cache
128128+│ └── dhall
129129+│ └── 122027abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
130130+├── binary.dhall
131131+└── source.dhall
132132+```
133133+134134+… where:
135135+136136+* `source.dhall` contains the result of interpreting our Dhall package:
137137+138138+ ```bash
139139+ $ cat ./result/source.dhall
140140+ True
141141+ ```
142142+143143+* The `.cache` subdirectory contains one binary cache product encoding the
144144+ same result as `source.dhall`:
145145+146146+ ```bash
147147+ $ dhall decode < ./result/.cache/dhall/122027abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
148148+ True
149149+ ```
150150+151151+* `binary.dhall` contains a Dhall expression which handles fetching and decoding
152152+ the same cache product:
153153+154154+ ```bash
155155+ $ cat ./result/binary.dhall
156156+ missing sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
157157+ $ cp -r ./result/.cache .cache
158158+159159+ $ chmod -R u+w .cache
160160+161161+ $ XDG_CACHE_HOME=.cache dhall --file ./result/binary.dhall
162162+ True
163163+ ```
164164+165165+The `source.dhall` file is only present for packages that specify
166166+`source = true;`. By default, Dhall packages omit the `source.dhall` in order
167167+to conserve disk space when they are used exclusively as dependencies. For
168168+example, if we build the Prelude package it will only contain the binary
169169+encoding of the expression:
170170+171171+```bash
172172+$ nix build --file ./example.nix dhallPackages.Prelude
173173+174174+$ tree -a result
175175+result
176176+├── .cache
177177+│ └── dhall
178178+│ └── 122026b0ef498663d269e4dc6a82b0ee289ec565d683ef4c00d0ebdd25333a5a3c98
179179+└── binary.dhall
180180+181181+2 directories, 2 files
182182+```
183183+184184+Typically, you only specify `source = true;` for the top-level Dhall expression
185185+of interest (such as our example `true.nix` Dhall package). However, if you
186186+wish to specify `source = true` for all Dhall packages, then you can amend the
187187+Dhall overlay like this:
188188+189189+```nix
190190+ dhallOverrides = self: super: {
191191+ # Enable source for all Dhall packages
192192+ buildDhallPackage =
193193+ args: super.buildDhallPackage (args // { source = true; });
194194+195195+ true = self.callPackage ./true.nix { };
196196+ };
197197+```
198198+199199+… and now the Prelude will contain the fully decoded result of interpreting
200200+the Prelude:
201201+202202+```bash
203203+$ nix build --file ./example.nix dhallPackages.Prelude
204204+205205+$ tree -a result
206206+result
207207+├── .cache
208208+│ └── dhall
209209+│ └── 122026b0ef498663d269e4dc6a82b0ee289ec565d683ef4c00d0ebdd25333a5a3c98
210210+├── binary.dhall
211211+└── source.dhall
212212+213213+$ cat ./result/source.dhall
214214+{ Bool =
215215+ { and =
216216+ \(_ : List Bool) ->
217217+ List/fold Bool _ Bool (\(_ : Bool) -> \(_ : Bool) -> _@1 && _) True
218218+ , build = \(_ : Type -> _ -> _@1 -> _@2) -> _ Bool True False
219219+ , even =
220220+ \(_ : List Bool) ->
221221+ List/fold Bool _ Bool (\(_ : Bool) -> \(_ : Bool) -> _@1 == _) True
222222+ , fold =
223223+ \(_ : Bool) ->
224224+…
225225+```
226226+227227+## Packaging functions
228228+229229+We already saw an example of using `buildDhallPackage` to create a Dhall
230230+package from a single file, but most Dhall packages consist of more than one
231231+file and there are two derived utilities that you may find more useful when
232232+packaging multiple files:
233233+234234+* `buildDhallDirectoryPackage` - build a Dhall package from a local directory
235235+236236+* `buildDhallGitHubPackage` - build a Dhall package from a GitHub repository
237237+238238+The `buildDhallPackage` is the lowest-level function and accepts the following
239239+arguments:
240240+241241+* `name`: The name of the derivation
242242+243243+* `dependencies`: Dhall dependencies to build and cache ahead of time
244244+245245+* `code`: The top-level expression to build for this package
246246+247247+ Note that the `code` field accepts an arbitrary Dhall expression. You're
248248+ not limited to just a file.
249249+250250+* `source`: Set to `true` to include the decoded result as `source.dhall` in the
251251+ build product, at the expense of requiring more disk space
252252+253253+* `documentationRoot`: Set to the root directory of the package if you want
254254+ `dhall-docs` to generate documentation underneath the `docs` subdirectory of
255255+ the build product
256256+257257+The `buildDhallDirectoryPackage` is a higher-level function implemented in terms
258258+of `buildDhallPackage` that accepts the following arguments:
259259+260260+* `name`: Same as `buildDhallPackage`
261261+262262+* `dependencies`: Same as `buildDhallPackage`
263263+264264+* `source`: Same as `buildDhallPackage`
265265+266266+* `src`: The directory containing Dhall code that you want to turn into a Dhall
267267+ package
268268+269269+* `file`: The top-level file (`package.dhall` by default) that is the entrypoint
270270+ to the rest of the package
271271+272272+* `document`: Set to `true` to generate documentation for the package
273273+274274+The `buildDhallGitHubPackage` is another higher-level function implemented in
275275+terms of `buildDhallPackage` that accepts the following arguments:
276276+277277+* `name`: Same as `buildDhallPackage`
278278+279279+* `dependencies`: Same as `buildDhallPackage`
280280+281281+* `source`: Same as `buildDhallPackage`
282282+283283+* `owner`: The owner of the repository
284284+285285+* `repo`: The repository name
286286+287287+* `rev`: The desired revision (or branch, or tag)
288288+289289+* `directory`: The subdirectory of the Git repository to package (if a
290290+ directory other than the root of the repository)
291291+292292+* `file`: The top-level file (`${directory}/package.dhall` by default) that is
293293+ the entrypoint to the rest of the package
294294+295295+* `document`: Set to `true` to generate documentation for the package
296296+297297+Additionally, `buildDhallGitHubPackage` accepts the same arguments as
298298+`fetchFromGitHub`, such as `sha256` or `fetchSubmodules`.
299299+300300+## `dhall-to-nixpkgs`
301301+302302+You can use the `dhall-to-nixpkgs` command-line utility to automate
303303+packaging Dhall code. For example:
304304+305305+```bash
306306+$ nix-env --install --attr haskellPackages.dhall-nixpkgs
307307+308308+$ nix-env --install --attr nix-prefetch-git # Used by dhall-to-nixpkgs
309309+310310+$ dhall-to-nixpkgs github https://github.com/Gabriel439/dhall-semver.git
311311+{ buildDhallGitHubPackage, Prelude }:
312312+ buildDhallGitHubPackage {
313313+ name = "dhall-semver";
314314+ githubBase = "github.com";
315315+ owner = "Gabriel439";
316316+ repo = "dhall-semver";
317317+ rev = "2d44ae605302ce5dc6c657a1216887fbb96392a4";
318318+ fetchSubmodules = false;
319319+ sha256 = "0y8shvp8srzbjjpmnsvz9c12ciihnx1szs0yzyi9ashmrjvd0jcz";
320320+ directory = "";
321321+ file = "package.dhall";
322322+ source = false;
323323+ document = false;
324324+ dependencies = [ (Prelude.overridePackage { file = "package.dhall"; }) ];
325325+ }
326326+```
327327+328328+The utility takes care of automatically detecting remote imports and converting
329329+them to package dependencies. You can also use the utility on local
330330+Dhall directories, too:
331331+332332+```bash
333333+$ dhall-to-nixpkgs directory ~/proj/dhall-semver
334334+{ buildDhallDirectoryPackage, Prelude }:
335335+ buildDhallDirectoryPackage {
336336+ name = "proj";
337337+ src = /Users/gabriel/proj/dhall-semver;
338338+ file = "package.dhall";
339339+ source = false;
340340+ document = false;
341341+ dependencies = [ (Prelude.overridePackage { file = "package.dhall"; }) ];
342342+ }
343343+```
344344+345345+## Overriding dependency versions
346346+347347+Suppose that we change our `true.dhall` example expression to depend on an older
348348+version of the Prelude (19.0.0):
349349+350350+```dhall
351351+-- ./true.dhall
352352+353353+let Prelude =
354354+ https://prelude.dhall-lang.org/v19.0.0/package.dhall
355355+ sha256:eb693342eb769f782174157eba9b5924cf8ac6793897fc36a31ccbd6f56dafe2
356356+357357+in Prelude.Bool.not False
358358+```
359359+360360+If we try to rebuild that expression the build will fail:
361361+362362+```
363363+$ nix build --file ./example.nix dhallPackages.true
364364+builder for '/nix/store/0f1hla7ff1wiaqyk1r2ky4wnhnw114fi-true.drv' failed with exit code 1; last 10 log lines:
365365+366366+ Dhall was compiled without the 'with-http' flag.
367367+368368+ The requested URL was: https://prelude.dhall-lang.org/v19.0.0/package.dhall
369369+370370+371371+ 4│ https://prelude.dhall-lang.org/v19.0.0/package.dhall
372372+ 5│ sha256:eb693342eb769f782174157eba9b5924cf8ac6793897fc36a31ccbd6f56dafe2
373373+374374+ /nix/store/rsab4y99h14912h4zplqx2iizr5n4rc2-true.dhall:4:7
375375+[1 built (1 failed), 0.0 MiB DL]
376376+error: build of '/nix/store/0f1hla7ff1wiaqyk1r2ky4wnhnw114fi-true.drv' failed
377377+```
378378+379379+… because the default Prelude selected by Nixpkgs revision
380380+`94b2848559b12a8ed1fe433084686b2a81123c99is` is version 20.1.0, which doesn't
381381+have the same integrity check as version 19.0.0. This means that version
382382+19.0.0 is not cached and the interpreter is not allowed to fall back to
383383+importing the URL.
384384+385385+However, we can override the default Prelude version by using `dhall-to-nixpkgs`
386386+to create a Dhall package for our desired Prelude:
387387+388388+```bash
389389+$ dhall-to-nixpkgs github https://github.com/dhall-lang/dhall-lang.git \
390390+ --name Prelude \
391391+ --directory Prelude \
392392+ --rev v19.0.0 \
393393+ > Prelude.nix
394394+```
395395+396396+… and then referencing that package in our Dhall overlay, by either overriding
397397+the Prelude globally for all packages, like this:
398398+399399+```bash
400400+ dhallOverrides = self: super: {
401401+ true = self.callPackage ./true.nix { };
402402+403403+ Prelude = self.callPackage ./Prelude.nix { };
404404+ };
405405+```
406406+407407+… or selectively overriding the Prelude dependency for just the `true` package,
408408+like this:
409409+410410+```bash
411411+ dhallOverrides = self: super: {
412412+ true = self.callPackage ./true.nix {
413413+ Prelude = self.callPackage ./Prelude.nix { };
414414+ };
415415+ };
416416+```
417417+418418+## Overrides
419419+420420+You can override any of the arguments to `buildDhallGitHubPackage` or
421421+`buildDhallDirectoryPackage` using the `overridePackage` attribute of a package.
422422+For example, suppose we wanted to selectively enable `source = true` just for the Prelude. We can do that like this:
423423+424424+```nix
425425+ dhallOverrides = self: super: {
426426+ Prelude = super.Prelude.overridePackage { source = true; };
427427+428428+ …
429429+ };
430430+```
431431+432432+[semantic-integrity-checks]: https://docs.dhall-lang.org/tutorials/Language-Tour.html#installing-packages