Compiling a yesod project on nixos

Recently I wrote a couple of little scripts for helping build haskell projects on nixos.  Here’s how to use them to help build a yesod project.

In this example I’ve checked out my scripts with git into my home directory, like so:

[bburdette@nixosthe1 ~]$ git clone https://github.com/bburdette/hsnixinit.git

Here I’m assuming that there’s no ghc (or yesod) installed with nix-env.  I like to leave them uninstalled, and set up dependencies in my projects to pull them in as needed.  However, to get started we’ll need the ‘yesod’ utility to create a yesod skeleton project.   At this point I should say I’m planning to use a nixpkgs repo that I cloned, in case I want to add some packages (purescript).  Its important to use the yesod-bin that goes with this repo, because of all the version dependencies it puts into the .cabal file when you make a scaffolding project.  If you don’t plan on using your own repo, just omit “~/nixpkgs” in the steps below.

So let’s install yesod-bin from my nixpkgs repo:

[bburdette@nixosthe1 blah3]$ nix-env -i yesod-bin -f ~/nixpkgs
installing `yesod-bin-1.2.12.3'
building path(s) `/nix/store/xci405330nsjqwmk4qw7azglgdfzbw0s-user-environment'
created 6095 symlinks in user environment
[bburdette@nixosthe1 blah3]$ cd ..
[bburdette@nixosthe1 ~]$ yesod init
Welcome to the Yesod scaffolder.
I'm going to be creating a skeleton Yesod project for you.

What do you want to call your project? We'll use this for the cabal name.

Project name: blah4
Yesod uses Persistent for its (you guessed it) persistence layer.
This tool will build in either SQLite or PostgreSQL or MongoDB support for you.
We recommend starting with SQLite: it has no dependencies.

s = sqlite
p = postgresql
pf = postgresql + Fay (experimental)
mongo = mongodb
mysql = MySQL
simple = no database, no auth
url = Let me specify URL containing a site (advanced)

So, what'll it be? s
That's it! I'm creating your files now...

---------------------------------------

___
{-) |\
[m,].-"-. /
[][__][__] \(/\__/\)/
[__][__][__][__]~~~~ | |
[][__][__][__][__][] / |
[__][__][__][__][__]| /| |
[][__][__][__][__][]| || | ~~~~
ejm [__][__][__][__][__]__,__, \__/
---------------------------------------

The foundation for your web application has been built.
There are a lot of resources to help you use Yesod.
Start with the book: http://www.yesodweb.com/book
Take part in the community: http://yesodweb.com/page/community
Start your project:

cd blah4 && cabal sandbox init && cabal install --enable-tests .
[bburdette@nixosthe1 ~]$ nix-env -e yesod-bin
uninstalling `yesod-bin-1.2.12.3'

Ok, now I have a blah4.cabal file.  I uninstalled yesod-bin again at the end so I won’t use the wrong version for creating another project.  Now to create a shell.nix and default.nix to pull in the dependencies – ghc, etc.


[bburdette@nixosthe1 blah4]$ ~/hsnixinit/setup.sh blah4 ~/nixpkgs
[bburdette@nixosthe1 blah4]$ ls
app devel.hs Model.hs shell.nix
Application.hs Foundation.hs blah4.cabal static
config Handler ns templates
default.nix Import.hs Settings tests
deploy messages Settings.hs

So the new files are default.nix, shell.nix and the script ns.  Next, let’s pull in the dependencies with the ‘ns’ script – which is just a shortcut for “nix-shell -I nixpkgs=~/nixpkgs”.  At this stage you may get a lot of compiling happening, or downloading of binary packages.  On my system I already have the packages so it only changes the prompt to nix-shell.

Once ‘ns’ completes, then we “cabal sandbox init”, and then “cabal install” to build the project.

[bburdette@nixosthe1 blah4]$ ./ns

[nix-shell:~/blah4]$ cabal sandbox init
Writing a default package environment file to
/home/bburdette/blah4/cabal.sandbox.config
Creating a new sandbox at /home/bburdette/blah4/.cabal-sandbox

[nix-shell:~/blah4]$ cabal install
Resolving dependencies...
Notice: installing into a sandbox located at
/home/bburdette/blah4/.cabal-sandbox
Configuring blah4-0.0.0...
Building blah4-0.0.0...
Installed blah4-0.0.0

[nix-shell:~/blah4]$ 

So that’s that. The project can be run. But, now the “yesod” command is missing, and we’d like that in order to run the server in development mode, where it automatically recompiles the project whenever source code files change.

To make that available, we’ll add it in to the ‘default.nix’ file, at the top and in a new section, buildTools.


{ cabal, aeson, conduit, dataDefault, fastLogger, hjsmin, hspec
, httpConduit, monadControl, monadLogger, persistent
, persistentSqlite, persistentTemplate, resourcet, shakespeare
, text, transformers, waiExtra, waiLogger, warp, yaml, yesod
, yesodAuth, yesodCore, yesodForm, yesodStatic, yesodTest, 
yesodBin
}:

cabal.mkDerivation (self: {
  pname = "blah4";
  version = "0.0.0";
  src=./.;
  isLibrary = true;
  isExecutable = true;
  buildDepends = [
    aeson conduit dataDefault fastLogger hjsmin httpConduit
    monadControl monadLogger persistent persistentSqlite
    persistentTemplate shakespeare text waiExtra waiLogger warp yaml
    yesod yesodAuth yesodCore yesodForm yesodStatic
  ];
  buildTools = [ yesodBin ];
  testDepends = [
    hspec monadLogger persistent persistentSqlite resourcet
    transformers yesod yesodCore yesodTest
  ];
  meta = {
    license = self.stdenv.lib.licenses.unfree;
    platforms = self.ghc.meta.platforms;
  };
})

After editing the file, exit from nix-shell and reenter it again to pull in the yesod tool.

[nix-shell:~/blah4]$ exit
exit
[bburdette@nixosthe1 blah4]$ ./ns

[nix-shell:~/blah4]$ yesod devel
Yesod devel server. Press ENTER to quit