Skip to content

Commit

Permalink
Add inferno cache and switch CI to build with Nix (#24)
Browse files Browse the repository at this point in the history
Closes #21 

There are some instructions in the readme on how to enable the new
Inferno cache for local development.

CI will now build with Nix and push the artifacts to the cache. If you
configure the cache locally you can pull them, making most Nix rebuilds
much faster.

CI jobs will generally be faster. They'll only be slower (albeit
considerably slower) when large updates happen with dependencies (e.g. a
new haskell.nix revision)

I also disabled HLS in the dev shells (this is unrelated to the changes
in this PR but I discovered it while making the changes here; see #25
for more details)
  • Loading branch information
ngua authored Jan 11, 2023
1 parent 552fd3f commit 75b278c
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 104 deletions.
49 changes: 0 additions & 49 deletions .github/workflows/build-and-test.yml

This file was deleted.

32 changes: 32 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: build

on:
workflow_dispatch:
push:
branches:
- "main"
pull_request:
branches:
- "main"

concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 300
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v18
with:
extra_nix_config: |
substituters = https://cache.nixos.org https://cache.iog.io
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=
- uses: cachix/cachix-action@v8
with:
name: inferno
authToken: "${{ secrets.CACHIX_TOKEN }}"
- run: |
nix build -L .#
69 changes: 48 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,18 @@ Specifically, the project comprises of:
* Basic prelude
* A version control server to manage script histories and versions

## Dev Setup
## Nix prerequisites

We currently only offer a Nix-based build system for building and developing `inferno` packages. You can build the project components directly with Nix or enter a Nix-based development environment to build or work on the project with Cabal.

### Nix prerequisites

1. Install Nix v2.8 or greater
### Install Nix v2.8 or greater

If you don't have Nix installed, follow the directions [here](https://nixos.org/download.html). This repository uses flakes, an up-and-coming Nix feature, and we recommend installing v2.8 or greater for the best compatibility.
If you don't have Nix installed, follow the directions [here](https://nixos.org/download.html). This repository uses flakes, a new Nix feature, and we recommend installing v2.8 or greater for the best compatibility.

2. Enable required flakes settings
### Enable required flakes settings

Certain features that flakes require are still marked as experimental and must be explicitly enabled.
Certain features that flakes require are still marked as experimental and must be explicitly enabled. These features are required to build or develop this project.

On non-NixOS systems, edit `~/.config/nix/nix.conf` or `/etc/nix/nix.conf` and add the following lines:

Expand All @@ -37,29 +36,39 @@ experimental-features = nix-command flakes

On NixOS, you can add the same line to `nix.extraOptions` in your system configuration.

3. Set up IOG's binary caches
### Configure the binary caches

