mirror of
https://github.com/srid/haskell-flake.git
synced 2024-10-26 23:25:23 +03:00
docs: community.flake.parts host (#209)
This commit is contained in:
parent
e1f6540334
commit
b5127379bb
@ -2,9 +2,9 @@
|
||||
|
||||
<img src="./doc/logo.webp" width=100 />
|
||||
|
||||
There are [several ways](https://nixos.wiki/wiki/Haskell) to manage Haskell packages using Nix with varying degrees of integration. `haskell-flake` makes Haskell development, packaging and deployment with Nix flakes a lot [simpler](https://flakular.in/haskell-flake/start#under-the-hood) than other existing approaches. This project is set up as a modern [`flake-parts`](https://flake.parts/) module to integrate easily into other Nix projects and shell development environments in a lightweight and modular way.
|
||||
There are [several ways](https://nixos.wiki/wiki/Haskell) to manage Haskell packages using Nix with varying degrees of integration. `haskell-flake` makes Haskell development, packaging and deployment with Nix flakes a lot [simpler](https://community.flake.parts/haskell-flake/start#under-the-hood) than other existing approaches. This project is set up as a modern [`flake-parts`](https://flake.parts/) module to integrate easily into other Nix projects and shell development environments in a lightweight and modular way.
|
||||
|
||||
To see more background information, guides and best practices, visit https://flakular.in/haskell-flake
|
||||
To see more background information, guides and best practices, visit https://community.flake.parts/haskell-flake
|
||||
|
||||
Caveat: `haskell-flake` only supports the Haskell package manager [Cabal](https://www.haskell.org/cabal/),
|
||||
so your project must have a top-level `.cabal` file (single package project) or a `cabal.project` file
|
||||
@ -73,7 +73,7 @@ this [Haskell multi-package project Nix example](https://github.com/srid/haskell
|
||||
|
||||
## Documentation
|
||||
|
||||
https://flakular.in/haskell-flake
|
||||
https://community.flake.parts/haskell-flake
|
||||
|
||||
## Discussion
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
For contributing to the docs, please see
|
||||
|
||||
https://flakular.in/about#contributing
|
||||
https://community.flake.parts/about#contributing
|
||||
|
@ -19,7 +19,7 @@ relies on `data-files` in its cabal (which data-files can be, for instance, `js`
|
||||
|
||||
But how do you arrive at this point in the first place? i.e how do you pin point the exact store paths that are causing the increase in size? These are the rough steps that you can follow, if you are packaging it as part of a docker image:
|
||||
|
||||
- Build and scan [the docker image](/docker) for store paths that are taking up the most space:
|
||||
- Build and scan [the docker image](/haskell-flake/docker) for store paths that are taking up the most space:
|
||||
```bash
|
||||
nix build .#dockerImage
|
||||
docker load -i < result
|
||||
|
@ -1,9 +0,0 @@
|
||||
---
|
||||
slug: /haskell-flake/ref
|
||||
---
|
||||
|
||||
# Reference
|
||||
|
||||
Documentation on all module options provided by `haskell-flake` can be found here: https://flake.parts/options/haskell-flake.html
|
||||
|
||||
For documentation on nixpkgs library of functions, see https://nixos.org/manual/nixpkgs/unstable/#haskell
|
11
doc/ref/_category_.json
Normal file
11
doc/ref/_category_.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"label": "Reference",
|
||||
"position": 5,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"slug": "/haskell-flake/ref"
|
||||
},
|
||||
"customProps": {
|
||||
"description": "Documentation on all module options provided by `haskell-flake` can be found here: https://flake.parts/options/haskell-flake.html For documentation on nixpkgs library of functions, see https://nixos.org/manual/nixpkgs/unstable/#haskell"
|
||||
}
|
||||
}
|
121
doc/ref/docker.md
Normal file
121
doc/ref/docker.md
Normal file
@ -0,0 +1,121 @@
|
||||
---
|
||||
slug: /haskell-flake/docker
|
||||
---
|
||||
|
||||
# Building a docker image
|
||||
|
||||
Building a docker image is much simpler with Nix compared to writing `Dockerfile`. Since the entire build process is handled by Nix flakes, most of what's left to do for docker image creation is copying of the derivations and configuration.
|
||||
|
||||
## Writing the Nix to build the docker image
|
||||
|
||||
Consider a haskell-flake project "foo". To copy the binaries generated by the `default` package to `/bin` on the image, one can use `copyToRoot` attribute offered by [`dockerTools.buildImage`](https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-dockerTools). For example:
|
||||
|
||||
```nix
|
||||
{
|
||||
# Inside perSystem
|
||||
packages.dockerImage = pkgs.dockerTools.buildImage {
|
||||
name = "foo";
|
||||
copyToRoot = pkgs.buildEnv {
|
||||
paths = with pkgs; [
|
||||
self'.packages.default
|
||||
];
|
||||
name = "foo-root";
|
||||
pathsToLink = [ "/bin" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
In addition to copying over the flake `packages`, we may also copy *paths* in the project. `self` can be added to `paths` to expose the project directory.
|
||||
```nix
|
||||
{
|
||||
copyToRoot = pkgs.buildEnv {
|
||||
paths = with pkgs; [
|
||||
coreutils
|
||||
bash
|
||||
self
|
||||
];
|
||||
name = "foo-root";
|
||||
pathsToLink = [ "/foo_sub" "/bin" ];
|
||||
};
|
||||
}
|
||||
```
|
||||
If you'd like your docker image to run your haskell project's default package when the container starts, use the following config:
|
||||
```nix
|
||||
{
|
||||
# Inside dockerImage's `buildImage`
|
||||
config = {
|
||||
Cmd = [ "${pkgs.lib.getExe self'.packages.default}" ];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Build the docker image
|
||||
|
||||
To build the docker image *as a Nix derivation*, run:
|
||||
|
||||
```bash
|
||||
nix build .#dockerImage
|
||||
```
|
||||
|
||||
To load this image into your local docker image registry, run:
|
||||
|
||||
```bash
|
||||
docker load -i $(nix build .#dockerImage --print-out-paths)
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
### Size
|
||||
|
||||
Docker images including Haskell packages can be optimized using the methods described [here](/haskell-flake/size).
|
||||
|
||||
### Time
|
||||
|
||||
If you don't want `docker images` showing that the image was created several decades ago, use the following:
|
||||
```nix
|
||||
{
|
||||
# Inside perSystem.packages' `dockerImage`:
|
||||
pkgs.dockerTools.buildImage {
|
||||
name = "foo";
|
||||
created = "now";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Tag
|
||||
|
||||
If you want to tag the images with the commit id of the working copy:
|
||||
|
||||
```nix
|
||||
{
|
||||
# Inside perSystem.packages' `dockerImage`:
|
||||
pkgs.dockerTools.buildImage {
|
||||
name = "foo";
|
||||
tag = builtins.substring 0 9 (self.rev or "dev");
|
||||
};
|
||||
}
|
||||
```
|
||||
[`builtins.substring 0 9 self.rev`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-substring) is the same as `git rev-parse --short HEAD`. `self.rev` is non-null only on a clean working copy and hence the tag is set to `dev` when the working copy is dirty.
|
||||
|
||||
### SSL certs
|
||||
|
||||
In order to be able to make https connections from inside of the docker image, you must expose the cacert Nix package via the relevant environment variable:
|
||||
|
||||
```nix
|
||||
{
|
||||
# Inside dockerTools.buildImage
|
||||
config = {
|
||||
Env = [
|
||||
"SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
|
||||
# Ref: https://hackage.haskell.org/package/x509-system-1.6.7/docs/src/System.X509.Unix.html#getSystemCertificateStore
|
||||
"SYSTEM_CERTIFICATE_PATH=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
|
||||
];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
- [Sample flake-parts module for docker](https://github.com/nammayatri/nammayatri/pull/14/files#diff-18ea3dd9a6a84702796b8dac608d0cad8e396a7c2e8c52732fcb7e5f52d1b0b9)
|
157
doc/ref/nixpkgs-haskell.md
Normal file
157
doc/ref/nixpkgs-haskell.md
Normal file
@ -0,0 +1,157 @@
|
||||
---
|
||||
slug: /haskell-flake/nixpkgs-haskell
|
||||
---
|
||||
|
||||
# Nixifying a Haskell project using nixpkgs
|
||||
|
||||
This tutorial enables you to write a flake using nothing but [nixpkgs] to nixify an existing Haskell project. The tutorial serves a pedagogic purpose; in the real-world scenario, we recommend that you use [haskell-flake](/haskell-flake/start).
|
||||
|
||||
[nixpkgs] provides two important functions for developing Haskell projects that we'll extensively use here. They are `callCabal2nix` and `shellFor`, and are described below.
|
||||
|
||||
:::info To learn more
|
||||
- [Official manual](https://nixos.org/manual/nixpkgs/unstable/#haskell)
|
||||
:::
|
||||
|
||||
## callCabal2nix
|
||||
|
||||
[`callCabal2nix`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/haskell-modules/make-package-set.nix) produces a derivation for building a Haskell package from source. This source can be any path, including a local directory (eg.: `./.`) or a flake input. We'll use `callCabal2nix` to build a package from source during overriding the Haskell package set using overlays (see below).
|
||||
|
||||
## Package sets
|
||||
|
||||
[nixpkgs] also provides a Haskell package set (built, in part, from Stackage but also Hackage) for each GHC compiler version. The default compiler's package set is provided in `pkgs.haskellPackages`. In the repl session below, we locate and build the `aeson` package:
|
||||
|
||||
```nix
|
||||
❯ nix repl github:nixos/nixpkgs/nixpkgs-unstable
|
||||
nix-repl> pkgs = legacyPackages.${builtins.currentSystem}
|
||||
|
||||
nix-repl> pkgs.haskellPackages.aeson
|
||||
«derivation /nix/store/sjaqjjnizd7ybirh94ixs51x4n17m97h-aeson-2.0.3.0.drv»
|
||||
|
||||
nix-repl> :b pkgs.haskellPackages.aeson
|
||||
|
||||
This derivation produced the following outputs:
|
||||
doc -> /nix/store/xjvm45wxqasnd5p2kk9ngcc0jbjhx1pf-aeson-2.0.3.0-doc
|
||||
out -> /nix/store/1dc6b11k93a6j9im50m7qj5aaa5p01wh-aeson-2.0.3.0
|
||||
```
|
||||
|
||||
### Overlays
|
||||
|
||||
:::info To learn more
|
||||
- [NixOS Wiki on Overlays](https://nixos.wiki/wiki/Overlays)
|
||||
- [Overlay implementation in fixed-points.nix](https://github.com/NixOS/nixpkgs/blob/master/lib/fixed-points.nix)
|
||||
:::
|
||||
|
||||
|
||||
Using the overlay system, you can *extend* this package set, to either add new packages or override existing ones. The package set exposes a function called `extend` for this purpose. In the repl session below, we extend the default Haskell package set to override the `shower` package to be built from the Git repo instead:
|
||||
|
||||
```nix
|
||||
nix-repl> :b pkgs.haskellPackages.shower
|
||||
|
||||
This derivation produced the following outputs:
|
||||
doc -> /nix/store/crzcx007h9j0p7qj35kym2rarkrjp9j1-shower-0.2.0.3-doc
|
||||
out -> /nix/store/zga3nhqcifrvd58yx1l9aj4raxhcj2mr-shower-0.2.0.3
|
||||
|
||||
nix-repl> myHaskellPackages = pkgs.haskellPackages.extend
|
||||
(self: super: {
|
||||
shower = self.callCabal2nix "shower"
|
||||
(pkgs.fetchgit {
|
||||
url = "https://github.com/monadfix/shower.git";
|
||||
rev = "2d71ea1";
|
||||
sha256 = "sha256-vEck97PptccrMX47uFGjoBVSe4sQqNEsclZOYfEMTns=";
|
||||
}) {};
|
||||
})
|
||||
|
||||
nix-repl> :b myHaskellPackages.shower
|
||||
|
||||
This derivation produced the following outputs:
|
||||
doc -> /nix/store/vkpfbnnzyywcpfj83pxnj3n8dfz4j4iy-shower-0.2.0.3-doc
|
||||
out -> /nix/store/55cgwfmayn84ynknhg74bj424q8fz5rl-shower-0.2.0.3
|
||||
```
|
||||
|
||||
Notice how we used `callCabal2nix` to build a new Haskell package from the source (located in the specified Git repository).
|
||||
|
||||
## Development shell
|
||||
|
||||
A Haskell development environment can be provided in one of the two ways. The native way will use the (language-independent) `mkShell` function (Generic shell). However to get full IDE support, it is best to use the (haskell-specific) `shellFor` function (Haskell shell).
|
||||
|
||||
### Haskell shell
|
||||
|
||||
:::info To learn more
|
||||
- [Official manual on `shellFor`](https://nixos.org/manual/nixpkgs/unstable/#haskell-shellFor)
|
||||
:::
|
||||
|
||||
|
||||
Suppose we have a Haskell project called "foo" with `foo.cabal`. You would create the development shell for this project as follows:
|
||||
|
||||
```nix
|
||||
devShells.default = pkgs.haskellPackages.shellFor {
|
||||
packages = p: [
|
||||
p.foo
|
||||
];
|
||||
buildInputs = with pkgs.haskellPackages; [
|
||||
ghcid
|
||||
cabal-install
|
||||
haskell-language-server
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
The `packages` argument to `shellFor` simply indicates that the given packages are available locally in the flake root, and that `cabal` should build them from the local source (rather than using the Nix store derivation for example). The `buildInputs` argument is similar to that of `mkShell` -- it allows you to specify the packages you want to be made available in the development shell.
|
||||
|
||||
From inside of `nix develop` shell, launch your pre-configured text editor (for example, VSCode with the [Haskell extension](https://marketplace.visualstudio.com/items?itemName=haskell.haskell) installed). You should have full IDE support.
|
||||
|
||||
## Example
|
||||
|
||||
The flake for [haskell-multi-nix](https://github.com/srid/haskell-multi-nix) is presented below. This project has two Haskell packages "foo" and "bar".
|
||||
|
||||
```nix
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||
};
|
||||
outputs = { self, nixpkgs, ... }:
|
||||
let
|
||||
# TODO: Change this to your current system, or use flake-utils/flake-parts.
|
||||
system = "aarch64-darwin";
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
overlay = self: super: {
|
||||
# Local packages in the repository
|
||||
foo = self.callCabal2nix "foo" ./foo { };
|
||||
bar = self.callCabal2nix "bar" ./bar { };
|
||||
# TODO: Put any library dependency overrides here
|
||||
};
|
||||
# Extend the `pkgs.haskellPackages` attrset using an overlay.
|
||||
#
|
||||
# Note that we can also extend the package set using more than one
|
||||
# overlay. To do that we can either chain the `extend` calls or use
|
||||
# the `composeExtensions` (or `composeManyExtensions`) function to
|
||||
# merge the overlays.
|
||||
haskellPackages' = pkgs.haskellPackages.extend overlay;
|
||||
in
|
||||
{
|
||||
packages.${system} = {
|
||||
inherit (haskellPackages') foo bar;
|
||||
default = haskellPackages'.bar;
|
||||
};
|
||||
# This is how we provide a multi-package dev shell in Haskell.
|
||||
# By using the `shellFor` function.
|
||||
devShells.${system}.default = haskellPackages'.shellFor {
|
||||
packages = p: [
|
||||
p.foo
|
||||
p.bar
|
||||
];
|
||||
buildInputs = with haskellPackages'; [
|
||||
ghcid
|
||||
cabal-install
|
||||
haskell-language-server
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
You can confirm that the package builds by running either `nix build .#foo` or `nix build .#bar`, as well as that IDE support is configured correctly by running `nix develop -c haskell-language-server`.
|
||||
|
||||
A variation of this flake supporting multiple systems (via use of flake-parts) can be found [here](https://github.com/srid/haskell-multi-nix/blob/nixpkgs/flake.nix).
|
||||
|
||||
[nixpkgs]: https://zero-to-nix.com/concepts/nixpkgs
|
@ -5,7 +5,7 @@ sidebar_position: 1
|
||||
|
||||
# Getting Started
|
||||
|
||||
Before using `haskell-flake` you must first [install Nix](/install).
|
||||
Before using `haskell-flake` you must first [install Nix](https://flakular.in/install).
|
||||
|
||||
## Existing projects
|
||||
|
||||
@ -33,10 +33,10 @@ You may also use https://github.com/srid/haskell-template which already uses `ha
|
||||
## Under the hood
|
||||
|
||||
:::tip Under the hood
|
||||
See [this tutorial](/nixpkgs-haskell) to understand what it takes to package a Haskell application without haskell-flake.
|
||||
See [this tutorial](/haskell-flake/nixpkgs-haskell) to understand what it takes to package a Haskell application without haskell-flake.
|
||||
:::
|
||||
|
||||
When nixifying a Haskell project without flake-parts (thus without haskell-flake) you would generally use the [raw Haskell infrastructure from nixpkgs](/nixpkgs-haskell). haskell-flake uses these functions, while exposing a simpler [modular](/mod) API on top: your `flake.nix` becomes more [declarative](https://github.com/srid/haskell-template/blob/304fb5a1adfb25c7691febc15911b588a364a5f7/flake.nix#L27-L39) and less [imperative](https://github.com/srid/haskell-template/blob/3fc6858830ecee3d2fe1dfe9a8bfa2047cf561ac/flake.nix#L20-L79).
|
||||
When nixifying a Haskell project without flake-parts (thus without haskell-flake) you would generally use the [raw Haskell infrastructure from nixpkgs](/haskell-flake/nixpkgs-haskell). haskell-flake uses these functions, while exposing a simpler [modular](https://flake.parts) API on top: your `flake.nix` becomes more [declarative](https://github.com/srid/haskell-template/blob/304fb5a1adfb25c7691febc15911b588a364a5f7/flake.nix#L27-L39) and less [imperative](https://github.com/srid/haskell-template/blob/3fc6858830ecee3d2fe1dfe9a8bfa2047cf561ac/flake.nix#L20-L79).
|
||||
|
||||
In addition, compared to using plain nixpkgs, haskell-flake supports:
|
||||
|
||||
|
@ -16,10 +16,10 @@
|
||||
haskellProjects.default = {
|
||||
# The base package set representing a specific GHC version.
|
||||
# By default, this is pkgs.haskellPackages.
|
||||
# You may also create your own. See https://flakular.in/haskell-flake/package-set
|
||||
# You may also create your own. See https://community.flake.parts/haskell-flake/package-set
|
||||
# basePackages = pkgs.haskellPackages;
|
||||
|
||||
# Extra package information. See https://flakular.in/haskell-flake/dependency
|
||||
# Extra package information. See https://community.flake.parts/haskell-flake/dependency
|
||||
#
|
||||
# Note that local packages are automatically included in `packages`
|
||||
# (defined by `defaults.packages` option).
|
||||
|
Loading…
Reference in New Issue
Block a user