Skip to content

Commit 59db146

Browse files
committed
Create 2023-07-14-devx.md
1 parent 1d7f46d commit 59db146

File tree

1 file changed

+193
-0
lines changed

1 file changed

+193
-0
lines changed

blog/2023-07-14-devx.md

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
---
2+
slug: 2023-07-14-devx
3+
title: The IOG's Developer Experience Shell
4+
authors: [yvan]
5+
tags: [devx, haskell.nix, hix, iogx, nix]
6+
---
7+
8+
# The IOG's Developer Experience Shell
9+
10+
The IOG's Developer Experience Shell, or `DevX` for short, is an opinionated development environment tailored for Haskell.
11+
Built on top of Nix expressions, it provides a reproducible and seamless, full-featured developer shell with tools such as `cabal-install`, `ghc`, `hls`, and `hlint`.
12+
13+
The DevX shell's approach is a "one shell that fits all" solution for IOG's project needs.
14+
This article aims to give you a technical deep dive on how to use it in your own Haskell project and how we managed such a substantial closure in a convenient way.
15+
16+
`DevX` is built upon `haskell.nix`, a framework for building Haskell packages with Nix.
17+
In short, `haskell.nix` turns your Cabal or Stack project and its dependencies into a Nix expression.
18+
We will explain how to use `haskell.nix` on its own using `hix`.
19+
20+
We will conclude by introducing `iogx`, a Flake Template for Haskell Projects that we use at IOG.
21+
22+
## Getting started
23+
24+
The `devx` GitHub repository provides a comprehensive [README](https://github.com/input-output-hk/devx) that documents the different outputs that `flake.nix` provides.
25+
But, as this article assumes you might have not so much knowledge of how to deal with Nix, we will quickly discuss three ergonomic ways of using this tool with no Nix knowledge required.
26+
27+
### Direnv
28+
29+
`direnv` is an quite handy tool that allows you to load/unload the development environment automatically based on your current directory.
30+
It's an excellent way to avoid polluting your `.profile` or shell rc files.
31+
32+
You can learn how to install `direnv` [here](https://direnv.net).
33+
You may then need to hook up direnv in your shell; you can consult the dedicated [`direnv` and `devx`](./docs/direnv.md) guide for detailed instructions on integration.
34+
35+
You will also need to have Nix installed to using DevX shell.
36+
Then just add an `.envrc` file with the following content in the root of your project:
37+
```
38+
# https://github.com/nix-community/nix-direnv A fast, persistent use_nix/use_flake implementation for direnv:
39+
if ! has nix_direnv_version || ! nix_direnv_version 2.3.0; then
40+
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.3.0/direnvrc" "sha256-Dmd+j63L84wuzgyjITIfSxSD57Tx7v51DMxVZOsiUD8="
41+
fi
42+
# https://github.com/input-output-hk/devx Slightly opinionated shared GitHub Action for Cardano-Haskell projects
43+
use flake "github:input-output-hk/devx#ghc8107"
44+
```
45+
`DevX` supports a variety of compiler versions, typically the latest for each series from 8.10 to 9.6. Along with the core GHC version, [it also offers various flavours, denoted as suffixes to the compiler names](https://github.com/input-output-hk/devx#compilers-and-flavours).
46+
47+
The `nix-direnv` prefix is not necessary, but it's a good way to prevent Nix from garbage collecting your shell while the directory exists!
48+
49+
### GitHub Action
50+
51+
We also provide a `DevX` GitHub Action, leveraging a unique technique of pre-evaluating the closure of the development environment, compressing it, and uploading it to `ghcr.io`.
52+
This approach drastically reduces the instantiation time of the developer shell, and will talk about it a bit more in details later in this article.
53+
54+
Here's how you might utilize the DevX GitHub Action in your workflow:
55+
```
56+
- name: Build
57+
uses: input-output-hk/actions/devx@latest
58+
with:
59+
platform: 'x86_64-linux'
60+
target-platform: '-windows'
61+
compiler-nix-name: 'ghc8107'
62+
minimal: false
63+
iog: true
64+
- name: Build
65+
shell: devx {0}
66+
run: |
67+
cabal update
68+
cabal build
69+
```
70+
71+
### VSCode DevContainer and GitHub CodeSpace
72+
73+
Finally, we also offer support for VSCode DevContainers and GitHub CodeSpaces.
74+
To make the DevX developer shell available in a VSCode DevContainer or GitHub CodeSpace, simply add a file named `.devcontainer/devcontainer.json` with the following content:
75+
```
76+
{
77+
"image":"ghcr.io/input-output-hk/devx-devcontainer:ghc8107",
78+
"customizations":{
79+
"vscode":{
80+
"extensions":[
81+
"haskell.haskell"
82+
],
83+
"settings":{
84+
"haskell.manageHLS":"PATH"
85+
}
86+
}
87+
}
88+
}
89+
```
90+
You can follow the [Microsoft tutorial](https://code.visualstudio.com/docs/devcontainers/tutorial) to set-up your VSCode local DevContainer or you can give it a try by [opening a GitHub Codespace](https://codespaces.new/input-output-hk/cardano-base?quickstart=1) on [`cardano-base`](https://github.com/input-output-hk/cardano-base) repository!
91+
92+
## Benchmarking
93+
94+
To showcase the efficiency and speed that our download closure hack brings compared to a call to `nix develop`, we'll present a short benchmarking comparison.
95+
96+
What isn't measured is the time for evaluating the closure, compressing it, and uploading it to `ghcr.io`, as it's done by our CI and represents the caching part of the process.
97+
We measure the speed of downloading, decompressing, and performing a `nix import` on the closure against the speed of `nix develop`, so we essentially save the time of the evaluation of the Nix expression:
98+
99+
**TODO: add the benchmarks ...**
100+
101+
## Hix
102+
103+
Hix is a command-line tool designed to facilitate the addition of `haskell.nix` support to existing Haskell projects.
104+
You need Nix installed and configured with `experimental-features = [ "nix-command" "flakes" ];` (details can be found at the [NixOS Wiki](https://nixos.wiki/wiki/Flakes)).
105+
106+
### Initializing Hix and Using Nix
107+
108+
The `hix init` command is used to add a `flake.nix` and `nix/hix.nix` file to the project.
109+
110+
Once this is done, you can utilize regular Nix tools.
111+
For instance, to run `cabal build` on the `hello` package from Hackage, you would execute the following:
112+
```shell
113+
cabal unpack hello
114+
cd hello-1.0.0.2
115+
nix run "github:input-output-hk/haskell.nix#hix" -- init
116+
nix develop
117+
cabal build
118+
```
119+
120+
You can view the contents of the flake using `nix flake show`.
121+
To build a component with Nix, use `nix build .#hello:exe:hello`, and to build and run a component, `nix run .#hello:exe:hello` would be the command of choice.
122+
123+
### Installing Hix
124+
125+
Hix can be installed with the following command:
126+
127+
```shell
128+
nix-env -iA hix -f https://github.com/input-output-hk/haskell.nix/tarball/master
129+
```
130+
131+
To update Hix to the latest version, simply run `hix update`.
132+
133+
### Using Hix Commands
134+
135+
Commands like `hix develop`, `hix flake`, `hix build`, and `hix run` work similarly to their Nix counterparts.
136+
However, instead of utilizing the `flake.nix`, a boilerplate Haskell.nix `flake.nix` file is added to `.hix-flake/flake.nix`.
137+
This approach can be beneficial if the project already includes a `flake.nix` or if there's no intention to maintain one.
138+
139+
Once this step is done, you can execute commands without the need for `hix init`:
140+
141+
```shell
142+
hix develop
143+
hix flake show
144+
hix build .#hello:exe:hello
145+
hix run .#hello:exe:hello
146+
```
147+
148+
### Using `hix-shell` and `hix-build`
149+
150+
The `hix-shell` and `hix-build` commands emulate the behaviour of `nix-build` and `hix-shell` if a boilerplate `default.nix` and `shell.nix` were present.
151+
These commands are executed as follows:
152+
```shell
153+
hix-shell --run 'cabal build all'
154+
hix-build -A hsPkgs.hello.components.exes.hello
155+
```
156+
157+
Hix streamlines the use of Haskell.nix, offering an easier way to integrate it into your existing Haskell projects.
158+
159+
## IOGX: A Flake Template for Haskell Projects at IOG
160+
161+
IOGX is a flake template that offers a development experience for Haskell projects at IOG. Its vision is to provide a JSON-like, declarative interface to Nix, enabling developers unfamiliar with the Nix language to maintain and enhance the Nix sources independently with minimal effort.
162+
163+
### Getting Started with IOGX
164+
165+
Kick-start your project with IOGX by running the following command:
166+
```
167+
nix flake init --template github:input-output-hk/iogx
168+
```
169+
This command generates a `flake.nix` and a `nix` folder containing various file templates.
170+
These files form the *filesystem-based* API of IOGX.
171+
172+
The next steps involve populating the templates in the `nix` folder, leaving `flake.nix` mostly untouched.
173+
Based on the contents of the `nix` folder, IOGX populates your flake outputs.
174+
175+
### IOGX Features
176+
177+
IOGX comes packed with numerous features that enhance the Haskell development process:
178+
179+
- **GHC Build Matrices**: IOGX enables defining a set of GHC versions, for each of which it generates `devShells`, `packages`, `apps`, `checks`, and `hydraJobs`. These outputs also include profiled builds and Windows cross-compiled builds.
180+
181+
- **Extensible Development Shells**: Every `devShell` comes with a complete Haskell toolchain that can be easily extended with new packages, custom scripts, environment variables, and hooks.
182+
183+
- **Automatic Hydra Jobset**: By default, your `hydraJobs` will include every Haskell component in your project. Test suites will run in CI automatically.
184+
185+
- **Easy Code Formatting**: IOGX employs [`pre-commit-hooks`](https://github.com/cachix/pre-commit-hooks.nix) for source tree formatting. These hooks are easily configurable and run automatically in CI unless explicitly disabled.
186+
187+
- **Read The Docs Support**: If your project requires a [Read The Docs](https://readthedocs.org) site, IOGX will include the necessary tools and scripts and add the relevant derivations to CI.
188+
189+
To delve deeper into IOGX and its API, refer to the comprehensive [API Reference](https://github.com/input-output-hk/iogx#3-api-reference). IOGX aims to facilitate a pleasant and efficient development process for Haskell projects at IOG, minimizing the need for extensive Nix language knowledge.
190+
191+
## Final Thoughts
192+
193+
**TODO ...**

0 commit comments

Comments
 (0)