This project uses IOG's `haskell.nix`; IOG provides binary caches which must be used in order to build this project. When you first run a `nix` command in this repository, you will be prompted to allow certain configuration values to be set:
It is _highly_ recommended to configure two extra Nix binary caches to download artifacts when building this project. We offer our own public [Cachix](https://cachix.org) cache (`inferno`) that is populated on CI. Since this project uses IOG's `haskell.nix`, you should also add IOG's
binary caches. Although our cache contains some of the same artifacts as IOG's, you should still configure the latter in case a critical dependency (e.g. GHC) has not yet been cached by us, Cachix is experiencing an outage, or you make local changes that would require rebuilding a large dependency (e.g. upgrading to a new GHC version).

**Important**: If you do not enable at least IOG's binary cache, you _will_ build GHC from source several times! This will take at least several hours in most cases.

There are two methods for enabling the caches. The flake will attempt to set the relevant values for you automatically. Caveats apply to this process, so you may need to enable them manually.

#### Automatic configuration

When you first run a `nix` command in this repository, you will be prompted to allow certain configuration values to be set:

```
$ nix develop
do you want to allow configuration setting 'extra-substituters' to be set to 'https://cache.iog.io' (y/N)? y
do you want to allow configuration setting 'extra-substituters' to be set to 'https://cache.iog.io https://inferno.cachix.org' (y/N)? y
do you want to permanently mark this value as trusted (y/N)? y
do you want to allow configuration setting 'extra-trusted-public-keys' to be set to 'hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=' (y/N)? y
do you want to allow configuration setting 'extra-trusted-public-keys' to be set to 'hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= inferno.cachix.org-1:48GsOmEfRPXpTZsQSmnD2P42lpbUeHrjlzyhasL5rug=' (y/N)? y
do you want to permanently mark this value as trusted (y/N)? y
```

Accepting these prompts will set the required configuration values for you. Marking them as trusted will ensure that they are used for future `nix` invocations in this repository.
Accepting these prompts will set the required configuration values for you. Marking them as trusted will ensure that they are used for future `nix` invocations in this repository. No further configuration is required.

If you would prefer to configure the binary caches manually, you can do so by following the instructions [here](https://input-output-hk.github.io/haskell.nix/tutorials/getting-started.html#setting-up-the-binary-cache).
**Important**: If you are on NixOS or otherwise using a multi-user Nix install, you **must** be a trusted user to set substituters. If you are not a trusted user, enabling the options prompted by the flake will have no effect (non-trusted users are disallowed from doing this) and you must configure the caches manually.

**Important**: If you do not enable the binary caches, you _will_ build GHC from source several times! If you find yourself building GHC despite having set the required configuration values (or allowed the flake to do so for you), something has gone wrong:
If you see output similar to

- If you set the cache values manually, make sure that you restarted the Nix daemon on non-NixOS systems
- If you accepted the prompts from the flake, you may not have permissions to set these values. Either set them manually in your system-wide configuration or continue reading below
```
warning: ignoring untrusted substituter 'https://cache.iog.io'
```

**Important**: If you are on NixOS or otherwise using a multi-user Nix install, you **must** be a trusted user to set substituters. If you are not a trusted user, enabling the options prompted by the flake will have no effect (non-trusted users are disallowed from doing this).
when running a `nix` command, you are not a trusted user and the settings from the flake will not be applied even if you have selected `y` for each prompt.

On non-NixOS systems, add the following to the system-wide configuration (`/etc/nix/nix.conf`):

Expand All @@ -75,9 +84,27 @@ trusted-users = @wheel root

On NixOS, add the user/group name to the list under [`nix.settings.trusted-users`](https://search.nixos.org/options?show=nix.settings.trusted-users).

If you do not wish to add yourself as a trusted user, you will need to configure the binary caches [manually](https://input-output-hk.github.io/haskell.nix/tutorials/getting-started.html#setting-up-the-binary-cache).
If you do not wish to add yourself as a trusted user, you will need to configure the binary caches manually as explained below.

#### Manual configuration

**Note**: Even after configuring IOG's binary caches, you will still need to build a large number of Haskell libraries as IOG does not cache these. Even if you are building dozens of Haskell libraries, this is not unusual.
##### IOG's cache

You can configure IOG's cache manually by following the instructions [here](https://input-output-hk.github.io/haskell.nix/tutorials/getting-started.html#setting-up-the-binary-cache). Again, not enabling this cache will require you to build GHC from source several times.

##### The `inferno` cache

The `inferno` cache can be manually enabled in two ways:

- By installing the [`cachix`](https://search.nixos.org/packages?show=cachix) CLI tool and then running `cachix use inferno`. This method is preferable if you are already using Cachix for other binary caches (e.g. `https://nix-community.cachix.org/`)
- By manually copying the cache URL (`https://inferno.cachix.org`) and key (`inferno.cachix.org-1:48GsOmEfRPXpTZsQSmnD2P42lpbUeHrjlzyhasL5rug=`) to `substituters` and `trusted-public-keys`, respectively, in `/etc/nix/nix.conf`

#### Troubleshooting

If you find yourself building GHC despite having set the required configuration values (or allowed the flake to do so for you), something has gone wrong:

- If you set the cache values manually, make sure that you restarted the Nix daemon on non-NixOS systems
- If you accepted the prompts from the flake, you may not have permissions to set these values. Either set them manually in your system-wide configuration or continue reading below

### Building or working on the project

Expand Down Expand Up @@ -139,7 +166,7 @@ $ nix build .#inferno-lsp-server
$ ./result/bin/inferno-lsp-server
```

#### Entering a development environment
### Entering a development environment

To enter a development environment suitable for working on the `inferno` project itself, use `nix develop`. `cabal`, `haskell-language-server`, and other development tools will be available in the shell.

Expand All @@ -150,7 +177,7 @@ $ cabal repl inferno-core

Do note that building with Cabal directly outside of this Nix environment (that is, by installing the package set directly with a version of Cabal installed on your system) _will not work_.

##### Developing frontend packages
#### Developing frontend packages

There are two flake packages that build VS Code extensions for Inferno, `vscode-inferno-syntax-highlighting` and `vscode-inferno-lsp-server`. Two identically named `devShells` correspond to these packages and can be entered to work on them. After entering the development environment, `cd` to the directory containing the sources for the extension; for example:

Expand All @@ -161,7 +188,7 @@ $ cd ./vscode-inferno-syntax-highlighting

`npm` and all of the JS dependencies are available in the shell. The `NODE_PATH` points to generated `node_modules` in the Nix store and the environment variable `NPM_CONFIG_PACKAGE_LOCK_ONLY` is enabled. This is to ensure that the same dependencies are used everywhere (i.e. in the flake's `packages` as well as the corresponding `devShells`). Accordingly, `npm install` will only update the `package-lock.json`. After modifying dependencies listed in the `package.json`, update the lockfile, exit the shell, and then re-enter it using `nix develop`.

#### Formatting all sources
### Formatting all sources

To format all of the Nix and Haskell sources, run `nix fmt`. **Note**: this command assumes that certain executables are available on the `PATH`; please enter the development environment with `nix develop` before trying to run the formatter.

Expand Down
88 changes: 54 additions & 34 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
# These are required to build the project, otherwise GHC will be built from
# source (this is not always possible using haskell.nix either), so it makes
# sense to enable them directly in the flake
extra-substituters = [ "https://cache.iog.io" ];
extra-substituters = [
"https://cache.iog.io"
"https://inferno.cachix.org"
];
extra-trusted-public-keys = [
"hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ="
"inferno.cachix.org-1:48GsOmEfRPXpTZsQSmnD2P42lpbUeHrjlzyhasL5rug="
];
bash-prompt = "\\[\\e[0;37m\\](\\[\\e[0m\\]nix) \\[\\e[0;1;91m\\]inferno \\[\\e[0m\\]\\w \\[\\e[0;1m\\\\[\\e[0m\\]";
};
Expand Down Expand Up @@ -75,29 +79,31 @@
# This also means that everything needs to be parameterized by `pkgs`

# Get the autogenerated flake outputs from `haskell.nix`, for different
# GHC versions
flakesFor = pkgs: builtins.listToAttrs
# GHC versions, with or without profiling enabled
flakesFor = pkgs: {
"${defaultCompiler}-prof" = (
infernoFor {
inherit pkgs;
compiler = defaultCompiler;
profiling = true;
ghcOptions = [ "-eventlog" ];
}
).flake { };
}
// builtins.listToAttrs
(
# only GHC 8.10.7 or newer is supported on M1 Macs
lib.lists.forEach
(
[ defaultCompiler ]
++ lib.optional (pkgs.system != "aarch64-darwin") "ghc884"
# only GHC 8.10.7 or newer is supported on M1 Macs
++ lib.optional (pkgs.system != "aarch64-darwin") "ghc884"
)
(compiler: lib.attrsets.nameValuePair
compiler
# TODO
# Do we want to enable any `crossPlatforms` here?
((infernoFor { inherit compiler pkgs; }).flake { })
) ++
lib.lists.forEach [ defaultCompiler ]
(compiler: lib.attrsets.nameValuePair
(compiler + "-prof")
((infernoFor {
inherit compiler pkgs;
profiling = true;
ghcOptions = [ "-eventlog" ];
}).flake { })
(compiler:
lib.attrsets.nameValuePair
compiler
# TODO
# Do we want to enable any `crossPlatforms` here?
((infernoFor { inherit compiler pkgs; }).flake { })
)
);

Expand All @@ -111,16 +117,20 @@
compiler-nix-name = compiler;
src = builtins.path {
path = ./.;
filter = path: type:
filter = path: _:
builtins.any
(ext: baseNameOf path != ext)
[ ".nix" ".md" ];
(ext: !lib.hasSuffix ext path)
[ ".nix" ".md" ".yml" ];
};
shell = {
withHoogle = true;
tools = {
cabal = { };
haskell-language-server = { };
# FIXME
# See https://github.com/plow-technologies/inferno/issues/25
#
# # This is the final supported version for our current compilers
# haskell-language-server = "1.8.0.0";
};
buildInputs = [ pkgs.nixpkgs-fmt ] ++
# ormolu build currently segfaults on the M1
Expand Down Expand Up @@ -226,6 +236,8 @@
};
in
lib.attrsets.mapAttrs'
# FIXME
# `ghc884` is broken, see https://github.com/plow-technologies/inferno/issues/23
(compiler: v: lib.attrsets.nameValuePair compiler v.devShell)
flakes
// {
Expand All @@ -248,25 +260,33 @@
};
in
ps // {
# Build all packages and checks
default = pkgs.runCommand "check"
# Build all `packages`, `checks`, and `devShells`
default = pkgs.runCommand "everything"
{
combined = builtins.attrValues self.checks.${system}
++ builtins.attrValues ps;
combined = builtins.concatLists
[
(builtins.attrValues self.checks.${system})
(builtins.attrValues ps)
(
lib.mapAttrsToList
(_: v: v.inputDerivation)
(
# See https://github.com/plow-technologies/inferno/issues/23
builtins.removeAttrs self.devShells.${system} [ "ghc884" ]
)
)
];
}
''
echo $combined
touch $out
'';
};

apps =
let
inherit (flakes.${defaultCompiler}) apps;
in
{
inferno-lsp-server = apps."inferno-lsp:exe:inferno-lsp-server";
} // collectOutputs "apps" flakes;
apps = collectOutputs "apps" flakes // {
inferno-lsp-server =
flakes.${defaultCompiler}.apps."inferno-lsp:exe:inferno-lsp-server";
};

# Usage: `nix build .#checks.<SYSTEM>.<check>`, e.g.
#
Expand Down

0 comments on commit 75b278c

Please sign in to comment.