This is my personal configuration for home manager
By default, import <nixpkgs> { } will implicitly use an empty or user-defined configuration in ~/.nixpkgs/config.nix
Also may need to increase size of tmpfs, as nix uses this as part of building the store.
look for something like /run/user/1000
df -h
sudo mount -o remount,size=2G /run/user/1000
- https://nix.dev/recommended-reading
- https://haskell4nix.readthedocs.io/nixpkgs-users-guide.htmlhttps://haskell4nix.readthedocs.io/
- https://ryantm.github.io/nixpkgs/builders/trivial-builders/#chap-trivial-builders
https://discourse.nixos.org/t/nix-haskell-development-2020/6170
nix-prefetch-git https://github.com/nixos/nixpkgs-channels.git refs/heads/nixos-20.03 > nix/nixos-20.03.json
You can use 'trival builders' https://ryantm.github.io/nixpkgs/builders/trivial-builders/#chap-trivial-builders to write files to the nix store and create bash scripts.
x = pkgs.writeShellScriptBin "my-file"
''
echo "hello my file 243"
'';
my-cow-message = pkgs.writeText "my-cow-message2"
''
hello matt!
'';
my-cow = pkgs.writeShellApplication {
name = "my-cow-example";
runtimeInputs = [ pkgs.cowsay pkgs.bat ];
text =
''
cowsay < ${my-cow-message}
'';
};
# in terminal
./my-cow-example
ghc version has its own packages. Be careful, if you use a new ghc, you could get errors since older packages might not support this ghc yet.
{ compiler ? "ghc883" }:
pkgs.haskell.packages."${compiler}"
You need to add this to .bashrc so nix is added to the path so we can access the nix packages.
# add nix to the path and then start the tmuxinator which is nix based
if [ -e $HOME/.nix-profile/etc/profile.d/nix.sh ]; then
source $HOME/.nix-profile/etc/profile.d/nix.sh
tmuxinator
fi
Run the initial setup which will build all the derivations which may take a while.
home-manager switch
docker daemon cant connect when installing it via home-manager. https://docs.docker.com/install/linux/docker-ce/ubuntu/
sudo usermod -aG docker your-user
Instruct the terminal to start tmuxinator.
Create a custom launcher
right click panel > panel > add items > add a launcher > within the laucher add an xfce terminal
go into the configuration and then add this startup command
xfce4-terminal -e 'tmuxinator start'
Tell intellij where openjdk is within the nix-store. You can find this out by doing
which java
ls -ln ~/.nix-profile/bin | grep java
# get the path from above, you'll notice its in the lib directory
cd /nix/store/rj4ryx8xbwy1mmlv6l21ciqzak1v9dig-home-manager-path/lib
Create a custom launcher with this command
google-chrome-stable --password-store=basic
use tmux list-windows to find the custom layout syntax after building the layout you want within tmux.
nix-channel --update
home-manager switch
nix-shell is perhaps one of the most valuable tools in the Nix toolset. In a sentence, it allows users to enter a sub-shell with specific Nix packages set-up in a sort-of virtual environment.
haskell packaging is a little weird - https://nixos.org/nixpkgs/manual/#how-to-create-a-development-environment
Instead of the default package set haskellPackages, you can also use the more precise name haskell.compiler.ghc7102, which has the advantage that it refers to the same GHC version regardless of what Nixpkgs considers “default” at any given time. The below statements are the same.
nix-shell --pure -p haskellPackages.ghc haskellPackages.cabal-install
nix-shell --pure -p haskell.compiler.ghc865 haskell.packages.ghc865.cabal-install
you can create shell.nix and using mkShell derivation to bootstrap a shell without having to do it via
cli.
everything is a derivation (recipe on how to build something). If an application isnt on nixpkgs, you can
create it yourself like I did with daml.
The general tip is that there are build phases, you can override them to suit your goals. https://nixos.org/nixpkgs/manual/#ssec-controlling-phases
The interesting thing is, in the fixup phase, it will call this bash function patchShebangs which will
make sure all bash scripts in a directory or file have their shebang bash bash referring to the nix store version.
patchShebangs fileA dirA dirB ...
There is also another function where you call specifiy the single file to replace something in.
substituteInPlace ./install.sh \
--replace '/usr/bin/env bash' ${bash}/bin/bash
https://maybevoid.com/posts/2019-01-27-getting-started-haskell-nix.html https://haskell-at-work.com/episodes/2018-05-13-introduction-to-cabal.html
nix is used to manage dependencies rather than have stack do it
--pure - The --pure flag makes sure that you can only access the packages you have defined, so that you do not accidentally use global packages that you have installed on your system.
--run lets you execute the command automatically without needing to manually enter the shell.
cd ~/haskell/sample
nix-shell --pure -p haskell.compiler.ghc865 haskell.packages.ghc865.cabal-install --run "cabal init"
haskell.packages.ghc865.ghcWithPackages represents additional packages/libraries to register
with ghc so you can import them into cabal build file.
You will see there are often 2 variants of packages in the nix store, 1 within haskellPackages.*,
and the other in the global package space.
This statement is saying that I want mtl, pandoc available in ghc that I can import or declare
as a dependency in the cabal file. To prove this
Note: You might be curious as to the similarity to these
haskell.packages.ghc865.cabal-install - use cabal-install which has been build with ghc865
haskell.compiler.ghc865 - the actual compiler, no packages
nix-shell --pure -p "haskell.packages.ghc865.ghcWithPackages (haskellPackages: with haskellPackages; [ mtl pandoc ])" cabal-install ghcid hlint brittany
ghc-pkg list mtl
ghc-pkg list pandoc
The the rest cabal-install ghcid hlint brittany are just available
globally in the nix shell as they are tools used for development etc, not actual libraries.
Its useful to have these globally, since vscode depends some of these to work with plugins as it
assumes they are available on the $PATH.
nix-shell --pure -p "haskell.packages.ghc865.ghcWithPackages (haskellPackages: with haskellPackages; [ mtl pandoc ])" cabal-install ghcid hlint brittany
nix-shell --pure -p "haskell.packages.ghc865.ghcWithPackages (haskellPackages: with haskellPackages; [ megaparsec ])"
You can use the cabal new-* commands to to anything else
https://www.parsonsmatt.org/2018/05/19/ghcid_for_the_win.html
nix-shell --pure -p "haskell.packages.ghc865.ghcWithPackages (p: with pkgs; [ghcid cabal-install which])""
nix-env -f "<nixpkgs>" -qaP -A haskellPackages
or use nix repl
nix repl
:l <nixpkgs>
haskellPackages.<tab>
haskell.packages.<tab>
code --list-extensions --show-versions
Include --unpack if its a tarball
nix-prefetch-url --unpack https://github.com/bitcoinunlimited/bitcoinunlimited/archive/9fcdbf50585744696c74c162398cea4f026efda4.tar.gz
nix-prefetch-url https://panaeon.gallery.vsassets.io/_apis/public/gallery/publisher/panaeon/extension/dhall-lang/0.0.4/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage
config.nix contains the haskell package overrides as per nix docs https://nixos.org/nixpkgs/manual/#users-guide-to-the-haskell-infrastructure
It may be confusing what packages already come preinstalled with the haskell.packages. Its easier to just
create a nix-shell and see if the command already exists!
nix-shell '<nixpkgs>' -A myHaskellEnv
Note the section on configuring the cache
https://github.com/Infinisil/all-hies
nix-shell --pure -p ghc cabal-install --run "cabal init" nix-shell --pure -p cabal2nix --run "cabal2nix ." > default.nix nix-shell --pure -p ghc ghcid which
nix-shell --pure -p ghc cabal-install --run "cabal install && cabal update"
makeWrapper
${pkgs.myVsCode}/bin/code
$out/bin/code
--prefix PATH : ${lib.makeBinPath [ hieWrapper ]}
pkgs.runCommand "${pkgs.myVsCode.name}" {
nativeBuildInputs = [ pkgs.makeWrapper ];
} ''
echo "MAKING COMMAND ${pkgs.myVsCode.name}"
mkdir -p
echo "makeWrapper args" echo "${pkgs.myVsCode}/bin/code" echo "$out/bin/code"
wrapProgram
wrapProgram ${pkgs.myVsCode}/bin/code --prefix PATH : ${lib.makeBinPath [ hie ]}
my-haskell-env = self.haskell.packages.ghc865.ghcWithHoogle (haskellPackages: with haskellPackages; [ hlint brittany mtl dhall ghcid # hoogle # dhall-json # dhall-lsp-server ]);
derivation .drv is a receipe describing what you want to build. Its really just an attribute set
with a few special key=value pairs.
you then 'realise' the derivation but executes the side effect of running the recipe to build something.
the cool thing with nix is, each derivations default toString is to print out derivation path.
builtins.toString coreutils
"${coreutils}"
nix gives you a $out path which is pre calculated based on the inputs of the derivation. this is where your builder scripts will place the build artifacts. Think of $out as this nice safe place nix creates for you waiting for you to put your build artifact files. It's like Nix reserved a slot in the nix store for us, and we must fill it.
if you make your own derivation, you must make sure to create an $out directory otherwise derivation will fail to be created.
this means you can refer to other derivations by using "${pkgs.name}/bin" because the $out paths are already known since they are all determined by a hash of the derivation inputs.
the .drv file is the representation of the build action to perform in order to build the out path. it has buildInputs which needs to be built before this .drv can be built.
every attribute in the derivation attribute set, is available an as environment variable in the builder script.
installing libraries with nix-env is not good practice. We prefer to have isolated environments for development.
nix-shell is great for spinning up a isolated sandbox with all the dependencies you need without polluting
your main system. use nixos or home-manager to manage system packages.
during playing around, you'll likely create lots of generations so its good to do some clean up.
The thing with garbage collecting is that previous generations can still hold a reference to the deleted package making it ineligble for garbage collection.
# install a package to try out
nix-env -iA nixpkgs.bsdgames
nix-store -q --roots `which fortune`
# => look at the path to the store (it should be gone after nix-collect-garbage)
# The nix-store command can be used to query the GC roots that refer to a given derivation. In this case, our current user environment does refer to bsd-games.
nix-store -q --roots `which fortune`
nix-env --list-generations
# now try remove it
nix-env -e bsd-games
nix-collect-garbage
ls -l ${the original nix-store location of bsdgames}
It wasnt removed because older profiles refer to this package. so we need to clean up and remove old profiles
# the -d option of nix-collect-garbage is used to delete old generations of all profiles, then collect garbage.
nix-collect-garbage -d
# I think something like this also does a similar thing
ls -l /nix/var/nix/profiles/per-user/matt
nix-env --delete-generations old
home-manager generations
home-manager (follow the prompts)
given you have a .nix file (demo.nix) with a function
{ a, b, c, d }:
stdenv.mkDerivation {
...
}
its annoying to have to pass this in manually at the callsite
let
demo = import ./demo.nix with pkgs; { inherit a b c d };
# NEW
p = import <nixpkgs> {};
demo = p.callPackage demo { d = overrideThisPackageOnly; }
because input args and package names are often the same, this essentially just finds which args
you need for nixpkgs and calls the function for you automatically!
nix and cabal is all you need, no need for stack anymore.
To create a new haskell project. Note how I copy a ghcid configuration that nix home-manager creates.
This is because its the only way to get the vs code extension to run ghcid with a custom command of using
cabal new-repl rather than the defaul cabal repl.
The issue with ghcid is that when you try use it with multiple modules sometimes it refreshes with only 1 module active. You need to go to another module, make a type and this will reload it and pick back up the other modules...
cabal-install is the cabal cli tool.
mkdir my-project
cd my-project
nix-shell --pure -p ghc cabal-install --run "cabal init && cp ~/.ghcid ."
nix-shell --pure -p ghc cabal-install --run "cabal init"
nix-shell --pure -p cabal2nix --run "cabal2nix ." > default.nix
nix-shell --pure -p ghc ghcid cabal-install which
The simplest way is to add ghc-options to the cabal file so its centralised in 1 place for ghcid to pickup.
using cabal version 3
cabal-version: 3.0
name: m4
version: 0.1.0.0
build-type: Simple
extra-source-files: CHANGELOG.md
common shared-properties
default-language: Haskell2010
build-depends:
base >=4.12 && <4.13
ghc-options:
-Wall
-Wincomplete-record-updates
-Wincomplete-uni-patterns
-Wredundant-constraints
-ferror-spans
-fno-break-on-exception
-fno-break-on-error
executable m4
import: shared-properties
main-is: Main.hs
other-modules: Contra