Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more flakes support and getting started guide #972

Merged
merged 8 commits into from
Feb 22, 2021
112 changes: 112 additions & 0 deletions docs/tutorials/getting-started-flakes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Getting started with flakes

This version of the getting started guide is for users who
are using [Nix Flakes](https://nixos.wiki/wiki/Flakes).
The non flakes version of the guide is [here](getting-started.md).

`haskell.nix` can automatically translate your
[Cabal](https://cabal.readthedocs.io/en/latest/cabal-project.html)
or [Stack](https://docs.haskellstack.org/en/stable/README/#quick-start-guide)
project and its dependencies into Nix code.

Assuming you have [Nix](https://nixos.org/download.html) installed, you can
start setting up your project.

## Setting up the binary cache

IMPORTANT: you *must* do this or you *will* build several copies of GHC!

You can configure Nix to use our binary cache, which is pushed to by CI, so should contain the artifacts that you need.

You need to add the following sections to `/etc/nix/nix.conf` or, if you are a trusted user, `~/.config/nix/nix.conf` (if you don't know what a "trusted user" is, you probably want to do the former).

```
trusted-public-keys = [...] hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= [...]
substituters = [...] https://hydra.iohk.io [...]
```

This can be tricky to get setup properly. If you're still having trouble getting cache hits, consult the corresponding [troubleshooting section](../reference/troubleshooting#why-am-i-building-ghc).

## Scaffolding

The following work with `stack.yaml` and `cabal.project` based
projects.

Add `flake.nix`:

```nix
{
description = "A very basic flake";
inputs.haskellNix.url = "github:input-output-hk/haskell.nix";
inputs.nixpkgs.follows = "haskellNix/nixpkgs-unstable";
inputs.flake-utils.url = "github:numtide/flake-utils";
outputs = { self, nixpkgs, flake-utils, haskellNix }:
flake-utils.lib.eachSystem [ "x86_64-linux" "x86_64-darwin" ] (system:
let
overlays = [ haskellNix.overlay
(final: prev: {
# This overlay adds our project to pkgs
helloProject =
final.haskell-nix.project' {
src = ./.;
compiler-nix-name = "ghc8104";
};
})
];
pkgs = import nixpkgs { inherit system overlays; };
flake = pkgs.helloProject.flake {};
in flake // {
# Built by `nix build .`
defaultPackage = flake.packages."hello:exe:hello";

# This is used by `nix develop .` to open a shell for use with
# `cabal`, `hlint` and `haskell-language-server`
devShell = pkgs.helloProject.shellFor {
tools = {
cabal = "latest";
hlint = "latest";
haskell-language-server = "latest";
};
};
});
}
```

!!! note "git dependencies"
If you have git dependencies in your project, you'll need
to [calculate sha256 hashes for them](./source-repository-hashes.md).

### Working with a project

Top-level attributes are Haskell packages (incl. dependencies) part of your project.

To build the library component of a package in the project run:

```shell
nix build .#your-package-name:lib:your-package-name
```

There are also other components such as `exe`, `test` and `benchmark`.
To build an executable:

```shell
nix build .#your-package-name:exe:your-exe-name
```

To use the `devShell` provided by the flake run:

```shell
nix develop .
cabal repl your-package-name:lib:your-package-name
cabal build your-package-name
```

To open a shell for use with `stack` see [the following issue](https://github.com/input-output-hk/haskell.nix/issues/689#issuecomment-643832619).

## Going forward

Read through [project](../reference/library.md#project) function reference to see how the API works.

There are a number of things to explore further in the tutorials section.

[haskell.nix]: https://github.com/input-output-hk/haskell.nix
14 changes: 11 additions & 3 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
{
description = "Alternative Haskell Infrastructure for Nixpkgs";

outputs = { self }:
inputs = {
# Note: keep this in sync with sources.json!
nixpkgs.url = github:NixOS/nixpkgs/f02bf8ffb9a5ec5e8f6f66f1e5544fd2aa1a0693;
nixpkgs-2003.url = github:NixOS/nixpkgs/7f73e46625f508a793700f5110b86f1a53341d6e;
nixpkgs-2009.url = github:NixOS/nixpkgs/f02bf8ffb9a5ec5e8f6f66f1e5544fd2aa1a0693;
nixpkgs-unstable.url = github:NixOS/nixpkgs/410bbd828cdc6156aecd5bc91772ad3a6b1099c7;
};

outputs = { self, nixpkgs, ... }:
{

internal = rec {
Expand All @@ -27,7 +35,7 @@
# `builtins.currentSystem` will not be supported in flakes.
# https://github.com/NixOS/rfcs/pull/49/files#diff-a5a138ca225433534de8d260f225fe31R429
overlay = self.overlays.combined-eval-on-build;
overlays = self.internal.overlaysOverrideable { sourcesOverride = self.sources; };
overlays = self.internal.overlaysOverrideable { sourcesOverride = self.internal.sources; };

legacyPackages = let
genAttrs = lst: f:
Expand All @@ -36,7 +44,7 @@
value = f name;
}) lst);
in genAttrs [ "x86_64-linux" "x86_64-darwin" ] (system:
import self.internal.sources.nixpkgs
import nixpkgs
(self.internal.nixpkgsArgs // { localSystem = { inherit system; }; }));
};
}
55 changes: 54 additions & 1 deletion overlays/haskell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -560,14 +560,67 @@ final: prev: {
}
) (builtins.removeAttrs rawProject.hsPkgs
# These are functions not packages
[ "shellFor" "makeConfigFiles" "ghcWithHoogle" "ghcWithPackages" ]);
[ "shellFor" "makeConfigFiles" "ghcWithHoogle" "ghcWithPackages" "buildPackages" ]);

projectCoverageReport = haskellLib.projectCoverageReport project (map (pkg: pkg.coverageReport) (final.lib.attrValues (haskellLib.selectProjectPackages hsPkgs)));

projectCross = (final.lib.mapAttrs (_: pkgs:
rawProject.projectFunction pkgs.haskell-nix rawProject.projectArgs
) final.pkgsCross) // { recurseForDerivations = false; };

# Helper function that can be used to make a Nix Flake out of a project
# by including a flake.nix. See docs/tutorials/getting-started-flakes.md
# for an example flake.nix file.
# This flake function maps the build outputs to the flake `packages`,
# `checks` and `apps` output attributes.
flake = {
packages ? haskellLib.selectProjectPackages
}:
let packageNames = builtins.attrNames (packages project.hsPkgs);
in {
# Used by:
# `nix build .#pkg-name:lib:pkg-name`
# `nix build .#pkg-name:lib:sublib-name`
# `nix build .#pkg-name:exe:exe-name`
# `nix build .#pkg-name:test:test-name`
packages = builtins.listToAttrs (
final.lib.concatMap (packageName:
let package = project.hsPkgs.${packageName};
in final.lib.optional (package.components ? library)
{ name = "${packageName}:lib:${packageName}"; value = package.components.library; }
++ final.lib.mapAttrsToList (n: v:
{ name = "${packageName}:lib:${n}"; value = v; })
(package.components.sublibs)
++ final.lib.mapAttrsToList (n: v:
{ name = "${packageName}:exe:${n}"; value = v; })
(package.components.exes)
++ final.lib.mapAttrsToList (n: v:
{ name = "${packageName}:test:${n}"; value = v; })
(package.components.tests)
) packageNames);
# Used by:
# `nix check .#pkg-name:test:test-name`
checks = builtins.listToAttrs (
final.lib.concatMap (packageName:
let package = project.hsPkgs.${packageName};
in final.lib.mapAttrsToList (n: v:
{ name = "${packageName}:test:${n}"; value = v; })
(final.lib.filterAttrs (_: v: final.lib.isDerivation v) (package.checks))
) packageNames);
# Used by:
# `nix run .#pkg-name:exe:exe-name`
# `nix run .#pkg-name:test:test-name`
apps = builtins.listToAttrs (
final.lib.concatMap (packageName:
let package = project.hsPkgs.${packageName};
in final.lib.mapAttrsToList (n: v:
{ name = "${packageName}:exe:${n}"; value = { type = "app"; program = v.exePath; }; })
(package.components.exes)
++ final.lib.mapAttrsToList (n: v:
{ name = "${packageName}:test:${n}"; value = { type = "app"; program = v.exePath; }; })
(package.components.tests)
) packageNames);
};
inherit (rawProject.hsPkgs) makeConfigFiles ghcWithHoogle ghcWithPackages shellFor;
});

Expand Down