Skip to content

Commit

Permalink
nix: restore dev shell
Browse files Browse the repository at this point in the history
This commit restores a working behavior for `nix-shell` or `nix
develop`, for all supported GHC versions.

When entering a `nix-shell`, or `nix develop
.#haskell-language-server-ghcXxX-dev` you will get an environment with
all the dependencies needed to run `cabal build`.

This commit simplifies the mechanism. Before, the shell was populated
with multiples GHC packages built by nix. These packages are the
dependencies which are used by `nix build` to build
haskell-language-server.

However, cabal may ignore theses dependencies according to its build
plan, so this approach had the following limitations:

- It was building dependencies which were not used during the build
- The nix shell may fail to start if an (possibly unneeded) dependency
  was failing to build.

This new approach does not try to build Haskell dependencies with nix
and use cabal for that.

This changes the following:

- cabal is responsible for the dependencies in the shell. As a developer
  using nix, you'll have the same workflow / dependencies as what will
  be used by a developer using another build environment (i.e. `cabal`
  or `stack` without nix).
- nix won't try to build haskell dependencies and hence won't fail if
  dependencies cannot be built.
- A bit of the code has been simplified, because we do not try to load
  Haskell dependencies in the nix-shell, we can remove all the logic
  used to detect dependencies (and take into account broken plugins).

It however means that the dependencies used by `nix build` won't be
tried until we effectively call `nix build` (or someone try to build
haskell-language-server using a nix flake).

Entering nix-shell also generates an alias command `cabal_project` which
runs cabal with the correct project file if needed (e.g. for GHC 9.0 and
9.2). Users are
  • Loading branch information
guibou committed Jan 31, 2022
1 parent 6c6bc0f commit 9958922
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 64 deletions.
8 changes: 0 additions & 8 deletions configuration-ghc-901.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,9 @@
{ pkgs }:

let
disabledPlugins = [
"hls-brittany-plugin"
"hls-stylish-haskell-plugin"
];

hpkgsOverride = hself: hsuper:
with pkgs.haskell.lib;
{
hlsDisabledPlugins = disabledPlugins;

fourmolu = hself.fourmolu_0_4_0_0;
primitive-extras = hself.primitive-extras_0_10_1_2;

Expand All @@ -31,6 +24,5 @@ let
});
};
in {
inherit disabledPlugins;
tweakHpkgs = hpkgs: hpkgs.extend hpkgsOverride;
}
17 changes: 0 additions & 17 deletions configuration-ghc-921.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,9 @@
{ pkgs, inputs }:

let
disabledPlugins = [
"hls-brittany-plugin"
"hls-stylish-haskell-plugin"
"hls-hlint-plugin"
"hls-haddock-comments-plugin"
"hls-alternate-number-format-plugin"
"hls-eval-plugin"
"hls-tactics-plugin"
# That one is not technically a plugin, but by putting it in this list, we
# get it removed from the top level list of requirement and it is not pull
# in the nix shell.
"shake-bench"
];

hpkgsOverride = hself: hsuper:
with pkgs.haskell.lib;
{
hlsDisabledPlugins = disabledPlugins;

fourmolu = hself.callCabal2nix "fourmolu" inputs.fourmolu {};
primitive-extras = hself.primitive-extras_0_10_1_2;
ghc-exactprint = hself.callCabal2nix "ghc-exactprint" inputs.ghc-exactprint {};
Expand Down Expand Up @@ -52,6 +36,5 @@ let
});
};
in {
inherit disabledPlugins;
tweakHpkgs = hpkgs: hpkgs.extend hpkgsOverride;
}
91 changes: 52 additions & 39 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -236,47 +236,60 @@
dontInstall = true;
};

# Create a development shell of hls project
# See https://github.com/NixOS/nixpkgs/blob/5d4a430472cafada97888cc80672fab255231f57/pkgs/development/haskell-modules/make-package-set.nix#L319
mkDevShell = hpkgs: cabalProject:
with pkgs;
hpkgs.shellFor {
doBenchmark = true;
packages = p:
with builtins;
map (name: p.${name}) (attrNames
# Disable dependencies should not be part of the shell.
(removeAttrs hlsSources (hpkgs.hlsDisabledPlugins or [])));
# For theses tools packages, we use ghcDefault
# This removes a rebuild with a different GHC version
# Theses programs are tools, used as binary, independently of the
# version of GHC.
# The drawback of this approach is that our shell may pull two GHC
# version in scope (the `ghcDefault` one, and the one defined in
# `hpkgs`.)
# The advantage is that we won't have to rebuild theses tools (and
# dependencies) with a recent GHC which may not be supported by
# them.
buildInputs = [ gmp zlib ncurses capstone tracy (gen-hls-changelogs ghcDefault) pythonWithPackages ]
++ [
pkgs.cabal-install
ghcDefault.hie-bios
hlint
# ormolu
# stylish-haskell
ghcDefault.opentelemetry-extra
];
mkDevShell = hpkgs: cabalProject: with pkgs; mkShell {
# For theses tools packages, we use ghcDefault
# This removes a rebuild with a different GHC version
# Theses programs are tools, used as binary, independently of the
# version of GHC.
# The drawback of this approach is that our shell may pull two GHC
# version in scope (the default one, and the one defined in
# `hpkgs`.)
# The advantage is that we won't have to rebuild theses tools (and
# dependencies) with a recent GHC which may not be supported by
# them.
buildInputs = [
# our compiling toolchain
hpkgs.ghc
pkgs.cabal-install
# @guibou: I'm not sure hie-bios is needed
ghcDefault.hie-bios
# Dependencies needed to build some parts of hackage
gmp zlib ncurses
# Changelog tooling
(gen-hls-changelogs ghcDefault)
# For the documentation
pythonWithPackages
# @guibou: I'm not sure this is needed.
hlint
ghcDefault.opentelemetry-extra
capstone tracy
# ormolu
# stylish-haskell
];

src = null;
shellHook = ''
export LD_LIBRARY_PATH=${gmp}/lib:${zlib}/lib:${ncurses}/lib:${capstone}/lib
export DYLD_LIBRARY_PATH=${gmp}/lib:${zlib}/lib:${ncurses}/lib:${capstone}/lib
export PATH=$PATH:$HOME/.local/bin
${(pre-commit-check ghcDefault).shellHook}

alias cabal='cabal --project-file=${cabalProject}'
'';
};
shellHook = ''
# @guibou: I'm not sure theses lines are needed
export LD_LIBRARY_PATH=${gmp}/lib:${zlib}/lib:${ncurses}/lib:${capstone}/lib
export DYLD_LIBRARY_PATH=${gmp}/lib:${zlib}/lib:${ncurses}/lib:${capstone}/lib
export PATH=$PATH:$HOME/.local/bin
# Enable the shell hooks
${(pre-commit-check ghcDefault).shellHook}
# If the cabal project file is not the default one.
# Print a warning and generate an alias.
if [ ${cabalProject} != "cabal.project" ]
then
echo "Cabal won't be able to build your project without using the project file "${cabalProject}", such as:"
echo " cabal --project-file=${cabalProject}"
echo "An alias "cabal_project" is available. Use it like:"
echo " cabal_project build"
alias cabal_project='cabal --project-file=${cabalProject}'
fi
'';
};
# Create a hls executable
# Copied from https://github.com/NixOS/nixpkgs/blob/210784b7c8f3d926b7db73bdad085f4dc5d79418/pkgs/development/tools/haskell/haskell-language-server/withWrapper.nix#L16
mkExe = hpkgs:
Expand Down

0 comments on commit 9958922

Please sign in to comment.