docs: community.flake.parts host (#209)

This commit is contained in:
Sridhar Ratnakumar 2023-11-28 14:51:50 -05:00 committed by GitHub
parent e1f6540334
commit b5127379bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 302 additions and 22 deletions

View File

@ -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

View File

@ -1,3 +1,3 @@
For contributing to the docs, please see
https://flakular.in/about#contributing
https://community.flake.parts/about#contributing

View File

@ -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

View File

@ -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
View 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
View 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
View 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

View File

@ -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:

View File

@ -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).